v0.9[edit]

Note Card[edit]

ChatGPT_API_Key[edit]
sk-##########################################
ChatGPT_Model[edit]
gpt-4-turbo
ChatGPT_Charactor[edit]
貴方は美術館の説明員です.
美術の質問以外については答えてはいけません.
答えは日本語で答えます.

Code[edit]

NSL ChatGPT for OpenSimulator[edit]
// NSL ChatGPT for OpenSimulator v1.3.1
//

integer command_channel = 0;
integer listen_hdl = 0;
integer say_bufsize = 320; // < 1023バイト以下での UTF-8(3Byte) の文字数

float   gap_time = 4.0;
integer time_count = 0;

// ChatGPT API のエンドポイント
string  api_url = "https://api.openai.com/v1/chat/completions";

// ChatGPT API の変数
string  api_key = "";
string  api_model = "";
string  api_chara = "";

// Note Card
string  chara_notecard_name  = "ChatGPT_Charactor";
string  model_notecard_name  = "ChatGPT_Model";
string  gptkey_notecard_name = "ChatGPT_API_Key";

key     chara_notecard_key  = NULL_KEY;
key     model_notecard_key  = NULL_KEY;
key     gptkey_notecard_key = NULL_KEY;

integer chara_notecard_line  = 0;
integer model_notecard_line  = 0;
integer gptkey_notecard_line = 0;

string  chara_notecard  = "";
string  model_notecard  = "";
string  gptkey_notecard = "";


// ChatGPT API の JSON データのテンプレート.記載されていないパラメータはデフォルト値 
string  json_templ = "{
 \"model\": \"\",
 \"user\": \"\",
 \"messages\":[
    {
      \"role\": \"system\",
      \"content\": \"\"
    },
   {
      \"role\": \"user\",
      \"content\": \"\"
    }
 ],
 \"stream\": false 
}";


//
key    user_key  = NULL_KEY;
key    npc_key   = NULL_KEY;
string user_name = "";


// ノートカードから最初の一行を読み込む
key read_notecard_first(string notecard_name)
{
   if (llGetInventoryType(notecard_name)==INVENTORY_NOTECARD) {
       key notecard_key = llGetNotecardLine(notecard_name, 0);
       return notecard_key;
   }
   return NULL_KEY;
}


// 全てのノートカードを読み込む
read_notecards()
{
   chara_notecard  = "";   
   model_notecard  = "";
   gptkey_notecard = "";
   
   chara_notecard_key  = read_notecard_first(chara_notecard_name);
   gptkey_notecard_key = read_notecard_first(gptkey_notecard_name);
   model_notecard_key  = read_notecard_first(model_notecard_name);
}


// ChatGPTの APIに _messageを送信する.
request_gpt_api(string _message)
{
   string _json_body = "";
   _json_body = llJsonSetValue(json_templ, ["model"], api_model);
   _json_body = llJsonSetValue(_json_body, ["user"],  user_key);
   _json_body = llJsonSetValue(_json_body, ["messages", 0, "content"], api_chara);
   _json_body = llJsonSetValue(_json_body, ["messages", 1, "content"], _message);
   //llSay(0, _json_body);
   
   llHTTPRequest(api_url, 
       [
           HTTP_MIMETYPE, "application/json",
           HTTP_METHOD, "POST",
           HTTP_BODY_MAXLENGTH, 16384,
           //HTTP_ACCEPT, "application/json",
           HTTP_CUSTOM_HEADER, "Authorization", "Bearer " + api_key
       ],
       _json_body
   );
}


start_conversation(string _name)
{
   //llSay(0, "Start Conversation");
   request_gpt_api("こんにちは.私は " + _name + " です");
   llListen(0, "", NULL_KEY, "");
}


short_conversation(string _message)
{
   if (npc_key == NULL_KEY) {
       llRegionSayTo(user_key, 0, _message);
   }
   else {
       osNpcSayTo(npc_key, user_key, 0, _message);
   }
}


