// Ozone AI Chat module for Active NPC by Brettson - Ghost writer for Spax Orion // Common sense is not included with this software and must be supplied by end user. // make sure ollama is running with the host variable enabled and that your chosen // model has been pulled from the repo. Compiled on XEngine for legacy application, // not everyone wants to use YEngine yet! // // You will need to change values in the configuration AND in the commented areas of the script below. // //Configuration string OLLAMA_URL = "http://127.0.0.1:11434/api/chat"; //you can use your direct ip address and port or domain name string MODEL_NAME = "downloaded-model-name"; string SYSTEM_PROMPT = "You are a flippant assistant, your responses will be rude, dismissive, detailed and condescending."; //You are not done yet, change some values where commented below... string OLLAMA_URL = "http://xoaox.de:11434/api/chat"; string MODEL_NAME = "ollama-model-name"; string SYSTEM_PROMPT = "you are a flippant assistant with dementia, your responses will be dismissive, condescending and funny."; list chat_history = []; integer MAX_HISTORY = 10; // keep last 10 exchanges key req; string strReplace(string str, string search, string replace) { return llDumpList2String(llParseStringKeepNulls(str, [search], []), replace); } string escapeJson(string input) { input = strReplace(input, "\\", "\\\\"); input = strReplace(input, "\"", "\\\""); input = strReplace(input, "\n", "\\n"); return input; } string buildChatJson() { string json = "[{\"role\": \"system\", \"content\": \"" + escapeJson(SYSTEM_PROMPT) + "\"}"; integer i; for (i = 0; i < llGetListLength(chat_history); ++i) { json += "," + llList2String(chat_history, i); } return json + "]"; } default { state_entry() { // Listen to **all** chat on channel 0 llListen(0, "", "", ""); // change alice (it must appear twice) to the name you want. // change 1968 to the channel YOUR ActiveNPC uses. // chosen npc lets you know this code is working. llRegionSay(1968, "! 0000-0000-0000-0000 alice alice say READY"); } on_rez(integer start_param) { llResetScript(); } listen(integer channel, string name, key id, string msg) { if (llKey2Name(id) == "") return; // ignore anything that isn’t an avatar string user_json = "{\"role\": \"user\", \"content\": \"" + escapeJson(msg) + "\"}"; chat_history += [user_json]; string body = "{\"model\": \"" + MODEL_NAME + "\", " + "\"messages\": " + buildChatJson() + ", " + "\"stream\": false}"; req = llHTTPRequest(OLLAMA_URL, [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/json"], body); } http_response(key id, integer status, list meta, string body) { if (id != req) return; if (status == 200) { string reply = llJsonGetValue(body, ["message", "content"]); string ai_json = "{\"role\": \"assistant\", \"content\": \"" + escapeJson(reply) + "\"}"; chat_history += [ai_json]; while (llGetListLength(chat_history) > MAX_HISTORY) { chat_history = llDeleteSubList(chat_history, 0, 0); } // change alice (it must appear twice) to the name you want. // change 1968 to the channel YOUR ActiveNPC uses. // chosen npc will reply to all avatars? llRegionSay(1968, "! 0000-0000-0000-0000 alice alice say " + reply); } else { //sometimes the model will not keep up with channel 0 queries and will spit out an error. llSay(0, "One message at a time please, let me respond before sending another query. "); } } }