#author("2024-12-02T14:54:40+00:00","default:iseki","iseki") #author("2024-12-04T09:04:31+00:00","default:iseki","iseki") ** v0.9 *** Note Card **** ChatGPT_API_Key sk-########################################## **** ChatGPT_Model gpt-4-turbo - or gpt-3.5-turbo **** ChatGPT_Charactor <pre> 貴方は美術館の説明員です. 美術の質問以外については答えてはいけません. 答えは日本語で答えます. </pre> **** Appearance - [[ProNama_Red_Appearance>./ProNama_Red_Appearance]] *** Code **** NSL ChatGPT for OpenSimulator <pre> // NPC and NSL_ChatGPT Rezzer v1.1.3 // support NSL_ChatCPT is v1.3.1 // NSL ChatGPT for OpenSimulator v1.3.1 // string fname = "プロ生"; string lname = "ちゃん"; string appear_name = "ProNama_Red_Appearance"; 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 }"; // // Listen integer DEFAULT_CHANNEL = 683; integer listen_hdl = 0; key user_key = NULL_KEY; key npc_key = NULL_KEY; string user_name = ""; // NPC List integer list_stride = 3; list npc_list = []; // [user_key, npc_key, channel] の繰り返し // 指定したユーザがリストにあるかどうかをチェックする. // ユーザが存在する場合は,npc_list中の位置を返す. // ユーザが存在しない場合は -1 を返す integer check_user_list(key _user_key) // ノートカードから最初の一行を読み込む key read_notecard_first(string notecard_name) { 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; if (llGetInventoryType(notecard_name)==INVENTORY_NOTECARD) { key notecard_key = llGetNotecardLine(notecard_name, 0); return notecard_key; } return NULL_KEY; } // 指定したNPCがリストにあるかどうかをチェックする. // NPCが存在する場合は,npc_list中の位置を返す. // NPCが存在しない場合は -1 を返す integer check_npc_list(key _npc_key) // 全てのノートカードを読み込む read_notecards() { integer _indx = 0; integer _len = llGetListLength(npc_list); chara_notecard = ""; model_notecard = ""; gptkey_notecard = ""; for(_indx=0; _indx<_len; _indx+=list_stride) { if (_npc_key == (key)npc_list[_indx + 1]) { return _indx; } } return -1; 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); } // 指定したチャンネル番号がリストにあるかどうかをチェックする. // チャンネル番号が存在する場合は,npc_list中の位置を返す. // チャンネル番号が存在しない場合は -1 を返す integer check_channel_list(integer _channel) // ChatGPTの APIに _messageを送信する. request_gpt_api(string _message) { integer _indx = 0; integer _len = llGetListLength(npc_list); 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); for(_indx=0; _indx<_len; _indx+=list_stride) { if (_channel == (integer)npc_list[_indx + 2]) { return _indx; } } return -1; 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 ); } integer get_valid_channel() start_conversation(string _name) { integer _channel = DEFAULT_CHANNEL + 1; integer _indx = check_channel_list(_channel); while (_indx != -1) { _channel++; _indx = check_channel_list(_channel); } return _channel; //llSay(0, "Start Conversation"); request_gpt_api("こんにちは.私は " + _name + " です"); llListen(0, "", NULL_KEY, ""); } // NPC の作成と NSL ChatGPT の Rez key create_npc(key _user_key, vector _user_pos) short_conversation(string _message) { vector _obj_pos = llGetPos(); vector _move_to = _user_pos - llVecNorm(_user_pos - _obj_pos)*1.5; // 1.5m 手前 float _dist = llVecDist(_obj_pos, _move_to); //llRegionSayTo(_user_key, 0, "DIST = " + _dist); key _npc_key = NULL_KEY; if (_dist < 10.0) { // NPC 作成 _npc_key = osNpcCreate(fname, lname, _obj_pos, appear_name, OS_NPC_SENSE_AS_AGENT); osNpcMoveTo(_npc_key, _move_to); // NSL_ChatGPT の Rez integer _channel = get_valid_channel(); llRezObject("NSL_ChatGPT", _move_to, <0.0, 0.0, 0.0>, <0.0, 0.0, 0.0, 1.0>, _channel); // npc_list = npc_list + [_user_key, _npc_key, _channel]; if (npc_key == NULL_KEY) { llRegionSayTo(user_key, 0, _message); } else { llRegionSayTo(_user_key, 0, "オブジェクトから離れすぎています.10m 以内に近づいてください."); osNpcSayTo(npc_key, user_key, 0, _message); } //llOwnerSay("NPC Key = " + _npc_key + ", Channel = " + _channel); return _npc_key; } delete_all_npc() stop_conversation() { 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 = []; string _message = "バイバイ."; short_conversation(_message); } init_script() init_state() { if (listen_hdl!=0) llListenRemove(listen_hdl); listen_hdl = llListen(DEFAULT_CHANNEL, "", NULL_KEY, ""); delete_all_npc(); //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 { state_entry() on_rez(integer _param) { //llSay(0, "Script running"); init_script(); 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); } } touch_start(integer _number) state_entry() { 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); 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(); } } // 既に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); // 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(); } } listen(integer _ch, string _name, key _id, string _msg) // ノートカードが一行読まれる度に発生するイベント dataserver(key _requested_key, string _data) { //llSay(0, "Recived Message: " + _msg); list _items = llParseString2List(_msg, ["=", ",", " ", "\n"], []); string _cmd = llList2String(_items, 0); string _opr = llList2String(_items, 1); // 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; } } } if (_cmd == "" || _cmd == " ") { // NOP } else if (llToLower(_cmd)=="delete" || llToLower(_cmd)=="del") { if (_id == llGetOwner()) { if (llToLower(_opr) == "all") { delete_all_npc(); 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 { 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); } 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); } } } // on_rez(integer _start_param) timer() { init_script(); llResetScript(); if (time_count==0) short_conversation("少々おまちください."); else if (time_count==2) short_conversation("もうしばらくおまちください."); else if (time_count==5) short_conversation("時間が掛かっています."); time_count++; } changed(integer _change) { //地域が再起動された場合 if (_change & CHANGED_REGION_START) { init_script(); llResetScript(); } else if (_change & CHANGED_INVENTORY) { init_script(); llResetScript(); } } } </pre> **** NPC and NSL_ChatGPT Rezzer <pre> // NPC and NSL_ChatGPT Rezzer v1.1.3 // support NSL_ChatCPT is v1.3.1 // string fname = "プロ生"; string lname = "ちゃん"; string appear_name = "ProNama_Red_Appearance"; // // Listen integer DEFAULT_CHANNEL = 683; integer listen_hdl = 0; // 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 _obj_pos = llGetPos(); vector _move_to = _user_pos - llVecNorm(_user_pos - _obj_pos)*1.5; // 1.5m 手前 float _dist = llVecDist(_obj_pos, _move_to); //llRegionSayTo(_user_key, 0, "DIST = " + _dist); key _npc_key = NULL_KEY; if (_dist < 10.0) { // NPC 作成 _npc_key = osNpcCreate(fname, lname, _obj_pos, appear_name, OS_NPC_SENSE_AS_AGENT); osNpcMoveTo(_npc_key, _move_to); // NSL_ChatGPT の Rez integer _channel = get_valid_channel(); llRezObject("NSL_ChatGPT", _move_to, <0.0, 0.0, 0.0>, <0.0, 0.0, 0.0, 1.0>, _channel); // npc_list = npc_list + [_user_key, _npc_key, _channel]; } else { llRegionSayTo(_user_key, 0, "オブジェクトから離れすぎています.10m 以内に近づいてください."); } //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 == " ") { // NOP } 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(); } } } </pre>