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 00000000..9a521e3f Binary files /dev/null and b/public/icon/patreon.png differ 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/lang/en.ts b/src/lang/en.ts index f42cc627..a3d5a464 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,8 @@ export const languageEnglish = { textScreenBorder: "Text Screen Borders", ttsReadOnlyQuoted: "Read Only Quoted", ttsStop: "Stop TTS", - askRemoval:"Ask Removal" -} + askRemoval:"Ask Removal", + replaceGlobalNote: "Global Note Replacement", + charLoreBook: 'Character Lorebook', + globalLoreBook: 'Global Lorebook', +} \ No newline at end of file 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 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 diff --git a/src/lib/Setting/Pages/BotSettings.svelte b/src/lib/Setting/Pages/BotSettings.svelte index 7b5897d6..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,26 +37,10 @@

{language.chatBot}

{language.model} - - + {language.submodel} - + + {#if $DataBase.aiModel === 'palm2' || $DataBase.subModel === 'palm2'} Palm2 {language.apiKey} @@ -78,6 +63,17 @@ {/each} {/if} +{#if $DataBase.aiModel === "novelai" || $DataBase.subModel === "novelai"} + 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} @@ -98,12 +94,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/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 173b1787..ce1e9737 100644 --- a/src/lib/Setting/Settings.svelte +++ b/src/lib/Setting/Settings.svelte @@ -1,5 +1,5 @@
-
+

{language.presets}

@@ -35,6 +35,12 @@ {presets.name} {/if}
+ +
+
+ {#each $DataBase.loreBook as lore, ind} + +
+ + {/each} +
+ + +
+
+
+ + \ No newline at end of file diff --git a/src/lib/SideBars/CharConfig.svelte b/src/lib/SideBars/CharConfig.svelte index 9f3bf036..2d0051bf 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,10 @@ {language.systemPrompt} - {language.chatNotes} - - {tokens.localNote} {language.tokens} - + {language.replaceGlobalNote} + + + {#if currentChar.data.chats[currentChar.data.chatPage].supaMemoryData && currentChar.data.chats[currentChar.data.chatPage].supaMemoryData.length > 4} {language.SuperMemory} 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/lib/SideBars/Sidebar.svelte b/src/lib/SideBars/Sidebar.svelte index a306e2f7..eaf99e65 100644 --- a/src/lib/SideBars/Sidebar.svelte +++ b/src/lib/SideBars/Sidebar.svelte @@ -289,132 +289,87 @@
-
-
{ - 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} +
+ import { DataBase } from "src/ts/database"; + import { isTauri } from "src/ts/globalApi"; + import { getHordeModels } from "src/ts/horde/getModels"; + + export let value = "" + + +{#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 9bd3051e..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){ @@ -222,6 +222,26 @@ 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", + } + } + if(checkNullish(data.loreBook)){ + data.loreBookPage = 0 + data.loreBook = [{ + name: "My First LoreBook", + data: [] + }] + } changeLanguage(data.language) @@ -246,7 +266,9 @@ export interface loreBook{ mode: 'multiple'|'constant'|'normal', alwaysActive: boolean selective:boolean - extentions?:{} + extentions?:{ + risu_case_sensitive:boolean + } } export interface character{ @@ -290,6 +312,7 @@ export interface character{ supaMemory?:boolean additionalAssets?:[string, string][] ttsReadOnlyQuoted?:boolean + replaceGlobalNote:string } @@ -366,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 @@ -431,6 +459,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{ @@ -542,7 +581,7 @@ export function updateTextTheme(){ } } -export function changeToPreset(id =0){ +export function saveCurrentPreset(){ let db = get(DataBase) let pres = db.botPresets pres[db.botPresetsId] = { @@ -568,6 +607,23 @@ export function changeToPreset(id =0){ bias: db.bias } db.botPresets = pres + DataBase.set(db) +} + +export function copyPreset(id:number){ + saveCurrentPreset() + let db = get(DataBase) + let pres = db.botPresets + const newPres = cloneDeep(pres[id]) + newPres.name += " Copy" + db.botPresets.push(newPres) + DataBase.set(db) +} + +export function changeToPreset(id =0){ + saveCurrentPreset() + let db = get(DataBase) + let pres = db.botPresets const newPres = pres[id] db.botPresetsId = id db.apiType = newPres.apiType ?? db.apiType 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 564ecdaa..26c7b18b 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) @@ -104,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', @@ -120,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) }) } @@ -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/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, diff --git a/src/ts/process/request.ts b/src/ts/process/request.ts index 34235e34..83dab435 100644 --- a/src/ts/process/request.ts +++ b/src/ts/process/request.ts @@ -3,8 +3,10 @@ import type { OpenAIChat } from "."; import { DataBase, setDatabase, type character } from "../database"; import { pluginProcess } from "./plugins"; import { language } from "../../lang"; -import { stringlizeChat } from "./stringlize"; -import { globalFetch } from "../globalApi"; +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 } } @@ -53,6 +55,11 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' switch(aiModel){ case 'gpt35': case 'gpt4':{ + + for(let i=0;i { + + 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) diff --git a/src/ts/process/stringlize.ts b/src/ts/process/stringlize.ts index b8fb6777..62e58d4d 100644 --- a/src/ts/process/stringlize.ts +++ b/src/ts/process/stringlize.ts @@ -8,14 +8,48 @@ export function stringlizeChat(formated:OpenAIChat[], char:string = ''){ let resultString:string[] = [] for(const form of formated){ if(form.role === 'system'){ - resultString.push("'System Note: " + form.content) + resultString.push("system note: " + form.content) } - else if(form.role === 'user'){ - resultString.push("user: " + form.content) + else if(form.name){ + resultString.push(form.name + ": " + form.content) } - else if(form.role === 'assistant'){ - resultString.push("assistant: " + form.content) + else{ + resultString.push(form.content) } } return resultString.join('\n\n') + `\n\n${char}:` +} + +export function unstringlizeChat(text:string, formated:OpenAIChat[], char:string = ''){ + console.log(text) + 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 = text.substring(0, minIndex).trim() + } + + return text } \ No newline at end of file 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