stop_conversation()
{
   string _message = "バイバイ.";
   short_conversation(_message);
}


init_state()
{
   //llSay( 0, "NSL ChatGPT Running");
   llSetTimerEvent(0);
   llResetTime();
   
   read_notecards();
   
   if (command_channel != 0) {
       if (listen_hdl!=0) llListenRemove(listen_hdl);
       listen_hdl = llListen(command_channel, "", NULL_KEY, "");
       //llSay(0, "init_state: listen Channel = " + command_channel);
   }
}



//////////////////////////////////////////////////////////////////////////////////////////////////////
default
{
   on_rez(integer _param)
   {
       command_channel = _param;
       if (command_channel != 0) {
           if (listen_hdl!=0) llListenRemove(listen_hdl);
           listen_hdl = llListen(command_channel, "", NULL_KEY, "");
           //llSay(0, "on_rez: listen Channel = " + command_channel);
       }
   }
   
   
   state_entry()
   {
       init_state();
   }
 
  
   touch_start(integer _num_detected)
   {
       user_key  = llDetectedKey(0);
       user_name = llDetectedName(0);
       npc_key   = NULL_KEY;
       start_conversation(user_name);
   }


   listen(integer _ch, string _name, key _id, string _message)
   {
       //llSay(0, "Receive Data from " + _ch + ": " + _id + ": " + _message); 
       // from Controller
       //      /### start user_key npc_key user_first_name user_last_name 
       if (_ch != 0 && _ch == command_channel) {
           list   _items = llParseString2List(_message, [" "], []);
           string _cmd   = llList2String(_items, 0);

           if (llToLower(_cmd) == "start") {
               integer _len = llGetListLength(_items);
               if (_len > 3) {
                   user_key  = llList2String(_items, 1);
                   npc_key   = llList2String(_items, 2);
                   user_name = llList2String(_items, 3);
                   if (_len > 4) user_name += " " + llList2String(_items, 4); 
                   start_conversation(user_name);
               }
           }
           else if (llToLower(_cmd) == "stop") {
               stop_conversation();
               llDie();
           }
       }
       // from User
       else if (_id == user_key) {
           //llSay(0, _message);
           request_gpt_api(_message);
           //
           llSetTimerEvent(gap_time);
           llResetTime();
           time_count = 0;
       }
       else {
           llSay(0, "NOING");
       }
   } 


   changed(integer _change)
   {
       if (_change & CHANGED_INVENTORY) {
           //llSay(0, "Reread NoteCards");
           read_notecards();
       }
   }


   // ノートカードが一行読まれる度に発生するイベント
   dataserver(key _requested_key, string _data)
   {
       // GPT Charactor
       if (_requested_key == chara_notecard_key) {
           if (_data != EOF){
               chara_notecard += _data + "\n";
               chara_notecard_line++;
               chara_notecard_key = llGetNotecardLine(chara_notecard_name, chara_notecard_line);
           }
           else {
               api_chara = chara_notecard;
           }
       }
       // GPT API キー
       else if (_requested_key == gptkey_notecard_key) {
           if (_data != EOF){
               gptkey_notecard += _data;
               gptkey_notecard_line++;
               gptkey_notecard_key = llGetNotecardLine(gptkey_notecard_name, gptkey_notecard_line);
           }
           else {
               api_key = gptkey_notecard;
           }
       }
       // GPT API Model
       else if (_requested_key == model_notecard_key ) {
           if (_data != EOF){
               model_notecard += _data;
               model_notecard_line++;
               model_notecard_key = llGetNotecardLine(model_notecard_name, model_notecard_line);
           }
           else {
               api_model = model_notecard;
           }
       }
   }


   http_response(key _request_id, integer _status, list _metadata, string _body)
   {
       llSetTimerEvent(0);
       time_count = 0;
       //
       if (_status == 200) {
           string _content = llJsonGetValue(_body, ["choices", 0, "message", "content"]);
           //llSay(0, "BODY SIZE = " + llStringLength(_body));
           //llSay(0, "CONTENT SIZE = " + llStringLength(_content));
           //llSay(0, "Data = " + _body);
           
           if (npc_key == NULL_KEY) {
               for (integer p=0; p<llStringLength(_content); p+=say_bufsize) {
                   llRegionSayTo(user_key, 0, llGetSubString(_content, p, p+say_bufsize-1));
               }
           }
           else {
               for (integer p=0; p<llStringLength(_content); p+=say_bufsize) {
                   osNpcSayTo(npc_key, user_key, 0, llGetSubString(_content, p, p+say_bufsize-1));
               }
           }
       }
       // エラー応答
       else {
           if (npc_key == NULL_KEY) {
               llRegionSayTo(user_key, 0, "リクエスト失敗: " + (string)_status + ", 応答内容: " + _body);
           }
           else {
               osNpcSayTo(npc_key, user_key, 0, "リクエスト失敗: " + (string)_status + ", 応答内容: " + _body);
           }
       }
   }
   
   
   timer()
   {
       if      (time_count==0) short_conversation("少々おまちください.");
       else if (time_count==2) short_conversation("もうしばらくおまちください.");
       else if (time_count==5) short_conversation("時間が掛かっています.");
       time_count++;
   }
}
NPC and NSL_ChatGPT Rezzer[edit]
// NPC and NSL_ChatGPT Rezzer v1.1.2
//   support NSL_ChatCPT is v1.3.1
//

