diff --git a/src/lib/ChatScreens/Chat.svelte b/src/lib/ChatScreens/Chat.svelte index 57103313..1342f104 100644 --- a/src/lib/ChatScreens/Chat.svelte +++ b/src/lib/ChatScreens/Chat.svelte @@ -7,7 +7,7 @@ import { DataBase, type character, type groupChat } from "../../ts/storage/database"; import { selectedCharID } from "../../ts/stores"; import { translate } from "../../ts/translator/translator"; - import { replacePlaceholders } from "../../ts/util"; + import { risuChatParser } from "src/ts/process/scripts"; export let message = '' export let name = '' export let isLastMemory:boolean @@ -56,13 +56,13 @@ async function displaya(message:string){ if($DataBase.autoTranslate && $DataBase.translator !== ''){ if(msgTranslated==='') - msgDisplay = replacePlaceholders(message, name) - msgDisplay = await translate(replacePlaceholders(message, name), false) + msgDisplay = risuChatParser(message, {chara: name, chatID: idx}) + msgDisplay = await translate(risuChatParser(message, {chara: name, chatID: idx}), false) msgTranslated = msgDisplay translated = true; } else{ - msgDisplay = replacePlaceholders(message, name) + msgDisplay = risuChatParser(message, {chara: name, chatID: idx}) } } @@ -130,13 +130,13 @@ translated = true return } - msgDisplay = (await translate(replacePlaceholders(message, name), false)) + msgDisplay = (await translate(risuChatParser(message, {chara: name, chatID: idx}), false)) msgTranslated = msgDisplay translating = false translated = true } else{ - msgDisplay = replacePlaceholders(message, name) + msgDisplay = risuChatParser(message, {chara: name, chatID: idx}) translated = false } }}> diff --git a/src/ts/process/exampleMessages.ts b/src/ts/process/exampleMessages.ts index 970d7ff4..e27b1780 100644 --- a/src/ts/process/exampleMessages.ts +++ b/src/ts/process/exampleMessages.ts @@ -1,6 +1,6 @@ import type { OpenAIChat } from "."; import type { character } from "../storage/database"; -import { replacePlaceholders } from "../util"; +import { risuChatParser } from "./scripts"; export function exampleMessage(char:character, userName:string):OpenAIChat[]{ if(char.exampleMessage === ''){ @@ -58,7 +58,7 @@ export function exampleMessage(char:character, userName:string):OpenAIChat[]{ result = result.map((r) => { return { role: r.role, - content: replacePlaceholders(r.content, char.name) + content: risuChatParser(r.content, {chara: char}) } }) diff --git a/src/ts/process/index.ts b/src/ts/process/index.ts index e8d7f5f5..ceb2dbd7 100644 --- a/src/ts/process/index.ts +++ b/src/ts/process/index.ts @@ -5,10 +5,10 @@ import { ChatTokenizer, tokenizeNum } from "../tokenizer"; import { language } from "../../lang"; import { alertError } from "../alert"; import { loadLoreBookPrompt } from "./lorebook"; -import { findCharacterbyId, replacePlaceholders } from "../util"; +import { findCharacterbyId } from "../util"; import { requestChatData } from "./request"; import { stableDiff } from "./stableDiff"; -import { processScript, processScriptFull } from "./scripts"; +import { processScript, processScriptFull, risuChatParser } from "./scripts"; import { exampleMessage } from "./exampleMessages"; import { sayTTS } from "./tts"; import { supaMemory } from "./memory/supaMemory"; @@ -183,31 +183,31 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n return chatObjects; } - unformated.main.push(...formatPrompt(replacePlaceholders(mainp + ((db.additionalPrompt === '' || (!db.promptPreprocess)) ? '' : `\n${db.additionalPrompt}`), currentChar.name))) + unformated.main.push(...formatPrompt(risuChatParser(mainp + ((db.additionalPrompt === '' || (!db.promptPreprocess)) ? '' : `\n${db.additionalPrompt}`), {chara: currentChar}))) if(db.jailbreakToggle){ - unformated.jailbreak.push(...formatPrompt(replacePlaceholders(db.jailbreak, currentChar.name))) + unformated.jailbreak.push(...formatPrompt(risuChatParser(db.jailbreak, {chara: currentChar}))) } - unformated.globalNote.push(...formatPrompt(replacePlaceholders(currentChar.replaceGlobalNote?.replaceAll('{{original}}', db.globalNote) || db.globalNote, currentChar.name))) + unformated.globalNote.push(...formatPrompt(risuChatParser(currentChar.replaceGlobalNote?.replaceAll('{{original}}', db.globalNote) || db.globalNote, {chara:currentChar}))) } if(currentChat.note){ unformated.authorNote.push({ role: 'system', - content: replacePlaceholders(currentChat.note, currentChar.name) + content: risuChatParser(currentChat.note, {chara: currentChar}) }) } { - let description = replacePlaceholders((db.promptPreprocess ? db.descriptionPrefix: '') + currentChar.desc, currentChar.name) + let description = risuChatParser((db.promptPreprocess ? db.descriptionPrefix: '') + currentChar.desc, {chara: currentChar}) if(currentChar.personality){ - description += replacePlaceholders("\n\nDescription of {{char}}: " + currentChar.personality,currentChar.name) + description += risuChatParser("\n\nDescription of {{char}}: " + currentChar.personality, {chara: currentChar}) } if(currentChar.scenario){ - description += replacePlaceholders("\n\nCircumstances and context of the dialogue: " + currentChar.scenario,currentChar.name) + description += risuChatParser("\n\nCircumstances and context of the dialogue: " + currentChar.scenario, {chara: currentChar}) } unformated.description.push({ @@ -227,19 +227,19 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n const lorepmt = await loadLoreBookPrompt() unformated.lorebook.push({ role: 'system', - content: replacePlaceholders(lorepmt.act, currentChar.name) + content: risuChatParser(lorepmt.act, {chara: currentChar}) }) if(db.personaPrompt){ unformated.personaPrompt.push({ role: 'system', - content: replacePlaceholders(db.personaPrompt, currentChar.name) + content: risuChatParser(db.personaPrompt, {chara: currentChar}) }) } if(lorepmt.special_act){ unformated.postEverything.push({ role: 'system', - content: replacePlaceholders(lorepmt.special_act, currentChar.name) + content: risuChatParser(lorepmt.special_act, {chara: currentChar}) }) } @@ -275,7 +275,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n const chat:OpenAIChat = { role: 'assistant', content: processScript(nowChatroom, - replacePlaceholders(firstMsg, currentChar.name), + risuChatParser(firstMsg, {chara: currentChar}), 'editprocess') } chats.push(chat) @@ -284,7 +284,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n const ms = currentChat.message for(const msg of ms){ - let formedChat = processScript(nowChatroom,replacePlaceholders(msg.data, currentChar.name), 'editprocess') + let formedChat = processScript(nowChatroom,risuChatParser(msg.data, {chara: currentChar}), 'editprocess') let name = '' if(msg.role === 'char'){ if(msg.saying){ diff --git a/src/ts/process/scripts.ts b/src/ts/process/scripts.ts index 32332d7c..b517c4ba 100644 --- a/src/ts/process/scripts.ts +++ b/src/ts/process/scripts.ts @@ -1,6 +1,6 @@ import { get } from "svelte/store"; import { CharEmotion, selectedCharID } from "../stores"; -import { DataBase, setDatabase, type character, type customscript, type groupChat } from "../storage/database"; +import { DataBase, setDatabase, type character, type customscript, type groupChat, type Database } from "../storage/database"; import { downloadFile } from "../storage/globalApi"; import { alertError, alertNormal } from "../alert"; import { language } from "src/lang"; @@ -130,56 +130,12 @@ export function processScriptFull(char:character|groupChat, data:string, mode:Sc } } else{ - - function skr(da:string){ - return da.replace(/{{(.+?)}}/g, (v, p1:string) => { - if(p1 === 'previous_char_chat'){ - if(chatID !== -1){ - const selchar = db.characters[get(selectedCharID)] - const chat = selchar.chats[selchar.chatPage] - let pointer = chatID - 1 - while(pointer >= 0){ - if(chat.message[pointer].role === 'char'){ - return chat.message[pointer].data - } - pointer-- - } - return selchar.firstMsgIndex === -1 ? selchar.firstMessage : selchar.alternateGreetings[selchar.firstMsgIndex] - } - return - } - if(p1 === 'previous_user_chat'){ - if(chatID !== -1){ - const selchar = db.characters[get(selectedCharID)] - const chat = selchar.chats[selchar.chatPage] - let pointer = chatID - 1 - while(pointer >= 0){ - if(chat.message[pointer].role === 'user'){ - return chat.message[pointer].data - } - pointer-- - } - return selchar.firstMsgIndex === -1 ? selchar.firstMessage : selchar.alternateGreetings[selchar.firstMsgIndex] - } - } - if(p1.startsWith('getvar')){ - const v = p1.split("::")[1] - const d =getVarChat(chatID) - return d[v] ?? "[Null]" - } - if(p1.startsWith('calc')){ - const v = p1.split("::")[1] - return calcString(v).toString() - } - return v - }) - } - let mOut = skr(outScript.replace(dreg, "$&")) + let mOut = risuChatParser(outScript.replace(dreg, "$&"), {chatID: chatID, db:db}) if(randomness.test(data)){ const list = data.split('|||') data = list[Math.floor(Math.random()*list.length)]; } - data = skr(data.replace(reg, mOut)) + data = risuChatParser(data.replace(reg, mOut), {chatID: chatID, db:db}) } } } @@ -187,6 +143,134 @@ export function processScriptFull(char:character|groupChat, data:string, mode:Sc } +const rgx = /{{(.+?)}}/gm +export function risuChatParser(da:string, arg:{ + chatID?:number + db?:Database + chara?:string|character +} = {}):string{ + const chatID = arg.chatID ?? -1 + const db = arg.db ?? get(DataBase) + return da.replace(rgx, (v, p1:string) => { + const lowerCased = p1.toLocaleLowerCase() + switch(lowerCased){ + case 'previous_char_chat':{ + if(chatID !== -1){ + const selchar = db.characters[get(selectedCharID)] + const chat = selchar.chats[selchar.chatPage] + let pointer = chatID - 1 + while(pointer >= 0){ + if(chat.message[pointer].role === 'char'){ + return chat.message[pointer].data + } + pointer-- + } + return selchar.firstMsgIndex === -1 ? selchar.firstMessage : selchar.alternateGreetings[selchar.firstMsgIndex] + } + return '' + } + case 'previous_user_chat':{ + if(chatID !== -1){ + const selchar = db.characters[get(selectedCharID)] + const chat = selchar.chats[selchar.chatPage] + let pointer = chatID - 1 + while(pointer >= 0){ + if(chat.message[pointer].role === 'user'){ + return chat.message[pointer].data + } + pointer-- + } + return selchar.firstMsgIndex === -1 ? selchar.firstMessage : selchar.alternateGreetings[selchar.firstMsgIndex] + } + return '' + } + case 'char': + case 'bot':{ + const chara = arg.chara + if(chara){ + if(typeof(chara) === 'string'){ + return chara + } + else{ + return chara.name + } + } + let selectedChar = get(selectedCharID) + let currentChar = db.characters[selectedChar] + return currentChar.name + } + case 'user':{ + return db.username + } + case 'personality': + case 'char_persona':{ + const argChara = arg.chara + const chara = (argChara && typeof(argChara) !== 'string') ? argChara : (db.characters[get(selectedCharID)]) + if(chara.type === 'group'){ + return "" + } + return chara.personality + } + case 'persona': + case 'user_persona':{ + const argChara = arg.chara + const chara = (argChara && typeof(argChara) !== 'string') ? argChara : (db.characters[get(selectedCharID)]) + if(chara.type === 'group'){ + return "" + } + return chara.personality + } + case 'ujb': + case 'global_note':{ + return db.globalNote + } + case 'chat_index':{ + return chatID.toString() + } + case 'blank': + case 'none':{ + return '' + } + } + const arra = p1.split("::") + if(arra.length > 1){ + const v = arra[1] + switch(arra[0]){ + case 'getvar':{ + const d =getVarChat(chatID) + return d[v] ?? "[Null]" + } + case 'calc':{ + return calcString(v).toString() + } + case 'addvar': + case 'setvar':{ + return '' + } + case 'button':{ + return `` + } + case 'risu':{ + return `` + } + } + } + if(p1.startsWith('random')){ + if(p1.startsWith('random::')){ + const randomIndex = Math.floor(Math.random() * (arra.length - 1)) + 1 + return arra[randomIndex] + } + else{ + const arr = p1.split(/\:|\,/g) + const randomIndex = Math.floor(Math.random() * (arr.length - 1)) + 1 + return arr[randomIndex] + } + } + return v + }) +} + + export function getVarChat(targetIndex = -1){ const db = get(DataBase) const selchar = db.characters[get(selectedCharID)] @@ -196,10 +280,15 @@ export function getVarChat(targetIndex = -1){ targetIndex = chat.message.length - 1 } let vars:{[key:string]:string} = {} + let rules:{ + key:string + rule:string + arg:string + }[] = [] const fm = selchar.firstMsgIndex === -1 ? selchar.firstMessage : selchar.alternateGreetings[selchar.firstMsgIndex] const rg = /(\{\{setvar::(.+?)::(.+?)\}\})/gu const rg2 = /(\{\{addvar::(.+?)::(.+?)\}\})/gu - const m = fm.matchAll(rg) + const rg3 = /(\{\{varrule_(.+?)::(.+?)::(.+?)\}\})/gu function process(text:string){ const m = text.matchAll(rg) for(const a of m){ @@ -213,11 +302,54 @@ export function getVarChat(targetIndex = -1){ vars[a[2]] = (parseInt(vars[a[2]]) + parseInt(a[3])).toString() } } + const m3 = text.matchAll(rg3) + for(const a of m3){ + if(a.length === 5){ + rules.push({ + key: a[3], + rule: a[2], + arg: a[4] + }) + } + } } process(fm) while( i <= targetIndex ){ process(chat.message[i].data) i += 1 } + + for(const rule of rules){ + if(vars[rule.key] === undefined){ + continue + } + switch(rule.rule){ + case "max":{ + if(parseInt(vars[rule.key]) > parseInt(rule.arg)){ + vars[rule.key] = rule.arg + } + break + } + case "min":{ + if(parseInt(vars[rule.key]) > parseInt(rule.arg)){ + vars[rule.key] = rule.arg + } + break + } + case 'overflow':{ + const exArg = rule.arg.split("::") + let rv = parseInt(vars[rule.key]) + const val = parseInt(exArg[0]) + const tg = exArg[1] + + if(isNaN(val) || isNaN(rv)){ + break + } + + vars[tg] = (Math.floor(rv / val)).toString() + vars[rule.key] = (Math.floor(rv % val)).toString() + } + } + } return vars } \ No newline at end of file