From a84f13e7ba3e89489d08fbc2b68e9e8557cf399b Mon Sep 17 00:00:00 2001 From: kwaroran Date: Sun, 30 Jun 2024 22:28:20 +0900 Subject: [PATCH] ref: lua --- src/ts/process/lua.ts | 704 ++++++++++++++++++++++++++++++++++++- src/ts/process/triggers.ts | 312 +--------------- 2 files changed, 706 insertions(+), 310 deletions(-) diff --git a/src/ts/process/lua.ts b/src/ts/process/lua.ts index dbbb4674..8b0f5b59 100644 --- a/src/ts/process/lua.ts +++ b/src/ts/process/lua.ts @@ -1,15 +1,699 @@ -import type { LuaEngine } from "wasmoon"; -import type { character, groupChat } from "../storage/database"; -import { risuChatParser } from "../parser"; +import { getChatVar, risuChatParser, setChatVar } from "../parser"; +import { LuaEngine, LuaFactory } from "wasmoon"; +import type { Chat, character, groupChat } from "../storage/database"; +import { get } from "svelte/store"; +import { CurrentCharacter, CurrentChat } from "../stores"; +import { alertError, alertInput, alertNormal } from "../alert"; +import { HypaProcesser } from "./memory/hypamemory"; +import { generateAIImage } from "./stableDiff"; +import { writeInlayImage } from "./files/image"; +import type { OpenAIChat } from "."; +import { requestChatData } from "./request"; +import { v4 } from "uuid"; -export let LuaSafeIds = new Set() +let luaFactory:LuaFactory +let luaEngine:LuaEngine +let lastCode = '' +let LuaSafeIds = new Set() +let LuaLowLevelIds = new Set() -export function registerLuaProcess(engine:LuaEngine, char:character|groupChat) { - engine.global.set('cbs', (code:string) => { - const parsed = risuChatParser(code, { - chara: char, +export async function runLua(code:string, arg:{ + char?:character|groupChat, + chat?:Chat + setVar?: (key:string, value:string) => void, + getVar?: (key:string) => string, + lowLevelAccess?: boolean, + mode?: string +}){ + const char = arg.char ?? get(CurrentCharacter) + const setVar = arg.setVar ?? setChatVar + const getVar = arg.getVar ?? getChatVar + const mode = arg.mode ?? 'manual' + let chat = arg.chat ?? get(CurrentChat) + let stopSending = false + let lowLevelAccess = arg.lowLevelAccess ?? false + + if(!luaEngine || lastCode !== code){ + if(luaEngine){ + luaEngine.global.close() + } + if(!luaFactory){ + makeLuaFactory() + } + luaEngine = await luaFactory.createEngine() + luaEngine.global.set('cbs', (code:string) => { + const parsed = risuChatParser(code, { + chara: char, + }) + return parsed }) - return parsed - }) + luaEngine.global.set('setChatVar', (id:string,key:string, value:string) => { + if(!LuaSafeIds.has(id)){ + return + } + setVar(key, value) + }) + luaEngine.global.set('getChatVar', (id:string,key:string) => { + if(!LuaSafeIds.has(id)){ + return + } + return getVar(key) + }) + luaEngine.global.set('stopChat', (id:string) => { + if(!LuaSafeIds.has(id)){ + return + } + stopSending = true + }) + luaEngine.global.set('alertError', (id:string, value:string) => { + if(!LuaSafeIds.has(id)){ + return + } + alertError(value) + }) + luaEngine.global.set('alertNormal', (id:string, value:string) => { + if(!LuaSafeIds.has(id)){ + return + } + alertNormal(value) + }) + luaEngine.global.set('alertInput', (id:string, value:string) => { + if(!LuaSafeIds.has(id)){ + return + } + return alertInput(value) + }) + luaEngine.global.set('setChat', (id:string, index:number, value:string) => { + if(!LuaSafeIds.has(id)){ + return + } + const message = chat.message?.at(index) + if(message){ + message.data = value + } + CurrentChat.set(chat) + }) + luaEngine.global.set('setChatRole', (id:string, index:number, value:string) => { + if(!LuaSafeIds.has(id)){ + return + } + const message = chat.message?.at(index) + if(message){ + message.role = value === 'user' ? 'user' : 'char' + } + CurrentChat.set(chat) + }) + luaEngine.global.set('cutChat', (id:string, start:number, end:number) => { + if(!LuaSafeIds.has(id)){ + return + } + chat.message = chat.message.slice(start,end) + CurrentChat.set(chat) + }) + luaEngine.global.set('removeChat', (id:string, index:number) => { + if(!LuaSafeIds.has(id)){ + return + } + chat.message.splice(index, 1) + CurrentChat.set(chat) + }) + luaEngine.global.set('addChat', (id:string, role:string, value:string) => { + if(!LuaSafeIds.has(id)){ + return + } + let roleData:'user'|'char' = role === 'user' ? 'user' : 'char' + chat.message.push({role: roleData, data: value}) + CurrentChat.set(chat) + }) + luaEngine.global.set('insertChat', (id:string, index:number, role:string, value:string) => { + if(!LuaSafeIds.has(id)){ + return + } + let roleData:'user'|'char' = role === 'user' ? 'user' : 'char' + chat.message.splice(index, 0, {role: roleData, data: value}) + CurrentChat.set(chat) + }) + luaEngine.global.set('removeChat', (id:string, index:number) => { + if(!LuaSafeIds.has(id)){ + return + } + chat.message.splice(index, 1) + CurrentChat.set(chat) + }) + luaEngine.global.set('getChatLength', (id:string) => { + if(!LuaSafeIds.has(id)){ + return + } + return chat.message.length + }) + luaEngine.global.set('getFullChatMain', (id:string) => { + const data = JSON.stringify(chat.message.map((v) => { + return { + role: v.role, + data: v.data + } + })) + return data + }) + + luaEngine.global.set('setFullChatMain', (id:string, value:string) => { + const realValue = JSON.parse(value) + if(!LuaSafeIds.has(id)){ + return + } + chat.message = realValue.map((v) => { + return { + role: v.role, + data: v.data + } + }) + CurrentChat.set(chat) + }) + + luaEngine.global.set('logMain', (value:string) => { + console.log(JSON.parse(value)) + }) + + //Low Level Access + luaEngine.global.set('similarity', (id:string, source:string, value:string[]) => { + if(!LuaLowLevelIds.has(id)){ + return + } + const processer = new HypaProcesser('MiniLM') + processer.addText(value) + return processer.similaritySearch(source) + }) + + luaEngine.global.set('generateImage', async (id:string, value:string, negValue:string = '') => { + if(!LuaLowLevelIds.has(id)){ + return + } + const gen = await generateAIImage(value, char as character, negValue, 'inlay') + if(!gen){ + return 'Error: Image generation failed' + } + const imgHTML = new Image() + imgHTML.src = gen + const inlay = await writeInlayImage(imgHTML) + return `{{inlay::${inlay}}}` + }) + + luaEngine.global.set('LLMMain', async (id:string, promptStr:string) => { + let prompt:{ + role: string, + content: string + }[] = JSON.parse(promptStr) + if(!LuaLowLevelIds.has(id)){ + return + } + let promptbody:OpenAIChat[] = prompt.map((dict) => { + let role:'system'|'user'|'assistant' = 'assistant' + switch(dict['role']){ + case 'system': + case 'sys': + role = 'system' + break + case 'user': + role = 'user' + break + case 'assistant': + case 'bot': + case 'char':{ + role = 'assistant' + break + } + } + + return { + content: dict['content'] ?? '', + role: role, + } + }) + const result = await requestChatData({ + formated: promptbody, + bias: {}, + useStreaming: false, + noMultiGen: true, + }, 'model') + + if(result.type === 'fail'){ + return JSON.stringify({ + success: false, + result: 'Error: ' + result.result + }) + } + + if(result.type === 'streaming' || result.type === 'multiline'){ + return JSON.stringify({ + success: false, + result: result.result + }) + } + + return JSON.stringify({ + success: true, + result: result.result + }) + }) + + luaEngine.global.set('simpleLLM', async (id:string, prompt:string) => { + if(!LuaLowLevelIds.has(id)){ + return + } + const result = await requestChatData({ + formated: [{ + role: 'user', + content: prompt + }], + bias: {}, + useStreaming: false, + noMultiGen: true, + }, 'model') + + if(result.type === 'fail'){ + return { + success: false, + result: 'Error: ' + result.result + } + } + + if(result.type === 'streaming' || result.type === 'multiline'){ + return { + success: false, + result: result.result + } + } + + return { + success: true, + result: result.result + } + }) + + await luaEngine.doString(luaCodeWarper(code)) + lastCode = code + } + let accessKey = v4() + LuaSafeIds.add(accessKey) + if(lowLevelAccess){ + LuaLowLevelIds.add(v4()) + } + let res:any + try { + switch(mode){ + case 'input':{ + const func = luaEngine.global.get('onInput') + if(func){ + res = await func(accessKey) + } + } + case 'output':{ + const func = luaEngine.global.get('onOutput') + if(func){ + res = await func(accessKey) + } + } + case 'start':{ + const func = luaEngine.global.get('onStart') + if(func){ + res = await func(accessKey) + } + } + default:{ + const func = luaEngine.global.get(mode) + if(func){ + res = await func(accessKey) + } + } + } + if(res === false){ + stopSending = true + } + } catch (error) { + + alertError('Lua Error: ' + error) + console.error(error) + } + + LuaSafeIds.delete(accessKey) + LuaLowLevelIds.delete(accessKey) + + return { + stopSending, chat, res + } } +async function makeLuaFactory(){ + luaFactory = new LuaFactory() + await luaFactory.mountFile(`json.lua`,String.raw` +-- +-- json.lua +-- +-- Copyright (c) 2020 rxi +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- +local json = { _version = "0.1.2" } +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- +local encode +local escape_char_map = { + [ "\\" ] = "\\", + [ "\"" ] = "\"", + [ "\b" ] = "b", + [ "\f" ] = "f", + [ "\n" ] = "n", + [ "\r" ] = "r", + [ "\t" ] = "t", +} +local escape_char_map_inv = { [ "/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end +local function escape_char(c) + return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) +end +local function encode_nil(val) + return "null" +end +local function encode_table(val, stack) + local res = {} + stack = stack or {} + -- Circular reference? + if stack[val] then error("circular reference") end + stack[val] = true + if rawget(val, 1) ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end +function json.encode(val) + return ( encode(val) ) +end +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- +local parse +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(1, 4), 16 ) + local n2 = tonumber( s:sub(7, 10), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end +local function parse_string(str, i) + local res = "" + local j = i + 1 + local k = j + while j <= #str do + local x = str:byte(j) + if x < 32 then + decode_error(str, j, "control character in string") + elseif x == 92 then -- '\': Escape + res = res .. str:sub(k, j - 1) + j = j + 1 + local c = str:sub(j, j) + if c == "u" then + local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) + or str:match("^%x%x%x%x", j + 1) + or decode_error(str, j - 1, "invalid unicode escape in string") + res = res .. parse_unicode_escape(hex) + j = j + #hex + else + if not escape_chars[c] then + decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") + end + res = res .. escape_char_map_inv[c] + end + k = j + 1 + elseif x == 34 then -- '"': End of string + res = res .. str:sub(k, j - 1) + return res, j + 1 + end + j = j + 1 + end + decode_error(str, i, "expected closing quote for string") +end +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + local res, idx = parse(str, next_char(str, 1, space_chars, true)) + idx = next_char(str, idx, space_chars, true) + if idx <= #str then + decode_error(str, idx, "trailing garbage") + end + return res +end +return json +`); +} + +function luaCodeWarper(code:string){ + return ` +json = require 'json' + +function getFullChat(id) + return json.decode(getFullChatMain(id)) +end + +function setFullChat(id, value) + setFullChatMain(id, json.encode(value)) +end + +function log(value) + logMain(json.encode(value)) +end + +function LLM(id, prompt) + return json.decode(LLMMain(id, json.encode(prompt))) +end + +${code} +` +} \ No newline at end of file diff --git a/src/ts/process/triggers.ts b/src/ts/process/triggers.ts index 1c01f5e8..4e1efe3d 100644 --- a/src/ts/process/triggers.ts +++ b/src/ts/process/triggers.ts @@ -12,14 +12,8 @@ import { HypaProcesser } from "./memory/hypamemory"; import { requestChatData } from "./request"; import { generateAIImage } from "./stableDiff"; import { writeInlayImage } from "./files/image"; -import { LuaEngine, LuaFactory } from "wasmoon"; -import { v4 } from "uuid"; +import { runLua } from "./lua"; -let luaFactory:LuaFactory -let luaEngine:LuaEngine -let lastCode = '' -let LuaSafeIds = new Set() -let LuaLowLevelIds = new Set() export interface triggerscript{ comment: string; @@ -548,301 +542,19 @@ export async function runTrigger(char:character,mode:triggerMode, arg:{ break } case 'triggerlua':{ - if(!luaEngine || lastCode !== effect.code){ - if(luaEngine){ - luaEngine.global.close() - } - luaFactory = new LuaFactory() - luaEngine = await luaFactory.createEngine() - luaEngine.global.set('cbs', (code:string) => { - const parsed = risuChatParser(code, { - chara: char, - }) - return parsed - }) - luaEngine.global.set('setChatVar', (id:string,key:string, value:string) => { - if(!LuaSafeIds.has(id)){ - return - } - setVar(key, value) - }) - luaEngine.global.set('getChatVar', (id:string,key:string) => { - if(!LuaSafeIds.has(id)){ - return - } - return getVar(key) - }) - luaEngine.global.set('stopChat', (id:string) => { - if(!LuaSafeIds.has(id)){ - return - } - stopSending = true - }) - luaEngine.global.set('alertError', (id:string, value:string) => { - if(!LuaSafeIds.has(id)){ - return - } - alertError(value) - }) - luaEngine.global.set('alertNormal', (id:string, value:string) => { - if(!LuaSafeIds.has(id)){ - return - } - alertNormal(value) - }) - luaEngine.global.set('alertInput', (id:string, value:string) => { - if(!LuaSafeIds.has(id)){ - return - } - return alertInput(value) - }) - luaEngine.global.set('setChat', (id:string, index:number, value:string) => { - if(!LuaSafeIds.has(id)){ - return - } - const message = chat.message?.at(index) - if(message){ - message.data = value - } - CurrentChat.set(chat) - }) - luaEngine.global.set('setChatRole', (id:string, index:number, value:string) => { - if(!LuaSafeIds.has(id)){ - return - } - const message = chat.message?.at(index) - if(message){ - message.role = value === 'user' ? 'user' : 'char' - } - CurrentChat.set(chat) - }) - luaEngine.global.set('cutChat', (id:string, start:number, end:number) => { - if(!LuaSafeIds.has(id)){ - return - } - chat.message = chat.message.slice(start,end) - CurrentChat.set(chat) - }) - luaEngine.global.set('removeChat', (id:string, index:number) => { - if(!LuaSafeIds.has(id)){ - return - } - chat.message.splice(index, 1) - CurrentChat.set(chat) - }) - luaEngine.global.set('addChat', (id:string, role:string, value:string) => { - if(!LuaSafeIds.has(id)){ - return - } - let roleData:'user'|'char' = role === 'user' ? 'user' : 'char' - chat.message.push({role: roleData, data: value}) - CurrentChat.set(chat) - }) - luaEngine.global.set('insertChat', (id:string, index:number, role:string, value:string) => { - if(!LuaSafeIds.has(id)){ - return - } - let roleData:'user'|'char' = role === 'user' ? 'user' : 'char' - chat.message.splice(index, 0, {role: roleData, data: value}) - CurrentChat.set(chat) - }) - luaEngine.global.set('removeChat', (id:string, index:number) => { - if(!LuaSafeIds.has(id)){ - return - } - chat.message.splice(index, 1) - CurrentChat.set(chat) - }) - luaEngine.global.set('getChatLength', (id:string) => { - if(!LuaSafeIds.has(id)){ - return - } - return chat.message.length - }) - luaEngine.global.set('getFullChat', (id:string) => { - if(!LuaSafeIds.has(id)){ - return - } - return chat.message.map((v) => { - return { - role: v.role, - data: v.data - } - }) - }) + const triggerCodeResult = await runLua(effect.code,{ + lowLevelAccess: trigger.lowLevelAccess, + mode: mode === 'manual' ? arg.manualName : mode, + setVar: setVar, + getVar: getVar, + char: char, + chat: chat, + }) - luaEngine.global.set('setFullChat', (id:string, value:any[]) => { - if(!LuaSafeIds.has(id)){ - return - } - chat.message = value.map((v) => { - return { - role: v.role, - data: v.data - } - }) - CurrentChat.set(chat) - }) - - //Low Level Access - luaEngine.global.set('similarity', (id:string, source:string, value:string[]) => { - if(!LuaLowLevelIds.has(id)){ - return - } - const processer = new HypaProcesser('MiniLM') - processer.addText(value) - return processer.similaritySearch(source) - }) - - luaEngine.global.set('generateImage', async (id:string, value:string, negValue:string = '') => { - if(!LuaLowLevelIds.has(id)){ - return - } - const gen = await generateAIImage(value, char, negValue, 'inlay') - if(!gen){ - return 'Error: Image generation failed' - } - const imgHTML = new Image() - imgHTML.src = gen - const inlay = await writeInlayImage(imgHTML) - return `{{inlay::${inlay}}}` - }) - - luaEngine.global.set('LLM', async (id:string, prompt:{ - role: string, - content: string - }[]) => { - if(!LuaLowLevelIds.has(id)){ - return - } - let promptbody:OpenAIChat[] = prompt.map((dict) => { - let role:'system'|'user'|'assistant' = 'assistant' - switch(dict['role']){ - case 'system': - case 'sys': - role = 'system' - break - case 'user': - role = 'user' - break - case 'assistant': - case 'bot': - case 'char':{ - role = 'assistant' - break - } - } - - return { - content: dict['content'] ?? '', - role: role, - } - }) - const result = await requestChatData({ - formated: promptbody, - bias: {}, - useStreaming: false, - noMultiGen: true, - }, 'model') - - if(result.type === 'fail'){ - return { - success: false, - result: 'Error: ' + result.result - } - } - - if(result.type === 'streaming' || result.type === 'multiline'){ - return { - success: false, - result: result.result - } - } - - return { - success: true, - result: result.result - } - }) - - luaEngine.global.set('simpleLLM', async (id:string, prompt:string) => { - const result = await requestChatData({ - formated: [{ - role: 'user', - content: prompt - }], - bias: {}, - useStreaming: false, - noMultiGen: true, - }, 'model') - - if(result.type === 'fail'){ - return { - success: false, - result: 'Error: ' + result.result - } - } - - if(result.type === 'streaming' || result.type === 'multiline'){ - return { - success: false, - result: result.result - } - } - - return { - success: true, - result: result.result - } - }) - - await luaEngine.doString(effect.code) - lastCode = effect.code + if(triggerCodeResult.stopSending){ + stopSending = true } - let accessKey = v4() - LuaSafeIds.add(accessKey) - if(trigger.lowLevelAccess){ - LuaLowLevelIds.add(v4()) - } - try { - let res:any - switch(mode){ - case 'input':{ - const func = luaEngine.global.get('onInput') - if(func){ - res = await func(accessKey) - } - } - case 'output':{ - const func = luaEngine.global.get('onOutput') - if(func){ - res = await func(accessKey) - } - } - case 'start':{ - const func = luaEngine.global.get('onStart') - if(func){ - res = await func(accessKey) - } - } - case 'manual':{ - const func = luaEngine.global.get(arg.manualName) - if(func){ - res = await func(accessKey) - } - } - } - if(res === false){ - stopSending = true - } - } catch (error) { - - alertError('Lua Error: ' + error) - console.error(error) - } - - LuaSafeIds.delete(accessKey) - LuaLowLevelIds.delete(accessKey) + chat = triggerCodeResult.chat break } }