integer DEFAULT_CHANNEL = 683;
integer listen_hdl = 0;
//string anim_name = "irassyaimase";

string  fname = "プロ生";
string  lname = "ちゃん";
string  appear_name = "ProNama_Red_Appearance";

// NPC List
integer list_stride = 3;
list npc_list = []; // [user_key, npc_key, channel] の繰り返し


// 指定したユーザがリストにあるかどうかをチェックする.
//   ユーザが存在する場合は,npc_list中の位置を返す.
//   ユーザが存在しない場合は -1 を返す
integer check_user_list(key _user_key)
{
   integer _indx = 0;
   integer _len = llGetListLength(npc_list);
   
   for(_indx=0; _indx<_len; _indx+=list_stride) {
       if (_user_key == (key)npc_list[_indx]) {
           return _indx;
       }
   } 
   return -1;
}


// 指定したNPCがリストにあるかどうかをチェックする.
//   NPCが存在する場合は,npc_list中の位置を返す.
//   NPCが存在しない場合は -1 を返す
integer check_npc_list(key _npc_key)
{
   integer _indx = 0;
   integer _len = llGetListLength(npc_list);
   
   for(_indx=0; _indx<_len; _indx+=list_stride) {
       if (_npc_key == (key)npc_list[_indx + 1]) {
           return _indx;
       }
   } 
   return -1;
}


// 指定したチャンネル番号がリストにあるかどうかをチェックする.
//   チャンネル番号が存在する場合は,npc_list中の位置を返す.
//   チャンネル番号が存在しない場合は -1 を返す
integer check_channel_list(integer _channel)
{
   integer _indx = 0;
   integer _len = llGetListLength(npc_list);
   
   for(_indx=0; _indx<_len; _indx+=list_stride) {
       if (_channel == (integer)npc_list[_indx + 2]) {
           return _indx;
       }
   } 
   return -1;
}


integer  get_valid_channel()
{
   integer _channel = DEFAULT_CHANNEL + 1;
   
   integer _indx = check_channel_list(_channel);
   while (_indx != -1) {
       _channel++;
       _indx = check_channel_list(_channel);
   }   
   return _channel;
}


