Files
risuai/src/ts/process/triggers.ts
2023-08-02 06:24:08 +09:00

194 lines
6.5 KiB
TypeScript

import { cloneDeep } from "lodash";
import { getVarChat, risuChatParser } from "../parser";
import type { Chat, character } from "../storage/database";
export interface triggerscript{
comment: string;
type: 'start'|'manual'|'output'|'input'
conditions: triggerCondition[]
effect:triggerEffect[]
}
export type triggerCondition = triggerConditionsVar|triggerConditionsExists|triggerConditionsChatIndex
export type triggerEffect = triggerEffectSetvar|triggerEffectSystemPrompt|triggerEffectImpersonate
export type triggerConditionsVar = {
type:'var'
var:string
value:string
operator:'='|'!='|'>'|'<'|'>='|'<='|'null'
}
export type triggerConditionsChatIndex = {
type:'chatindex'
value:string
operator:'='|'!='|'>'|'<'|'>='|'<='|'null'
}
export type triggerConditionsExists ={
type: 'exists'
value:string
type2: 'strict'|'loose'|'regex',
depth: number
}
export interface triggerEffectSetvar{
type: 'setvar',
operator: '='|'+='|'-='|'*='|'/='
var:string
value:string
}
export interface triggerEffectSystemPrompt{
type: 'systemprompt',
location: 'start'|'historyend'|'promptend',
value:string
}
export interface triggerEffectImpersonate{
type: 'impersonate'
role: 'user'|'char',
value:string
}type triggerMode = 'start'|'manual'|'output'|'input'
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: ''
}
const triggers = char.triggerscript
const chat = arg.chat ?? char.chats[char.chatPage]
if(!triggers){
return null
}
let varValues = getVarChat(-1, char)
let varValuesChanged = false
for(const trigger of triggers){
if(mode !== trigger.type){
continue
}
let pass = true
for(const condition of trigger.conditions){
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{
switch(condition.operator){
case '=':
if(varValue !== condition.value){
pass = false
}
break
case '!=':
if(varValue === condition.value){
pass = false
}
break
case '>':
if(Number(varValue) > Number(condition.value)){
pass = false
}
break
case '<':
if(Number(varValue) < Number(condition.value)){
pass = false
}
break
case '>=':
if(Number(varValue) >= Number(condition.value)){
pass = false
}
break
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(val)
}
else if(condition.type2 === 'loose'){
pass = da.toLowerCase().includes(val.toLowerCase())
}
else if(condition.type2 === 'regex'){
pass = new RegExp(val).test(da)
}
}
if(!pass){
break
}
}
if(!pass){
continue
}
for(const effect of trigger.effect){
if(effect.type === 'setvar'){
switch(effect.operator){
case '=':
varValues[effect.var] = effect.value
break
case '+=':
varValues[effect.var] = (Number(varValues[effect.var]) + Number(effect.value)).toString()
break
case '-=':
varValues[effect.var] = (Number(varValues[effect.var]) - Number(effect.value)).toString()
break
case '*=':
varValues[effect.var] = (Number(varValues[effect.var]) * Number(effect.value)).toString()
break
case '/=':
varValues[effect.var] = (Number(varValues[effect.var]) / Number(effect.value)).toString()
break
}
varValuesChanged = true
}
else if(effect.type === 'systemprompt'){
additonalSysPrompt[effect.location] += effect.value + "\n\n"
}
else if(effect.type === 'impersonate'){
if(effect.role === 'user'){
chat.message.push({role: 'user', data: effect.value})
}
else if(effect.role === 'char'){
chat.message.push({role: 'char', data: effect.value})
}
}
}
}
if(varValuesChanged){
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('')
}
if(arg.chat !== undefined && arg.chat !== null){
char.chats[char.chatPage] = chat
}
return {additonalSysPrompt, chat}
}