Files
risuai/src/ts/process/supaMemory.ts
2023-06-07 09:47:27 +09:00

228 lines
7.9 KiB
TypeScript

import { get } from "svelte/store";
import type { OpenAIChat } from ".";
import { DataBase, type Chat, type character, type groupChat } from "../storage/database";
import { tokenize } from "../tokenizer";
import { findCharacterbyId } from "../util";
import { requestChatData } from "./request";
export async function supaMemory(
chats:OpenAIChat[],
currentTokens:number,
maxContextTokens:number,
room:Chat,
char:character|groupChat,
chatAdditonalTokens:number
): Promise<{ currentTokens: number; chats: OpenAIChat[]; error?:string; memory?:string;lastId?:string}>{
const db = get(DataBase)
currentTokens += 10
if(currentTokens > maxContextTokens){
let coIndex = -1
for(let i=0;i<chats.length;i++){
if(chats[i].memo === 'NewChat'){
coIndex = i
break
}
}
if(coIndex !== -1){
for(let i=0;i<coIndex;i++){
currentTokens -= (await tokenize(chats[0].content) + chatAdditonalTokens)
chats.splice(0, 1)
}
}
let supaMemory = ''
let lastId = ''
if(room.supaMemoryData && room.supaMemoryData.length > 4){
const splited = room.supaMemoryData.split('\n')
const id = splited.splice(0,1)[0]
const data = splited.join('\n')
let i =0;
while(true){
if(chats.length === 0){
return {
currentTokens: currentTokens,
chats: chats,
error: "SupaMemory: chat ID not found"
}
}
if(chats[0].memo === id){
lastId = id
break
}
currentTokens -= (await tokenize(chats[0].content) + chatAdditonalTokens)
chats.splice(0, 1)
i += 1
}
supaMemory = data
currentTokens += await tokenize(supaMemory) + chatAdditonalTokens
}
if(currentTokens < maxContextTokens){
chats.unshift({
role: "system",
content: supaMemory
})
return {
currentTokens: currentTokens,
chats: chats
}
}
async function summarize(stringlizedChat:string){
const supaPrompt = db.supaMemoryPrompt === '' ?
"[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.supaMemoryType !== 'subModel'){
const promptbody = stringlizedChat + '\n\n' + supaPrompt + "\n\nOutput:"
const da = await fetch("https://api.openai.com/v1/completions",{
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + db.supaMemoryKey
},
method: "POST",
body: JSON.stringify({
"model": db.supaMemoryType === 'curie' ? "text-curie-001" : "text-davinci-003",
"prompt": promptbody,
"max_tokens": 600,
"temperature": 0
})
})
if(da.status < 200 || da.status >= 300){
return {
currentTokens: currentTokens,
chats: chats,
error: "SupaMemory: HTTP: " + await da.text()
}
}
result = (await da.json()).choices[0].text.trim()
}
else {
const promptbody:OpenAIChat[] = [
{
role: "user",
content: stringlizedChat
},
{
role: "system",
content: supaPrompt
}
]
const da = await requestChatData({
formated: promptbody,
bias: {}
}, 'submodel')
if(da.type === 'fail' || da.type === 'streaming'){
return {
currentTokens: currentTokens,
chats: chats,
error: "SupaMemory: HTTP: " + da.result
}
}
result = da.result
}
return result
}
while(currentTokens > maxContextTokens){
const beforeToken = currentTokens
let maxChunkSize = maxContextTokens > 3500 ? 1200 : Math.floor(maxContextTokens / 3)
let summarized = false
let chunkSize = 0
let stringlizedChat = ''
let spiceLen = 0
while(true){
const cont = chats[spiceLen]
if(!cont){
currentTokens = beforeToken
stringlizedChat = ''
chunkSize = 0
spiceLen = 0
if(summarized){
if(maxChunkSize < 500){
return {
currentTokens: currentTokens,
chats: chats,
error: "Not Enough Tokens"
}
}
maxChunkSize = maxChunkSize * 0.7
}
else{
const result = await summarize(supaMemory)
if(typeof(result) !== 'string'){
return result
}
console.log(currentTokens)
currentTokens -= await tokenize(supaMemory)
currentTokens += await tokenize(result + '\n\n')
console.log(currentTokens)
supaMemory = result + '\n\n'
summarized = true
if(currentTokens <= maxContextTokens){
break
}
}
continue
}
const tokens = await tokenize(cont.content) + chatAdditonalTokens
if((chunkSize + tokens) > maxChunkSize){
if(stringlizedChat === ''){
stringlizedChat += `${cont.role === 'assistant' ? char.type === 'group' ? '' : char.name : db.username}: ${cont.content}\n\n`
}
lastId = cont.memo
break
}
stringlizedChat += `${cont.role === 'assistant' ? char.type === 'group' ? '' : char.name : db.username}: ${cont.content}\n\n`
spiceLen += 1
currentTokens -= tokens
chunkSize += tokens
}
chats.splice(0, spiceLen)
if(stringlizedChat !== ''){
const result = await summarize(stringlizedChat)
if(typeof(result) !== 'string'){
return result
}
const tokenz = await tokenize(result + '\n\n') + chatAdditonalTokens
currentTokens += tokenz
supaMemory += result.replace(/\n+/g,'\n') + '\n\n'
}
}
chats.unshift({
role: "system",
content: supaMemory
})
return {
currentTokens: currentTokens,
chats: chats,
memory: lastId + '\n' + supaMemory,
lastId: lastId
}
}
return {
currentTokens: currentTokens,
chats: chats
}
}