diff --git a/src/lang/en.ts b/src/lang/en.ts index 85e33bcf..97cf7a56 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -359,10 +359,11 @@ export const languageEnglish = { changeFolderColor: "Change Folder Color", fullWordMatching: "Full Word Matching", botSettingAtStart: "Bot Menu when Launch", - triggerStart: "On start of a chat", + triggerStart: "On chat Send", + triggerInput: "On user's output", triggerOutput: "On character's output", - triggerManual: "Manual Trigger Only", - triggerCondVar: "If Variable is", + triggerManual: "Manual trigger only", + triggerCondVar: "If Variable", triggerCondExists: "If Text Exists on Chat", triggerScript: "Trigger Script", triggerMatchRegex: "Match with Regex", @@ -376,7 +377,7 @@ export const languageEnglish = { greaterEqual: "Greater or Equal to", lessEqual: "Less or Equal to", triggerEffSysPrompt: 'Add System Prompt', - triggerEffSetVar: 'Set Variable', + triggerEffSetVar: 'Modify Variable', triggerEffImperson: 'Send Chat', varableName: "Variable Name", role: "Role", @@ -386,5 +387,14 @@ export const languageEnglish = { historyend: "End of History", always: "Always", noEffect: "No Effect", - + invaildTriggerEffect: "This effect doesn't works for this trigger type.", + operator: "Operator", + TriggerSetToVar: "Set to Variable", + TriggerAddToVar: "Add to Variable", + TriggerSubToVar: "Subtract from Variable", + TriggerMulToVar: "Multiply to Variable", + TriggerDivToVar: "Divide from Variable", + isNull: "is not set", + ifChatIndex: "If chat index", + ifRandom: "If random", } \ No newline at end of file diff --git a/src/lib/ChatScreens/DefaultChatScreen.svelte b/src/lib/ChatScreens/DefaultChatScreen.svelte index 161f38dc..bb175fce 100644 --- a/src/lib/ChatScreens/DefaultChatScreen.svelte +++ b/src/lib/ChatScreens/DefaultChatScreen.svelte @@ -19,6 +19,7 @@ import Help from '../Others/Help.svelte'; import AssetInput from './AssetInput.svelte'; import { downloadFile } from 'src/ts/storage/globalApi'; + import { runTrigger } from 'src/ts/process/triggers'; let messageInput:string = '' let messageInputTranslate:string = '' @@ -61,6 +62,11 @@ else{ const char = $DataBase.characters[selectedChar] if(char.type === 'character'){ + let triggerResult = runTrigger(char,'input', {chat: char.chats[char.chatPage]}) + if(triggerResult){ + cha = triggerResult.chat.message + } + cha.push({ role: 'user', data: processScript(char,messageInput,'editinput') diff --git a/src/lib/SideBars/CharConfig.svelte b/src/lib/SideBars/CharConfig.svelte index b1806729..9054a840 100644 --- a/src/lib/SideBars/CharConfig.svelte +++ b/src/lib/SideBars/CharConfig.svelte @@ -469,7 +469,7 @@ let script = currentChar.data.triggerscript script.push({ comment: "", - type: "output", + type: "start", conditions: [], effect: [] }) diff --git a/src/lib/SideBars/Scripts/TriggerData.svelte b/src/lib/SideBars/Scripts/TriggerData.svelte index def3acfa..7de6a265 100644 --- a/src/lib/SideBars/Scripts/TriggerData.svelte +++ b/src/lib/SideBars/Scripts/TriggerData.svelte @@ -50,8 +50,9 @@ {language.type} - {language.triggerOutput} {language.triggerStart} + {language.triggerOutput} + {language.triggerInput} {language.triggerManual} @@ -100,9 +101,18 @@ operator: '=' } } + if(cond.type === 'chatindex'){ + cond = { + type: 'chatindex', + value: '', + operator: '=' + } + } + }}> {language.triggerCondExists} {language.triggerCondVar} + {language.ifChatIndex} {#if cond.type === 'exists'} @@ -117,9 +127,11 @@ {language.searchDepth} {/if} - {#if cond.type === 'var'} - {language.varableName} - + {#if cond.type === 'var' || cond.type === 'chatindex'} + {#if cond.type === 'var'} + {language.varableName} + + {/if} {language.value} {language.equal} @@ -128,19 +140,33 @@ {language.less} {language.greaterEqual} {language.lessEqual} + {language.isNull} + - + {#if cond.operator !== 'null'} + + {/if} {/if} {/each} Effects @@ -174,7 +200,8 @@ effect = { type: 'setvar', var: '', - value: '' + value: '', + operator: '=' } } if(effect.type === 'impersonate'){ @@ -185,11 +212,16 @@ } } }}> - {language.triggerEffSysPrompt} + {#if effect.type === 'systemprompt' || value.type === 'start'} + {language.triggerEffSysPrompt} + {/if} {language.triggerEffSetVar} {language.triggerEffImperson} {#if effect.type === 'systemprompt'} + {#if value.type !== 'start'} + {language.invaildTriggerEffect} + {/if} {language.location} {language.promptstart} @@ -202,6 +234,14 @@ {#if effect.type === 'setvar'} {language.varableName} + {language.operator} + + {language.TriggerSetToVar} + {language.TriggerAddToVar} + {language.TriggerSubToVar} + {language.TriggerMulToVar} + {language.TriggerDivToVar} + {language.value} {/if} diff --git a/src/ts/parser.ts b/src/ts/parser.ts index 7b94ef40..c44a3a1e 100644 --- a/src/ts/parser.ts +++ b/src/ts/parser.ts @@ -305,7 +305,7 @@ function wppParser(data:string){ const rgx = /(?:{{|<)(.+?)(?:}}|>)/gm -type matcherArg = {chatID:number,db:Database,chara:character|string,rmVar:boolean} +type matcherArg = {chatID:number,db:Database,chara:character|string,rmVar:boolean,var?:{[key:string]:string}} const matcher = (p1:string,matcherArg:matcherArg) => { if(p1.length > 10000){ return '' @@ -448,7 +448,7 @@ const matcher = (p1:string,matcherArg:matcherArg) => { const v = arra[1] switch(arra[0]){ case 'getvar':{ - const d =getVarChat(chatID) + const d = matcherArg.var ?? getVarChat(chatID) return d[v] ?? "[Null]" } case 'calc':{ @@ -568,7 +568,8 @@ export function risuChatParser(da:string, arg:{ chatID?:number db?:Database chara?:string|character|groupChat - rmVar?:boolean + rmVar?:boolean, + var?:{[key:string]:string} } = {}):string{ const chatID = arg.chatID ?? -1 const db = arg.db ?? get(DataBase) @@ -597,7 +598,8 @@ export function risuChatParser(da:string, arg:{ chatID: chatID, chara: chara, rmVar: arg.rmVar ?? false, - db: db + db: db, + var: arg.var ?? null } while(pointer < da.length){ switch(da[pointer]){ diff --git a/src/ts/process/index.ts b/src/ts/process/index.ts index 3d15223b..6ab037d7 100644 --- a/src/ts/process/index.ts +++ b/src/ts/process/index.ts @@ -15,6 +15,7 @@ import { supaMemory } from "./memory/supaMemory"; import { v4 } from "uuid"; import { cloneDeep } from "lodash"; import { groupOrder } from "./group"; +import { runTrigger, type additonalSysPrompt } from "./triggers"; export interface OpenAIChat{ role: 'system'|'user'|'assistant'|'function' @@ -185,7 +186,6 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n chatObjects.push({ role, content }); } - console.log(chatObjects) return chatObjects; } @@ -288,7 +288,14 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n currentTokens += await tokenizer.tokenizeChat(chat) } - const ms = currentChat.message + let ms = currentChat.message + + const triggerResult = runTrigger(currentChar, 'start', {chat: currentChat}) + if(triggerResult){ + currentChat = triggerResult.chat + ms = currentChat.message + } + for(const msg of ms){ let formedChat = processScript(nowChatroom,risuChatParser(msg.data, {chara: currentChar, rmVar: true}), 'editprocess') let name = '' @@ -368,6 +375,29 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n unformated.chats = chats + + if(triggerResult){ + if(triggerResult.additonalSysPrompt.promptend){ + unformated.postEverything.push({ + role: 'system', + content: triggerResult.additonalSysPrompt.promptend + }) + } + if(triggerResult.additonalSysPrompt.historyend){ + unformated.lastChat.push({ + role: 'system', + content: triggerResult.additonalSysPrompt.historyend + }) + } + if(triggerResult.additonalSysPrompt.start){ + unformated.lastChat.unshift({ + role: 'system', + content: triggerResult.additonalSysPrompt.start + }) + } + } + + //make into one let formated:OpenAIChat[] = [] @@ -462,6 +492,11 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n } } + const triggerResult = runTrigger(currentChar, 'output', {chat:currentChat}) + if(triggerResult){ + db.characters[selectedChar].chats[selectedChat] = triggerResult.chat + setDatabase(db) + } await sayTTS(currentChar, result) } else{ @@ -477,6 +512,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n saying: currentChar.chaId }) db.characters[selectedChar].reloadKeys += 1 + const triggerResult = runTrigger(currentChar, 'output', {chat:currentChat}) + if(triggerResult){ + db.characters[selectedChar].chats[selectedChat] = triggerResult.chat + } await sayTTS(currentChar, result) setDatabase(db) } @@ -646,7 +685,6 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n const msgs = db.characters[selectedChar].chats[selectedChat].message let msgStr = '' for(let i = (msgs.length - 1);i>=0;i--){ - console.log(i,msgs.length,msgs[i]) if(msgs[i].role === 'char'){ msgStr = `character: ${msgs[i].data.replace(/\n/, ' ')} \n` + msgStr } @@ -663,5 +701,6 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n setDatabase(db) } } + return true } \ No newline at end of file diff --git a/src/ts/process/triggers.ts b/src/ts/process/triggers.ts index 2e7420a2..53b4a6e2 100644 --- a/src/ts/process/triggers.ts +++ b/src/ts/process/triggers.ts @@ -1,5 +1,6 @@ -import { getVarChat } from "../parser"; -import type { character } from "../storage/database"; +import { cloneDeep } from "lodash"; +import { getVarChat, risuChatParser } from "../parser"; +import type { Chat, character } from "../storage/database"; export interface triggerscript{ comment: string; @@ -8,7 +9,7 @@ export interface triggerscript{ effect:triggerEffect[] } -export type triggerCondition = triggerConditionsVar|triggerConditionsExists +export type triggerCondition = triggerConditionsVar|triggerConditionsExists|triggerConditionsChatIndex export type triggerEffect = triggerEffectSetvar|triggerEffectSystemPrompt|triggerEffectImpersonate @@ -16,7 +17,13 @@ export type triggerConditionsVar = { type:'var' var:string value:string - operator:'='|'!='|'>'|'<'|'>='|'<=' + operator:'='|'!='|'>'|'<'|'>='|'<='|'null' +} + +export type triggerConditionsChatIndex = { + type:'chatindex' + value:string + operator:'='|'!='|'>'|'<'|'>='|'<='|'null' } export type triggerConditionsExists ={ @@ -45,8 +52,17 @@ export interface triggerEffectImpersonate{ value:string }type triggerMode = 'start'|'manual'|'output'|'input' -export function runTrigger(char:character,mode:triggerMode){ - let additonalSysPrompt = { +export type additonalSysPrompt = { + start:string, + historyend: string, + promptend: string +} + +export function runTrigger(char:character,mode:triggerMode, arg:{ + chat?: Chat +} = {}){ + char = cloneDeep(char) + let additonalSysPrompt:additonalSysPrompt = { start:'', historyend: '', promptend: '' @@ -54,9 +70,9 @@ export function runTrigger(char:character,mode:triggerMode){ let varValues = getVarChat(-1, char) let varValuesChanged = false const triggers = char.triggerscript - const chat = char.chats[char.chatPage] + const chat = arg.chat ?? char.chats[char.chatPage] if(!triggers){ - return {additonalSysPrompt, char} + return null } for(const trigger of triggers){ @@ -66,61 +82,63 @@ export function runTrigger(char:character,mode:triggerMode){ let pass = true for(const condition of trigger.conditions){ - if(condition.type === 'var'){ - const varValue = varValues[condition.var] + if(condition.type === 'var' || condition.type === 'chatindex'){ + const varValue = (condition.type === 'var') ? (varValues[condition.var] ?? '[Null]') : (chat.message.length) if(varValue === undefined || varValue === null){ pass = false break } else{ - if(condition.operator === '='){ - if(varValue !== condition.value){ - pass = false + switch(condition.operator){ + case '=': + if(varValue !== condition.value){ + pass = false + } break - } - } - else if(condition.operator === '!='){ - if(varValue === condition.value){ - pass = false + case '!=': + if(varValue === condition.value){ + pass = false + } break - } - } - else if(condition.operator === '>'){ - if(Number(varValue) > Number(condition.value)){ - pass = false + case '>': + if(Number(varValue) > Number(condition.value)){ + pass = false + } break - } - } - else if(condition.operator === '<'){ - if(Number(varValue) < Number(condition.value)){ - pass = false + case '<': + if(Number(varValue) < Number(condition.value)){ + pass = false + } break - } - } - else if(condition.operator === '>='){ - if(Number(varValue) >= Number(condition.value)){ - pass = false + case '>=': + if(Number(varValue) >= Number(condition.value)){ + pass = false + } break - } - } - else if(condition.operator === '<='){ - if(Number(varValue) <= Number(condition.value)){ - pass = false + case '<=': + if(Number(varValue) <= Number(condition.value)){ + pass = false + } + break + case 'null': + if(varValue !== '[Null]'){ + pass = false + } break - } } } } else if(condition.type === 'exists'){ + const val = risuChatParser(condition.value,{chara:char, var:varValues}) let da = chat.message.slice(0-condition.depth).map((v)=>v.data).join(' ') if(condition.type2 === 'strict'){ - pass = da.split(' ').includes(condition.value) + pass = da.split(' ').includes(val) } else if(condition.type2 === 'loose'){ - pass = da.toLowerCase().includes(condition.value.toLowerCase()) + pass = da.toLowerCase().includes(val.toLowerCase()) } else if(condition.type2 === 'regex'){ - pass = new RegExp(condition.value).test(da) + pass = new RegExp(val).test(da) } } if(!pass){ @@ -169,8 +187,9 @@ export function runTrigger(char:character,mode:triggerMode){ chat.message[chat.message.length-1].data = chat.message.at(-1).data.replaceAll(/{{(setvar|getvar)::.+?}}/gis,'') + Object.keys(varValues).map((v)=>`{{setvar::${v}::${varValues[v]}}}`).join('') } - char.chats[char.chatPage] = chat - - return {additonalSysPrompt, char} + if(arg.chat !== undefined && arg.chat !== null){ + char.chats[char.chatPage] = chat + } + return {additonalSysPrompt, chat} } \ No newline at end of file