diff --git a/src/lang/en.ts b/src/lang/en.ts index c98423b1..4e805d11 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -100,6 +100,7 @@ export const languageEnglish = { oaiRandomUser: "If enabled, random uuid would be put on user parameter on request, and would be changed on refresh. this can be used to prevent AI from identifying user.", inlayImages: "If enabled, images could be inlayed to the chat and AIs can see it if they support it.", metrica: 'Metric Systemizer is a plugin that converts metrics to imperial units when request, and vice versa on output to show user metric system while using imperial for performace. it is not recommended to use this plugin when using imperial units on chat.', + lorePlus: "LoreBook+ is a experimental feature that uses vectordb instead of just string matching for better bot making experience and better matching performace." }, setup: { chooseProvider: "Choose AI Provider", @@ -447,4 +448,5 @@ export const languageEnglish = { depthPrompt: "Depth Prompt", largePortrait: "Portrait", postImage: "Post Image", + lorePlus: "LoreBook+", } \ No newline at end of file diff --git a/src/lib/SideBars/LoreBook/LoreBookData.svelte b/src/lib/SideBars/LoreBook/LoreBookData.svelte index 1c34437d..80646875 100644 --- a/src/lib/SideBars/LoreBook/LoreBookData.svelte +++ b/src/lib/SideBars/LoreBook/LoreBookData.svelte @@ -12,6 +12,7 @@ export let onRemove: () => void = () => {} export let onClose: () => void = () => {} export let onOpen: () => void = () => {} + export let lorePlus = false export let idx:number let open = false @@ -47,47 +48,57 @@
{language.name} - {#if !value.alwaysActive} - {language.activationKeys} - {language.activationKeysInfo} - - - {#if value.selective} - {language.SecondaryKeys} + {#if !lorePlus} + {#if !value.alwaysActive} + {language.activationKeys} {language.activationKeysInfo} - + + + {#if value.selective} + {language.SecondaryKeys} + {language.activationKeysInfo} + + {/if} {/if} {/if} - {#if !(value.activationPercent === undefined || value.activationPercent === null)} - {language.activationProbability} - { - if(isNaN(value.activationPercent) || !value.activationPercent || value.activationPercent < 0){ - value.activationPercent = 0 - } - if(value.activationPercent > 100){ - value.activationPercent = 100 - } - }} /> + {#if !lorePlus} + {#if !(value.activationPercent === undefined || value.activationPercent === null)} + {language.activationProbability} + { + if(isNaN(value.activationPercent) || !value.activationPercent || value.activationPercent < 0){ + value.activationPercent = 0 + } + if(value.activationPercent > 100){ + value.activationPercent = 100 + } + }} /> + {/if} + {/if} + {#if !lorePlus} + {language.insertOrder} + {/if} - {language.insertOrder} - {language.prompt}
-
- - -
-
- {#if value.activationPercent === undefined || value.activationPercent === null} - {value.activationPercent = 50}}/> - {:else} - {value.activationPercent = null}}/> - {/if} - -
+ {#if !lorePlus} +
+ + +
+ {/if} + {#if !lorePlus} +
+ {#if value.activationPercent === undefined || value.activationPercent === null} + {value.activationPercent = 50}}/> + {:else} + {value.activationPercent = null}}/> + {/if} + +
+ {/if}
{/if} diff --git a/src/lib/SideBars/LoreBook/LoreBookList.svelte b/src/lib/SideBars/LoreBook/LoreBookList.svelte index bf5d86ec..c459c97e 100644 --- a/src/lib/SideBars/LoreBook/LoreBookList.svelte +++ b/src/lib/SideBars/LoreBook/LoreBookList.svelte @@ -8,6 +8,7 @@ export let globalMode = false export let submenu = 0 + export let lorePlus = false let stb: Sortable = null let ele: HTMLDivElement let sorted = 0 @@ -94,7 +95,7 @@ let lore = $CurrentCharacter.globalLore lore.splice(i, 1) $CurrentCharacter.globalLore = lore - }} onOpen={onOpen} onClose={onClose}/> + }} onOpen={onOpen} onClose={onClose} lorePlus={lorePlus}/> {/each} {/if} {:else if submenu === 1} @@ -106,7 +107,7 @@ let lore = $CurrentChat.localLore lore.splice(i, 1) $CurrentChat.localLore = lore - }} onOpen={onOpen} onClose={onClose}/> + }} onOpen={onOpen} onClose={onClose} lorePlus={lorePlus}/> {/each} {/if} {/if} diff --git a/src/lib/SideBars/LoreBook/LoreBookSetting.svelte b/src/lib/SideBars/LoreBook/LoreBookSetting.svelte index 8b836d16..f78ffdc8 100644 --- a/src/lib/SideBars/LoreBook/LoreBookSetting.svelte +++ b/src/lib/SideBars/LoreBook/LoreBookSetting.svelte @@ -7,6 +7,7 @@ import Check from "../../UI/GUI/CheckInput.svelte"; import NumberInput from "../../UI/GUI/NumberInput.svelte"; import LoreBookList from "./LoreBookList.svelte"; + import Help from "src/lib/Others/Help.svelte"; let submenu = 0 export let globalMode = false @@ -35,7 +36,7 @@ {#if !globalMode} {submenu === 0 ? $CurrentCharacter.type === 'group' ? language.groupLoreInfo : language.globalLoreInfo : language.localLoreInfo} {/if} - + {:else} {#if $CurrentCharacter.loreSettings}
@@ -68,6 +69,11 @@ />
{/if} +
+ +
{/if} {#if submenu !== 2} diff --git a/src/ts/process/lorebook.ts b/src/ts/process/lorebook.ts index 946067a3..38bff940 100644 --- a/src/ts/process/lorebook.ts +++ b/src/ts/process/lorebook.ts @@ -6,6 +6,7 @@ import { checkNullish, selectSingleFile } from "../util"; import { alertError, alertNormal } from "../alert"; import { language } from "../../lang"; import { downloadFile } from "../storage/globalApi"; +import { HypaProcesser } from "./memory/hypamemory"; export function addLorebook(type:number) { let selectedID = get(selectedCharID) @@ -61,6 +62,8 @@ interface formatedLore{ const rmRegex = / |\n/g export async function loadLoreBookPrompt(){ + + const selectedID = get(selectedCharID) const db = get(DataBase) const char = db.characters[selectedID] @@ -74,6 +77,10 @@ export async function loadLoreBookPrompt(){ const loreToken = char.loreSettings?.tokenBudget ?? db.loreBookToken const fullWordMatching = char.loreSettings?.fullWordMatching ?? false + if(char.lorePlus){ + return await loadLoreBookPlusPrompt() + } + let activatiedPrompt: string[] = [] let formatedLore:formatedLore[] = [] @@ -201,6 +208,94 @@ export async function loadLoreBookPrompt(){ } } +export async function loadLoreBookPlusPrompt(){ + 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 globalLore = db.loreBook[db.loreBookPage]?.data ?? [] + const fullLore = characterLore.concat(chatLore.concat(globalLore)).filter((v) => { return v.content }) + const currentChat = char.chats[page].message + const loreDepth = char.loreSettings?.scanDepth ?? db.loreBookDepth + const loreToken = char.loreSettings?.tokenBudget ?? db.loreBookToken + + interface formatedLorePlus{ + content: string + simularity:number + } + + let formatedLores:formatedLorePlus[] = [] + let activatiedPrompt: string[] = [] + const hypaProcesser = new HypaProcesser('MiniLM') + + + const formatedChatMain = currentChat.slice(currentChat.length - loreDepth,currentChat.length).map((msg) => { + return msg.data + }).join('||').replace(rmRegex,'').toLocaleLowerCase() + const chatVec = await hypaProcesser.testText(formatedChatMain) + + + for(const lore of fullLore){ + let key = (lore.key ?? '').replace(rmRegex, '').toLocaleLowerCase().split(',') + key.push(lore.comment) + + let vec:number[] + + if(lore.loreCache && lore.loreCache.key === lore.content){ + const vect = lore.loreCache.data[0] + const v = Buffer.from(vect, 'base64') + const f = new Float32Array(v.buffer) + vec = Array.from(f) + } + else{ + vec = await hypaProcesser.testText(lore.content) + lore.loreCache = { + key: lore.content, + data: [Buffer.from(new Float32Array(vec).buffer).toString('base64')] + } + } + + + + formatedLores.push({ + content: lore.content, + simularity: hypaProcesser.similarityCheck(chatVec, vec) + }) + } + + formatedLores.sort((a, b) => { + return b.simularity - a.simularity + }) + + let i=0; + while(i < formatedLores.length){ + const lore = formatedLores[i] + const totalTokens = await tokenize(activatiedPrompt.concat([lore.content]).join('\n\n')) + if(totalTokens > loreToken){ + break + } + activatiedPrompt.push(lore.content) + i++ + } + + + let sactivated:string[] = [] + activatiedPrompt = activatiedPrompt.filter((v) => { + 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') + } + +} export async function importLoreBook(mode:'global'|'local'|'sglobal'){ const selectedID = get(selectedCharID) diff --git a/src/ts/process/memory/hypamemory.ts b/src/ts/process/memory/hypamemory.ts index 47f00793..9147de1f 100644 --- a/src/ts/process/memory/hypamemory.ts +++ b/src/ts/process/memory/hypamemory.ts @@ -79,7 +79,15 @@ export class HypaProcesser{ return result } - + async testText(text:string){ + const forageResult:number[] = await this.forage.getItem(text) + if(forageResult){ + return forageResult + } + const vec = (await this.embedDocuments([text]))[0] + await this.forage.setItem(text, vec) + return vec + } async addText(texts:string[]) { @@ -147,7 +155,11 @@ export class HypaProcesser{ ]); return result; - } + } + + similarityCheck(query1:number[],query2: number[]) { + return similarity.cosine(query1, query2) + } } diff --git a/src/ts/storage/database.ts b/src/ts/storage/database.ts index 2306bd08..8809a550 100644 --- a/src/ts/storage/database.ts +++ b/src/ts/storage/database.ts @@ -526,6 +526,10 @@ export interface loreBook{ risu_case_sensitive:boolean } activationPercent?:number + loreCache?:{ + key:string + data:string[] + } } export interface character{ @@ -590,6 +594,7 @@ export interface character{ depth_prompt?: { depth: number, prompt: string } extentions?:{[key:string]:any} largePortrait?:boolean + lorePlus?:boolean } @@ -632,6 +637,7 @@ export interface groupChat{ backgroundCSS?:string oneAtTime?:boolean virtualscript?:string + lorePlus?:boolean } export interface botPreset{