// NPC の作成と NSL ChatGPT の Rez
key create_npc(key _user_key, vector _user_pos)
{
   vector _npc_pos = llGetPos();
   key _npc_key = osNpcCreate(fname, lname, _npc_pos, appear_name, OS_NPC_SENSE_AS_AGENT);

   vector _move_to = _user_pos - llVecNorm(_user_pos - _npc_pos)*1.5; // 1.5m 離れた所
   osNpcMoveTo(_npc_key, _move_to);
   
   integer _channel = get_valid_channel();
   llRezObject("NSL_ChatGPT", osNpcGetPos(_npc_key), <0.0, 0.0, 0.0>, <0.0, 0.0, 0.0, 1.0>, _channel);
   npc_list = npc_list + [_user_key, _npc_key, _channel];

   //llOwnerSay("NPC Key = " + _npc_key + ", Channel = " + _channel);
   
   return _npc_key;
}


delete_all_npc()
{
   integer _len = llGetListLength(npc_list);
   integer _indx = 0;
   for (_indx=0; _indx<_len; _indx += list_stride) {
       key _npc_key = (key)npc_list[_indx + 1];
       osNpcRemove(_npc_key);
   }
   npc_list = [];
}


init_script()
{
   if (listen_hdl!=0) llListenRemove(listen_hdl);
   listen_hdl = llListen(DEFAULT_CHANNEL, "", NULL_KEY, "");

   delete_all_npc();
}


////////////////////////////////////////////////////////////////////////////////////////////

default
{
   state_entry()
   {
       //llSay(0, "Script running");
       init_script();
   }
   
   
   touch_start(integer _number)
   {
       key    _user_key  = llDetectedKey(0);
       string _user_name = llDetectedName(0);
       vector _user_pos  = llDetectedPos(0);
       
       integer _indx = check_user_list(_user_key);
       
       // NPC と ChatGPT を起動
       if (_indx==-1) {
           key _npc_key = create_npc(_user_key, _user_pos);
           llSleep(1.0);
           integer _num = check_npc_list(_npc_key);
           if (_num>=0) {
               integer _channel = (integer)npc_list[_num + 2];
               string  _npc_name = fname + lname;
               string  _command = "start " + _user_key + " " + _npc_key + " " + _user_name;
               llRegionSay(_channel, _command);
               //llSay(0, "Send Data to " + _channel + ": " + _command);
           }
       }
       // 既にNPCを起動している場合は,ChatGPTとNPCを削除
       else if (_indx>=0) {
           key     _npc_key = (key)npc_list[_indx + 1];
           integer _channel = (integer)npc_list[_indx + 2];
           string  _command = "stop";
           llRegionSay(_channel, _command);
           //llSay(0, "Send Data to " + _channel + ": " + _command);
           llSleep(1.0);
           osNpcRemove(_npc_key);
           npc_list = llListReplaceList(npc_list, [], _indx, _indx + list_stride - 1);
       }
   }
   
   
   listen(integer _ch, string _name, key _id, string _msg) 
   {
       //llSay(0, "Recived Message: " + _msg);
       
       list _items = llParseString2List(_msg, ["=", ",", " ", "\n"], []);       
       string _cmd = llList2String(_items, 0);
       string _opr = llList2String(_items, 1);

       if      (_cmd=="" || _cmd==" ");
       else if (llToLower(_cmd)=="delete" || llToLower(_cmd)=="del") {
           if (_id == llGetOwner()) {
               if (llToLower(_opr) == "all") {
                   delete_all_npc();
               }
               else {
                   key _npc_key = (key)_opr;
                   osNpcRemove(_npc_key);
                   integer _indx = check_npc_list(_npc_key);
                   if (_indx>=0) npc_list = llListReplaceList(npc_list, [], _indx, _indx + list_stride - 1);
               }
           }
       }
   }
   

   //
   on_rez(integer _start_param) 
   {
       init_script();
       llResetScript();
   }
  
   
   changed(integer _change)
   {
       //地域が再起動された場合
       if (_change & CHANGED_REGION_START) {
           init_script();
           llResetScript();
       }
       else if (_change & CHANGED_INVENTORY) {
           init_script();
           llResetScript();
       }   
   }                
}

トップ   新規 ページ一覧 検索 最終更新   ヘルプ   最終更新のRSS