[feat] trigger runner2

This commit is contained in:
kwaroran
2023-07-28 05:53:12 +09:00
parent 0e9f3cbce0
commit 7b768d3e73
7 changed files with 186 additions and 70 deletions

View File

@@ -359,10 +359,11 @@ export const languageEnglish = {
changeFolderColor: "Change Folder Color", changeFolderColor: "Change Folder Color",
fullWordMatching: "Full Word Matching", fullWordMatching: "Full Word Matching",
botSettingAtStart: "Bot Menu when Launch", 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", triggerOutput: "On character's output",
triggerManual: "Manual Trigger Only", triggerManual: "Manual trigger only",
triggerCondVar: "If Variable is", triggerCondVar: "If Variable",
triggerCondExists: "If Text Exists on Chat", triggerCondExists: "If Text Exists on Chat",
triggerScript: "Trigger Script", triggerScript: "Trigger Script",
triggerMatchRegex: "Match with Regex", triggerMatchRegex: "Match with Regex",
@@ -376,7 +377,7 @@ export const languageEnglish = {
greaterEqual: "Greater or Equal to", greaterEqual: "Greater or Equal to",
lessEqual: "Less or Equal to", lessEqual: "Less or Equal to",
triggerEffSysPrompt: 'Add System Prompt', triggerEffSysPrompt: 'Add System Prompt',
triggerEffSetVar: 'Set Variable', triggerEffSetVar: 'Modify Variable',
triggerEffImperson: 'Send Chat', triggerEffImperson: 'Send Chat',
varableName: "Variable Name", varableName: "Variable Name",
role: "Role", role: "Role",
@@ -386,5 +387,14 @@ export const languageEnglish = {
historyend: "End of History", historyend: "End of History",
always: "Always", always: "Always",
noEffect: "No Effect", 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",
} }

View File

@@ -19,6 +19,7 @@
import Help from '../Others/Help.svelte'; import Help from '../Others/Help.svelte';
import AssetInput from './AssetInput.svelte'; import AssetInput from './AssetInput.svelte';
import { downloadFile } from 'src/ts/storage/globalApi'; import { downloadFile } from 'src/ts/storage/globalApi';
import { runTrigger } from 'src/ts/process/triggers';
let messageInput:string = '' let messageInput:string = ''
let messageInputTranslate:string = '' let messageInputTranslate:string = ''
@@ -61,6 +62,11 @@
else{ else{
const char = $DataBase.characters[selectedChar] const char = $DataBase.characters[selectedChar]
if(char.type === 'character'){ if(char.type === 'character'){
let triggerResult = runTrigger(char,'input', {chat: char.chats[char.chatPage]})
if(triggerResult){
cha = triggerResult.chat.message
}
cha.push({ cha.push({
role: 'user', role: 'user',
data: processScript(char,messageInput,'editinput') data: processScript(char,messageInput,'editinput')

View File

@@ -469,7 +469,7 @@
let script = currentChar.data.triggerscript let script = currentChar.data.triggerscript
script.push({ script.push({
comment: "", comment: "",
type: "output", type: "start",
conditions: [], conditions: [],
effect: [] effect: []
}) })

View File

@@ -50,8 +50,9 @@
<TextInput size="sm" bind:value={value.comment} /> <TextInput size="sm" bind:value={value.comment} />
<span class="text-neutral-200 mt-4">{language.type}</span> <span class="text-neutral-200 mt-4">{language.type}</span>
<SelectInput bind:value={value.type}> <SelectInput bind:value={value.type}>
<OptionInput value="output">{language.triggerOutput}</OptionInput>
<OptionInput value="start">{language.triggerStart}</OptionInput> <OptionInput value="start">{language.triggerStart}</OptionInput>
<OptionInput value="output">{language.triggerOutput}</OptionInput>
<OptionInput value="input">{language.triggerInput}</OptionInput>
<OptionInput value="manual">{language.triggerManual}</OptionInput> <OptionInput value="manual">{language.triggerManual}</OptionInput>
</SelectInput> </SelectInput>
@@ -100,9 +101,18 @@
operator: '=' operator: '='
} }
} }
if(cond.type === 'chatindex'){
cond = {
type: 'chatindex',
value: '',
operator: '='
}
}
}}> }}>
<OptionInput value="exists">{language.triggerCondExists}</OptionInput> <OptionInput value="exists">{language.triggerCondExists}</OptionInput>
<OptionInput value="var">{language.triggerCondVar}</OptionInput> <OptionInput value="var">{language.triggerCondVar}</OptionInput>
<OptionInput value="chatindex">{language.ifChatIndex}</OptionInput>
</SelectInput> </SelectInput>
{#if cond.type === 'exists'} {#if cond.type === 'exists'}
@@ -117,9 +127,11 @@
<span class="text-gray-400 text-sm">{language.searchDepth}</span> <span class="text-gray-400 text-sm">{language.searchDepth}</span>
<NumberInput size="sm" bind:value={cond.depth} /> <NumberInput size="sm" bind:value={cond.depth} />
{/if} {/if}
{#if cond.type === 'var'} {#if cond.type === 'var' || cond.type === 'chatindex'}
<span class="text-gray-400 text-sm">{language.varableName}</span> {#if cond.type === 'var'}
<TextInput size="sm" bind:value={cond.var} /> <span class="text-gray-400 text-sm">{language.varableName}</span>
<TextInput size="sm" bind:value={cond.var} />
{/if}
<span class="text-gray-400 text-sm">{language.value}</span> <span class="text-gray-400 text-sm">{language.value}</span>
<SelectInput bind:value={cond.operator} size="sm"> <SelectInput bind:value={cond.operator} size="sm">
<OptionInput value="=">{language.equal}</OptionInput> <OptionInput value="=">{language.equal}</OptionInput>
@@ -128,19 +140,33 @@
<OptionInput value="<">{language.less}</OptionInput> <OptionInput value="<">{language.less}</OptionInput>
<OptionInput value=">=">{language.greaterEqual}</OptionInput> <OptionInput value=">=">{language.greaterEqual}</OptionInput>
<OptionInput value="<=">{language.lessEqual}</OptionInput> <OptionInput value="<=">{language.lessEqual}</OptionInput>
<OptionInput value="null">{language.isNull}</OptionInput>
</SelectInput> </SelectInput>
<TextInput size="sm" bind:value={cond.value} /> {#if cond.operator !== 'null'}
<TextInput size="sm" bind:value={cond.value} />
{/if}
{/if} {/if}
{/each} {/each}
</div> </div>
<span class="text-neutral-200 mt-4">Effects <span class="text-neutral-200 mt-4">Effects
<button aria-labelledby="Add Effects" class="float-right text-gray-400 hover:text-green-500" on:click={() => { <button aria-labelledby="Add Effects" class="float-right text-gray-400 hover:text-green-500" on:click={() => {
value.effect.push({ if(value.type === 'start'){
type: 'systemprompt', value.effect.push({
value: '', type: 'systemprompt',
location: 'historyend' value: '',
}) location: 'historyend'
})
}
else{
value.effect.push({
type: 'setvar',
var: '',
value: '',
operator: '='
})
}
value.effect = value.effect value.effect = value.effect
}}><PlusIcon size={18} /></button> }}><PlusIcon size={18} /></button>
@@ -174,7 +200,8 @@
effect = { effect = {
type: 'setvar', type: 'setvar',
var: '', var: '',
value: '' value: '',
operator: '='
} }
} }
if(effect.type === 'impersonate'){ if(effect.type === 'impersonate'){
@@ -185,11 +212,16 @@
} }
} }
}}> }}>
<OptionInput value="systemprompt">{language.triggerEffSysPrompt}</OptionInput> {#if effect.type === 'systemprompt' || value.type === 'start'}
<OptionInput value="systemprompt">{language.triggerEffSysPrompt}</OptionInput>
{/if}
<OptionInput value="setvar">{language.triggerEffSetVar}</OptionInput> <OptionInput value="setvar">{language.triggerEffSetVar}</OptionInput>
<OptionInput value="impersonate">{language.triggerEffImperson}</OptionInput> <OptionInput value="impersonate">{language.triggerEffImperson}</OptionInput>
</SelectInput> </SelectInput>
{#if effect.type === 'systemprompt'} {#if effect.type === 'systemprompt'}
{#if value.type !== 'start'}
<span class="text-red-400 text-sm">{language.invaildTriggerEffect}</span>
{/if}
<span class="text-gray-400 text-sm">{language.location}</span> <span class="text-gray-400 text-sm">{language.location}</span>
<SelectInput bind:value={effect.location} size="sm"> <SelectInput bind:value={effect.location} size="sm">
<OptionInput value="start">{language.promptstart}</OptionInput> <OptionInput value="start">{language.promptstart}</OptionInput>
@@ -202,6 +234,14 @@
{#if effect.type === 'setvar'} {#if effect.type === 'setvar'}
<span class="text-gray-400 text-sm">{language.varableName}</span> <span class="text-gray-400 text-sm">{language.varableName}</span>
<TextInput size="sm" bind:value={effect.var} /> <TextInput size="sm" bind:value={effect.var} />
<span class="text-gray-400 text-sm">{language.operator}</span>
<SelectInput bind:value={effect.operator} size="sm">
<OptionInput value="=">{language.TriggerSetToVar}</OptionInput>
<OptionInput value="+=">{language.TriggerAddToVar}</OptionInput>
<OptionInput value="-=">{language.TriggerSubToVar}</OptionInput>
<OptionInput value="*=">{language.TriggerMulToVar}</OptionInput>
<OptionInput value="/=">{language.TriggerDivToVar}</OptionInput>
</SelectInput>
<span class="text-gray-400 text-sm">{language.value}</span> <span class="text-gray-400 text-sm">{language.value}</span>
<TextInput size="sm" bind:value={effect.value} /> <TextInput size="sm" bind:value={effect.value} />
{/if} {/if}

View File

@@ -305,7 +305,7 @@ function wppParser(data:string){
const rgx = /(?:{{|<)(.+?)(?:}}|>)/gm 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) => { const matcher = (p1:string,matcherArg:matcherArg) => {
if(p1.length > 10000){ if(p1.length > 10000){
return '' return ''
@@ -448,7 +448,7 @@ const matcher = (p1:string,matcherArg:matcherArg) => {
const v = arra[1] const v = arra[1]
switch(arra[0]){ switch(arra[0]){
case 'getvar':{ case 'getvar':{
const d =getVarChat(chatID) const d = matcherArg.var ?? getVarChat(chatID)
return d[v] ?? "[Null]" return d[v] ?? "[Null]"
} }
case 'calc':{ case 'calc':{
@@ -568,7 +568,8 @@ export function risuChatParser(da:string, arg:{
chatID?:number chatID?:number
db?:Database db?:Database
chara?:string|character|groupChat chara?:string|character|groupChat
rmVar?:boolean rmVar?:boolean,
var?:{[key:string]:string}
} = {}):string{ } = {}):string{
const chatID = arg.chatID ?? -1 const chatID = arg.chatID ?? -1
const db = arg.db ?? get(DataBase) const db = arg.db ?? get(DataBase)
@@ -597,7 +598,8 @@ export function risuChatParser(da:string, arg:{
chatID: chatID, chatID: chatID,
chara: chara, chara: chara,
rmVar: arg.rmVar ?? false, rmVar: arg.rmVar ?? false,
db: db db: db,
var: arg.var ?? null
} }
while(pointer < da.length){ while(pointer < da.length){
switch(da[pointer]){ switch(da[pointer]){

View File

@@ -15,6 +15,7 @@ import { supaMemory } from "./memory/supaMemory";
import { v4 } from "uuid"; import { v4 } from "uuid";
import { cloneDeep } from "lodash"; import { cloneDeep } from "lodash";
import { groupOrder } from "./group"; import { groupOrder } from "./group";
import { runTrigger, type additonalSysPrompt } from "./triggers";
export interface OpenAIChat{ export interface OpenAIChat{
role: 'system'|'user'|'assistant'|'function' role: 'system'|'user'|'assistant'|'function'
@@ -185,7 +186,6 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
chatObjects.push({ role, content }); chatObjects.push({ role, content });
} }
console.log(chatObjects)
return chatObjects; return chatObjects;
} }
@@ -288,7 +288,14 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
currentTokens += await tokenizer.tokenizeChat(chat) 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){ for(const msg of ms){
let formedChat = processScript(nowChatroom,risuChatParser(msg.data, {chara: currentChar, rmVar: true}), 'editprocess') let formedChat = processScript(nowChatroom,risuChatParser(msg.data, {chara: currentChar, rmVar: true}), 'editprocess')
let name = '' let name = ''
@@ -368,6 +375,29 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
unformated.chats = chats 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 //make into one
let formated:OpenAIChat[] = [] 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) await sayTTS(currentChar, result)
} }
else{ else{
@@ -477,6 +512,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
saying: currentChar.chaId saying: currentChar.chaId
}) })
db.characters[selectedChar].reloadKeys += 1 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) await sayTTS(currentChar, result)
setDatabase(db) setDatabase(db)
} }
@@ -646,7 +685,6 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
const msgs = db.characters[selectedChar].chats[selectedChat].message const msgs = db.characters[selectedChar].chats[selectedChat].message
let msgStr = '' let msgStr = ''
for(let i = (msgs.length - 1);i>=0;i--){ for(let i = (msgs.length - 1);i>=0;i--){
console.log(i,msgs.length,msgs[i])
if(msgs[i].role === 'char'){ if(msgs[i].role === 'char'){
msgStr = `character: ${msgs[i].data.replace(/\n/, ' ')} \n` + msgStr msgStr = `character: ${msgs[i].data.replace(/\n/, ' ')} \n` + msgStr
} }
@@ -663,5 +701,6 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
setDatabase(db) setDatabase(db)
} }
} }
return true return true
} }

View File

@@ -1,5 +1,6 @@
import { getVarChat } from "../parser"; import { cloneDeep } from "lodash";
import type { character } from "../storage/database"; import { getVarChat, risuChatParser } from "../parser";
import type { Chat, character } from "../storage/database";
export interface triggerscript{ export interface triggerscript{
comment: string; comment: string;
@@ -8,7 +9,7 @@ export interface triggerscript{
effect:triggerEffect[] effect:triggerEffect[]
} }
export type triggerCondition = triggerConditionsVar|triggerConditionsExists export type triggerCondition = triggerConditionsVar|triggerConditionsExists|triggerConditionsChatIndex
export type triggerEffect = triggerEffectSetvar|triggerEffectSystemPrompt|triggerEffectImpersonate export type triggerEffect = triggerEffectSetvar|triggerEffectSystemPrompt|triggerEffectImpersonate
@@ -16,7 +17,13 @@ export type triggerConditionsVar = {
type:'var' type:'var'
var:string var:string
value:string value:string
operator:'='|'!='|'>'|'<'|'>='|'<=' operator:'='|'!='|'>'|'<'|'>='|'<='|'null'
}
export type triggerConditionsChatIndex = {
type:'chatindex'
value:string
operator:'='|'!='|'>'|'<'|'>='|'<='|'null'
} }
export type triggerConditionsExists ={ export type triggerConditionsExists ={
@@ -45,8 +52,17 @@ export interface triggerEffectImpersonate{
value:string value:string
}type triggerMode = 'start'|'manual'|'output'|'input' }type triggerMode = 'start'|'manual'|'output'|'input'
export function runTrigger(char:character,mode:triggerMode){ export type additonalSysPrompt = {
let additonalSysPrompt = { start:string,
historyend: string,
promptend: string
}
export function runTrigger(char:character,mode:triggerMode, arg:{
chat?: Chat
} = {}){
char = cloneDeep(char)
let additonalSysPrompt:additonalSysPrompt = {
start:'', start:'',
historyend: '', historyend: '',
promptend: '' promptend: ''
@@ -54,9 +70,9 @@ export function runTrigger(char:character,mode:triggerMode){
let varValues = getVarChat(-1, char) let varValues = getVarChat(-1, char)
let varValuesChanged = false let varValuesChanged = false
const triggers = char.triggerscript const triggers = char.triggerscript
const chat = char.chats[char.chatPage] const chat = arg.chat ?? char.chats[char.chatPage]
if(!triggers){ if(!triggers){
return {additonalSysPrompt, char} return null
} }
for(const trigger of triggers){ for(const trigger of triggers){
@@ -66,61 +82,63 @@ export function runTrigger(char:character,mode:triggerMode){
let pass = true let pass = true
for(const condition of trigger.conditions){ for(const condition of trigger.conditions){
if(condition.type === 'var'){ if(condition.type === 'var' || condition.type === 'chatindex'){
const varValue = varValues[condition.var] const varValue = (condition.type === 'var') ? (varValues[condition.var] ?? '[Null]') : (chat.message.length)
if(varValue === undefined || varValue === null){ if(varValue === undefined || varValue === null){
pass = false pass = false
break break
} }
else{ else{
if(condition.operator === '='){ switch(condition.operator){
if(varValue !== condition.value){ case '=':
pass = false if(varValue !== condition.value){
pass = false
}
break break
} case '!=':
} if(varValue === condition.value){
else if(condition.operator === '!='){ pass = false
if(varValue === condition.value){ }
pass = false
break break
} case '>':
} if(Number(varValue) > Number(condition.value)){
else if(condition.operator === '>'){ pass = false
if(Number(varValue) > Number(condition.value)){ }
pass = false
break break
} case '<':
} if(Number(varValue) < Number(condition.value)){
else if(condition.operator === '<'){ pass = false
if(Number(varValue) < Number(condition.value)){ }
pass = false
break break
} case '>=':
} if(Number(varValue) >= Number(condition.value)){
else if(condition.operator === '>='){ pass = false
if(Number(varValue) >= Number(condition.value)){ }
pass = false
break break
} case '<=':
} if(Number(varValue) <= Number(condition.value)){
else if(condition.operator === '<='){ pass = false
if(Number(varValue) <= Number(condition.value)){ }
pass = false break
case 'null':
if(varValue !== '[Null]'){
pass = false
}
break break
}
} }
} }
} }
else if(condition.type === 'exists'){ 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(' ') let da = chat.message.slice(0-condition.depth).map((v)=>v.data).join(' ')
if(condition.type2 === 'strict'){ if(condition.type2 === 'strict'){
pass = da.split(' ').includes(condition.value) pass = da.split(' ').includes(val)
} }
else if(condition.type2 === 'loose'){ else if(condition.type2 === 'loose'){
pass = da.toLowerCase().includes(condition.value.toLowerCase()) pass = da.toLowerCase().includes(val.toLowerCase())
} }
else if(condition.type2 === 'regex'){ else if(condition.type2 === 'regex'){
pass = new RegExp(condition.value).test(da) pass = new RegExp(val).test(da)
} }
} }
if(!pass){ 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('') 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 if(arg.chat !== undefined && arg.chat !== null){
char.chats[char.chatPage] = chat
return {additonalSysPrompt, char} }
return {additonalSysPrompt, chat}
} }