HyperV2 Custom settings enhancement (#511)

# PR Checklist
- [x] Did you check if it works normally in all models? *ignore this
when it dosen't uses models*
- [x] Did you check if it works normally in all of web, local and node
hosted versions? if it dosen't, did you blocked it in those versions?
- [x] Did you added a type def?

# Description
~No bug, work as intended. But, haven't checked actual summary with it.
Very unstable, need confirmation/check.~
### **NO bug, work as intended, summarizes correctly, moving mainChunks
to chunks works well, no re-summarization issues. It works!**


Added new variable to database.ts, which indicates if HypaV2 Memory is
activated or not.
hypav2: boolean
This was added to stop overlapping of memoryType, when HypaV2 Memory is
selected and supaMemoryModel is changed.

Added supaMemoryType selection, HypaMemoryType selection,
supaMemoryPrompt changing section on OtherBotSettings.svelte, and
implemented on hypav2.ts.
Also added OpenAI key when summarization model is GPT 3.5 instruct.
Also suggested memoryAlgorithmType:string variable on database.ts, to
further add more memory types.

![image](https://github.com/kwaroran/RisuAI/assets/73149145/5d167b03-d7e7-41a1-8875-1780561cd3ac)

fixed minor punctuations, and changed summarize function of
hypav2.ts(same as the one on supaMemory.ts)
This commit is contained in:
kwaroran
2024-06-19 03:49:19 +09:00
committed by GitHub
7 changed files with 305 additions and 178 deletions

View File

@@ -276,23 +276,31 @@
<span class="text-textcolor mt-4">{language.type}</span> <span class="text-textcolor mt-4">{language.type}</span>
<SelectInput value={ <SelectInput value={
$DataBase.supaMemoryType === 'hypaV2' ? 'hypaV2' : $DataBase.hypav2 ? 'hypaV2' :
$DataBase.supaMemoryType !== 'none' ? 'supaMemory' : $DataBase.supaModelType !== 'none' ? 'supaMemory' :
$DataBase.hanuraiEnable ? 'hanuraiMemory' : 'none' $DataBase.hanuraiEnable ? 'hanuraiMemory' : 'none'
} on:change={(v) => { } on:change={(v) => {
//@ts-ignore //@ts-ignore
const value = v.target.value const value = v.target.value
if (value === 'supaMemory'){ if (value === 'supaMemory'){
$DataBase.supaMemoryType = 'distilbart' $DataBase.supaModelType = 'distilbart'
$DataBase.memoryAlgorithmType = 'supaMemory'
$DataBase.hypav2 = false
$DataBase.hanuraiEnable = false $DataBase.hanuraiEnable = false
} else if (value === 'hanuraiMemory'){ } else if (value === 'hanuraiMemory'){
$DataBase.supaMemoryType = 'none' $DataBase.supaModelType = 'none'
$DataBase.memoryAlgorithmType = 'hanuraiMemory'
$DataBase.hypav2 = false
$DataBase.hanuraiEnable = true $DataBase.hanuraiEnable = true
} else if (value === 'hypaV2') { } else if (value === 'hypaV2') {
$DataBase.supaMemoryType = 'hypaV2' $DataBase.supaModelType = 'distilbart'
$DataBase.memoryAlgorithmType = 'hypaMemoryV2'
$DataBase.hypav2= true
$DataBase.hanuraiEnable = false $DataBase.hanuraiEnable = false
} else { } else {
$DataBase.supaMemoryType = 'none' $DataBase.supaModelType = 'none'
$DataBase.memoryAlgorithmType = 'none'
$DataBase.hypav2 = false
$DataBase.hanuraiEnable = false $DataBase.hanuraiEnable = false
} }
}}> }}>
@@ -309,27 +317,45 @@
<div class="flex"> <div class="flex">
<Check bind:check={$DataBase.hanuraiSplit} name="Text Spliting"/> <Check bind:check={$DataBase.hanuraiSplit} name="Text Spliting"/>
</div> </div>
{:else if $DataBase.supaMemoryType === 'hypaV2'} {:else if $DataBase.hypav2}
<span class="mb-2 text-textcolor2 text-sm text-wrap break-words max-w-full">{language.hypaV2Desc}</span> <span class="mb-2 text-textcolor2 text-sm text-wrap break-words max-w-full">{language.hypaV2Desc}</span>
<span class="text-textcolor mt-4">{language.SuperMemory} {language.model}</span>
<SelectInput className="mt-2 mb-2" bind:value={$DataBase.supaModelType}>
<OptionInput value="distilbart">distilbart-cnn-6-6 (Free/Local)</OptionInput>
<OptionInput value="instruct35">OpenAI 3.5 Turbo Instruct</OptionInput>
<OptionInput value="subModel">{language.submodel}</OptionInput>
</SelectInput>
{#if $DataBase.supaModelType === 'davinci' || $DataBase.supaModelType === 'curie' || $DataBase.supaModelType === 'instruct35'}
<span class="text-textcolor">{language.SuperMemory} OpenAI Key</span>
<TextInput size="sm" marginBottom bind:value={$DataBase.supaMemoryKey}/>
{/if}
<span class="text-textcolor">{language.SuperMemory} Prompt</span>
<TextInput size="sm" marginBottom bind:value={$DataBase.supaMemoryPrompt} placeholder="Leave it blank to use default"/>
<span class="text-textcolor">{language.HypaMemory} Model</span>
<SelectInput className="mt-2 mb-2" bind:value={$DataBase.hypaModel}>
<OptionInput value="MiniLM">MiniLM-L6-v2 (Free / Local)</OptionInput>
<OptionInput value="nomic">Nomic (Free / Local)</OptionInput>
<OptionInput value="ada">OpenAI Ada (Davinci / Curie Only)</OptionInput>
</SelectInput>
<span class="text-textcolor">{language.hypaChunkSize}</span> <span class="text-textcolor">{language.hypaChunkSize}</span>
<NumberInput size="sm" marginBottom bind:value={$DataBase.hypaChunkSize} min={100} /> <NumberInput size="sm" marginBottom bind:value={$DataBase.hypaChunkSize} min={100} />
<span class="text-textcolor">{language.hypaAllocatedTokens}</span> <span class="text-textcolor">{language.hypaAllocatedTokens}</span>
<NumberInput size="sm" marginBottom bind:value={$DataBase.hypaAllocatedTokens} min={100} /> <NumberInput size="sm" marginBottom bind:value={$DataBase.hypaAllocatedTokens} min={100} />
{:else if $DataBase.supaMemoryType !== 'none'} {:else if ($DataBase.supaModelType !== 'none' && $DataBase.hypav2 === false)}
<span class="mb-2 text-textcolor2 text-sm text-wrap break-words max-w-full">{language.supaDesc}</span> <span class="mb-2 text-textcolor2 text-sm text-wrap break-words max-w-full">{language.supaDesc}</span>
<span class="text-textcolor mt-4">{language.SuperMemory} {language.model}</span> <span class="text-textcolor mt-4">{language.SuperMemory} {language.model}</span>
<SelectInput className="mt-2 mb-2" bind:value={$DataBase.supaMemoryType}> <SelectInput className="mt-2 mb-2" bind:value={$DataBase.supaModelType}>
<OptionInput value="distilbart" >distilbart-cnn-6-6 (Free/Local)</OptionInput> <OptionInput value="distilbart" >distilbart-cnn-6-6 (Free/Local)</OptionInput>
<OptionInput value="instruct35" >OpenAI 3.5 Turbo Instruct</OptionInput> <OptionInput value="instruct35" >OpenAI 3.5 Turbo Instruct</OptionInput>
<OptionInput value="subModel" >{language.submodel}</OptionInput> <OptionInput value="subModel" >{language.submodel}</OptionInput>
</SelectInput> </SelectInput>
<span class="text-textcolor">{language.maxSupaChunkSize}</span> <span class="text-textcolor">{language.maxSupaChunkSize}</span>
<NumberInput size="sm" marginBottom bind:value={$DataBase.maxSupaChunkSize} min={100} /> <NumberInput size="sm" marginBottom bind:value={$DataBase.maxSupaChunkSize} min={100} />
{#if $DataBase.supaMemoryType === 'davinci' || $DataBase.supaMemoryType === 'curie' || $DataBase.supaMemoryType === 'instruct35'} {#if $DataBase.supaModelType === 'davinci' || $DataBase.supaModelType === 'curie' || $DataBase.supaModelType === 'instruct35'}
<span class="text-textcolor">{language.SuperMemory} OpenAI Key</span> <span class="text-textcolor">{language.SuperMemory} OpenAI Key</span>
<TextInput size="sm" marginBottom bind:value={$DataBase.supaMemoryKey}/> <TextInput size="sm" marginBottom bind:value={$DataBase.supaMemoryKey}/>
{/if} {/if}
{#if $DataBase.supaMemoryType !== 'none'} {#if $DataBase.supaModelType !== 'none'}
<span class="text-textcolor">{language.SuperMemory} Prompt</span> <span class="text-textcolor">{language.SuperMemory} Prompt</span>
<TextInput size="sm" marginBottom bind:value={$DataBase.supaMemoryPrompt} placeholder="Leave it blank to use default"/> <TextInput size="sm" marginBottom bind:value={$DataBase.supaMemoryPrompt} placeholder="Leave it blank to use default"/>
{/if} {/if}

View File

@@ -257,7 +257,7 @@
{/each} {/each}
{#if $DataBase.supaMemoryType !== 'none' || $DataBase.hanuraiEnable} {#if $DataBase.supaModelType !== 'none' || $DataBase.hanuraiEnable}
{#if $DataBase.hanuraiEnable} {#if $DataBase.hanuraiEnable}
<div class="flex mt-2 items-center"> <div class="flex mt-2 items-center">
<Check bind:check={currentChar.data.supaMemory} name={ language.hanuraiMemory}/> <Check bind:check={currentChar.data.supaMemory} name={ language.hanuraiMemory}/>
@@ -904,7 +904,7 @@
<span> <Help key="utilityBot" name={language.utilityBot}/></span> <span> <Help key="utilityBot" name={language.utilityBot}/></span>
</div> </div>
{#if $DataBase.supaMemoryType === 'hypaV2'} {#if $DataBase.supaModelType !== 'none' && $DataBase.hypav2}
<Button <Button
on:click={() => { on:click={() => {
currentChar.data.chats[currentChar.data.chatPage].hypaV2Data ??= { currentChar.data.chats[currentChar.data.chatPage].hypaV2Data ??= {

View File

@@ -165,7 +165,7 @@
</div> </div>
{/each} {/each}
{#if $DataBase.supaMemoryType !== 'none' || $DataBase.hanuraiEnable} {#if $DataBase.supaModelType !== 'none' || $DataBase.hanuraiEnable}
{#if $DataBase.hanuraiEnable} {#if $DataBase.hanuraiEnable}
<div class="flex mt-2 items-center"> <div class="flex mt-2 items-center">
<CheckInput bind:check={chara.supaMemory} name={ language.hanuraiMemory}/> <CheckInput bind:check={chara.supaMemory} name={ language.hanuraiMemory}/>

View File

@@ -714,7 +714,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
currentTokens += await tokenizer.tokenizeChat(chat) currentTokens += await tokenizer.tokenizeChat(chat)
} }
if(nowChatroom.supaMemory && (db.supaMemoryType !== 'none' || db.hanuraiEnable)){ if(nowChatroom.supaMemory && (db.supaModelType !== 'none' || db.hanuraiEnable || db.hypav2)){
chatProcessStage.set(2) chatProcessStage.set(2)
if(db.hanuraiEnable){ if(db.hanuraiEnable){
const hn = await hanuraiMemory(chats, { const hn = await hanuraiMemory(chats, {
@@ -730,9 +730,11 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
chats = hn.chats chats = hn.chats
currentTokens = hn.tokens currentTokens = hn.tokens
} }
else if(db.supaMemoryType === 'hypaV2'){ else if(db.hypav2){ //HypaV2 support needs to be changed like this.
const sp = await hypaMemoryV2(chats, currentTokens, maxContextTokens, currentChat, nowChatroom, tokenizer) const sp = await hypaMemoryV2(chats, currentTokens, maxContextTokens, currentChat, nowChatroom, tokenizer)
console.log("All chats: ", chats)
if(sp.error){ if(sp.error){
console.log(sp)
alertError(sp.error) alertError(sp.error)
return false return false
} }

View File

@@ -4,209 +4,306 @@ import type { ChatTokenizer } from "src/ts/tokenizer";
import { get } from "svelte/store"; import { get } from "svelte/store";
import { requestChatData } from "../request"; import { requestChatData } from "../request";
import { HypaProcesser } from "./hypamemory"; import { HypaProcesser } from "./hypamemory";
import { globalFetch } from "src/ts/storage/globalApi";
import { runSummarizer } from "../transformers";
import { last, remove } from "lodash";
export interface HypaV2Data{ export interface HypaV2Data {
chunks: { chunks: {
text:string text: string;
targetId:string targetId: string;
}[] }[];
mainChunks: { mainChunks: {
text:string text: string;
targetId:string targetId: string;
}[] }[];
} }
async function summary(stringlizedChat: string): Promise<{ success: boolean; data: string }> {
const db = get(DataBase);
console.log("Summarizing");
async function summary(stringlizedChat:string):Promise<{ if (db.supaModelType === 'distilbart') {
success:boolean try {
data:string const sum = await runSummarizer(stringlizedChat);
}>{ return { success: true, data: sum };
const promptbody:OpenAIChat[] = [ } catch (error) {
{ return {
role: "user", success: false,
content: stringlizedChat data: "SupaMemory: Summarizer: " + `${error}`
}, };
{
role: "system",
content: "Summarize this roleplay scene in a coherent narrative format for future reference. Summarize what happened, focusing on events and interactions between them. If someone or something is new or changed, include a brief characterization of them."
}
]
const da = await requestChatData({
formated: promptbody,
bias: {},
useStreaming: false,
noMultiGen: true
}, 'model')
if(da.type === 'fail' || da.type === 'streaming' || da.type === 'multiline'){
return {
data: "Hypamemory HTTP: " + da.result,
success: false
} }
} }
return {
data: da.result, const supaPrompt = db.supaMemoryPrompt === '' ?
success: true "[Summarize the ongoing role story, It must also remove redundancy and unnecessary text and content from the output to reduce tokens for gpt3 and other sublanguage models]\n"
: db.supaMemoryPrompt;
let result = '';
if (db.supaModelType !== 'subModel') {
const promptbody = stringlizedChat + '\n\n' + supaPrompt + "\n\nOutput:";
const da = await globalFetch("https://api.openai.com/v1/completions", {
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + db.supaMemoryKey
},
method: "POST",
body: {
"model": db.supaModelType === 'curie' ? "text-curie-001"
: db.supaModelType === 'instruct35' ? 'gpt-3.5-turbo-instruct'
: "text-davinci-003",
"prompt": promptbody,
"max_tokens": 600,
"temperature": 0
}
})
console.log("Using openAI instruct 3.5 for SupaMemory");
try {
if (!da.ok) {
return {
success: false,
data: "SupaMemory: HTTP: " + JSON.stringify(da)
};
}
result = (await da.data)?.choices[0]?.text?.trim();
if (!result) {
return {
success: false,
data: "SupaMemory: HTTP: " + JSON.stringify(da)
};
}
return { success: true, data: result };
} catch (error) {
return {
success: false,
data: "SupaMemory: HTTP: " + error
};
}
} else {
const promptbody: OpenAIChat[] = [
{
role: "user",
content: stringlizedChat
},
{
role: "system",
content: supaPrompt
}
];
console.log("Using submodel: ", db.subModel, "for supaMemory model");
const da = await requestChatData({
formated: promptbody,
bias: {},
useStreaming: false,
noMultiGen: true
}, 'submodel');
if (da.type === 'fail' || da.type === 'streaming' || da.type === 'multiline') {
return {
success: false,
data: "SupaMemory: HTTP: " + da.result
};
}
result = da.result;
} }
return { success: true, data: result };
} }
export async function hypaMemoryV2( export async function hypaMemoryV2(
chats:OpenAIChat[], chats: OpenAIChat[],
currentTokens:number, currentTokens: number,
maxContextTokens:number, maxContextTokens: number,
room:Chat, room: Chat,
char:character|groupChat, char: character | groupChat,
tokenizer:ChatTokenizer, tokenizer: ChatTokenizer,
arg:{asHyper?:boolean} = {} arg: { asHyper?: boolean, summaryModel?: string, summaryPrompt?: string, hypaModel?: string } = {}
): Promise<{ currentTokens: number; chats: OpenAIChat[]; error?:string; memory?:HypaV2Data;}>{ ): Promise<{ currentTokens: number; chats: OpenAIChat[]; error?: string; memory?: HypaV2Data; }> {
const db = get(DataBase) const db = get(DataBase);
const data: HypaV2Data = room.hypaV2Data ?? { chunks: [], mainChunks: [] };
const data:HypaV2Data = room.hypaV2Data ?? { let allocatedTokens = db.hypaAllocatedTokens;
chunks:[], let chunkSize = db.hypaChunkSize;
mainChunks:[] currentTokens += allocatedTokens + 50;
} let mainPrompt = "";
const lastTwoChats = chats.slice(-2);
//this is for the prompt // Error handling for infinite summarization attempts
let summarizationFailures = 0;
const maxSummarizationFailures = 3;
let lastMainChunkTargetId = '';
let allocatedTokens = db.hypaAllocatedTokens // Ensure correct targetId matching
let chunkSize = db.hypaChunkSize const getValidChatIndex = (targetId: string) => {
currentTokens += allocatedTokens return chats.findIndex(chat => chat.memo === targetId);
currentTokens += 50 //this is for the template prompt };
let mainPrompt = ""
while(data.mainChunks.length > 0){ // Processing mainChunks
const chunk = data.mainChunks[0] if (data.mainChunks.length > 0) {
const ind = chats.findIndex(e => e.memo === chunk.targetId) const chunk = data.mainChunks[0];
if(ind === -1){ const ind = getValidChatIndex(chunk.targetId);
data.mainChunks.shift() if (ind !== -1) {
continue const removedChats = chats.splice(0, ind + 1);
console.log("removed chats", removedChats);
for (const chat of removedChats) {
currentTokens -= await tokenizer.tokenizeChat(chat);
}
mainPrompt = chunk.text;
const mpToken = await tokenizer.tokenizeChat({ role: 'system', content: mainPrompt });
allocatedTokens -= mpToken;
} }
const removedChats = chats.splice(0, ind)
for(const chat of removedChats){
currentTokens -= await tokenizer.tokenizeChat(chat)
}
chats = chats.slice(ind)
mainPrompt = chunk.text
const mpToken = await tokenizer.tokenizeChat({role:'system', content:mainPrompt})
allocatedTokens -= mpToken
break
} }
while(currentTokens >= maxContextTokens){ // Token management loop
while (currentTokens >= maxContextTokens) {
let idx = 0 let idx = 0;
let targetId = '' let targetId = '';
const halfData:OpenAIChat[] = [] const halfData: OpenAIChat[] = [];
let halfDataTokens = 0 let halfDataTokens = 0;
while(halfDataTokens < chunkSize){ while (halfDataTokens < chunkSize && (idx <= chats.length - 4)) { // Ensure latest two chats are not added to summarization.
const chat = chats[idx] const chat = chats[idx];
if(!chat){ halfDataTokens += await tokenizer.tokenizeChat(chat);
break halfData.push(chat);
} idx++;
halfDataTokens += await tokenizer.tokenizeChat(chat) targetId = chat.memo;
halfData.push(chat) console.log("current target chat: ", chat);
idx++
targetId = chat.memo
} }
const stringlizedChat = halfData.map(e => `${e.role}: ${e.content}`).join('\n') // Avoid summarizing the last two chats
if (halfData.length < 3) break;
const summaryData = await summary(stringlizedChat) const stringlizedChat = halfData.map(e => `${e.role}: ${e.content}`).join('\n');
const summaryData = await summary(stringlizedChat);
if(!summaryData.success){ if (!summaryData.success) {
return { summarizationFailures++;
currentTokens: currentTokens, if (summarizationFailures >= maxSummarizationFailures) {
chats: chats, return {
error: summaryData.data currentTokens: currentTokens,
chats: chats,
error: "Summarization failed multiple times. Aborting to prevent infinite loop."
};
} }
continue;
} }
const summaryDataToken = await tokenizer.tokenizeChat({role:'system', content:summaryData.data}) summarizationFailures = 0; // Reset failure counter on success
mainPrompt += `\n\n${summaryData.data}`
currentTokens -= halfDataTokens const summaryDataToken = await tokenizer.tokenizeChat({ role: 'system', content: summaryData.data });
allocatedTokens -= summaryDataToken mainPrompt += `\n\n${summaryData.data}`;
currentTokens -= halfDataTokens;
allocatedTokens -= summaryDataToken;
data.mainChunks.unshift({ data.mainChunks.unshift({
text: mainPrompt, text: summaryData.data,
targetId: targetId targetId: targetId
}) });
if(allocatedTokens < 1500){ // Split the summary into chunks based on double line breaks
const summarizedMp = await summary(mainPrompt) const splitted = summaryData.data.split('\n\n').map(e => e.trim()).filter(e => e.length > 0);
const mpToken = await tokenizer.tokenizeChat({role:'system', content:mainPrompt})
const summaryToken = await tokenizer.tokenizeChat({role:'system', content:summarizedMp.data})
allocatedTokens -= summaryToken // Update chunks with the new summary
allocatedTokens += mpToken data.chunks.push(...splitted.map(e => ({
text: e,
targetId: targetId
})));
const splited = mainPrompt.split('\n\n').map(e => e.trim()).filter(e => e.length > 0) // Remove summarized chats
chats.splice(0, idx);
data.chunks.push(...splited.map(e => ({
text: e,
targetId: targetId
})))
data.mainChunks[0].text = mainPrompt
}
} }
const processer = new HypaProcesser("nomic")
await processer.addText(data.chunks.filter(v => { // Construct the mainPrompt from mainChunks until half of the allocatedTokens are used
return v.text.trim().length > 0 mainPrompt = "";
}).map((v) => { let mainPromptTokens = 0;
return "search_document: " + v.text.trim() for (const chunk of data.mainChunks) {
})) const chunkTokens = await tokenizer.tokenizeChat({ role: 'system', content: chunk.text });
if (mainPromptTokens + chunkTokens > allocatedTokens / 2) break;
mainPrompt += `\n\n${chunk.text}`;
mainPromptTokens += chunkTokens;
lastMainChunkTargetId = chunk.targetId;
}
let scoredResults:{[key:string]:number} = {} // Fetch additional memory from chunks
for(let i=0;i<3;i++){ const processor = new HypaProcesser(db.hypaModel);
const pop = chats[chats.length - i - 1] processor.oaikey = db.supaMemoryKey;
if(!pop){
break // Find the smallest index of chunks with the same targetId as lastMainChunkTargetId
const lastMainChunkIndex = data.chunks.reduce((minIndex, chunk, index) => {
if (chunk.targetId === lastMainChunkTargetId) {
return Math.min(minIndex, index);
} }
const searched = await processer.similaritySearchScored(`search_query: ${pop.content}`) return minIndex;
for(const result of searched){ }, data.chunks.length);
const score = result[1]/(i+1)
if(scoredResults[result[0]]){ // Filter chunks to only include those older than the last mainChunk's targetId
scoredResults[result[0]] += score const olderChunks = lastMainChunkIndex !== data.chunks.length
}else{ ? data.chunks.slice(0, lastMainChunkIndex)
scoredResults[result[0]] = score : data.chunks;
}
console.log("Older Chunks:", olderChunks);
// Add older chunks to processor for similarity search
await processor.addText(olderChunks.filter(v => v.text.trim().length > 0).map(v => "search_document: " + v.text.trim()));
let scoredResults: { [key: string]: number } = {};
for (let i = 0; i < 3; i++) {
const pop = chats[chats.length - i - 1];
if (!pop) break;
const searched = await processor.similaritySearchScored(`search_query: ${pop.content}`);
for (const result of searched) {
const score = result[1] / (i + 1);
scoredResults[result[0]] = (scoredResults[result[0]] || 0) + score;
} }
} }
const scoredArray = Object.entries(scoredResults).sort((a,b) => b[1] - a[1]) const scoredArray = Object.entries(scoredResults).sort((a, b) => b[1] - a[1]);
let chunkResultPrompts = "";
let chunkResultPrompts = "" let chunkResultTokens = 0;
while(allocatedTokens > 0){ while (allocatedTokens - mainPromptTokens - chunkResultTokens > 0 && scoredArray.length > 0) {
const target = scoredArray.shift() const [text] = scoredArray.shift();
if(!target){ const tokenized = await tokenizer.tokenizeChat({ role: 'system', content: text.substring(14) });
break if (tokenized > allocatedTokens - mainPromptTokens - chunkResultTokens) break;
} chunkResultPrompts += text.substring(14) + '\n\n';
const tokenized = await tokenizer.tokenizeChat({ chunkResultTokens += tokenized;
role: 'system',
content: target[0].substring(14)
})
if(tokenized > allocatedTokens){
break
}
chunkResultPrompts += target[0].substring(14) + '\n\n'
allocatedTokens -= tokenized
} }
const fullResult = `<Past Events Summary>${mainPrompt}</Past Events Summary>\n<Past Events Details>${chunkResultPrompts}</Past Events Details>`;
const fullResult = `<Past Events Summary>${mainPrompt}</Past Events Summary>\n<Past Events Details>${chunkResultPrompts}</Past Events Details>`
chats.unshift({ chats.unshift({
role: "system", role: "system",
content: fullResult, content: fullResult,
memo: "supaMemory" memo: "supaMemory"
}) });
// Add the remaining chats after the last mainChunk's targetId
const lastTargetId = data.mainChunks.length > 0 ? data.mainChunks[0].targetId : null;
if (lastTargetId) {
const lastIndex = getValidChatIndex(lastTargetId);
if (lastIndex !== -1) {
const remainingChats = chats.slice(lastIndex + 1);
chats = [chats[0], ...remainingChats];
}
}
// Add last two chats if they exist and are not duplicates
if (lastTwoChats.length === 2) {
const [lastChat1, lastChat2] = lastTwoChats;
if (!chats.some(chat => chat.memo === lastChat1.memo)) {
chats.push(lastChat1);
}
if (!chats.some(chat => chat.memo === lastChat2.memo)) {
chats.push(lastChat2);
}
}
console.log("model being used: ", db.hypaModel, db.supaModelType, "\nCurrent session tokens: ", currentTokens, "\nAll chats, including memory system prompt: ", chats, "\nMemory data, with all the chunks: ", data);
return { return {
currentTokens: currentTokens, currentTokens: currentTokens,
chats: chats, chats: chats,
memory: data memory: data
} };
} }

View File

@@ -183,7 +183,7 @@ export async function supaMemory(
async function summarize(stringlizedChat:string){ async function summarize(stringlizedChat:string){
if(db.supaMemoryType === 'distilbart'){ if(db.supaModelType === 'distilbart'){
try { try {
const sum = await runSummarizer(stringlizedChat) const sum = await runSummarizer(stringlizedChat)
return sum return sum
@@ -204,7 +204,7 @@ export async function supaMemory(
let result = '' let result = ''
if(db.supaMemoryType !== 'subModel'){ if(db.supaModelType !== 'subModel'){
const promptbody = stringlizedChat + '\n\n' + supaPrompt + "\n\nOutput:" const promptbody = stringlizedChat + '\n\n' + supaPrompt + "\n\nOutput:"
const da = await globalFetch("https://api.openai.com/v1/completions",{ const da = await globalFetch("https://api.openai.com/v1/completions",{
@@ -214,8 +214,8 @@ export async function supaMemory(
}, },
method: "POST", method: "POST",
body: { body: {
"model": db.supaMemoryType === 'curie' ? "text-curie-001" "model": db.supaModelType === 'curie' ? "text-curie-001"
: db.supaMemoryType === 'instruct35' ? 'gpt-3.5-turbo-instruct' : db.supaModelType === 'instruct35' ? 'gpt-3.5-turbo-instruct'
: "text-davinci-003", : "text-davinci-003",
"prompt": promptbody, "prompt": promptbody,
"max_tokens": 600, "max_tokens": 600,

View File

@@ -230,8 +230,8 @@ export function setDatabase(data:Database){
if(checkNullish(data.supaMemoryKey)){ if(checkNullish(data.supaMemoryKey)){
data.supaMemoryKey = "" data.supaMemoryKey = ""
} }
if(checkNullish(data.supaMemoryType)){ if(checkNullish(data.supaModelType)){
data.supaMemoryType = "none" data.supaModelType = "none"
} }
if(checkNullish(data.askRemoval)){ if(checkNullish(data.askRemoval)){
data.askRemoval = true data.askRemoval = true
@@ -527,7 +527,7 @@ export interface Database{
useStreaming:boolean useStreaming:boolean
palmAPI:string, palmAPI:string,
supaMemoryKey:string supaMemoryKey:string
supaMemoryType:string supaModelType:string
textScreenColor?:string textScreenColor?:string
textBorder?:boolean textBorder?:boolean
textScreenRounded?:boolean textScreenRounded?:boolean
@@ -569,6 +569,8 @@ export interface Database{
useAdditionalAssetsPreview:boolean, useAdditionalAssetsPreview:boolean,
usePlainFetch:boolean usePlainFetch:boolean
hypaMemory:boolean hypaMemory:boolean
hypav2:boolean
memoryAlgorithmType:string // To enable new memory module/algorithms
proxyRequestModel:string proxyRequestModel:string
ooba:OobaSettings ooba:OobaSettings
ainconfig: AINsettings ainconfig: AINsettings