From 3f4baac593ebf5c5fa178767c03673f575b0a788 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 02:39:56 +0900 Subject: [PATCH 01/16] [feat] better stringlizer --- src/ts/process/index.ts | 19 ++++++++++++------- src/ts/process/request.ts | 5 +++++ src/ts/process/stringlize.ts | 9 +++------ 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/ts/process/index.ts b/src/ts/process/index.ts index 564ecdaa..93d537e4 100644 --- a/src/ts/process/index.ts +++ b/src/ts/process/index.ts @@ -18,6 +18,7 @@ export interface OpenAIChat{ role: 'system'|'user'|'assistant' content: string memo?:string + name?:string } export const doingChat = writable(false) @@ -200,22 +201,26 @@ export async function sendChat(chatProcessIndex = -1):Promise { const ms = currentChat.message for(const msg of ms){ let formedChat = processScript(currentChar,replacePlaceholders(msg.data, currentChar.name), 'editprocess') - if(nowChatroom.type === 'group'){ - if(msg.saying && msg.role === 'char'){ - formedChat = `${findCharacterbyIdwithCache(msg.saying).name}: ${formedChat}` - + let name = '' + if(msg.role === 'char'){ + if(msg.saying){ + name = `${findCharacterbyIdwithCache(msg.saying).name}` } - else if(msg.role === 'user'){ - formedChat = `${db.username}: ${formedChat}` + 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 + memo: msg.chatId, + name: name }) currentTokens += (await tokenize(formedChat) + 1) } diff --git a/src/ts/process/request.ts b/src/ts/process/request.ts index 34235e34..124aa07f 100644 --- a/src/ts/process/request.ts +++ b/src/ts/process/request.ts @@ -53,6 +53,11 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' switch(aiModel){ case 'gpt35': case 'gpt4':{ + + for(let i=0;i Date: Wed, 24 May 2023 04:16:34 +0900 Subject: [PATCH 02/16] [feat] novelai support --- src/lib/Setting/Pages/BotSettings.svelte | 52 +++++++++++++++++------- src/lib/Setting/Settings.svelte | 4 +- src/ts/database.ts | 24 +++++++++++ src/ts/process/request.ts | 48 +++++++++++++++++++++- 4 files changed, 110 insertions(+), 18 deletions(-) diff --git a/src/lib/Setting/Pages/BotSettings.svelte b/src/lib/Setting/Pages/BotSettings.svelte index 7b5897d6..313b56b7 100644 --- a/src/lib/Setting/Pages/BotSettings.svelte +++ b/src/lib/Setting/Pages/BotSettings.svelte @@ -37,24 +37,38 @@

{language.chatBot}

{language.model} {language.submodel} - + + + + + + + {#if $DataBase.aiModel === 'novelai' || isTauri} + + {/if} + + {#if $DataBase.plugins.length > 0} + + {/if} + {#if $DataBase.aiModel === 'palm2' || $DataBase.subModel === 'palm2'} @@ -78,6 +92,11 @@ {/each} {/if} +{#if $DataBase.aiModel === "novelai" || $DataBase.subModel === "novelai"} + NovelAI Bearer Token + + +{/if} {#if $DataBase.aiModel === 'textgen_webui' || $DataBase.subModel === 'textgen_webui'} TextGen {language.providerURL} @@ -98,12 +117,15 @@ {tokens.globalNote} {language.tokens} {language.maxContextSize} + {#if $DataBase.aiModel === 'gpt35'} {:else if $DataBase.aiModel === 'gpt4' || $DataBase.aiModel === 'textgen_webui'} {:else if $DataBase.aiModel === 'custom'} +{:else} + {/if} {language.maxResponseSize} diff --git a/src/lib/Setting/Settings.svelte b/src/lib/Setting/Settings.svelte index 173b1787..bfbac3cb 100644 --- a/src/lib/Setting/Settings.svelte +++ b/src/lib/Setting/Settings.svelte @@ -10,8 +10,8 @@ import AdvancedSettings from "./Pages/AdvancedSettings.svelte"; import { SizeStore, settingsOpen } from "src/ts/stores"; import Botpreset from "./botpreset.svelte"; - import Communities from "./Pages/Communities.svelte"; - import { openURL } from "src/ts/globalApi"; + import Communities from "./Pages/Communities.svelte"; + import { openURL } from "src/ts/globalApi"; let selected = -1 let openPresetList = false if(window.innerWidth >= 700){ diff --git a/src/ts/database.ts b/src/ts/database.ts index 9bd3051e..ba23de50 100644 --- a/src/ts/database.ts +++ b/src/ts/database.ts @@ -222,6 +222,19 @@ export function setDatabase(data:Database){ FontColorItalicBold: "#8C8D93" } } + if(checkNullish(data.hordeConfig)){ + data.hordeConfig = { + apiKey: "", + model: "", + softPrompt: "" + } + } + if(checkNullish(data.novelai)){ + data.novelai = { + token: "", + model: "clio-v1", + } + } changeLanguage(data.language) @@ -431,6 +444,17 @@ export interface Database{ textScreenRounded?:boolean textScreenBorder?:string characterOrder:(string|folder)[] + hordeConfig:hordeConfig, + novelai:{ + token:string, + model:string + } +} + +interface hordeConfig{ + apiKey:string + model:string + softPrompt:string } export interface folder{ diff --git a/src/ts/process/request.ts b/src/ts/process/request.ts index 124aa07f..e61cb9d2 100644 --- a/src/ts/process/request.ts +++ b/src/ts/process/request.ts @@ -4,7 +4,7 @@ import { DataBase, setDatabase, type character } from "../database"; import { pluginProcess } from "./plugins"; import { language } from "../../lang"; import { stringlizeChat } from "./stringlize"; -import { globalFetch } from "../globalApi"; +import { globalFetch, isTauri } from "../globalApi"; interface requestDataArgument{ formated: OpenAIChat[] @@ -173,6 +173,52 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' break } + case 'novelai':{ + if(!isTauri){ + return{ + type: 'fail', + result: "NovelAI doesn't work in web version." + } + } + const proompt = stringlizeChat(formated, currentChar?.name ?? '') + const params = { + "input": proompt, + "model":db.novelai.model, + "parameters":{ + "use_string":true, + "temperature":1.7, + "max_length":90, + "min_length":1, + "tail_free_sampling":0.6602, + "repetition_penalty":1.0565, + "repetition_penalty_range":340, + "repetition_penalty_frequency":0, + "repetition_penalty_presence":0, + "use_cache":false, + "return_full_text":false, + "prefix":"vanilla", + "order":[3,0]} + } + + const da = await globalFetch("https://api.novelai.net/ai/generate", { + body: params, + headers: { + "Authorization": "Bearer " + db.novelai.token + } + }) + + if((!da.ok )|| (!da.data.output)){ + return { + type: 'fail', + result: (language.errors.httpError + `${JSON.stringify(da.data)}`) + } + } + return { + type: "success", + result: da.data.output + } + } + case "textgen_webui":{ let DURL = db.textgenWebUIURL let bodyTemplate:any From 56264286b9b53794288eb6e32482113e625fe5ba Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 04:27:15 +0900 Subject: [PATCH 03/16] [feat] added unstringlizer --- src/ts/process/request.ts | 12 +++--------- src/ts/process/stringlize.ts | 38 +++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/ts/process/request.ts b/src/ts/process/request.ts index e61cb9d2..438561a0 100644 --- a/src/ts/process/request.ts +++ b/src/ts/process/request.ts @@ -3,7 +3,7 @@ import type { OpenAIChat } from "."; import { DataBase, setDatabase, type character } from "../database"; import { pluginProcess } from "./plugins"; import { language } from "../../lang"; -import { stringlizeChat } from "./stringlize"; +import { stringlizeChat, unstringlizeChat } from "./stringlize"; import { globalFetch, isTauri } from "../globalApi"; interface requestDataArgument{ @@ -215,7 +215,7 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' } return { type: "success", - result: da.data.output + result: unstringlizeChat(da.data.output, formated, currentChar?.name ?? '') } } @@ -291,15 +291,9 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' try { let result:string = isNewAPI ? dat.results[0].text : dat.data[0].substring(proompt.length) - for(const stopStr of stopStrings){ - if(result.endsWith(stopStr)){ - result.substring(0,result.length - stopStr.length) - } - } - return { type: 'success', - result: result + result: unstringlizeChat(result, formated, currentChar?.name ?? '') } } catch (error) { return { diff --git a/src/ts/process/stringlize.ts b/src/ts/process/stringlize.ts index 731178ed..c11c9386 100644 --- a/src/ts/process/stringlize.ts +++ b/src/ts/process/stringlize.ts @@ -10,9 +10,45 @@ export function stringlizeChat(formated:OpenAIChat[], char:string = ''){ if(form.role === 'system'){ resultString.push("system note: " + form.content) } - else{ + else if(form.name){ resultString.push(form.name + ": " + form.content) } + else{ + resultString.push(form.content) + } } return resultString.join('\n\n') + `\n\n${char}:` +} + +export function unstringlizeChat(text:string, formated:OpenAIChat[], char:string = ''){ + let minIndex = -1 + let chunks:string[] = ["system note:"] + if(char){ + chunks.push(`${char}:`) + } + + for(const form of formated){ + if(form.name){ + const chunk = `${form.name}:` + if(!chunks.includes(chunk)){ + chunks.push(chunk) + } + } + } + + for(const chunk of chunks){ + const ind = text.indexOf(chunk) + if(ind === -1){ + continue + } + if(minIndex === -1 || minIndex > ind){ + minIndex = ind + } + } + + if(minIndex !== -1){ + text.substring(0, minIndex) + } + + return text } \ No newline at end of file From 87203ed95f4a295840983a78cc0d17f1546a57f9 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 04:30:26 +0900 Subject: [PATCH 04/16] [fix] fixed unstringlizer --- src/ts/process/stringlize.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ts/process/stringlize.ts b/src/ts/process/stringlize.ts index c11c9386..62e58d4d 100644 --- a/src/ts/process/stringlize.ts +++ b/src/ts/process/stringlize.ts @@ -21,6 +21,7 @@ export function stringlizeChat(formated:OpenAIChat[], char:string = ''){ } export function unstringlizeChat(text:string, formated:OpenAIChat[], char:string = ''){ + console.log(text) let minIndex = -1 let chunks:string[] = ["system note:"] if(char){ @@ -47,7 +48,7 @@ export function unstringlizeChat(text:string, formated:OpenAIChat[], char:string } if(minIndex !== -1){ - text.substring(0, minIndex) + text = text.substring(0, minIndex).trim() } return text From 022f70f21478c8bc969a39166d9373e7b6ae78fd Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 04:41:59 +0900 Subject: [PATCH 05/16] fixed novelai name --- src/lib/Setting/Pages/BotSettings.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Setting/Pages/BotSettings.svelte b/src/lib/Setting/Pages/BotSettings.svelte index 313b56b7..6e78e188 100644 --- a/src/lib/Setting/Pages/BotSettings.svelte +++ b/src/lib/Setting/Pages/BotSettings.svelte @@ -44,7 +44,7 @@ {#if $DataBase.aiModel === 'novelai' || isTauri} - + {/if} {#if $DataBase.plugins.length > 0} From a999d6d78033cec6dd11f35e057841addce8edbf Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 08:49:35 +0900 Subject: [PATCH 06/16] [feat] added horde support, added spec2 requirements that didn't implemented --- src/lib/Setting/Pages/BotSettings.svelte | 43 +++------ src/lib/SideBars/CharConfig.svelte | 20 ++--- src/lib/UI/ModelList.svelte | 35 ++++++++ src/ts/characterCards.ts | 17 ++-- src/ts/characters.ts | 10 ++- src/ts/database.ts | 5 +- src/ts/horde/getModels.ts | 34 ++++++++ src/ts/process/index.ts | 6 +- src/ts/process/request.ts | 106 ++++++++++++++++++++++- 9 files changed, 214 insertions(+), 62 deletions(-) create mode 100644 src/lib/UI/ModelList.svelte create mode 100644 src/ts/horde/getModels.ts diff --git a/src/lib/Setting/Pages/BotSettings.svelte b/src/lib/Setting/Pages/BotSettings.svelte index 6e78e188..b1798739 100644 --- a/src/lib/Setting/Pages/BotSettings.svelte +++ b/src/lib/Setting/Pages/BotSettings.svelte @@ -6,6 +6,7 @@ import { customProviderStore, getCurrentPluginMax } from "src/ts/process/plugins"; import { isTauri } from "src/ts/globalApi"; import { tokenize } from "src/ts/tokenizer"; + import ModelList from "src/lib/UI/ModelList.svelte"; import DropList from "src/lib/SideBars/DropList.svelte"; import { PlusIcon, TrashIcon } from "lucide-svelte"; let tokens = { @@ -36,40 +37,10 @@

{language.chatBot}

{language.model} - - + {language.submodel} - + + {#if $DataBase.aiModel === 'palm2' || $DataBase.subModel === 'palm2'} Palm2 {language.apiKey} @@ -96,6 +67,12 @@ NovelAI Bearer Token +{/if} + +{#if $DataBase.aiModel.startsWith("horde") || $DataBase.subModel.startsWith("horde") } + Horde {language.apiKey} + + {/if} {#if $DataBase.aiModel === 'textgen_webui' || $DataBase.subModel === 'textgen_webui'} TextGen {language.providerURL} diff --git a/src/lib/SideBars/CharConfig.svelte b/src/lib/SideBars/CharConfig.svelte index 9f3bf036..137ffeb2 100644 --- a/src/lib/SideBars/CharConfig.svelte +++ b/src/lib/SideBars/CharConfig.svelte @@ -16,7 +16,7 @@ import RegexData from "./RegexData.svelte"; import { exportChar } from "src/ts/characterCards"; import { getElevenTTSVoices, getWebSpeechTTSVoices } from "src/ts/process/tts"; - import { checkCharOrder } from "src/ts/globalApi"; + import { checkCharOrder } from "src/ts/globalApi"; let subMenu = 0 let subberMenu = 0 @@ -181,10 +181,10 @@ {language.firstMessage} {tokens.firstMsg} {language.tokens} - {language.authorNote} - - {tokens.charaNote} {language.tokens} - + {language.authorNote} + + {tokens.localNote} {language.tokens} + {:else} {language.character} @@ -213,11 +213,6 @@ - {language.chatNotes} - - {tokens.localNote} {language.tokens} - - {/if}
@@ -520,10 +515,7 @@ {language.systemPrompt} - {language.chatNotes} - - {tokens.localNote} {language.tokens} - + {#if currentChar.data.chats[currentChar.data.chatPage].supaMemoryData && currentChar.data.chats[currentChar.data.chatPage].supaMemoryData.length > 4} {language.SuperMemory} diff --git a/src/lib/UI/ModelList.svelte b/src/lib/UI/ModelList.svelte new file mode 100644 index 00000000..0d20bd3a --- /dev/null +++ b/src/lib/UI/ModelList.svelte @@ -0,0 +1,35 @@ + + +{#await getHordeModels()} + +{:then models} + +{/await} \ No newline at end of file diff --git a/src/ts/characterCards.ts b/src/ts/characterCards.ts index 30bf445a..c9e25b8a 100644 --- a/src/ts/characterCards.ts +++ b/src/ts/characterCards.ts @@ -203,7 +203,8 @@ function convertOldTavernAndJSON(charaData:OldTavernChar, imgp:string|undefined characterVersion: 0, personality: charaData.personality ?? '', scenario:charaData.scenario ?? '', - firstMsgIndex: -1 + firstMsgIndex: -1, + replaceGlobalNote: "" } } @@ -381,7 +382,7 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array):Promise // see field `selective`. ignored if selective == false constant?: boolean // if true, always inserted in the prompt (within budget limit) position?: 'before_char' | 'after_char' // whether the entry is placed before or after the character defs - + case_sensitive?:boolean } \ No newline at end of file diff --git a/src/ts/characters.ts b/src/ts/characters.ts index 83774b78..e78c3bc9 100644 --- a/src/ts/characters.ts +++ b/src/ts/characters.ts @@ -275,7 +275,6 @@ export function characterFormatUpdate(index:number|character){ cha.exampleMessage = cha.exampleMessage ?? '' cha.creatorNotes = cha.creatorNotes ?? '' cha.systemPrompt = cha.systemPrompt ?? '' - cha.postHistoryInstructions = cha.postHistoryInstructions ?? '' cha.tags = cha.tags ?? [] cha.creator = cha.creator ?? '' cha.characterVersion = cha.characterVersion ?? 0 @@ -288,6 +287,12 @@ export function characterFormatUpdate(index:number|character){ character_version: 0 } + if(cha.postHistoryInstructions){ + cha.chats[cha.chatPage].note += "\n" + cha.postHistoryInstructions + cha.chats[cha.chatPage].note = cha.chats[cha.chatPage].note.trim() + cha.postHistoryInstructions = null + } + } if(checkNullish(cha.customscript)){ cha.customscript = [] @@ -332,7 +337,8 @@ export function createBlankChar():character{ characterVersion: 0, personality:"", scenario:"", - firstMsgIndex: -1 + firstMsgIndex: -1, + replaceGlobalNote: "" } } diff --git a/src/ts/database.ts b/src/ts/database.ts index ba23de50..eac656cf 100644 --- a/src/ts/database.ts +++ b/src/ts/database.ts @@ -259,7 +259,9 @@ export interface loreBook{ mode: 'multiple'|'constant'|'normal', alwaysActive: boolean selective:boolean - extentions?:{} + extentions?:{ + risu_case_sensitive:boolean + } } export interface character{ @@ -303,6 +305,7 @@ export interface character{ supaMemory?:boolean additionalAssets?:[string, string][] ttsReadOnlyQuoted?:boolean + replaceGlobalNote:string } diff --git a/src/ts/horde/getModels.ts b/src/ts/horde/getModels.ts new file mode 100644 index 00000000..b2b4e6d8 --- /dev/null +++ b/src/ts/horde/getModels.ts @@ -0,0 +1,34 @@ +import { sleep } from "../util" + +let modelList:string[]|'loading' = null + +//until horde is ready +modelList = [] + +export async function getHordeModels():Promise { + + if(modelList === null){ + try { + modelList = 'loading' + const models = await fetch("https://stablehorde.net/api/v2/status/models?type=text") + modelList = ((await models.json()).map((a) => { + return a.name + }) as string[]) + return modelList + } catch (error) { + modelList = null + return [] + } + } + else if(modelList === 'loading'){ + while(true){ + if(modelList !== 'loading'){ + return getHordeModels() + } + await sleep(10) + } + } + else{ + return modelList + } +} \ No newline at end of file diff --git a/src/ts/process/index.ts b/src/ts/process/index.ts index 93d537e4..26c7b18b 100644 --- a/src/ts/process/index.ts +++ b/src/ts/process/index.ts @@ -105,7 +105,7 @@ export async function sendChat(chatProcessIndex = -1):Promise { } if(!currentChar.utilityBot){ - const mainp = currentChar.systemPrompt.length > 3 ? currentChar.systemPrompt : db.mainPrompt + const mainp = currentChar.systemPrompt || db.mainPrompt unformated.main.push({ role: 'system', @@ -121,14 +121,14 @@ export async function sendChat(chatProcessIndex = -1):Promise { unformated.globalNote.push({ role: 'system', - content: replacePlaceholders(db.globalNote, currentChar.name) + content: replacePlaceholders(currentChar.replaceGlobalNote || db.globalNote, currentChar.name) }) } if(currentChat.note !== ''){ unformated.authorNote.push({ role: 'system', - content: replacePlaceholders(currentChar.postHistoryInstructions, currentChat.note) + content: replacePlaceholders(currentChat.note, currentChar.name) }) } diff --git a/src/ts/process/request.ts b/src/ts/process/request.ts index 438561a0..83dab435 100644 --- a/src/ts/process/request.ts +++ b/src/ts/process/request.ts @@ -5,6 +5,8 @@ import { pluginProcess } from "./plugins"; import { language } from "../../lang"; import { stringlizeChat, unstringlizeChat } from "./stringlize"; import { globalFetch, isTauri } from "../globalApi"; +import { alertError } from "../alert"; +import { sleep } from "../util"; interface requestDataArgument{ formated: OpenAIChat[] @@ -34,7 +36,7 @@ export async function requestChatData(arg:requestDataArgument, model:'model'|'su return da } trys += 1 - if(trys > db.requestRetrys){ + if(trys > db.requestRetrys || model.startsWith('horde')){ return da } } @@ -411,7 +413,107 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' } } } - default:{ + default:{ + if(aiModel.startsWith("horde:::")){ + const realModel = aiModel.split(":::")[1].trim() + + const workers = ((await (await fetch("https://stablehorde.net/api/v2/workers")).json()) as {id:string,models:string[]}[]).filter((a) => { + + if(a && a.models && a.id){ + console.log(a) + return a.models.includes(realModel) + } + return false + }).map((a) => { + return a.id + }) + + const argument = { + "prompt": "string", + "params": { + "n": 1, + "frmtadsnsp": false, + "frmtrmblln": false, + "frmtrmspch": false, + "frmttriminc": false, + "max_context_length": 200, + "max_length": 20, + "rep_pen": 3, + "rep_pen_range": 0, + "rep_pen_slope": 10, + "singleline": false, + "temperature": db.temperature / 25, + "tfs": 1, + "top_a": 1, + "top_k": 100, + "top_p": 1, + "typical": 1, + "sampler_order": [ + 0 + ] + }, + "trusted_workers": false, + "slow_workers": true, + "worker_blacklist": false, + "dry_run": false + } + + const da = await fetch("https://stablehorde.net/api/v2/generate/text/async", { + body: JSON.stringify(argument), + method: "POST", + headers: { + "content-type": "application/json", + "apikey": db.hordeConfig.apiKey + } + }) + + if(da.status !== 202){ + return { + type: "fail", + result: await da.text() + } + } + + const json:{ + id:string, + kudos:number, + message:string + } = await da.json() + + let warnMessage = "" + if(json.message && json.message.startsWith("Warning:")){ + warnMessage = "with " + json.message + } + + while(true){ + await sleep(1000) + const data = await (await fetch("https://stablehorde.net/api/v2/generate/text/status/" + json.id)).json() + if(!data.is_possible){ + fetch("https://stablehorde.net/api/v2/generate/text/status/" + json.id, { + method: "DELETE" + }) + return { + type: 'fail', + result: "Response not possible" + warnMessage + } + } + if(data.done){ + const generations:{text:string}[] = data.generations + if(generations && generations.length > 0){ + return { + type: "success", + result: generations[0].text + } + } + return { + type: 'fail', + result: "No Generations when done" + } + } + } + + + } return { type: 'fail', result: (language.errors.unknownModel) From 3f40371528e0196d270a92a898f555e33cc4fc66 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 08:53:13 +0900 Subject: [PATCH 07/16] [feat] added replace global note --- src/lang/en.ts | 8 +++++--- src/lib/SideBars/CharConfig.svelte | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/lang/en.ts b/src/lang/en.ts index f42cc627..4c9d618a 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -67,7 +67,7 @@ export const languageEnglish = { + "\n\n`````` Marks the beginning of a new conversation.", creatorQuotes: "Note that appearances on top of first message. Used to inform users about this character. It doesn't go into prompt.", systemPrompt: "A prompt that replaces main prompt in settings if its not blank.", - chatNote: "a note that strongly effects model behavior. embbedded to current chat. also known as memory.", + chatNote: "a note that strongly effects model behavior. embbedded to current chat. also known as memory or ujb.", personality: "A brief description about character's personality. \n\n**It is not recommended to use this option. Describe it in character description instead.**", scenario: "A brief description about character's scenario. \n\n**It is not recommended to use this option. Describe it in character description instead.**", utilityBot: "When activated, it ignores main prompt. \n\n**It is not recommended to use this option. Modifiy system prompt instead.**", @@ -76,7 +76,8 @@ export const languageEnglish = { superMemory: "SuperMemory makes your character memorize more by giving summarized data to AI.\n\n" + "SuperMemory model is a model that summarizes that text. davinci is recommended, and Auxiliary models are not recommended unless it is an unfiltered model with over 2000 tokens with great summarizing skill.\n\n" + "SuperMemory Prompt decides what prompt should be sent to summarize. if you leave it blank, it will use the default prompt. leaving blank is recommended.\n\n" - + "After it is all setup, you can able it in the setting of a character." + + "After it is all setup, you can able it in the setting of a character.", + replaceGlobalNote: "If its not blank, it replaces current global note to this." }, setup: { chooseProvider: "Choose AI Provider", @@ -266,5 +267,6 @@ export const languageEnglish = { textScreenBorder: "Text Screen Borders", ttsReadOnlyQuoted: "Read Only Quoted", ttsStop: "Stop TTS", - askRemoval:"Ask Removal" + askRemoval:"Ask Removal", + replaceGlobalNote: "Global Note Replacement" } diff --git a/src/lib/SideBars/CharConfig.svelte b/src/lib/SideBars/CharConfig.svelte index 137ffeb2..2d0051bf 100644 --- a/src/lib/SideBars/CharConfig.svelte +++ b/src/lib/SideBars/CharConfig.svelte @@ -515,6 +515,9 @@ {language.systemPrompt} + {language.replaceGlobalNote} + + {#if currentChar.data.chats[currentChar.data.chatPage].supaMemoryData && currentChar.data.chats[currentChar.data.chatPage].supaMemoryData.length > 4} {language.SuperMemory} From 3f0ebef7232dd7ff43d14aa9f86ba0a3eac054d1 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 09:40:53 +0900 Subject: [PATCH 08/16] [feat] global lorebook --- src/lang/en.ts | 6 +- .../Pages/GlobalLoreBookSettings.svelte | 11 +++ src/lib/Setting/Settings.svelte | 19 ++++- src/lib/Setting/lorepreset.svelte | 77 +++++++++++++++++++ src/lib/SideBars/LoreBookSetting.svelte | 29 +++++-- src/ts/database.ts | 12 +++ src/ts/process/lorebook.ts | 39 +++++++--- 7 files changed, 173 insertions(+), 20 deletions(-) create mode 100644 src/lib/Setting/Pages/GlobalLoreBookSettings.svelte create mode 100644 src/lib/Setting/lorepreset.svelte diff --git a/src/lang/en.ts b/src/lang/en.ts index 4c9d618a..a3d5a464 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -268,5 +268,7 @@ export const languageEnglish = { ttsReadOnlyQuoted: "Read Only Quoted", ttsStop: "Stop TTS", askRemoval:"Ask Removal", - replaceGlobalNote: "Global Note Replacement" -} + replaceGlobalNote: "Global Note Replacement", + charLoreBook: 'Character Lorebook', + globalLoreBook: 'Global Lorebook', +} \ No newline at end of file diff --git a/src/lib/Setting/Pages/GlobalLoreBookSettings.svelte b/src/lib/Setting/Pages/GlobalLoreBookSettings.svelte new file mode 100644 index 00000000..dc17babc --- /dev/null +++ b/src/lib/Setting/Pages/GlobalLoreBookSettings.svelte @@ -0,0 +1,11 @@ + +

{language.globalLoreBook}

+ + + \ No newline at end of file diff --git a/src/lib/Setting/Settings.svelte b/src/lib/Setting/Settings.svelte index bfbac3cb..ce1e9737 100644 --- a/src/lib/Setting/Settings.svelte +++ b/src/lib/Setting/Settings.svelte @@ -1,5 +1,5 @@ + +
+
+
+

{language.loreBook}

+
+ +
+
+ {#each $DataBase.loreBook as lore, ind} + +
+ + {/each} +
+ + +
+
+
+ + \ No newline at end of file diff --git a/src/lib/SideBars/LoreBookSetting.svelte b/src/lib/SideBars/LoreBookSetting.svelte index 59813b86..91489ee9 100644 --- a/src/lib/SideBars/LoreBookSetting.svelte +++ b/src/lib/SideBars/LoreBookSetting.svelte @@ -7,7 +7,7 @@ import LoreBookData from "./LoreBookData.svelte"; import Check from "../Others/Check.svelte"; let submenu = 0 - let globalMode = false + export let globalMode = false {#if !globalMode} @@ -30,9 +30,26 @@ {/if} {#if submenu !== 2} - {submenu === 0 ? $DataBase.characters[$selectedCharID].type === 'group' ? language.groupLoreInfo : language.globalLoreInfo : language.localLoreInfo} + {#if !globalMode} + {submenu === 0 ? $DataBase.characters[$selectedCharID].type === 'group' ? language.groupLoreInfo : language.globalLoreInfo : language.localLoreInfo} + {/if}
- {#if submenu === 0} + {#if globalMode} + {#if $DataBase.loreBook[$DataBase.loreBookPage].data.length === 0} + No Lorebook + {:else} + {#each $DataBase.loreBook[$DataBase.loreBookPage].data as book, i} + {#if i !== 0} +
+ {/if} + { + let lore = $DataBase.loreBook[$DataBase.loreBookPage].data + lore.splice(i, 1) + $DataBase.loreBook[$DataBase.loreBookPage].data = lore + }}/> + {/each} + {/if} + {:else if submenu === 0} {#if $DataBase.characters[$selectedCharID].globalLore.length === 0} No Lorebook {:else} @@ -96,16 +113,16 @@ {#if submenu !== 2}
- diff --git a/src/ts/database.ts b/src/ts/database.ts index eac656cf..1092e4a0 100644 --- a/src/ts/database.ts +++ b/src/ts/database.ts @@ -235,6 +235,13 @@ export function setDatabase(data:Database){ model: "clio-v1", } } + if(checkNullish(data.loreBook)){ + data.loreBookPage = 0 + data.loreBook = [{ + name: "My First LoreBook", + data: [] + }] + } changeLanguage(data.language) @@ -382,6 +389,11 @@ export interface Database{ jailbreakToggle:boolean loreBookDepth: number loreBookToken: number, + loreBook: { + name:string + data:loreBook[] + }[] + loreBookPage: number supaMemoryPrompt: string username: string userIcon: string diff --git a/src/ts/process/lorebook.ts b/src/ts/process/lorebook.ts index 8a523f1d..137fb056 100644 --- a/src/ts/process/lorebook.ts +++ b/src/ts/process/lorebook.ts @@ -10,7 +10,19 @@ import { downloadFile } from "../globalApi"; export function addLorebook(type:number) { let selectedID = get(selectedCharID) let db = get(DataBase) - if(type === 0){ + if(type === -1){ + db.loreBook[db.loreBookPage].data.push({ + key: '', + comment: `New Lore ${db.loreBook[db.loreBookPage].data.length + 1}`, + content: '', + mode: 'normal', + insertorder: 100, + alwaysActive: false, + secondkey: "", + selective: false + }) + } + else if(type === 0){ db.characters[selectedID].globalLore.push({ key: '', comment: `New Lore ${db.characters[selectedID].globalLore.length + 1}`, @@ -53,9 +65,10 @@ export async function loadLoreBookPrompt(){ const db = get(DataBase) const char = db.characters[selectedID] const page = char.chatPage - const globalLore = char.globalLore - const charLore = char.chats[page].localLore - const fullLore = globalLore.concat(charLore) + const characterLore = char.globalLore + const chatLore = char.chats[page].localLore + const globalLore = db.loreBook[db.loreBookPage].data + const fullLore = characterLore.concat(chatLore.concat(globalLore)) const currentChat = char.chats[page].message const loreDepth = char.loreSettings?.scanDepth ?? db.loreBookDepth const loreToken = char.loreSettings?.tokenBudget ?? db.loreBookToken @@ -144,11 +157,14 @@ export async function loadLoreBookPrompt(){ } -export async function importLoreBook(mode:'global'|'local'){ +export async function importLoreBook(mode:'global'|'local'|'sglobal'){ const selectedID = get(selectedCharID) let db = get(DataBase) const page = db.characters[selectedID].chatPage - let lore = mode === 'global' ? db.characters[selectedID].globalLore : db.characters[selectedID].chats[page].localLore + let lore = + mode === 'global' ? db.characters[selectedID].globalLore : + mode === 'sglobal' ? db.loreBook[db.loreBookPage].data : + db.characters[selectedID].chats[page].localLore const lorebook = (await selectSingleFile(['json'])).data if(!lorebook){ return @@ -189,6 +205,9 @@ export async function importLoreBook(mode:'global'|'local'){ if(mode === 'global'){ db.characters[selectedID].globalLore = lore } + if(mode === 'sglobal'){ + db.loreBook[db.loreBookPage].data = lore + } else{ db.characters[selectedID].chats[page].localLore = lore } @@ -198,13 +217,15 @@ export async function importLoreBook(mode:'global'|'local'){ } } -export async function exportLoreBook(mode:'global'|'local'){ +export async function exportLoreBook(mode:'global'|'local'|'sglobal'){ try { const selectedID = get(selectedCharID) const db = get(DataBase) const page = db.characters[selectedID].chatPage - const lore = mode === 'global' ? db.characters[selectedID].globalLore : db.characters[selectedID].chats[page].localLore - + const lore = + mode === 'global' ? db.characters[selectedID].globalLore : + mode === 'sglobal' ? db.loreBook[db.loreBookPage].data : + db.characters[selectedID].chats[page].localLore const stringl = Buffer.from(JSON.stringify({ type: 'risu', ver: 1, From db19f15cb07eaf1c6e35d230dbdb60b2b30be959 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 09:42:38 +0900 Subject: [PATCH 09/16] [fix] hide horde --- src/lib/UI/ModelList.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/UI/ModelList.svelte b/src/lib/UI/ModelList.svelte index 0d20bd3a..f7cd5490 100644 --- a/src/lib/UI/ModelList.svelte +++ b/src/lib/UI/ModelList.svelte @@ -26,10 +26,10 @@ {/if} - + {/await} \ No newline at end of file From bd138a1215bac61575798316ab600c2dc9afcffe Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 09:50:29 +0900 Subject: [PATCH 10/16] [feat] added copy to bot preset --- src/lib/Setting/botpreset.svelte | 12 +++++++++--- src/ts/database.ts | 19 ++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/lib/Setting/botpreset.svelte b/src/lib/Setting/botpreset.svelte index 80552432..b8279767 100644 --- a/src/lib/Setting/botpreset.svelte +++ b/src/lib/Setting/botpreset.svelte @@ -1,8 +1,8 @@
-
+

{language.presets}

@@ -35,6 +35,12 @@ {presets.name} {/if}
+ -
-
{ - e.preventDefault() - e.dataTransfer.dropEffect = 'move' - e.currentTarget.classList.add('bg-green-500') - }} on:dragleave={(e) => { - e.currentTarget.classList.remove('bg-green-500') - }} on:drop={(e) => { - e.preventDefault() - e.currentTarget.classList.remove('bg-green-500') - const da = currentDrag - if(da){ - inserter(da,{index:0}) - } - }} on:dragenter={preventAll} /> - {#if menuMode === 0} - {#each charImages as char, ind} -
{avatarDragStart({index:ind}, e)}} - on:dragover={avatarDragOver} - on:drop={(e) => {avatarDrop({index:ind}, e)}} - on:dragenter={preventAll} - on:contextmenu={preventAll} - > - - -
{ - if(char.type === "normal"){ - changeChar(char.index); - } - }} - on:keydown={(e) => { - if (e.key === "Enter") { + }}> + +
+
{ + e.preventDefault() + e.dataTransfer.dropEffect = 'move' + e.currentTarget.classList.add('bg-green-500') + }} on:dragleave={(e) => { + e.currentTarget.classList.remove('bg-green-500') + }} on:drop={(e) => { + e.preventDefault() + e.currentTarget.classList.remove('bg-green-500') + const da = currentDrag + if(da){ + inserter(da,{index:0}) + } + }} on:dragenter={preventAll} /> + {#if menuMode === 0} + {#each charImages as char, ind} +
{avatarDragStart({index:ind}, e)}} + on:dragover={avatarDragOver} + on:drop={(e) => {avatarDrop({index:ind}, e)}} + on:dragenter={preventAll} + on:contextmenu={preventAll} + > + + +
{ if(char.type === "normal"){ changeChar(char.index); } - } - }} - tabindex="0" - > - {#if char.type === 'normal'} - - {:else if char.type === "folder"} - { - if(char.type !== 'folder'){ - return - } - if(openFolders.includes(char.id)){ - openFolders.splice(openFolders.indexOf(char.id), 1) - } - else{ - openFolders.push(char.id) - } - openFolders = openFolders - }}> - {#if openFolders.includes(char.id)} - - {:else} - - {/if} - - {/if} -
-
- {#if char.type === 'folder' && openFolders.includes(char.id)} -
-
-
{ - e.preventDefault() - e.dataTransfer.dropEffect = 'move' - e.currentTarget.classList.add('bg-green-500') - }} on:dragleave={(e) => { - e.currentTarget.classList.remove('bg-green-500') - }} on:drop={(e) => { - e.preventDefault() - e.currentTarget.classList.remove('bg-green-500') - const da = currentDrag - if(da && char.type === 'folder'){ - inserter(da,{index:0,folder:char.id}) - } - }} on:dragenter={preventAll}/> - {#each char.folder as char2, ind} -
{if(char.type === 'folder'){avatarDragStart({index: ind, folder:char.id}, e)}}} - on:dragover={avatarDragOver} - on:drop={(e) => {if(char.type === 'folder'){avatarDrop({index: ind, folder:char.id}, e)}}} - on:dragenter={preventAll} - on:contextmenu={preventAll} + }} + on:keydown={(e) => { + if (e.key === "Enter") { + if(char.type === "normal"){ + changeChar(char.index); + } + } + }} + tabindex="0" > - - -
{ - if(char2.type === "normal"){ - changeChar(char2.index); - } - }} - on:keydown={(e) => { - if (e.key === "Enter") { - if(char2.type === "normal"){ - changeChar(char2.index); - } - } - }} - tabindex="0" - > - -
-
-
{ + {#if char.type === 'normal'} + + {:else if char.type === "folder"} + { + if(char.type !== 'folder'){ + return + } + if(openFolders.includes(char.id)){ + openFolders.splice(openFolders.indexOf(char.id), 1) + } + else{ + openFolders.push(char.id) + } + openFolders = openFolders + }}> + {#if openFolders.includes(char.id)} + + {:else} + + {/if} + + {/if} +
+
+ {#if char.type === 'folder' && openFolders.includes(char.id)} +
+
+
{ e.preventDefault() e.dataTransfer.dropEffect = 'move' e.currentTarget.classList.add('bg-green-500') @@ -425,68 +380,115 @@ e.currentTarget.classList.remove('bg-green-500') const da = currentDrag if(da && char.type === 'folder'){ - inserter(da,{index:ind+1,folder:char.id}) + inserter(da,{index:0,folder:char.id}) } }} on:dragenter={preventAll}/> - {/each} -
- {/if} -
{ - e.dataTransfer.dropEffect = 'move' - e.currentTarget.classList.add('bg-green-500') - }} on:dragleave={(e) => { - e.currentTarget.classList.remove('bg-green-500') - }} on:drop={(e) => { - e.preventDefault() - e.currentTarget.classList.remove('bg-green-500') - const da = currentDrag - if(da){ - inserter(da,{index:ind+1}) - } - }} on:dragenter={preventAll} /> - {/each} -
- {if(char.type === 'folder'){avatarDragStart({index: ind, folder:char.id}, e)}}} + on:dragover={avatarDragOver} + on:drop={(e) => {if(char.type === 'folder'){avatarDrop({index: ind, folder:char.id}, e)}}} + on:dragenter={preventAll} + on:contextmenu={preventAll} + > + + +
{ + if(char2.type === "normal"){ + changeChar(char2.index); + } + }} + on:keydown={(e) => { + if (e.key === "Enter") { + if(char2.type === "normal"){ + changeChar(char2.index); + } + } + }} + tabindex="0" + > + +
+
+
{ + e.preventDefault() + e.dataTransfer.dropEffect = 'move' + e.currentTarget.classList.add('bg-green-500') + }} on:dragleave={(e) => { + e.currentTarget.classList.remove('bg-green-500') + }} on:drop={(e) => { + e.preventDefault() + e.currentTarget.classList.remove('bg-green-500') + const da = currentDrag + if(da && char.type === 'folder'){ + inserter(da,{index:ind+1,folder:char.id}) + } + }} on:dragenter={preventAll}/> + {/each} +
+ {/if} +
{ + e.dataTransfer.dropEffect = 'move' + e.currentTarget.classList.add('bg-green-500') + }} on:dragleave={(e) => { + e.currentTarget.classList.remove('bg-green-500') + }} on:drop={(e) => { + e.preventDefault() + e.currentTarget.classList.remove('bg-green-500') + const da = currentDrag + if(da){ + inserter(da,{index:ind+1}) + } + }} on:dragenter={preventAll} /> + {/each} +
+ { + if (sideBarMode === 1) { + reseter(); + sideBarMode = 0; + } else { + reseter(); + sideBarMode = 1; + } + }} + > +
+ {:else} + { - if (sideBarMode === 1) { + if ($settingsOpen) { reseter(); - sideBarMode = 0; + settingsOpen.set(false); } else { reseter(); - sideBarMode = 1; + settingsOpen.set(true); } - }} - > -
- {:else} - { - if ($settingsOpen) { +
+ { reseter(); - settingsOpen.set(false); - } else { - reseter(); - settingsOpen.set(true); - } - }}> - { - reseter(); - openGrid(); - }}> - {/if} + openGrid(); + }}>
+ {/if} +
Date: Wed, 24 May 2023 10:02:37 +0900 Subject: [PATCH 13/16] [rm] removed novelai from modellis --- src/lib/UI/ModelList.svelte | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lib/UI/ModelList.svelte b/src/lib/UI/ModelList.svelte index f7cd5490..bd118304 100644 --- a/src/lib/UI/ModelList.svelte +++ b/src/lib/UI/ModelList.svelte @@ -18,9 +18,6 @@ - {#if value === 'novelai' || isTauri} - - {/if} {#if $DataBase.plugins.length > 0} From 756d09c7bb76a2e4191fc4074485bb448a251c04 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 10:03:29 +0900 Subject: [PATCH 14/16] [feat] added missing korean translations --- src/lang/ko.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lang/ko.ts b/src/lang/ko.ts index ddb30983..5b7dbaf0 100644 --- a/src/lang/ko.ts +++ b/src/lang/ko.ts @@ -246,6 +246,9 @@ export const languageKorean = { textScreenBorder: "채팅창 윤곽선", ttsReadOnlyQuoted: "따옴표 안 텍스트만 읽기", ttsStop: "TTS 중지", - askRemoval:"삭제 확인" + askRemoval:"삭제 확인", + replaceGlobalNote: "글로벌 노트 덮어쓰기", + charLoreBook: '캐릭터 로어북', + globalLoreBook: '글로벌 로어북', } \ No newline at end of file From bee825d97a975046658fdb95e8b4ca3be9097ed6 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 10:10:18 +0900 Subject: [PATCH 15/16] [feat] added patreon icon link --- public/icon/github-mark-white.svg | 1 + public/icon/patreon.png | Bin 0 -> 52210 bytes src/lib/Others/GithubStars.svelte | 21 +++++++++++++++++---- 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 public/icon/github-mark-white.svg create mode 100644 public/icon/patreon.png diff --git a/public/icon/github-mark-white.svg b/public/icon/github-mark-white.svg new file mode 100644 index 00000000..d5e64918 --- /dev/null +++ b/public/icon/github-mark-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/icon/patreon.png b/public/icon/patreon.png new file mode 100644 index 0000000000000000000000000000000000000000..9a521e3fd64d841c1499336e26b8004ad21826ca GIT binary patch literal 52210 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 Bh%x{G literal 0 HcmV?d00001 diff --git a/src/lib/Others/GithubStars.svelte b/src/lib/Others/GithubStars.svelte index 256ba57b..ecdcc210 100644 --- a/src/lib/Others/GithubStars.svelte +++ b/src/lib/Others/GithubStars.svelte @@ -1,11 +1,24 @@ - -{#if !isTauri} + +
+ {#if !isTauri} Star -{/if} + {:else} + + {/if} + +
\ No newline at end of file From 73a8805fce7711ed12d0f213bbc5de3fb920b197 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 24 May 2023 10:10:56 +0900 Subject: [PATCH 16/16] bump version to 1.16.0 --- src-tauri/tauri.conf.json | 2 +- src/ts/database.ts | 2 +- version.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 8f14b96e..5a146ac3 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "RisuAI", - "version": "1.15.6" + "version": "1.16.0" }, "tauri": { "allowlist": { diff --git a/src/ts/database.ts b/src/ts/database.ts index 5a0cc995..2047fd26 100644 --- a/src/ts/database.ts +++ b/src/ts/database.ts @@ -7,7 +7,7 @@ import { cloneDeep } from 'lodash'; export const DataBase = writable({} as any as Database) export const loadedStore = writable(false) -export let appVer = '1.15.6' +export let appVer = '1.16.0' export function setDatabase(data:Database){ diff --git a/version.json b/version.json index 27b8e9f0..dba713ae 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"version":"1.15.6"} \ No newline at end of file +{"version":"1.16.0"} \ No newline at end of file