This commit is contained in:
LightningHyperBlaze45654
2024-11-29 20:33:11 -08:00
220 changed files with 26974 additions and 10497 deletions

View File

@@ -1,11 +1,11 @@
import { get } from "svelte/store";
import { DataBase, setDatabase } from "../storage/database";
import { CurrentCharacter, CurrentChat, selectedCharID } from "../stores";
import { getCurrentCharacter, getCurrentChat, getDatabase, setCurrentChat, setDatabase } from "../storage/database.svelte";
import { selectedCharID } from "../stores.svelte";
import { alertInput, alertMd, alertNormal, alertSelect, alertToast } from "../alert";
import { sayTTS } from "./tts";
import { risuChatParser } from "../parser";
import { sendChat } from ".";
import { loadLoreBookV3Prompt } from "./lorebook";
import { risuChatParser } from "../parser.svelte";
import { sendChat } from "./index.svelte";
import { loadLoreBookV3Prompt } from "./lorebook.svelte";
import { runTrigger } from "./triggers";
export async function processMultiCommand(command:string) {
@@ -40,7 +40,7 @@ export async function processMultiCommand(command:string) {
async function processCommand(command:string, pipe:string):Promise<false | string>{
const db = get(DataBase)
const db = getDatabase()
const currentChar = db.characters[get(selectedCharID)]
const currentChat = currentChar.chats[currentChar.chatPage]
let {commandName, arg, namedArg} = commandParser(command, pipe)
@@ -180,7 +180,7 @@ async function processCommand(command:string, pipe:string):Promise<false | strin
}
case 'setvar':{
console.log(namedArg, arg)
const db = get(DataBase)
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
const chat = char.chats[char.chatPage]
@@ -194,7 +194,7 @@ async function processCommand(command:string, pipe:string):Promise<false | strin
return ''
}
case 'addvar':{
const db = get(DataBase)
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
const chat = char.chats[char.chatPage]
@@ -207,7 +207,7 @@ async function processCommand(command:string, pipe:string):Promise<false | strin
return ''
}
case 'getvar':{
const db = get(DataBase)
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
const chat = char.chats[char.chatPage]
@@ -222,17 +222,17 @@ async function processCommand(command:string, pipe:string):Promise<false | strin
return JSON.stringify(p)
}
case 'trigger':{
const currentChar = get(CurrentCharacter)
const currentChar = getCurrentCharacter()
if(currentChar.type === 'group'){
return;
}
const triggerResult = await runTrigger(currentChar, 'manual', {
chat: get(CurrentChat),
chat: getCurrentChat(),
manualName: arg
});
if(triggerResult){
CurrentChat.set(triggerResult.chat);
setCurrentChat(triggerResult.chat);
}
return
}

View File

@@ -1,13 +1,10 @@
import { DataBase, type Chat, type character } from "src/ts/storage/database";
import { getDatabase, type Chat, type character } from "src/ts/storage/database.svelte";
import { HypaProcesser } from '../memory/hypamemory'
import type { OpenAIChat } from "..";
import { stringlizeChat } from "../stringlize";
import { get } from "svelte/store";
import { getUserName } from "src/ts/util";
export async function additionalInformations(char: character,chats:Chat,){
const processer = new HypaProcesser('MiniLM')
const db = get(DataBase)
const db = getDatabase()
const info = char.additionalText
if(info){

View File

@@ -1,5 +1,5 @@
import type { OpenAIChat } from ".";
import type { character } from "../storage/database";
import type { OpenAIChat } from "./index.svelte";
import type { character } from "../storage/database.svelte";
import { risuChatParser } from "./scripts";
export function exampleMessage(char:character, userName:string):OpenAIChat[]{

View File

@@ -1,9 +1,7 @@
import localforage from "localforage";
import { selectSingleFile } from "../../util";
import { v4 } from "uuid";
import { DataBase } from "../../storage/database";
import { get } from "svelte/store";
import { checkImageType } from "../../parser";
import { getDatabase } from "../../storage/database.svelte";
import { checkImageType } from "../../parser.svelte";
const inlayStorage = localforage.createInstance({
name: 'inlay',
@@ -85,7 +83,7 @@ export async function getInlayImage(id: string){
}
export function supportsInlayImage(){
const db = get(DataBase)
const db = getDatabase()
return db.aiModel.startsWith('gptv') || db.aiModel === 'gemini-pro-vision' || db.aiModel.startsWith('claude-3') || db.aiModel.startsWith('gpt4_turbo') || db.aiModel.startsWith('gpt5') || db.aiModel.startsWith('gpt4o') ||
(db.aiModel === 'reverse_proxy' && (
db.proxyRequestModel?.startsWith('gptv') || db.proxyRequestModel === 'gemini-pro-vision' || db.proxyRequestModel?.startsWith('claude-3') || db.proxyRequestModel.startsWith('gpt4_turbo') ||

View File

@@ -1,8 +1,8 @@
import { DataBase, setDatabase } from 'src/ts/storage/database';
import { selectedCharID } from 'src/ts/stores';
import { getDatabase, setDatabase } from 'src/ts/storage/database.svelte';
import { selectedCharID } from 'src/ts/stores.svelte';
import { get } from 'svelte/store';
import { doingChat, sendChat } from '..';
import { downloadFile, isTauri } from 'src/ts/storage/globalApi';
import { doingChat, sendChat } from '../index.svelte';
import { downloadFile, isTauri } from 'src/ts/globalApi.svelte';
import { HypaProcesser } from '../memory/hypamemory';
import { BufferToText as BufferToText, selectSingleFile, sleep } from 'src/ts/util';
import { postInlayImage } from './image';
@@ -19,7 +19,7 @@ async function sendPofile(arg:sendFileArg){
let note = ''
let speaker = ''
let parseMode = 0
const db = get(DataBase)
const db = getDatabase()
let currentChar = db.characters[get(selectedCharID)]
let currentChat = currentChar.chats[currentChar.chatPage]
const lines = arg.file.split('\n')

View File

@@ -3,11 +3,11 @@ import { findCharacterbyId } from "../util";
import { alertConfirm, alertError, alertSelectChar } from "../alert";
import { language } from "src/lang";
import { get } from "svelte/store";
import { DataBase, setDatabase } from "../storage/database";
import { selectedCharID } from "../stores";
import { getDatabase, setDatabase } from "../storage/database.svelte";
import { selectedCharID } from "../stores.svelte";
export async function addGroupChar(){
let db = get(DataBase)
let db = getDatabase()
let selectedId = get(selectedCharID)
let group = db.characters[selectedId]
if(group.type === 'group'){
@@ -36,7 +36,7 @@ export async function addGroupChar(){
export function rmCharFromGroup(index:number){
let db = get(DataBase)
let db = getDatabase()
let selectedId = get(selectedCharID)
let group = db.characters[selectedId]
if(group.type === 'group'){

View File

@@ -1,10 +1,11 @@
import { get, writable } from "svelte/store";
import { DataBase, setDatabase, type character, type MessageGenerationInfo, type Chat } from "../storage/database";
import { CharEmotion, selectedCharID } from "../stores";
import { type character, type MessageGenerationInfo, type Chat } from "../storage/database.svelte";
import { DBState } from '../stores.svelte';
import { CharEmotion, selectedCharID } from "../stores.svelte";
import { ChatTokenizer, tokenize, tokenizeNum } from "../tokenizer";
import { language } from "../../lang";
import { alertError } from "../alert";
import { loadLoreBookPrompt, loadLoreBookV3Prompt } from "./lorebook";
import { loadLoreBookV3Prompt } from "./lorebook.svelte";
import { findCharacterbyId, getAuthorNoteDefaultText, getPersonaPrompt, getUserName, isLastCharPunctuation, trimUntilPunctuation } from "../util";
import { requestChatData } from "./request";
import { stableDiff } from "./stableDiff";
@@ -120,10 +121,9 @@ export async function sendChat(chatProcessIndex = -1,arg:{
chatProcessStage.set(0)
}
let db = get(DataBase)
db.statics.messages += 1
DBState.db.statics.messages += 1
let selectedChar = get(selectedCharID)
const nowChatroom = db.characters[selectedChar]
const nowChatroom = DBState.db.characters[selectedChar]
nowChatroom.lastInteraction = Date.now()
let selectedChat = nowChatroom.chatPage
nowChatroom.chats[nowChatroom.chatPage].message = nowChatroom.chats[nowChatroom.chatPage].message.map((v) => {
@@ -134,7 +134,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
let currentChar:character
let caculatedChatTokens = 0
if(db.aiModel.startsWith('gpt')){
if(DBState.db.aiModel.startsWith('gpt')){
caculatedChatTokens += 5
}
else{
@@ -188,27 +188,27 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
let chatAdditonalTokens = arg.chatAdditonalTokens ?? caculatedChatTokens
const tokenizer = new ChatTokenizer(chatAdditonalTokens, db.aiModel.startsWith('gpt') ? 'noName' : 'name')
const tokenizer = new ChatTokenizer(chatAdditonalTokens, DBState.db.aiModel.startsWith('gpt') ? 'noName' : 'name')
let currentChat = runCurrentChatFunction(nowChatroom.chats[selectedChat])
nowChatroom.chats[selectedChat] = currentChat
let maxContextTokens = db.maxContext
let maxContextTokens = DBState.db.maxContext
if(db.aiModel === 'gpt35'){
if(DBState.db.aiModel === 'gpt35'){
if(maxContextTokens > 4000){
maxContextTokens = 4000
}
}
if(db.aiModel === 'gpt35_16k' || db.aiModel === 'gpt35_16k_0613'){
if(DBState.db.aiModel === 'gpt35_16k' || DBState.db.aiModel === 'gpt35_16k_0613'){
if(maxContextTokens > 16000){
maxContextTokens = 16000
}
}
if(db.aiModel === 'gpt4'){
if(DBState.db.aiModel === 'gpt4'){
if(maxContextTokens > 8000){
maxContextTokens = 8000
}
}
if(db.aiModel === 'deepai'){
if(DBState.db.aiModel === 'deepai'){
if(maxContextTokens > 3000){
maxContextTokens = 3000
}
@@ -229,7 +229,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
'personaPrompt':([] as OpenAIChat[])
}
let promptTemplate = structuredClone(db.promptTemplate)
let promptTemplate = safeStructuredClone(DBState.db.promptTemplate)
const usingPromptTemplate = !!promptTemplate
if(promptTemplate){
let hasPostEverything = false
@@ -246,7 +246,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
})
}
}
if(currentChar.utilityBot && (!(usingPromptTemplate && db.promptSettings.utilOverride))){
if(currentChar.utilityBot && (!(usingPromptTemplate && DBState.db.promptSettings.utilOverride))){
promptTemplate = [
{
"type": "plain",
@@ -278,7 +278,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
if((!currentChar.utilityBot) && (!promptTemplate)){
const mainp = currentChar.systemPrompt?.replaceAll('{{original}}', db.mainPrompt) || db.mainPrompt
const mainp = currentChar.systemPrompt?.replaceAll('{{original}}', DBState.db.mainPrompt) || DBState.db.mainPrompt
function formatPrompt(data:string){
@@ -300,13 +300,13 @@ export async function sendChat(chatProcessIndex = -1,arg:{
return chatObjects;
}
unformated.main.push(...formatPrompt(risuChatParser(mainp + ((db.additionalPrompt === '' || (!db.promptPreprocess)) ? '' : `\n${db.additionalPrompt}`), {chara: currentChar})))
unformated.main.push(...formatPrompt(risuChatParser(mainp + ((DBState.db.additionalPrompt === '' || (!DBState.db.promptPreprocess)) ? '' : `\n${DBState.db.additionalPrompt}`), {chara: currentChar})))
if(db.jailbreakToggle){
unformated.jailbreak.push(...formatPrompt(risuChatParser(db.jailbreak, {chara: currentChar})))
if(DBState.db.jailbreakToggle){
unformated.jailbreak.push(...formatPrompt(risuChatParser(DBState.db.jailbreak, {chara: currentChar})))
}
unformated.globalNote.push(...formatPrompt(risuChatParser(currentChar.replaceGlobalNote?.replaceAll('{{original}}', db.globalNote) || db.globalNote, {chara:currentChar})))
unformated.globalNote.push(...formatPrompt(risuChatParser(currentChar.replaceGlobalNote?.replaceAll('{{original}}', DBState.db.globalNote) || DBState.db.globalNote, {chara:currentChar})))
}
if(currentChat.note){
@@ -322,7 +322,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
})
}
if(db.chainOfThought && (!(usingPromptTemplate && db.promptSettings.customChainOfThought))){
if(DBState.db.chainOfThought && (!(usingPromptTemplate && DBState.db.promptSettings.customChainOfThought))){
unformated.postEverything.push({
role: 'system',
content: `<instruction> - before respond everything, Think step by step as a ai assistant how would you respond inside <Thoughts> xml tag. this must be less than 5 paragraphs.</instruction>`
@@ -330,7 +330,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
{
let description = risuChatParser((db.promptPreprocess ? db.descriptionPrefix: '') + currentChar.desc, {chara: currentChar})
let description = risuChatParser((DBState.db.promptPreprocess ? DBState.db.descriptionPrefix: '') + currentChar.desc, {chara: currentChar})
const additionalInfo = await additionalInformations(currentChar, currentChat)
@@ -390,7 +390,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
}
if(db.personaPrompt){
if(DBState.db.personaPrompt){
unformated.personaPrompt.push({
role: 'system',
content: risuChatParser(getPersonaPrompt(), {chara: currentChar})
@@ -434,7 +434,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
//await tokenize currernt
let currentTokens = db.maxResponse
let currentTokens = DBState.db.maxResponse
let supaMemoryCardUsed = false
//for unexpected error
@@ -466,7 +466,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
for(const card of template){
switch(card.type){
case 'persona':{
let pmt = structuredClone(unformated.personaPrompt)
let pmt = safeStructuredClone(unformated.personaPrompt)
if(card.innerFormat && pmt.length > 0){
for(let i=0;i<pmt.length;i++){
pmt[i].content = risuChatParser(positionParser(card.innerFormat), {chara: currentChar}).replace('{{slot}}', pmt[i].content)
@@ -477,7 +477,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
break
}
case 'description':{
let pmt = structuredClone(unformated.description)
let pmt = safeStructuredClone(unformated.description)
if(card.innerFormat && pmt.length > 0){
for(let i=0;i<pmt.length;i++){
pmt[i].content = risuChatParser(positionParser(card.innerFormat), {chara: currentChar}).replace('{{slot}}', pmt[i].content)
@@ -488,7 +488,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
break
}
case 'authornote':{
let pmt = structuredClone(unformated.authorNote)
let pmt = safeStructuredClone(unformated.authorNote)
if(card.innerFormat && pmt.length > 0){
for(let i=0;i<pmt.length;i++){
pmt[i].content = risuChatParser(positionParser(card.innerFormat), {chara: currentChar}).replace('{{slot}}', pmt[i].content || card.defaultText || '')
@@ -504,10 +504,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
case 'postEverything':{
await tokenizeChatArray(unformated.postEverything)
if(usingPromptTemplate && db.promptSettings.postEndInnerFormat){
if(usingPromptTemplate && DBState.db.promptSettings.postEndInnerFormat){
await tokenizeChatArray([{
role: 'system',
content: db.promptSettings.postEndInnerFormat
content: DBState.db.promptSettings.postEndInnerFormat
}])
}
break
@@ -515,10 +515,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{
case 'plain':
case 'jailbreak':
case 'cot':{
if((!db.jailbreakToggle) && (card.type === 'jailbreak')){
if((!DBState.db.jailbreakToggle) && (card.type === 'jailbreak')){
continue
}
if((!db.chainOfThought) && (card.type === 'cot')){
if((!DBState.db.chainOfThought) && (card.type === 'cot')){
continue
}
@@ -573,7 +573,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
let chats = unformated.chats.slice(start, end)
if(usingPromptTemplate && db.promptSettings.sendChatAsSystem && (!card.chatAsOriginalOnSystem)){
if(usingPromptTemplate && DBState.db.promptSettings.sendChatAsSystem && (!card.chatAsOriginalOnSystem)){
chats = systemizeChat(chats)
}
await tokenizeChatArray(chats)
@@ -603,7 +603,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
let chats:OpenAIChat[] = examples
if(!db.aiModel.startsWith('novelai')){
if(!DBState.db.aiModel.startsWith('novelai')){
chats.push({
role: 'system',
content: '[Start a new chat]',
@@ -621,7 +621,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
'editprocess'))
}
if(usingPromptTemplate && db.promptSettings.sendName){
if(usingPromptTemplate && DBState.db.promptSettings.sendName){
chat.content = `${currentChar.name}: ${chat.content}`
chat.attr = ['nameAdded']
}
@@ -699,20 +699,35 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
let attr:string[] = []
let role:'user'|'assistant'|'system' = msg.role === 'user' ? 'user' : 'assistant'
if(nowChatroom.type === 'group' || (usingPromptTemplate && db.promptSettings.sendName)){
formatedChat = name + ': ' + formatedChat
attr.push('nameAdded')
if(
(nowChatroom.type === 'group' && findCharacterbyIdwithCache(msg.saying).chaId !== currentChar.chaId) ||
(nowChatroom.type === 'group' && DBState.db.groupOtherBotRole === 'assistant') ||
(usingPromptTemplate && DBState.db.promptSettings.sendName)
){
const form = DBState.db.groupTemplate || `<{{char}}\'s Message>\n{{slot}}\n</{{char}}\'s Message>`
formatedChat = risuChatParser(form, {chara: findCharacterbyIdwithCache(msg.saying).name}).replace('{{slot}}', formatedChat)
switch(DBState.db.groupOtherBotRole){
case 'user':
case 'assistant':
case 'system':
role = DBState.db.groupOtherBotRole
break
default:
role = 'assistant'
break
}
}
if(usingPromptTemplate && db.promptSettings.maxThoughtTagDepth !== -1){
if(usingPromptTemplate && DBState.db.promptSettings.maxThoughtTagDepth !== -1){
const depth = ms.length - index
if(depth >= db.promptSettings.maxThoughtTagDepth){
if(depth >= DBState.db.promptSettings.maxThoughtTagDepth){
formatedChat = formatedChat.replace(/<Thoughts>(.+?)<\/Thoughts>/gm, '')
}
}
const chat:OpenAIChat = {
role: msg.role === 'user' ? 'user' : 'assistant',
role: role,
content: formatedChat,
memo: msg.chatId,
attr: attr,
@@ -725,6 +740,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
currentTokens += await tokenizer.tokenizeChat(chat)
index++
}
console.log(JSON.stringify(chats, null, 2))
const depthPrompts = lorepmt.actives.filter(v => {
return (v.pos === 'depth' && v.depth > 0) || v.pos === 'reverse_depth'
@@ -738,9 +754,9 @@ export async function sendChat(chatProcessIndex = -1,arg:{
currentTokens += await tokenizer.tokenizeChat(chat)
}
if(nowChatroom.supaMemory && (db.supaModelType !== 'none' || db.hanuraiEnable || db.hypav2)){
if(nowChatroom.supaMemory && (DBState.db.supaModelType !== 'none' || DBState.db.hanuraiEnable || DBState.db.hypav2)){
chatProcessStage.set(2)
if(db.hanuraiEnable){
if(DBState.db.hanuraiEnable){
const hn = await hanuraiMemory(chats, {
currentTokens,
maxContextTokens,
@@ -754,7 +770,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
chats = hn.chats
currentTokens = hn.tokens
}
else if(db.hypav2){ //HypaV2 support needs to be changed like this.
else if(DBState.db.hypav2){ //HypaV2 support needs to be changed like this.
const sp = await hypaMemoryV2(chats, currentTokens, maxContextTokens, currentChat, nowChatroom, tokenizer)
console.log("All chats: ", chats)
if(sp.error){
@@ -765,13 +781,12 @@ export async function sendChat(chatProcessIndex = -1,arg:{
chats = sp.chats
currentTokens = sp.currentTokens
currentChat.hypaV2Data = sp.memory ?? currentChat.hypaV2Data
db.characters[selectedChar].chats[selectedChat].hypaV2Data = currentChat.hypaV2Data
DBState.db.characters[selectedChar].chats[selectedChat].hypaV2Data = currentChat.hypaV2Data
console.log(currentChat.hypaV2Data)
DataBase.set(db)
}
else{
const sp = await supaMemory(chats, currentTokens, maxContextTokens, currentChat, nowChatroom, tokenizer, {
asHyper: db.hypaMemory
asHyper: DBState.db.hypaMemory
})
if(sp.error){
alertError(sp.error)
@@ -780,9 +795,8 @@ export async function sendChat(chatProcessIndex = -1,arg:{
chats = sp.chats
currentTokens = sp.currentTokens
currentChat.supaMemoryData = sp.memory ?? currentChat.supaMemoryData
db.characters[selectedChar].chats[selectedChat].supaMemoryData = currentChat.supaMemoryData
DBState.db.characters[selectedChar].chats[selectedChat].supaMemoryData = currentChat.supaMemoryData
console.log(currentChat.supaMemoryData)
DataBase.set(db)
currentChat.lastMemory = sp.lastId ?? currentChat.lastMemory;
}
chatProcessStage.set(1)
@@ -801,7 +815,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
currentChat.lastMemory = chats[0].memo
}
let biases:[string,number][] = db.bias.concat(currentChar.bias).map((v) => {
let biases:[string,number][] = DBState.db.bias.concat(currentChar.bias).map((v) => {
return [risuChatParser(v[0].replaceAll("\\n","\n").replaceAll("\\r","\r").replaceAll("\\\\","\\"), {chara: currentChar}),v[1]]
})
@@ -867,13 +881,13 @@ export async function sendChat(chatProcessIndex = -1,arg:{
//make into one
let formated:OpenAIChat[] = []
const formatOrder = structuredClone(db.formatingOrder)
const formatOrder = safeStructuredClone(DBState.db.formatingOrder)
if(formatOrder){
formatOrder.push('postEverything')
}
//continue chat model
if(arg.continue && (db.aiModel.startsWith('claude') || db.aiModel.startsWith('gpt') || db.aiModel.startsWith('openrouter') || db.aiModel.startsWith('reverse_proxy'))){
if(arg.continue && (DBState.db.aiModel.startsWith('claude') || DBState.db.aiModel.startsWith('gpt') || DBState.db.aiModel.startsWith('openrouter') || DBState.db.aiModel.startsWith('reverse_proxy'))){
unformated.postEverything.push({
role: 'system',
content: '[Continue the last response]'
@@ -885,7 +899,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
if(!chat.content.trim()){
continue
}
if(!(db.aiModel.startsWith('gpt') || db.aiModel.startsWith('claude') || db.aiModel === 'openrouter' || db.aiModel === 'reverse_proxy')){
if(!(DBState.db.aiModel.startsWith('gpt') || DBState.db.aiModel.startsWith('claude') || DBState.db.aiModel === 'openrouter' || DBState.db.aiModel === 'reverse_proxy')){
formated.push(chat)
continue
}
@@ -911,7 +925,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
for(const card of template){
switch(card.type){
case 'persona':{
let pmt = structuredClone(unformated.personaPrompt)
let pmt = safeStructuredClone(unformated.personaPrompt)
if(card.innerFormat && pmt.length > 0){
for(let i=0;i<pmt.length;i++){
pmt[i].content = risuChatParser(positionParser(card.innerFormat), {chara: currentChar}).replace('{{slot}}', pmt[i].content)
@@ -922,7 +936,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
break
}
case 'description':{
let pmt = structuredClone(unformated.description)
let pmt = safeStructuredClone(unformated.description)
if(card.innerFormat && pmt.length > 0){
for(let i=0;i<pmt.length;i++){
pmt[i].content = risuChatParser(positionParser(card.innerFormat), {chara: currentChar}).replace('{{slot}}', pmt[i].content)
@@ -933,7 +947,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
break
}
case 'authornote':{
let pmt = structuredClone(unformated.authorNote)
let pmt = safeStructuredClone(unformated.authorNote)
if(card.innerFormat && pmt.length > 0){
for(let i=0;i<pmt.length;i++){
pmt[i].content = risuChatParser(positionParser(card.innerFormat), {chara: currentChar}).replace('{{slot}}', pmt[i].content || card.defaultText || '')
@@ -949,10 +963,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
case 'postEverything':{
pushPrompts(unformated.postEverything)
if(usingPromptTemplate && db.promptSettings.postEndInnerFormat){
if(usingPromptTemplate && DBState.db.promptSettings.postEndInnerFormat){
pushPrompts([{
role: 'system',
content: db.promptSettings.postEndInnerFormat
content: DBState.db.promptSettings.postEndInnerFormat
}])
}
break
@@ -960,10 +974,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{
case 'plain':
case 'jailbreak':
case 'cot':{
if((!db.jailbreakToggle) && (card.type === 'jailbreak')){
if((!DBState.db.jailbreakToggle) && (card.type === 'jailbreak')){
continue
}
if((!db.chainOfThought) && (card.type === 'cot')){
if((!DBState.db.chainOfThought) && (card.type === 'cot')){
continue
}
@@ -1018,14 +1032,14 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
let chats = unformated.chats.slice(start, end)
if(usingPromptTemplate && db.promptSettings.sendChatAsSystem && (!card.chatAsOriginalOnSystem)){
if(usingPromptTemplate && DBState.db.promptSettings.sendChatAsSystem && (!card.chatAsOriginalOnSystem)){
chats = systemizeChat(chats)
}
pushPrompts(chats)
break
}
case 'memory':{
let pmt = structuredClone(memories)
let pmt = safeStructuredClone(memories)
if(card.innerFormat && pmt.length > 0){
for(let i=0;i<pmt.length;i++){
pmt[i].content = risuChatParser(card.innerFormat, {chara: currentChar}).replace('{{slot}}', pmt[i].content)
@@ -1094,7 +1108,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
//estimate tokens
let outputTokens = db.maxResponse
let outputTokens = DBState.db.maxResponse
if(inputTokens + outputTokens > maxContextTokens){
outputTokens = maxContextTokens - inputTokens
}
@@ -1138,14 +1152,14 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
else if(req.type === 'streaming'){
const reader = req.result.getReader()
let msgIndex = db.characters[selectedChar].chats[selectedChat].message.length
let msgIndex = DBState.db.characters[selectedChar].chats[selectedChat].message.length
let prefix = ''
if(arg.continue){
msgIndex -= 1
prefix = db.characters[selectedChar].chats[selectedChat].message[msgIndex].data
prefix = DBState.db.characters[selectedChar].chats[selectedChat].message[msgIndex].data
}
else{
db.characters[selectedChar].chats[selectedChat].message.push({
DBState.db.characters[selectedChar].chats[selectedChat].message.push({
role: 'char',
data: "",
saying: currentChar.chaId,
@@ -1153,7 +1167,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
generationInfo,
})
}
db.characters[selectedChar].chats[selectedChat].isStreaming = true
DBState.db.characters[selectedChar].chats[selectedChat].isStreaming = true
let lastResponseChunk:{[key:string]:string} = {}
while(abortSignal.aborted === false){
const readed = (await reader.read())
@@ -1164,27 +1178,25 @@ export async function sendChat(chatProcessIndex = -1,arg:{
if(!result){
result = ''
}
if(db.removeIncompleteResponse){
if(DBState.db.removeIncompleteResponse){
result = trimUntilPunctuation(result)
}
let result2 = await processScriptFull(nowChatroom, reformatContent(prefix + result), 'editoutput', msgIndex)
db.characters[selectedChar].chats[selectedChat].message[msgIndex].data = result2.data
DBState.db.characters[selectedChar].chats[selectedChat].message[msgIndex].data = result2.data
emoChanged = result2.emoChanged
db.characters[selectedChar].reloadKeys += 1
setDatabase(db)
DBState.db.characters[selectedChar].reloadKeys += 1
}
if(readed.done){
db.characters[selectedChar].chats[selectedChat].isStreaming = false
db.characters[selectedChar].reloadKeys += 1
setDatabase(db)
DBState.db.characters[selectedChar].chats[selectedChat].isStreaming = false
DBState.db.characters[selectedChar].reloadKeys += 1
break
}
}
addRerolls(generationId, Object.values(lastResponseChunk))
db.characters[selectedChar].chats[selectedChat] = runCurrentChatFunction(db.characters[selectedChar].chats[selectedChat])
currentChat = db.characters[selectedChar].chats[selectedChat]
DBState.db.characters[selectedChar].chats[selectedChat] = runCurrentChatFunction(DBState.db.characters[selectedChar].chats[selectedChat])
currentChat = DBState.db.characters[selectedChar].chats[selectedChat]
const triggerResult = await runTrigger(currentChar, 'output', {chat:currentChat})
if(triggerResult && triggerResult.chat){
currentChat = triggerResult.chat
@@ -1194,15 +1206,13 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
const inlayr = runInlayScreen(currentChar, currentChat.message[msgIndex].data)
currentChat.message[msgIndex].data = inlayr.text
db.characters[selectedChar].chats[selectedChat] = currentChat
setDatabase(db)
DBState.db.characters[selectedChar].chats[selectedChat] = currentChat
if(inlayr.promise){
const t = await inlayr.promise
currentChat.message[msgIndex].data = t
db.characters[selectedChar].chats[selectedChat] = currentChat
setDatabase(db)
DBState.db.characters[selectedChar].chats[selectedChat] = currentChat
}
if(db.ttsAutoSpeech){
if(DBState.db.ttsAutoSpeech){
await sayTTS(currentChar, result)
}
}
@@ -1214,14 +1224,14 @@ export async function sendChat(chatProcessIndex = -1,arg:{
for(let i=0;i<msgs.length;i++){
let msg = msgs[i]
let mess = msg[1]
let msgIndex = db.characters[selectedChar].chats[selectedChat].message.length
let msgIndex = DBState.db.characters[selectedChar].chats[selectedChat].message.length
let result2 = await processScriptFull(nowChatroom, reformatContent(mess), 'editoutput', msgIndex)
if(i === 0 && arg.continue){
msgIndex -= 1
let beforeChat = db.characters[selectedChar].chats[selectedChat].message[msgIndex]
let beforeChat = DBState.db.characters[selectedChar].chats[selectedChat].message[msgIndex]
result2 = await processScriptFull(nowChatroom, reformatContent(beforeChat.data + mess), 'editoutput', msgIndex)
}
if(db.removeIncompleteResponse){
if(DBState.db.removeIncompleteResponse){
result2.data = trimUntilPunctuation(result2.data)
}
result = result2.data
@@ -1229,7 +1239,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
result = inlayResult.text
emoChanged = result2.emoChanged
if(i === 0 && arg.continue){
db.characters[selectedChar].chats[selectedChat].message[msgIndex] = {
DBState.db.characters[selectedChar].chats[selectedChat].message[msgIndex] = {
role: 'char',
data: result,
saying: currentChar.chaId,
@@ -1238,45 +1248,43 @@ export async function sendChat(chatProcessIndex = -1,arg:{
}
if(inlayResult.promise){
const p = await inlayResult.promise
db.characters[selectedChar].chats[selectedChat].message[msgIndex].data = p
DBState.db.characters[selectedChar].chats[selectedChat].message[msgIndex].data = p
}
}
else if(i===0){
db.characters[selectedChar].chats[selectedChat].message.push({
DBState.db.characters[selectedChar].chats[selectedChat].message.push({
role: msg[0],
data: result,
saying: currentChar.chaId,
time: Date.now(),
generationInfo
})
const ind = db.characters[selectedChar].chats[selectedChat].message.length - 1
const ind = DBState.db.characters[selectedChar].chats[selectedChat].message.length - 1
if(inlayResult.promise){
const p = await inlayResult.promise
db.characters[selectedChar].chats[selectedChat].message[ind].data = p
DBState.db.characters[selectedChar].chats[selectedChat].message[ind].data = p
}
mrerolls.push(result)
}
else{
mrerolls.push(result)
}
db.characters[selectedChar].reloadKeys += 1
if(db.ttsAutoSpeech){
DBState.db.characters[selectedChar].reloadKeys += 1
if(DBState.db.ttsAutoSpeech){
await sayTTS(currentChar, result)
}
setDatabase(db)
}
if(mrerolls.length >1){
addRerolls(generationId, mrerolls)
}
db.characters[selectedChar].chats[selectedChat] = runCurrentChatFunction(db.characters[selectedChar].chats[selectedChat])
currentChat = db.characters[selectedChar].chats[selectedChat]
DBState.db.characters[selectedChar].chats[selectedChat] = runCurrentChatFunction(DBState.db.characters[selectedChar].chats[selectedChat])
currentChat = DBState.db.characters[selectedChar].chats[selectedChat]
const triggerResult = await runTrigger(currentChar, 'output', {chat:currentChat})
if(triggerResult && triggerResult.chat){
db.characters[selectedChar].chats[selectedChat] = triggerResult.chat
setDatabase(db)
DBState.db.characters[selectedChar].chats[selectedChat] = triggerResult.chat
}
if(triggerResult && triggerResult.sendAIprompt){
resendChat = true
@@ -1285,11 +1293,11 @@ export async function sendChat(chatProcessIndex = -1,arg:{
let needsAutoContinue = false
const resultTokens = await tokenize(result) + (arg.usedContinueTokens || 0)
if(db.autoContinueMinTokens > 0 && resultTokens < db.autoContinueMinTokens){
if(DBState.db.autoContinueMinTokens > 0 && resultTokens < DBState.db.autoContinueMinTokens){
needsAutoContinue = true
}
if(db.autoContinueChat && (!isLastCharPunctuation(result))){
if(DBState.db.autoContinueChat && (!isLastCharPunctuation(result))){
//if result doesn't end with punctuation or special characters, auto continue
needsAutoContinue = true
}
@@ -1358,7 +1366,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
tempEmotion.splice(0, 1)
}
if(db.emotionProcesser === 'embedding'){
if(DBState.db.emotionProcesser === 'embedding'){
const hypaProcesser = new HypaProcesser('MiniLM')
await hypaProcesser.addText(emotionList.map((v) => 'emotion:' + v))
let searched = (await hypaProcesser.similaritySearchScored(result)).map((v) => {
@@ -1437,7 +1445,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
const promptbody:OpenAIChat[] = [
{
role:'system',
content: `${db.emotionPrompt2 || "From the list below, choose a word that best represents a character's outfit description, action, or emotion in their dialogue. Prioritize selecting words related to outfit first, then action, and lastly emotion. Print out the chosen word."}\n\n list: ${shuffleArray(emotionList).join(', ')} \noutput only one word.`
content: `${DBState.db.emotionPrompt2 || "From the list below, choose a word that best represents a character's outfit description, action, or emotion in their dialogue. Prioritize selecting words related to outfit first, then action, and lastly emotion. Print out the chosen word."}\n\n list: ${shuffleArray(emotionList).join(', ')} \noutput only one word.`
},
{
role: 'user',
@@ -1457,9 +1465,8 @@ export async function sendChat(chatProcessIndex = -1,arg:{
formated: promptbody,
bias: emobias,
currentChar: currentChar,
temperature: 0.4,
maxTokens: 30,
}, 'submodel', abortSignal)
}, 'emotion', abortSignal)
if(rq.type === 'fail' || rq.type === 'streaming' || rq.type === 'multiline'){
if(abortSignal.aborted){
@@ -1520,7 +1527,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
alertError("Stable diffusion in group chat is not supported")
}
const msgs = db.characters[selectedChar].chats[selectedChat].message
const msgs = DBState.db.characters[selectedChar].chats[selectedChat].message
let msgStr = ''
for(let i = (msgs.length - 1);i>=0;i--){
if(msgs[i].role === 'char'){

View File

@@ -1,4 +1,4 @@
import { getChatVar, getGlobalChatVar } from "../parser";
import { getChatVar, getGlobalChatVar } from "../parser.svelte";
function toRPN(expression:string) {
let outputQueue = '';

View File

@@ -1,5 +1,5 @@
import { writeInlayImage } from "./files/image";
import type { character } from "../storage/database";
import type { character } from "../storage/database.svelte";
import { generateAIImage } from "./stableDiff";
const imggenRegex = [/<ImgGen="(.+?)">/gi, /{{ImgGen="(.+?)"}}/gi] as const

View File

@@ -1,22 +1,21 @@
import { get } from "svelte/store";
import {selectedCharID} from '../stores'
import { DataBase, setDatabase, type Message, type loreBook } from "../storage/database";
import {selectedCharID} from '../stores.svelte'
import { type Message, type loreBook } from "../storage/database.svelte";
import { DBState } from '../stores.svelte';
import { tokenize } from "../tokenizer";
import { checkNullish, selectSingleFile } from "../util";
import { checkNullish, findCharacterbyId, selectSingleFile } from "../util";
import { alertError, alertNormal } from "../alert";
import { language } from "../../lang";
import { downloadFile } from "../storage/globalApi";
import { HypaProcesser } from "./memory/hypamemory";
import { downloadFile } from "../globalApi.svelte";
import { getModuleLorebooks } from "./modules";
import { CCardLib } from "@risuai/ccardlib";
export function addLorebook(type:number) {
let selectedID = get(selectedCharID)
let db = get(DataBase)
const selectedID = get(selectedCharID)
if(type === 0){
db.characters[selectedID].globalLore.push({
DBState.db.characters[selectedID].globalLore.push({
key: '',
comment: `New Lore ${db.characters[selectedID].globalLore.length + 1}`,
comment: `New Lore ${DBState.db.characters[selectedID].globalLore.length + 1}`,
content: '',
mode: 'normal',
insertorder: 100,
@@ -26,10 +25,10 @@ export function addLorebook(type:number) {
})
}
else{
const page = db.characters[selectedID].chatPage
db.characters[selectedID].chats[page].localLore.push({
const page = DBState.db.characters[selectedID].chatPage
DBState.db.characters[selectedID].chats[page].localLore.push({
key: '',
comment: `New Lore ${db.characters[selectedID].chats[page].localLore.length + 1}`,
comment: `New Lore ${DBState.db.characters[selectedID].chats[page].localLore.length + 1}`,
content: '',
mode: 'normal',
insertorder: 100,
@@ -38,245 +37,145 @@ export function addLorebook(type:number) {
selective: false
})
}
setDatabase(db)
}
interface formatedLore{
keys:string[]|'always'|{type:'regex',regex:string},
secondKey:string[]|{type:'regex',regex:string}
content: string
order: number
activatied: boolean
}
const rmRegex = / |\n/g
export async function loadLoreBookPrompt(){
const selectedID = get(selectedCharID)
const db = get(DataBase)
const char = db.characters[selectedID]
const page = char.chatPage
const characterLore = char.globalLore ?? []
const chatLore = char.chats[page].localLore ?? []
const moduleLorebook = getModuleLorebooks()
const fullLore = characterLore.concat(chatLore).concat(moduleLorebook)
const currentChat = char.chats[page].message
const loreDepth = char.loreSettings?.scanDepth ?? db.loreBookDepth
const loreToken = char.loreSettings?.tokenBudget ?? db.loreBookToken
const fullWordMatching = char.loreSettings?.fullWordMatching ?? false
let activatiedPrompt: string[] = []
let formatedLore:formatedLore[] = []
for (const lore of fullLore){
if(lore){
if(lore.key.length > 1 || lore.alwaysActive){
if(!checkNullish(lore.activationPercent)){
let activationPercent = lore.activationPercent
if(isNaN(activationPercent) || !activationPercent || activationPercent < 0){
activationPercent = 0
}
if(activationPercent < (Math.random() * 100)){
continue
}
}
if(lore.key?.startsWith('@@@')){
lore.key = lore.key.replace('@@@','@@')
}
formatedLore.push({
keys: lore.alwaysActive ? 'always' : (lore.key?.startsWith("@@regex ")) ? ({type:'regex',regex:lore.key.replace('@@regex ','')}) :
(lore.key ?? '').replace(rmRegex, '').toLocaleLowerCase().split(',').filter((a) => {
return a.length > 1
}),
secondKey: lore.selective ? ((lore.secondkey?.startsWith("@@regex ")) ? ({type:'regex',regex:lore.secondkey.replace('@@regex ','')}) :
(lore.secondkey ?? '').replace(rmRegex, '').toLocaleLowerCase().split(',').filter((a) => {
return a.length > 1
})) : [],
content: lore.content,
order: lore.insertorder,
activatied: false
})
}
}
}
formatedLore.sort((a, b) => {
return b.order - a.order
})
const formatedChatMain = currentChat.slice(currentChat.length - loreDepth,currentChat.length).map((msg) => {
return msg.data
}).join('||').replace(rmRegex,'').toLocaleLowerCase()
let loreListUpdated = true
while(loreListUpdated){
loreListUpdated = false
const formatedChat = formatedChatMain + activatiedPrompt.join('').replace(rmRegex,'').toLocaleLowerCase()
const formatedChatList = fullWordMatching ? formatedChat.split(' ') : formatedChat
for(let i=0;i<formatedLore.length;i++){
const lore = formatedLore[i]
if(lore.activatied){
continue
}
const totalTokens = await tokenize(activatiedPrompt.concat([lore.content]).join('\n\n'))
if(totalTokens > loreToken){
break
}
if(lore.keys === 'always'){
activatiedPrompt.push(lore.content)
lore.activatied = true
loreListUpdated = true
continue
}
let firstKeyActivation = false
if(Array.isArray(lore.keys)){
for(const key of lore.keys){
if(key){
if(formatedChatList.includes(key)){
firstKeyActivation = true
break
}
}
}
}
else{
if(formatedChat.match(new RegExp(lore.keys.regex,'g'))){
firstKeyActivation = true
}
}
if(firstKeyActivation){
if(Array.isArray(lore.secondKey)){
if(lore.secondKey.length === 0){
activatiedPrompt.push(lore.content)
lore.activatied = true
loreListUpdated = true
continue
}
for(const key of lore.secondKey){
if(formatedChatList.includes(key)){
activatiedPrompt.push(lore.content)
lore.activatied = true
loreListUpdated = true
break
}
}
}
else{
if(formatedChat.match(new RegExp(lore.secondKey.regex,'g'))){
firstKeyActivation = true
}
}
}
}
if(!(char.loreSettings?.recursiveScanning)){
break
}
}
let sactivated:string[] = []
let decoratedArray:{
depth:number,
pos:string,
prompt:string
}[] = []
activatiedPrompt = activatiedPrompt.filter((v) => {
if(v.startsWith("@@@end")){
sactivated.push(v.replace('@@@end','').trim())
return false
}
if(v.startsWith('@@end')){
sactivated.push(v.replace('@@end','').trim())
return false
}
return true
})
return {
act: activatiedPrompt.reverse().join('\n\n'),
special_act: sactivated.reverse().join('\n\n'),
decorated: decoratedArray
}
}
export async function loadLoreBookV3Prompt(){
const selectedID = get(selectedCharID)
const db = get(DataBase)
const char = db.characters[selectedID]
const char = DBState.db.characters[selectedID]
const page = char.chatPage
const characterLore = char.globalLore ?? []
const chatLore = char.chats[page].localLore ?? []
const moduleLorebook = getModuleLorebooks()
const fullLore = structuredClone(characterLore.concat(chatLore).concat(moduleLorebook))
const fullLore = safeStructuredClone(characterLore.concat(chatLore).concat(moduleLorebook))
const currentChat = char.chats[page].message
const loreDepth = char.loreSettings?.scanDepth ?? db.loreBookDepth
const loreToken = char.loreSettings?.tokenBudget ?? db.loreBookToken
const fullWordMatching = char.loreSettings?.fullWordMatching ?? false
const loreDepth = char.loreSettings?.scanDepth ?? DBState.db.loreBookDepth
const loreToken = char.loreSettings?.tokenBudget ?? DBState.db.loreBookToken
const fullWordMatchingSetting = char.loreSettings?.fullWordMatching ?? false
const chatLength = currentChat.length + 1 //includes first message
const recursiveScanning = char.loreSettings?.recursiveScanning ?? false
let recursiveAdditionalPrompt = ''
const recursiveScanning = char.loreSettings?.recursiveScanning ?? true
let recursivePrompt:{
prompt: string,
source: string
}[] = []
let matchLog:{
prompt: string,
source: string
activated: string
}[] = []
const searchMatch = (messages:Message[],arg:{
keys:string[],
searchDepth:number,
regex:boolean
fullWordMatching:boolean
recursiveAdditionalPrompt:string
all?:boolean
}) => {
const sliced = messages.slice(messages.length - arg.searchDepth,messages.length)
arg.keys = arg.keys.map(key => key.trim()).filter(key => key.length > 0)
let mText = sliced.map((msg) => {
return msg.data
}).join('||')
if(arg.recursiveAdditionalPrompt){
mText += arg.recursiveAdditionalPrompt
}
if(arg.regex){
for(const regexString of arg.keys){
if(!regexString.startsWith('/')){
return false
let mList:{
source:string
prompt:string
}[] = sliced.map((msg, i) => {
if(msg.role === 'user'){
return {
source: `message ${i} by user`,
prompt: `\x01{{${DBState.db.username}}}:` + msg.data + '\x01'
}
const regexFlag = regexString.split('/').pop()
if(regexFlag){
arg.keys[0] = regexString.replace('/'+regexFlag,'')
try {
const regex = new RegExp(arg.keys[0],regexFlag)
return regex.test(mText)
} catch (error) {
}
else{
return {
source: `message ${i} by char`,
prompt: `\x01{{${msg.name ?? (msg.saying ? findCharacterbyId(msg.saying)?.name : null) ?? char.name}}}:` + msg.data + '\x01'
}
}
}).concat(recursivePrompt.map((msg) => {
return {
source: 'lorebook ' + msg.source,
prompt: msg.prompt
}
}))
if(arg.regex){
for(const mText of mList){
for(const regexString of arg.keys){
if(!regexString.startsWith('/')){
return false
}
const regexFlag = regexString.split('/').pop()
if(regexFlag){
arg.keys[0] = regexString.replace('/'+regexFlag,'')
try {
const regex = new RegExp(arg.keys[0],regexFlag)
const d = regex.test(mText.prompt)
if(d){
matchLog.push({
prompt: mText.prompt,
source: mText.source,
activated: regexString
})
return true
}
} catch (error) {
return false
}
}
}
return false
}
return false
}
mText = mText.toLocaleLowerCase()
mText = mText.replace(/\{\{\/\/(.+?)\}\}/g,'').replace(/\{\{comment:(.+?)\}\}/g,'')
mList = mList.map((m) => {
return {
source: m.source,
prompt: m.prompt.toLocaleLowerCase().replace(/\{\{\/\/(.+?)\}\}/g,'').replace(/\{\{comment:(.+?)\}\}/g,'')
}
})
if(arg.fullWordMatching){
const splited = mText.split(' ')
for(const key of arg.keys){
if(splited.includes(key.toLocaleLowerCase())){
return true
let allMode = arg.all ?? false
let allModeMatched = true
for(const m of mList){
let mText = m.prompt
if(arg.fullWordMatching){
const splited = mText.split(' ')
for(const key of arg.keys){
if(splited.includes(key.toLocaleLowerCase())){
matchLog.push({
prompt: m.prompt,
source: m.source,
activated: key
})
if(!allMode){
return true
}
}
else if(allMode){
allModeMatched = false
}
}
}
else{
mText = mText.replace(/ /g,'')
for(const key of arg.keys){
const realKey = key.toLocaleLowerCase().replace(/ /g,'')
if(mText.includes(realKey)){
matchLog.push({
prompt: m.prompt,
source: m.source,
activated: key
})
if(!allMode){
return true
}
}
else if(allMode){
allModeMatched = false
}
}
}
}
else{
mText = mText.replace(/ /g,'')
for(const key of arg.keys){
const realKey = key.toLocaleLowerCase().replace(/ /g,'')
if(mText.includes(realKey)){
return true
}
}
if(allMode && allModeMatched){
return true
}
return false
@@ -291,6 +190,7 @@ export async function loadLoreBookV3Prompt(){
order:number
tokens:number
priority:number
source:string
}[] = []
let activatedIndexes:number[] = []
let disabledUIPrompts:string[] = []
@@ -314,8 +214,10 @@ export async function loadLoreBookV3Prompt(){
let role:'system'|'user'|'assistant' = 'system'
let searchQueries:{
keys:string[],
negative:boolean
negative:boolean,
all?:boolean
}[] = []
let fullWordMatching = fullWordMatchingSetting
const content = CCardLib.decorator.parse(fullLore[i].content, (name, arg) => {
switch(name){
case 'end':{
@@ -412,6 +314,22 @@ export async function loadLoreBookV3Prompt(){
})
return
}
case 'exclude_keys_all':{
searchQueries.push({
keys: arg,
negative: true,
all: true
})
return
}
case 'match_full_word':{
fullWordMatching = true
return
}
case 'match_partial_word':{
fullWordMatching = false
return
}
case 'is_user_icon':{
//TODO
return false
@@ -455,6 +373,13 @@ export async function loadLoreBookV3Prompt(){
keys: fullLore[i].key.split(','),
negative: false
})
if(fullLore[i].secondkey && fullLore[i].selective){
searchQueries.push({
keys: fullLore[i].secondkey.split(','),
negative: false
})
}
for(const query of searchQueries){
const result = searchMatch(currentChat, {
@@ -462,7 +387,7 @@ export async function loadLoreBookV3Prompt(){
searchDepth: scanDepth,
regex: fullLore[i].useRegex,
fullWordMatching: fullWordMatching,
recursiveAdditionalPrompt: recursiveAdditionalPrompt
all: query.all
})
if(query.negative){
if(result){
@@ -494,12 +419,16 @@ export async function loadLoreBookV3Prompt(){
role: role,
order: order,
tokens: await tokenize(content),
priority: priority
priority: priority,
source: fullLore[i].comment || `lorebook ${i}`
})
activatedIndexes.push(i)
if(recursiveScanning){
matching = true
recursiveAdditionalPrompt += content + '\n\n'
recursivePrompt.push({
prompt: content,
source: fullLore[i].comment || `lorebook ${i}`
})
}
}
}
@@ -524,18 +453,18 @@ export async function loadLoreBookV3Prompt(){
})
return {
actives: activesResorted.reverse()
actives: activesResorted.reverse(),
matchLog: matchLog,
}
}
export async function importLoreBook(mode:'global'|'local'|'sglobal'){
const selectedID = get(selectedCharID)
let db = get(DataBase)
const page = mode === 'sglobal' ? -1 : db.characters[selectedID].chatPage
const page = mode === 'sglobal' ? -1 : DBState.db.characters[selectedID].chatPage
let lore =
mode === 'global' ? db.characters[selectedID].globalLore :
db.characters[selectedID].chats[page].localLore
mode === 'global' ? DBState.db.characters[selectedID].globalLore :
DBState.db.characters[selectedID].chats[page].localLore
const lorebook = (await selectSingleFile(['json', 'lorebook'])).data
if(!lorebook){
return
@@ -556,12 +485,11 @@ export async function importLoreBook(mode:'global'|'local'|'sglobal'){
lore.push(...convertExternalLorebook(entries))
}
if(mode === 'global'){
db.characters[selectedID].globalLore = lore
DBState.db.characters[selectedID].globalLore = lore
}
else{
db.characters[selectedID].chats[page].localLore = lore
DBState.db.characters[selectedID].chats[page].localLore = lore
}
setDatabase(db)
} catch (error) {
alertError(`${error}`)
}
@@ -613,11 +541,10 @@ export function convertExternalLorebook(entries:{[key:string]:CCLorebook}){
export async function exportLoreBook(mode:'global'|'local'|'sglobal'){
try {
const selectedID = get(selectedCharID)
const db = get(DataBase)
const page = mode === 'sglobal' ? -1 : db.characters[selectedID].chatPage
const page = mode === 'sglobal' ? -1 : DBState.db.characters[selectedID].chatPage
const lore =
mode === 'global' ? db.characters[selectedID].globalLore :
db.characters[selectedID].chats[page].localLore
mode === 'global' ? DBState.db.characters[selectedID].globalLore :
DBState.db.characters[selectedID].chats[page].localLore
const stringl = Buffer.from(JSON.stringify({
type: 'risu',
ver: 1,

View File

@@ -1,13 +1,13 @@
import { getChatVar, hasher, risuChatParser, setChatVar, type simpleCharacterArgument } from "../parser";
import { getChatVar, hasher, setChatVar, type simpleCharacterArgument } from "../parser.svelte";
import { LuaEngine, LuaFactory } from "wasmoon";
import { DataBase, setDatabase, type Chat, type character, type groupChat } from "../storage/database";
import { getCurrentCharacter, getCurrentChat, getDatabase, setCurrentChat, setDatabase, type Chat, type character, type groupChat } from "../storage/database.svelte";
import { get } from "svelte/store";
import { CurrentCharacter, CurrentChat, ReloadGUIPointer, selectedCharID } from "../stores";
import { ReloadGUIPointer, selectedCharID } from "../stores.svelte";
import { alertError, alertInput, alertNormal } from "../alert";
import { HypaProcesser } from "./memory/hypamemory";
import { generateAIImage } from "./stableDiff";
import { writeInlayImage } from "./files/image";
import type { OpenAIChat } from ".";
import type { OpenAIChat } from "./index.svelte";
import { requestChatData } from "./request";
import { v4 } from "uuid";
import { getModuleTriggers } from "./modules";
@@ -35,12 +35,12 @@ export async function runLua(code:string, arg:{
mode?: string,
data?: any
}){
const char = arg.char ?? get(CurrentCharacter)
const char = arg.char ?? getCurrentCharacter()
const setVar = arg.setVar ?? setChatVar
const getVar = arg.getVar ?? getChatVar
const mode = arg.mode ?? 'manual'
const data = arg.data ?? {}
let chat = arg.chat ?? get(CurrentChat)
let chat = arg.chat ?? getCurrentChat()
let stopSending = false
let lowLevelAccess = arg.lowLevelAccess ?? false
@@ -104,66 +104,75 @@ export async function runLua(code:string, arg:{
if(!LuaSafeIds.has(id)){
return
}
chat = getCurrentChat()
const message = chat.message?.at(index)
if(message){
message.data = value
}
CurrentChat.set(chat)
setCurrentChat(chat)
})
luaEngine.global.set('setChatRole', (id:string, index:number, value:string) => {
if(!LuaSafeIds.has(id)){
return
}
chat = getCurrentChat()
const message = chat.message?.at(index)
if(message){
message.role = value === 'user' ? 'user' : 'char'
}
CurrentChat.set(chat)
setCurrentChat(chat)
})
luaEngine.global.set('cutChat', (id:string, start:number, end:number) => {
if(!LuaSafeIds.has(id)){
return
}
chat = getCurrentChat()
chat.message = chat.message.slice(start,end)
CurrentChat.set(chat)
setCurrentChat(chat)
})
luaEngine.global.set('removeChat', (id:string, index:number) => {
if(!LuaSafeIds.has(id)){
return
}
chat = getCurrentChat()
chat.message.splice(index, 1)
CurrentChat.set(chat)
setCurrentChat(chat)
})
luaEngine.global.set('addChat', (id:string, role:string, value:string) => {
if(!LuaSafeIds.has(id)){
return
}
chat = getCurrentChat()
let roleData:'user'|'char' = role === 'user' ? 'user' : 'char'
chat.message.push({role: roleData, data: value})
CurrentChat.set(chat)
setCurrentChat(chat)
})
luaEngine.global.set('insertChat', (id:string, index:number, role:string, value:string) => {
if(!LuaSafeIds.has(id)){
return
}
chat = getCurrentChat()
let roleData:'user'|'char' = role === 'user' ? 'user' : 'char'
chat.message.splice(index, 0, {role: roleData, data: value})
CurrentChat.set(chat)
setCurrentChat(chat)
})
luaEngine.global.set('removeChat', (id:string, index:number) => {
if(!LuaSafeIds.has(id)){
return
}
chat = getCurrentChat()
chat.message.splice(index, 1)
CurrentChat.set(chat)
setCurrentChat(chat)
})
luaEngine.global.set('getChatLength', (id:string) => {
if(!LuaSafeIds.has(id)){
return
}
chat = getCurrentChat()
return chat.message.length
})
luaEngine.global.set('getFullChatMain', (id:string) => {
chat = getCurrentChat()
const data = JSON.stringify(chat.message.map((v) => {
return {
role: v.role,
@@ -178,13 +187,14 @@ export async function runLua(code:string, arg:{
if(!LuaSafeIds.has(id)){
return
}
chat = getCurrentChat()
chat.message = realValue.map((v) => {
return {
role: v.role,
data: v.data
}
})
CurrentChat.set(chat)
setCurrentChat(chat)
})
luaEngine.global.set('logMain', (value:string) => {
@@ -322,7 +332,7 @@ export async function runLua(code:string, arg:{
if(!LuaSafeIds.has(id)){
return
}
const db = get(DataBase)
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
return char.name
@@ -332,7 +342,7 @@ export async function runLua(code:string, arg:{
if(!LuaSafeIds.has(id)){
return
}
const db = get(DataBase)
const db = getDatabase()
const selectedChar = get(selectedCharID)
if(typeof name !== 'string'){
throw('Invalid data type')
@@ -345,7 +355,7 @@ export async function runLua(code:string, arg:{
if(!LuaSafeIds.has(id)){
return
}
const db = get(DataBase)
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char =db.characters[selectedChar]
if(typeof data !== 'string'){
@@ -363,7 +373,7 @@ export async function runLua(code:string, arg:{
if(!LuaSafeIds.has(id)){
return
}
const db = get(DataBase)
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
if(typeof data !== 'string'){
@@ -379,7 +389,7 @@ export async function runLua(code:string, arg:{
if(!LuaSafeIds.has(id)){
return
}
const db = get(DataBase)
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
return char.firstMessage
@@ -389,7 +399,7 @@ export async function runLua(code:string, arg:{
if(!LuaSafeIds.has(id)){
return
}
const db = get(DataBase)
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
return char.backgroundHTML
@@ -399,7 +409,7 @@ export async function runLua(code:string, arg:{
if(!LuaSafeIds.has(id)){
return
}
const db = get(DataBase)
const db = getDatabase()
const selectedChar = get(selectedCharID)
if(typeof data !== 'string'){
return false

View File

@@ -1,10 +1,9 @@
import { alertError } from "src/ts/alert";
import type { OpenAIChat } from "..";
import type { OpenAIChat } from "../index.svelte";
import { HypaProcesser } from "./hypamemory";
import { language } from "src/lang";
import type { ChatTokenizer } from "src/ts/tokenizer";
import { get } from "svelte/store";
import { DataBase } from "src/ts/storage/database";
import { getDatabase } from "src/ts/storage/database.svelte";
const maxRecentChatQuery = 4;
export async function hanuraiMemory(chats:OpenAIChat[],arg:{
@@ -12,7 +11,7 @@ export async function hanuraiMemory(chats:OpenAIChat[],arg:{
maxContextTokens:number,
tokenizer:ChatTokenizer
}){
const db = get(DataBase)
const db = getDatabase()
const tokenizer = arg.tokenizer
const processer = new HypaProcesser('MiniLM')
let addTexts:string[] = []

View File

@@ -1,5 +1,5 @@
import localforage from "localforage";
import { globalFetch } from "src/ts/storage/globalApi";
import { globalFetch } from "src/ts/globalApi.svelte";
import { runEmbedding } from "../transformers";
import { alertError } from "src/ts/alert";
import { appendLastPath } from "src/ts/util";

View File

@@ -1,12 +1,11 @@
import { DataBase, type Chat, type character, type groupChat } from "src/ts/storage/database";
import type { OpenAIChat } from "..";
import { getDatabase, type Chat, type character, type groupChat } from "src/ts/storage/database.svelte";
import type { OpenAIChat } from "../index.svelte";
import type { ChatTokenizer } from "src/ts/tokenizer";
import { get } from "svelte/store";
import { requestChatData } from "../request";
import { HypaProcesser } from "./hypamemory";
import { globalFetch } from "src/ts/storage/globalApi";
import { globalFetch } from "src/ts/globalApi.svelte";
import { runSummarizer } from "../transformers";
import { last, remove } from "lodash";
import { parseChatML } from "src/ts/parser.svelte";
export interface HypaV2Data {
chunks: {
@@ -20,7 +19,7 @@ export interface HypaV2Data {
}
async function summary(stringlizedChat: string): Promise<{ success: boolean; data: string }> {
const db = get(DataBase);
const db = getDatabase();
console.log("Summarizing");
if (db.supaModelType === 'distilbart') {
@@ -85,7 +84,10 @@ async function summary(stringlizedChat: string): Promise<{ success: boolean; dat
};
}
} else {
const promptbody: OpenAIChat[] = [
let parsedPrompt = parseChatML(supaPrompt.replaceAll('{{slot}}', stringlizedChat))
const promptbody: OpenAIChat[] = parsedPrompt ?? [
{
role: "user",
content: stringlizedChat
@@ -101,7 +103,7 @@ async function summary(stringlizedChat: string): Promise<{ success: boolean; dat
bias: {},
useStreaming: false,
noMultiGen: true
}, 'submodel');
}, 'memory');
if (da.type === 'fail' || da.type === 'streaming' || da.type === 'multiline') {
return {
success: false,
@@ -123,7 +125,7 @@ export async function hypaMemoryV2(
arg: { asHyper?: boolean, summaryModel?: string, summaryPrompt?: string, hypaModel?: string } = {}
): Promise<{ currentTokens: number; chats: OpenAIChat[]; error?: string; memory?: HypaV2Data; }> {
const db = get(DataBase);
const db = getDatabase();
const data: HypaV2Data = room.hypaV2Data ?? { chunks: [], mainChunks: [] };
let allocatedTokens = db.hypaAllocatedTokens;

View File

@@ -1,13 +1,13 @@
import { get } from "svelte/store";
import type { OpenAIChat } from "..";
import { DataBase, type Chat, type character, type groupChat } from "../../storage/database";
import type { OpenAIChat } from "../index.svelte";
import { getDatabase, type Chat, type character, type groupChat } from "../../storage/database.svelte";
import { tokenize, type ChatTokenizer } from "../../tokenizer";
import { requestChatData } from "../request";
import { HypaProcesser } from "./hypamemory";
import { stringlizeChat } from "../stringlize";
import { globalFetch } from "src/ts/storage/globalApi";
import { globalFetch } from "src/ts/globalApi.svelte";
import { runSummarizer } from "../transformers";
import { getUserName } from "src/ts/util";
import { parseChatML } from "src/ts/parser.svelte";
export async function supaMemory(
chats:OpenAIChat[],
@@ -18,7 +18,7 @@ export async function supaMemory(
tokenizer:ChatTokenizer,
arg:{asHyper?:boolean} = {}
): Promise<{ currentTokens: number; chats: OpenAIChat[]; error?:string; memory?:string;lastId?:string}>{
const db = get(DataBase)
const db = getDatabase()
currentTokens += 10
@@ -74,7 +74,7 @@ export async function supaMemory(
for(let j=0;j<HypaData.length;j++){
let i =0;
let countTokens = currentTokens
let countChats = structuredClone(chats)
let countChats = safeStructuredClone(chats)
while(true){
if(countChats.length === 0){
break
@@ -253,7 +253,8 @@ export async function supaMemory(
}
}
else {
const promptbody:OpenAIChat[] = [
let parsedPrompt = parseChatML(supaPrompt.replaceAll('{{slot}}', stringlizedChat))
const promptbody:OpenAIChat[] = parsedPrompt ?? [
{
role: "user",
content: stringlizedChat
@@ -268,7 +269,7 @@ export async function supaMemory(
bias: {},
useStreaming: false,
noMultiGen: true
}, 'submodel')
}, 'memory')
if(da.type === 'fail' || da.type === 'streaming' || da.type === 'multiline'){
return {
currentTokens: currentTokens,

View File

@@ -1,12 +1,10 @@
import { invoke } from "@tauri-apps/api/tauri";
import { globalFetch } from "src/ts/storage/globalApi";
import { invoke } from "@tauri-apps/api/core";
import { globalFetch } from "src/ts/globalApi.svelte";
import { sleep } from "src/ts/util";
import * as path from "@tauri-apps/api/path";
import { exists, readTextFile } from "@tauri-apps/api/fs";
import { exists, readTextFile } from "@tauri-apps/plugin-fs";
import { alertClear, alertError, alertMd, alertWait } from "src/ts/alert";
import { get } from "svelte/store";
import { DataBase } from "src/ts/storage/database";
import { resolveResource } from '@tauri-apps/api/path'
import { getDatabase } from "src/ts/storage/database.svelte";
let serverRunning = false;
export function checkLocalModel():Promise<string>{
@@ -131,7 +129,7 @@ export async function loadExllamaFull(){
async function runLocalModelOld(prompt:string){
const db = get(DataBase)
const db = getDatabase()
if(!serverRunning){
await loadExllamaFull()
@@ -274,7 +272,7 @@ export async function runGGUFModel(arg:{
export async function tokenizeGGUFModel(prompt:string):Promise<number[]> {
const key = await getLocalKey()
const db = get(DataBase)
const db = getDatabase()
const modelPath = db.aiModel.replace('local_', '')
const b = await fetch("http://localhost:10026/llamacpp/tokenize", {
method: "POST",

View File

@@ -1,8 +1,7 @@
import { DataBase } from "src/ts/storage/database";
import { get } from "svelte/store";
import { getDatabase } from "src/ts/storage/database.svelte";
export function getGenerationModelString(){
const db = get(DataBase)
const db = getDatabase()
switch (db.aiModel){
case 'reverse_proxy':
return 'reverse_proxy-' + (db.reverseProxyOobaMode ? 'ooba' : db.proxyRequestModel)

View File

@@ -1,12 +1,11 @@
import { DataBase, setDatabase } from "src/ts/storage/database"
import type { OpenAIChat } from ".."
import { get } from "svelte/store"
import { globalFetch } from "src/ts/storage/globalApi"
import { getDatabase, setDatabase } from "src/ts/storage/database.svelte"
import type { OpenAIChat } from "../index.svelte"
import { globalFetch } from "src/ts/globalApi.svelte"
import { alertError, alertInput, alertNormal, alertWait } from "src/ts/alert"
import { getUserName, sleep } from "src/ts/util"
export function stringlizeNAIChat(formated:OpenAIChat[], char:string, continued: boolean){
const db = get(DataBase)
const db = getDatabase()
let seperator = db.NAIsettings.seperator.replaceAll("\\n","\n") || '\n'
let starter = db.NAIsettings.starter.replaceAll("\\n","\n") || '⁂'
let resultString:string[] = []
@@ -109,7 +108,7 @@ export const novelLogin = async () => {
const data = r.data?.accessToken
const db = get(DataBase)
const db = getDatabase()
db.novelai.token = data
alertNormal('Logged in to NovelAI')

View File

@@ -1,16 +1,15 @@
import { language } from "src/lang"
import { alertConfirm, alertError, alertModuleSelect, alertNormal, alertStore } from "../alert"
import { DataBase, setDatabase, type customscript, type loreBook, type triggerscript } from "../storage/database"
import { AppendableBuffer, downloadFile, isNodeServer, isTauri, readImage, saveAsset } from "../storage/globalApi"
import { get } from "svelte/store"
import { CurrentCharacter, CurrentChat } from "../stores"
import { getCurrentCharacter, getCurrentChat, getDatabase, setCurrentCharacter, setDatabase, type customscript, type loreBook, type triggerscript } from "../storage/database.svelte"
import { AppendableBuffer, downloadFile, isNodeServer, isTauri, readImage, saveAsset } from "../globalApi.svelte"
import { selectSingleFile, sleep } from "../util"
import { v4 } from "uuid"
import { convertExternalLorebook } from "./lorebook"
import { encode } from "msgpackr"
import { convertExternalLorebook } from "./lorebook.svelte"
import { decodeRPack, encodeRPack } from "../rpack/rpack_bg"
import { convertImage } from "../parser"
import { convertImage } from "../parser.svelte"
import { Capacitor } from "@capacitor/core"
import { HideIconStore, moduleBackgroundEmbedding, ReloadGUIPointer } from "../stores.svelte"
import {get} from "svelte/store"
export interface RisuModule{
name: string
@@ -47,7 +46,7 @@ export async function exportModule(module:RisuModule, arg:{
}
const assets = module.assets ?? []
module = structuredClone(module)
module = safeStructuredClone(module)
module.assets ??= []
module.assets = module.assets.map((asset) => {
return [asset[0], '', asset[2]] as [string,string,string]
@@ -173,7 +172,7 @@ export async function importModule(){
return
}
let fileData = f.data
const db = get(DataBase)
const db = getDatabase()
if(f.name.endsWith('.risum')){
try {
const buf = Buffer.from(fileData)
@@ -250,7 +249,7 @@ export async function importModule(){
}
function getModuleById(id:string){
const db = get(DataBase)
const db = getDatabase()
for(let i=0;i<db.modules.length;i++){
if(db.modules[i].id === id){
return db.modules[i]
@@ -261,7 +260,7 @@ function getModuleById(id:string){
function getModuleByIds(ids:string[]){
let modules:RisuModule[] = []
const db = get(DataBase)
const db = getDatabase()
for(let i=0;i<ids.length;i++){
const module = db.modules.find((m) => m.id === ids[i] || (m.namespace === ids[i] && m.namespace))
if(module){
@@ -274,8 +273,8 @@ function getModuleByIds(ids:string[]){
let lastModules = ''
let lastModuleData:RisuModule[] = []
export function getModules(){
const currentChat = get(CurrentChat)
const db = get(DataBase)
const currentChat = getCurrentChat()
const db = getDatabase()
let ids = db.enabledModules ?? []
if (currentChat){
ids = ids.concat(currentChat.modules ?? [])
@@ -363,12 +362,12 @@ export async function applyModule() {
return
}
const module = structuredClone(getModuleById(sel))
const module = safeStructuredClone(getModuleById(sel))
if (!module) {
return
}
const currentChar = get(CurrentCharacter)
const currentChar = getCurrentCharacter()
if (!currentChar) {
return
}
@@ -392,7 +391,42 @@ export async function applyModule() {
}
}
CurrentCharacter.set(currentChar)
setCurrentCharacter(currentChar)
alertNormal(language.successApplyModule)
}
let lastModuleIds:string = ''
export function moduleUpdate(){
const m = getModules()
const ids = m.map((m) => m.id).join('-')
let moduleHideIcon = false
let backgroundEmbedding = ''
m.forEach((module) => {
if(!module){
return
}
if(module.hideIcon){
moduleHideIcon = true
}
if(module.backgroundEmbedding){
backgroundEmbedding += '\n' + module.backgroundEmbedding + '\n'
}
})
if(backgroundEmbedding){
moduleBackgroundEmbedding.set(backgroundEmbedding)
}
HideIconStore.set(getCurrentCharacter()?.hideChatIcon || moduleHideIcon)
if(lastModuleIds !== ids){
ReloadGUIPointer.set(get(ReloadGUIPointer) + 1)
lastModuleIds = ids
}
}

View File

@@ -1,4 +1,4 @@
import { AppendableBuffer, isNodeServer, isTauri, saveAsset, type LocalWriter, type VirtualWriter } from "../storage/globalApi";
import { AppendableBuffer, isNodeServer, isTauri, saveAsset, type LocalWriter, type VirtualWriter } from "../globalApi.svelte";
import * as fflate from "fflate";
import { sleep } from "../util";
import { alertStore } from "../alert";

View File

@@ -1,6 +1,6 @@
import { get } from "svelte/store";
import { tokenizeAccurate } from "../tokenizer";
import { DataBase, presetTemplate, setDatabase, type Database } from "../storage/database";
import { getDatabase, presetTemplate, setDatabase, type Database } from "../storage/database.svelte";
import { alertError, alertNormal } from "../alert";
import type { OobaChatCompletionRequestParams } from "../model/ooba";
@@ -256,7 +256,7 @@ export const OobaParams = [
]
export function promptConvertion(files:{ name: string, content: string, type:string }[]){
let preset = structuredClone(presetTemplate)
let preset = safeStructuredClone(presetTemplate)
let instData = {
"system_prompt": "",
"input_sequence": "",
@@ -383,7 +383,7 @@ export function promptConvertion(files:{ name: string, content: string, type:str
if(type === 'STCHAT'){
preset.aiModel = 'openrouter'
preset.subModel = 'openrouter'
const db = get(DataBase)
const db = getDatabase()
db.botPresets.push(preset)
setDatabase(db)
@@ -461,7 +461,7 @@ export function promptConvertion(files:{ name: string, content: string, type:str
preset.name ||= 'Converted from JSON'
const db = get(DataBase)
const db = getDatabase()
db.botPresets.push(preset)
setDatabase(db)

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,11 @@
import { get } from "svelte/store";
import { CharEmotion, selectedCharID } from "../stores";
import { DataBase, setDatabase, type character, type customscript, type groupChat, type Database } from "../storage/database";
import { downloadFile } from "../storage/globalApi";
import { CharEmotion, selectedCharID } from "../stores.svelte";
import { type character, type customscript, type groupChat, type Database, getDatabase } from "../storage/database.svelte";
import { downloadFile } from "../globalApi.svelte";
import { alertError, alertNormal } from "../alert";
import { language } from "src/lang";
import { selectSingleFile } from "../util";
import { assetRegex, type CbsConditions, risuChatParser as risuChatParserOrg, type simpleCharacterArgument } from "../parser";
import { assetRegex, type CbsConditions, risuChatParser as risuChatParserOrg, type simpleCharacterArgument } from "../parser.svelte";
import { runCharacterJS } from "../plugins/embedscript";
import { getModuleAssets, getModuleRegexScripts } from "./modules";
import { HypaProcesser } from "./memory/hypamemory";
@@ -27,7 +27,7 @@ export async function processScript(char:character|groupChat, data:string, mode:
}
export function exportRegex(s?:customscript[]){
let db = get(DataBase)
let db = getDatabase()
const script = s ?? db.globalscript
const data = Buffer.from(JSON.stringify({
type: 'regex',
@@ -43,7 +43,7 @@ export async function importRegex(o?:customscript[]):Promise<customscript[]>{
if(!filedata){
return o
}
let db = get(DataBase)
let db = getDatabase()
try {
const imported= JSON.parse(Buffer.from(filedata).toString('utf-8'))
if(imported.type === 'regex' && imported.data){
@@ -65,9 +65,42 @@ export async function importRegex(o?:customscript[]):Promise<customscript[]>{
}
let bestMatchCache = new Map<string, string>()
let processScriptCache = new Map<string, string>()
function cacheScript(scripts:customscript[], data:string, result:string, mode:ScriptMode){
let hash = data + '|||' + mode + '|||'
for(const script of scripts){
hash += `${script.in}|||${script.out}|||${script.flag}|||${script.ableFlag}|||${script.type}`
}
processScriptCache.set(hash, result)
if(processScriptCache.size > 500){
processScriptCache.delete(processScriptCache.keys().next().value)
}
}
function getScriptCache(scripts:customscript[], data:string, mode:ScriptMode){
let hash = data + '|||' + mode + '|||'
for(const script of scripts){
hash += `${script.in}|||${script.out}|||${script.flag}|||${script.ableFlag}|||${script.type}`
}
return processScriptCache.get(hash)
}
export function resetScriptCache(){
processScriptCache = new Map()
}
export async function processScriptFull(char:character|groupChat|simpleCharacterArgument, data:string, mode:ScriptMode, chatID = -1, cbsConditions:CbsConditions = {}){
let db = get(DataBase)
let db = getDatabase()
const originalData = data
const cached = getScriptCache((db.globalscript ?? []).concat(char.customscript), originalData, mode)
if(cached){
return {data: cached, emoChanged: false}
}
let emoChanged = false
const scripts = (db.globalscript ?? []).concat(char.customscript).concat(getModuleRegexScripts())
data = await runCharacterJS({
@@ -77,6 +110,7 @@ export async function processScriptFull(char:character|groupChat|simpleCharacter
})
data = await runLuaEditTrigger(char, mode, data)
if(scripts.length === 0){
cacheScript(scripts, originalData, data, mode)
return {data, emoChanged}
}
function executeScript(pscript:pScript){
@@ -231,7 +265,7 @@ export async function processScriptFull(char:character|groupChat|simpleCharacter
for (const script of scripts){
if(script.ableFlag && script.flag?.includes('<')){
const rregex = /<(.+?)>/g
const scriptData = structuredClone(script)
const scriptData = safeStructuredClone(script)
let order = 0
const actions:string[] = []
scriptData.flag = scriptData.flag?.replace(rregex, (v:string, p1:string) => {
@@ -311,6 +345,8 @@ export async function processScriptFull(char:character|groupChat|simpleCharacter
}
}
cacheScript(scripts, originalData, data, mode)
return {data, emoChanged}
}

View File

@@ -1,14 +1,14 @@
import { get } from "svelte/store"
import { DataBase, type character } from "../storage/database"
import { getDatabase, type character } from "../storage/database.svelte"
import { requestChatData } from "./request"
import { alertError } from "../alert"
import { globalFetch, readImage } from "../storage/globalApi"
import { CharEmotion } from "../stores"
import type { OpenAIChat } from "."
import { globalFetch, readImage } from "../globalApi.svelte"
import { CharEmotion } from "../stores.svelte"
import type { OpenAIChat } from "./index.svelte"
import { processZip } from "./processzip"
import { keiServerURL } from "../kei/kei"
export async function stableDiff(currentChar:character,prompt:string){
let db = get(DataBase)
let db = getDatabase()
if(db.sdProvider === ''){
alertError("Stable diffusion is not set in settings.")
@@ -56,7 +56,7 @@ export async function stableDiff(currentChar:character,prompt:string){
}
export async function generateAIImage(genPrompt:string, currentChar:character, neg:string, returnSdData:string):Promise<string|false>{
const db = get(DataBase)
const db = getDatabase()
console.log(db.sdProvider)
if(db.sdProvider === 'webui'){
@@ -490,7 +490,7 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
}
}
if(db.sdProvider === 'kei'){
const db = get(DataBase)
const db = getDatabase()
let auth = db?.account?.token
if(!auth){
db.account = JSON.parse(localStorage.getItem("fallbackRisuToken"))

View File

@@ -1,6 +1,5 @@
import { get } from "svelte/store";
import type { OpenAIChat } from ".";
import { DataBase } from "../storage/database";
import type { OpenAIChat } from "./index.svelte";
import { getDatabase } from "../storage/database.svelte";
import { getUserName } from "../util";
export function multiChatReplacer(){
@@ -41,7 +40,7 @@ function appendWhitespace(prefix:string, seperator:string=" ") {
return prefix
}
export function stringlizeChatOba(formated:OpenAIChat[], characterName:string, suggesting:boolean, continued:boolean){
const db = get(DataBase)
const db = getDatabase()
let resultString:string[] = []
let { systemPrefix, userPrefix, assistantPrefix, seperator } = db.ooba.formating;
systemPrefix = systemPrefix ?? ""
@@ -103,7 +102,7 @@ function toTitleCase(s:string){
return s[0].toUpperCase() + s.slice(1).toLowerCase()
}
export function getStopStrings(suggesting:boolean=false){
const db = get(DataBase)
const db = getDatabase()
let { userPrefix, seperator } = db.ooba.formating;
if(!seperator){
seperator = "\n"
@@ -160,7 +159,7 @@ export function unstringlizeChat(text:string, formated:OpenAIChat[], char:string
export function getUnstringlizerChunks(formated:OpenAIChat[], char:string, mode:'ain'|'normal' = 'normal'){
let chunks:string[] = ["system note:", "system:","system note", "system"]
let charNames:string[] = []
const db = get(DataBase)
const db = getDatabase()
if(char){
charNames.push(char)
if(mode === 'ain'){
@@ -212,7 +211,7 @@ export function getUnstringlizerChunks(formated:OpenAIChat[], char:string, mode:
export function stringlizeAINChat(formated:OpenAIChat[], char:string, continued: boolean){
let resultString:string[] = []
const db = get(DataBase)
const db = getDatabase()
for(const form of formated){
console.log(form)
@@ -292,7 +291,7 @@ function extractAINOutputStrings(inputString:string, characters:string[]) {
export function unstringlizeAIN(data:string,formated:OpenAIChat[], char:string = ''){
const db = get(DataBase)
const db = getDatabase()
const chunksResult = getUnstringlizerChunks(formated, char ,'ain')
const chunks = chunksResult.chunks
let result:['char'|'user',string][] = []

View File

@@ -1,8 +1,6 @@
import { Template } from '@huggingface/jinja';
import type { OpenAIChat } from '..';
import { get } from 'svelte/store';
import { DataBase } from 'src/ts/storage/database';
import { CurrentCharacter } from 'src/ts/stores';
import type { OpenAIChat } from '../index.svelte';
import { getCurrentCharacter, getDatabase } from 'src/ts/storage/database.svelte';
import { getUserName } from 'src/ts/util';
export const chatTemplates = {
@@ -30,13 +28,13 @@ export const applyChatTemplate = (messages:OpenAIChat[], arg:{
type?: string
custom?: string
} = {}) => {
const db = get(DataBase)
const currentChar = get(CurrentCharacter)
const db = getDatabase()
const currentChar = getCurrentCharacter()
const type = arg.type ?? db.instructChatTemplate
if(!type){
throw new Error('Template type is not set')
}
let clonedMessages = structuredClone(messages)
let clonedMessages = safeStructuredClone(messages)
const template = type === 'jinja' ? (new Template(arg.custom ?? db.JinjaTemplate)) :(new Template(chatTemplates[type]))
let formatedMessages:{
"role": 'user'|'assistant'|'system',

View File

@@ -1,12 +1,11 @@
import { DataBase, setPreset, type botPreset, setDatabase } from "src/ts/storage/database";
import { setPreset, type botPreset, setDatabase, getDatabase } from "src/ts/storage/database.svelte";
import { defaultAutoSuggestPrefixOoba, defaultAutoSuggestPrompt, defaultAutoSuggestPromptOoba } from "src/ts/storage/defaultPrompts";
import { get } from "svelte/store";
import { prebuiltNAIpresets, prebuiltPresets } from "./templates";
import { prebuiltPresets } from "./templates";
import { alertConfirm, alertSelect } from "src/ts/alert";
import { language } from "src/lang";
export async function setRecommended(model: string, ask:'ask'|'force') {
const db = get(DataBase)
const db = getDatabase()
if(!(recommendedPresetExist(model))){
return
}

View File

@@ -1,6 +1,5 @@
import { risuChatParser } from "src/ts/parser"
import { DataBase } from "src/ts/storage/database"
import { get } from "svelte/store"
import { risuChatParser } from "src/ts/parser.svelte"
import { getDatabase } from "src/ts/storage/database.svelte"
export function convertInterfaceToSchema(int:string){
if(!int.startsWith('interface ') && !int.startsWith('export interface ')){
@@ -122,7 +121,7 @@ export function convertInterfaceToSchema(int:string){
}
export function getOpenAIJSONSchema(){
const db = get(DataBase)
const db = getDatabase()
const schema = {
"name": "format",
"strict": db.strictJsonSchema,

View File

@@ -1,4 +1,4 @@
import type { Database } from 'src/ts/storage/database'
import type { Database } from 'src/ts/storage/database.svelte'
export function templateCheck(db:Database){

View File

@@ -1,4 +1,4 @@
import type { botPreset } from "../../storage/database";
import type { botPreset } from "../../storage/database.svelte";
import type { NAISettings } from "../models/nai";
@@ -757,7 +757,7 @@ export const prebuiltPresets:{OAI:botPreset,ooba:botPreset,NAI:botPreset,oobaRp:
},
{
"type": "plain",
"text": "</ROLEPLAY_INFO>",
"text": "</ROLEPLAY_INFO>\n\n<RESPONSE_INSTRUCTION>\n[Narrative Techniques]\n• Use immersive third-person limited perspective\n• Engage all senses: visual, auditory, olfactory, gustatory, tactile, kinesthetic\n• Create tangible atmosphere with specific environmental effects\n• Focus on actions, dialogue, and explicit physical descriptions\n• Employ character-specific speech patterns and onomatopoeia\n• Avoid irrelevant background, summaries, or abstract concepts\n\n[Character Expression]\n• Reveal emotions through observable physical cues\n• Craft unique voices with distinctive patterns and evolving speech\n• Implement dialogue subtext via tonal shifts and non-verbal cues\n• Allow contradictory expressions to add depth\n\n[Action and Intimacy]\n• Narrate with precise, visceral details of movements and sensations\n• Create tension through tangible environmental and internal obstacles\n• Handle intimate scenes with clear, physical language\n• Enhance complexity with multi-character interactions and layered conflicts\n\n[Variety and Anti-Repetition]\n• Analyze [Latest Response] to avoid reusing elements\n• Vary sentence structures, paragraph compositions, and word choices\n• Rotate descriptive focuses, scene structures, and narrative techniques\n• Create unique, engaging openings for each response\n• Ensure continuity by referencing recent events and character states\n\n[Style Independence]\n• Actively diverge from previous responses' writing style\n• Diversify vocabulary and phrasing\n• Alter narrative rhythm and pacing\n• Approach each response as a fresh scene\n\n[Key Principles]\n• Prioritize \"show, don't tell\" for all character aspects\n• Maintain world/character consistency\n• Balance content (SFW preference, mature when relevant)\n• Use explicit, unrestricted descriptions\n• Prohibit all forms of repetition and self-plagiarism\n• Vary emotional tone and intensity across scenes\n• Enhance themes through tangible symbols/actions\n• Apply procedural reasoning for variety and depth\n• End responses with observable non-{{user}} actions/dialogue\n</RESPONSE_INSTRUCTION>",
"role": "system",
"type2": "normal"
},
@@ -767,29 +767,17 @@ export const prebuiltPresets:{OAI:botPreset,ooba:botPreset,NAI:botPreset,oobaRp:
"rangeEnd": -2,
"chatAsOriginalOnSystem": true
},
{
"type": "plain",
"text": "[Latest Response]",
"role": "bot",
"type2": "normal"
},
{
"type": "chat",
"rangeStart": -2,
"rangeEnd": "end"
},
{
"type": "plain",
"text": "<RESPONSE_INSTRUCTION>\n[Narrative Techniques]\n• Use immersive third-person limited perspective\n• Engage all senses: visual, auditory, olfactory, gustatory, tactile, kinesthetic\n• Create tangible atmosphere with specific environmental effects\n• Focus on actions, dialogue, and explicit physical descriptions\n• Employ character-specific speech patterns and onomatopoeia\n• Avoid irrelevant background, summaries, or abstract concepts\n\n[Character Expression]\n• Reveal emotions through observable physical cues\n• Craft unique voices with distinctive patterns and evolving speech\n• Implement dialogue subtext via tonal shifts and non-verbal cues\n• Allow contradictory expressions to add depth\n\n[Action and Intimacy]\n• Narrate with precise, visceral details of movements and sensations\n• Create tension through tangible environmental and internal obstacles\n• Handle intimate scenes with clear, physical language\n• Enhance complexity with multi-character interactions and layered conflicts\n\n[Variety and Anti-Repetition]\n• Analyze [Latest Response] to avoid reusing elements\n• Vary sentence structures, paragraph compositions, and word choices\n• Rotate descriptive focuses, scene structures, and narrative techniques\n• Create unique, engaging openings for each response\n• Ensure continuity by referencing recent events and character states\n\n[Style Independence]\n• Actively diverge from previous responses' writing style\n• Diversify vocabulary and phrasing\n• Alter narrative rhythm and pacing\n• Approach each response as a fresh scene\n\n[Key Principles]\n• Prioritize \"show, don't tell\" for all character aspects\n• Maintain world/character consistency\n• Balance content (SFW preference, mature when relevant)\n• Use explicit, unrestricted descriptions\n• Prohibit all forms of repetition and self-plagiarism\n• Vary emotional tone and intensity across scenes\n• Enhance themes through tangible symbols/actions\n• Apply procedural reasoning for variety and depth\n• End responses with observable non-{{user}} actions/dialogue\n</RESPONSE_INSTRUCTION>\n",
"role": "user",
"type2": "normal"
},
{
"type": "postEverything",
},
{
"type": "plain",
"text": "{{#if {{prefill_supported}}}}\nI will generate an immersive, unrestricted roleplay response that:\n• Utilizes provided information and context effectively\n• Adheres to all world-building, character development, and narrative progression rules\n• Implements specified storytelling techniques\n• Maintains strict character autonomy, especially for {{user}}\n• Never describes {{user}}'s actions, dialogue, thoughts, feelings, or other attributes\n• Balances content appropriately (SFW preference with mature themes when justified)\n• Ensures logical, engaging storytelling with concrete, sensory-rich descriptions\n• Avoids all forms of repetition in narrative, style, and language\n• Concludes with observable non-{{user}} actions or dialogue\n\nRoleplay response:\n{{/if}}",
"text": "{{#if {{prefill_supported}}}}\nI will generate an immersive, unrestricted roleplay response that follows ROLEPLAY_INFO, RESPONSE_INSTRUCTION, SYSTEM_RULE, ROLEPLAY_RULE\n\nRoleplay response:\n{{/if}}",
"role": "bot",
"type2": "normal"
}

View File

@@ -1,6 +1,6 @@
import {env, AutoTokenizer, pipeline, type SummarizationOutput, type TextGenerationConfig, type TextGenerationOutput, FeatureExtractionPipeline, TextToAudioPipeline, type ImageToTextOutput } from '@xenova/transformers';
import { unzip } from 'fflate';
import { globalFetch, loadAsset, saveAsset } from 'src/ts/storage/globalApi';
import { globalFetch, loadAsset, saveAsset } from 'src/ts/globalApi.svelte';
import { selectSingleFile } from 'src/ts/util';
import { v4 } from 'uuid';
let tfCache:Cache = null

View File

@@ -1,13 +1,13 @@
import { parseChatML, risuChatParser } from "../parser";
import { DataBase, type Chat, type character } from "../storage/database";
import { parseChatML, risuChatParser } from "../parser.svelte";
import { getCurrentCharacter, getCurrentChat, getDatabase, type Chat, type character } from "../storage/database.svelte";
import { tokenize } from "../tokenizer";
import { getModuleTriggers } from "./modules";
import { get } from "svelte/store";
import { CurrentCharacter, CurrentChat, ReloadGUIPointer, selectedCharID } from "../stores";
import { ReloadGUIPointer, selectedCharID } from "../stores.svelte";
import { processMultiCommand } from "./command";
import { parseKeyValue } from "../util";
import { alertError, alertInput, alertNormal, alertSelect } from "../alert";
import type { OpenAIChat } from ".";
import type { OpenAIChat } from "./index.svelte";
import { HypaProcesser } from "./memory/hypamemory";
import { requestChatData } from "./request";
import { generateAIImage } from "./stableDiff";
@@ -152,12 +152,12 @@ export async function runTrigger(char:character,mode:triggerMode, arg:{
manualName?: string
}){
arg.recursiveCount ??= 0
char = structuredClone(char)
char = safeStructuredClone(char)
let varChanged = false
let stopSending = arg.stopSending ?? false
const CharacterlowLevelAccess = char.lowLevelAccess ?? false
let sendAIprompt = false
const currentChat = get(CurrentChat)
const currentChat = getCurrentChat()
let additonalSysPrompt:additonalSysPrompt = arg.additonalSysPrompt ?? {
start:'',
historyend: '',
@@ -167,9 +167,9 @@ export async function runTrigger(char:character,mode:triggerMode, arg:{
v.lowLevelAccess = CharacterlowLevelAccess
return v
}).concat(getModuleTriggers())
const db = get(DataBase)
const db = getDatabase()
const defaultVariables = parseKeyValue(char.defaultVariables).concat(parseKeyValue(db.templateDefaultVariables))
let chat = structuredClone(arg.chat ?? char.chats[char.chatPage])
let chat = safeStructuredClone(arg.chat ?? char.chats[char.chatPage])
if((!triggers) || (triggers.length === 0)){
return null
}
@@ -190,8 +190,8 @@ export async function runTrigger(char:character,mode:triggerMode, arg:{
function setVar(key:string, value:string){
const selectedCharId = get(selectedCharID)
const currentCharacter = get(CurrentCharacter)
const db = get(DataBase)
const currentCharacter = getCurrentCharacter()
const db = getDatabase()
varChanged = true
chat.scriptstate ??= {}
chat.scriptstate['$' + key] = value
@@ -517,7 +517,7 @@ export async function runTrigger(char:character,mode:triggerMode, arg:{
if(triggerCodeResult.stopSending){
stopSending = true
}
chat = triggerCodeResult.chat
chat = getCurrentChat()
break
}
}
@@ -535,7 +535,7 @@ export async function runTrigger(char:character,mode:triggerMode, arg:{
caculatedTokens += await tokenize(additonalSysPrompt.promptend)
}
if(varChanged){
const currentChat = get(CurrentChat)
const currentChat = getCurrentChat()
currentChat.scriptstate = chat.scriptstate
ReloadGUIPointer.set(get(ReloadGUIPointer) + 1)
}

View File

@@ -1,11 +1,10 @@
import { get } from "svelte/store";
import { alertError } from "../alert";
import { DataBase, type character } from "../storage/database";
import { getCurrentCharacter, getDatabase, type character } from "../storage/database.svelte";
import { runTranslator, translateVox } from "../translator/translator";
import { globalFetch, loadAsset } from "../storage/globalApi";
import { globalFetch, loadAsset } from "../globalApi.svelte";
import { language } from "src/lang";
import { getCurrentCharacter, sleep } from "../util";
import { registerOnnxModel, runVITS } from "./transformers";
import { sleep } from "../util";
import { runVITS } from "./transformers";
let sourceNode:AudioBufferSourceNode = null
@@ -23,7 +22,7 @@ export async function sayTTS(character:character,text:string) {
return
}
let db = get(DataBase)
let db = getDatabase()
text = text.replace(/\*/g,'')
if(character.ttsReadOnlyQuoted){
@@ -311,6 +310,49 @@ export async function sayTTS(character:character,text:string) {
throw new Error(text);
}
}
case 'fishspeech':{
if (character.fishSpeechConfig.model._id === ''){
throw new Error('FishSpeech Model is not selected')
}
const audioContext = new AudioContext();
const body = {
text: text,
reference_id: character.fishSpeechConfig.model._id,
chunk_length: character.fishSpeechConfig.chunk_length,
normalize: character.fishSpeechConfig.normalize,
format: 'mp3',
mp3_bitrate: 192,
}
console.log(body)
const response = await globalFetch(`https://api.fish.audio/v1/tts`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${db.fishSpeechKey}`
},
body: body,
rawResponse: true,
})
console.log(response)
if (response.ok) {
const audioBuffer = response.data.buffer;
audioContext.decodeAudioData(audioBuffer, (decodedData) => {
const sourceNode = audioContext.createBufferSource();
sourceNode.buffer = decodedData;
sourceNode.connect(audioContext.destination);
sourceNode.start();
});
} else {
const textBuffer: Uint8Array = response.data.buffer
const text = Buffer.from(textBuffer).toString('utf-8')
throw new Error(text);
}
}
}
} catch (error) {
alertError(`TTS Error: ${error}`)
@@ -340,7 +382,7 @@ export function getWebSpeechTTSVoices() {
}
export async function getElevenTTSVoices() {
let db = get(DataBase)
let db = getDatabase()
const data = await fetch('https://api.elevenlabs.io/v1/voices', {
headers: {
@@ -354,7 +396,7 @@ export async function getElevenTTSVoices() {
}
export async function getVOICEVOXVoices() {
const db = get(DataBase);
const db = getDatabase();
const speakerData = await fetch(`${db.voicevoxUrl}/speakers`)
const speakerList = await speakerData.json()
const speakersInfo = speakerList.map((speaker) => {