import { get, writable } from "svelte/store"; import { DataBase, setDatabase, type character } from "../database"; import { CharEmotion, selectedCharID } from "../stores"; import { tokenize, tokenizeNum } from "../tokenizer"; import { language } from "../../lang"; import { alertError } from "../alert"; import { loadLoreBookPrompt } from "./lorebook"; import { findCharacterbyId, replacePlaceholders } from "../util"; import { requestChatData } from "./request"; import { stableDiff } from "./stableDiff"; import { processScript, processScriptFull } from "./scripts"; import { exampleMessage } from "./exampleMessages"; import { sayTTS } from "./tts"; import { supaMemory } from "./supaMemory"; import { v4 } from "uuid"; export interface OpenAIChat{ role: 'system'|'user'|'assistant' content: string memo?:string name?:string } export const doingChat = writable(false) export async function sendChat(chatProcessIndex = -1):Promise { let findCharCache:{[key:string]:character} = {} function findCharacterbyIdwithCache(id:string){ const d = findCharCache[id] if(!!d){ return d } else{ const r = findCharacterbyId(id) findCharCache[id] = r return r } } function reformatContent(data:string){ return data.trim().replace(`${currentChar.name}:`, '').trim() } let isDoing = get(doingChat) if(isDoing){ if(chatProcessIndex === -1){ return false } } doingChat.set(true) let db = get(DataBase) let selectedChar = get(selectedCharID) const nowChatroom = db.characters[selectedChar] let currentChar:character if(nowChatroom.type === 'group'){ if(chatProcessIndex === -1){ for(let i=0;i 4000){ maxContextTokens = 4000 } } if(db.aiModel === 'gpt4'){ if(maxContextTokens > 8000){ maxContextTokens = 8000 } } let unformated = { 'main':([] as OpenAIChat[]), 'jailbreak':([] as OpenAIChat[]), 'chats':([] as OpenAIChat[]), 'lorebook':([] as OpenAIChat[]), 'globalNote':([] as OpenAIChat[]), 'authorNote':([] as OpenAIChat[]), 'lastChat':([] as OpenAIChat[]), 'description':([] as OpenAIChat[]), } if(!currentChar.utilityBot){ const mainp = currentChar.systemPrompt || db.mainPrompt unformated.main.push({ role: 'system', content: replacePlaceholders(mainp + ((db.additionalPrompt === '' || (!db.promptPreprocess)) ? '' : `\n${db.additionalPrompt}`), currentChar.name) }) if(db.jailbreakToggle){ unformated.jailbreak.push({ role: 'system', content: replacePlaceholders(db.jailbreak, currentChar.name) }) } unformated.globalNote.push({ role: 'system', content: replacePlaceholders(currentChar.replaceGlobalNote || db.globalNote, currentChar.name) }) } if(currentChat.note){ unformated.authorNote.push({ role: 'system', content: replacePlaceholders(currentChat.note, currentChar.name) }) } { let description = replacePlaceholders((db.promptPreprocess ? db.descriptionPrefix: '') + currentChar.desc, currentChar.name) if(currentChar.personality){ description += replacePlaceholders("\n\nDescription of {{char}}: " + currentChar.personality,currentChar.name) } if(currentChar.scenario){ description += replacePlaceholders("\n\nCircumstances and context of the dialogue: " + currentChar.scenario,currentChar.name) } unformated.description.push({ role: 'system', content: description }) } unformated.lorebook.push({ role: 'system', content: replacePlaceholders(await loadLoreBookPrompt(), currentChar.name) }) //await tokenize currernt let currentTokens = (await tokenize(Object.keys(unformated).map((key) => { return (unformated[key] as OpenAIChat[]).map((d) => { return d.content }).join('\n\n') }).join('\n\n')) + db.maxResponse) + 150 const examples = exampleMessage(currentChar) for(const example of examples){ currentTokens += await tokenize(example.content) } let chats:OpenAIChat[] = examples chats.push({ role: 'system', content: '[Start a new chat]', memo: "NewChat" }) if(nowChatroom.type !== 'group'){ const firstMsg = nowChatroom.firstMsgIndex === -1 ? nowChatroom.firstMessage : nowChatroom.alternateGreetings[nowChatroom.firstMsgIndex] chats.push({ role: 'assistant', content: processScript(currentChar, replacePlaceholders(firstMsg, currentChar.name), 'editprocess') }) currentTokens += await tokenize(processScript(currentChar, replacePlaceholders(firstMsg, currentChar.name), 'editprocess')) } const ms = currentChat.message for(const msg of ms){ let formedChat = processScript(currentChar,replacePlaceholders(msg.data, currentChar.name), 'editprocess') let name = '' if(msg.role === 'char'){ if(msg.saying){ name = `${findCharacterbyIdwithCache(msg.saying).name}` } else{ name = `${currentChar.name}` } } else if(msg.role === 'user'){ name = `${db.username}` } if(!msg.chatId){ msg.chatId = v4() } chats.push({ role: msg.role === 'user' ? 'user' : 'assistant', content: formedChat, memo: msg.chatId, name: name }) currentTokens += (await tokenize(formedChat) + 1) } if(nowChatroom.type === 'group'){ const systemMsg = `[Write the next reply only as ${currentChar.name}]` chats.push({ role: 'system', content: systemMsg }) currentTokens += (await tokenize(systemMsg) + 1) } if(nowChatroom.supaMemory && db.supaMemoryType !== 'none'){ const sp = await supaMemory(chats, currentTokens, maxContextTokens, currentChat, nowChatroom) if(sp.error){ alertError(sp.error) return false } chats = sp.chats currentTokens = sp.currentTokens currentChat.supaMemoryData = sp.memory ?? currentChat.supaMemoryData currentChat.lastMemory = sp.lastId ?? currentChat.lastMemory } else{ while(currentTokens > maxContextTokens){ if(chats.length <= 1){ alertError(language.errors.toomuchtoken) return false } currentTokens -= (await tokenize(chats[0].content) + 1) chats.splice(0, 1) } currentChat.lastMemory = chats[0].memo console.log(currentChat.lastMemory) } let bias:{[key:number]:number} = {} for(let i=0;i 0){ const prompt = sysPrompts.join('\n') if(prompt.replace(/\n/g,'').length > 3){ formated.push({ role: 'system', content: prompt }) } sysPrompts = [] formated = formated.concat(cha) } else{ formated = formated.concat(cha) } } if(sysPrompts.length > 0){ const prompt = sysPrompts.join('\n') if(prompt.replace(/\n/g,'').length > 3){ formated.push({ role: 'system', content: prompt }) } sysPrompts = [] } for(let i=0;i 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array } let emotionList = currentEmotion.map((a) => { return a[0] }) let charemotions = get(CharEmotion) let tempEmotion = charemotions[currentChar.chaId] if(!tempEmotion){ tempEmotion = [] } if(tempEmotion.length > 4){ tempEmotion.splice(0, 1) } let emobias:{[key:number]:number} = {} for(const emo of emotionList){ const tokens = await tokenizeNum(emo) for(const token of tokens){ emobias[token] = 10 } } for(let i =0;i { return a[0] }) try { const emotion:string = rq.result.replace(/ |\n/g,'').trim().toLocaleLowerCase() let emotionSelected = false for(const emo of currentEmotion){ if(emo[0] === emotion){ const emos:[string, string,number] = [emo[0], emo[1], Date.now()] tempEmotion.push(emos) charemotions[currentChar.chaId] = tempEmotion CharEmotion.set(charemotions) emotionSelected = true break } } if(!emotionSelected){ for(const emo of currentEmotion){ if(emotion.includes(emo[0])){ const emos:[string, string,number] = [emo[0], emo[1], Date.now()] tempEmotion.push(emos) charemotions[currentChar.chaId] = tempEmotion CharEmotion.set(charemotions) emotionSelected = true break } } } if(!emotionSelected && emotionList.includes('neutral')){ const emo = currentEmotion[emotionList.indexOf('neutral')] const emos:[string, string,number] = [emo[0], emo[1], Date.now()] tempEmotion.push(emos) charemotions[currentChar.chaId] = tempEmotion CharEmotion.set(charemotions) emotionSelected = true } } catch (error) { alertError(language.errors.httpError + `${error}`) return true } } return true } else if(currentChar.viewScreen === 'imggen'){ if(chatProcessIndex !== -1){ alertError("Stable diffusion in group chat is not supported") } 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 } else{ msgStr = `user: ${msgs[i].data.replace(/\n/, ' ')} \n` + msgStr break } } const ch = await stableDiff(currentChar, msgStr) if(ch){ db.characters[selectedChar].chats[selectedChat].sdData = ch setDatabase(db) } } return true }