This commit is contained in:
Kwaroran
2025-02-06 09:49:23 +09:00
7 changed files with 119 additions and 19 deletions

View File

@@ -170,7 +170,7 @@ export const languageEnglish = {
summarizationPrompt: "The prompt that is used for summarization. if it is blank, it will use the default prompt. you can also use ChatML formating with {{slot}} for the chat data.", summarizationPrompt: "The prompt that is used for summarization. if it is blank, it will use the default prompt. you can also use ChatML formating with {{slot}} for the chat data.",
translatorPrompt: "The prompt that is used for translation. if it is blank, it will use the default prompt. you can also use ChatML formating with {{slot}} for the dest language, {{solt::content}} for the content, and {{slot::tnote}} for the translator note.", translatorPrompt: "The prompt that is used for translation. if it is blank, it will use the default prompt. you can also use ChatML formating with {{slot}} for the dest language, {{solt::content}} for the content, and {{slot::tnote}} for the translator note.",
translateBeforeHTMLFormatting: "If enabled, it will translate the text before Regex scripts and HTML formatting. this could make the token lesser but could break the formatting.", translateBeforeHTMLFormatting: "If enabled, it will translate the text before Regex scripts and HTML formatting. this could make the token lesser but could break the formatting.",
autoTranslateCachedOnly: "If enabled, it will automatically translate only the text that the user has translated previously.", autoTranslateCachedOnly: "If enabled with Auto Translation option on, it will automatically translate only the text that the user has translated previously.",
presetChain: "If it is not blank, the preset will be changed and applied randomly every time when user sends a message in the preset list in this input. preset list should be seperated by comma, for example, `preset1,preset2`.", presetChain: "If it is not blank, the preset will be changed and applied randomly every time when user sends a message in the preset list in this input. preset list should be seperated by comma, for example, `preset1,preset2`.",
legacyMediaFindings: "If enabled, it will use the old method to find media assets, without using the additional search algorithm.", legacyMediaFindings: "If enabled, it will use the old method to find media assets, without using the additional search algorithm.",
comfyWorkflow: "Put the API workflow of comfy UI. you can get your API workflow in comfy UI by pressing the 'Workflow > Export (API)' button. you must also put {{risu_prompt}} in you workflow text. the {{risu_prompt}} will be replaced with the prompt provided by the Risu.", comfyWorkflow: "Put the API workflow of comfy UI. you can get your API workflow in comfy UI by pressing the 'Workflow > Export (API)' button. you must also put {{risu_prompt}} in you workflow text. the {{risu_prompt}} will be replaced with the prompt provided by the Risu.",

View File

@@ -130,6 +130,9 @@ export const languageChineseTraditional = {
"translatorPrompt": "用於翻譯的提示詞。留空將使用默認提示。您還可以使用帶有 {{slot}} 的 ChatML 格式表示目標語言:用 {{slot::content}} 表示內容,用 {{slot::tnote}} 表示翻譯註釋。", "translatorPrompt": "用於翻譯的提示詞。留空將使用默認提示。您還可以使用帶有 {{slot}} 的 ChatML 格式表示目標語言:用 {{slot::content}} 表示內容,用 {{slot::tnote}} 表示翻譯註釋。",
"translateBeforeHTMLFormatting": "啟用後,將在正規表達式和 HTML 格式化之前翻譯文本。這可能減少 Token 數,但可能破壞格式。", "translateBeforeHTMLFormatting": "啟用後,將在正規表達式和 HTML 格式化之前翻譯文本。這可能減少 Token 數,但可能破壞格式。",
"autoTranslateCachedOnly": "啟用後,僅會自動翻譯使用者之前已翻譯的內容。", "autoTranslateCachedOnly": "啟用後,僅會自動翻譯使用者之前已翻譯的內容。",
"presetChain": "若欄位不為空,則每次使用者發送訊息時,系統會從此輸入中的預設列表中隨機變更並應用預設設定。預設列表應以逗號分隔,例如 `preset1,preset2`。",
"legacyMediaFindings": "啟用後,將使用舊版方法尋找媒體資源,而不使用額外的搜尋演算法。",
"comfyWorkflow": "請輸入 Comfy UI 的 API 工作流程。您可以在 Comfy UI 中點選「Workflow > Export (API)」按鈕以取得您的 API 工作流程。此外,您必須在工作流程文本中加入 {{risu_prompt}},該佔位符將被 Risu 提供的提示詞替換。",
"APIPool": "啟用後,系統將連接到 RisuAI 的 API 資源池。已啟用的使用者可共享免費、速率受限模型的 API 金鑰,從而利用其他使用者未充分使用的金鑰,增加對速率受限模型的請求次數。" "APIPool": "啟用後,系統將連接到 RisuAI 的 API 資源池。已啟用的使用者可共享免費、速率受限模型的 API 金鑰,從而利用其他使用者未充分使用的金鑰,增加對速率受限模型的請求次數。"
}, },
"setup": { "setup": {
@@ -375,7 +378,7 @@ export const languageChineseTraditional = {
"textScreenBorder": "文本視窗邊框", "textScreenBorder": "文本視窗邊框",
"ttsReadOnlyQuoted": "僅朗讀引號內容", "ttsReadOnlyQuoted": "僅朗讀引號內容",
"ttsStop": "停止語音合成", "ttsStop": "停止語音合成",
"askRemoval": "請求刪除", "askRemoval": "刪除訊息前進行確認",
"replaceGlobalNote": "替換全域備註", "replaceGlobalNote": "替換全域備註",
"charLoreBook": "角色 Lorebook", "charLoreBook": "角色 Lorebook",
"globalLoreBook": "全域 Lorebook", "globalLoreBook": "全域 Lorebook",
@@ -429,7 +432,7 @@ export const languageChineseTraditional = {
"toggleConfirmRecommendedPreset": "模型變更時詢問是否使用建議設定", "toggleConfirmRecommendedPreset": "模型變更時詢問是否使用建議設定",
"recommendedPreset": "使用建議設定", "recommendedPreset": "使用建議設定",
"persona": "使用者資訊", "persona": "使用者資訊",
"icon": "頭像", "icon": "圖示",
"account": "帳號", "account": "帳號",
"remove": "刪除", "remove": "刪除",
"creationSuccess": "創建成功", "creationSuccess": "創建成功",
@@ -447,7 +450,8 @@ export const languageChineseTraditional = {
"changeFolderName": "輸入新資料夾名稱(留空以取消)", "changeFolderName": "輸入新資料夾名稱(留空以取消)",
"cancel": "取消", "cancel": "取消",
"renameFolder": "重新命名資料夾", "renameFolder": "重新命名資料夾",
"changeFolderColor": "更資料夾顏色", "changeFolderColor": "更資料夾顏色",
"changeFolderImage": "變更資料夾圖片",
"fullWordMatching": "完整單詞匹配", "fullWordMatching": "完整單詞匹配",
"botSettingAtStart": "啟動時顯示機器人選單", "botSettingAtStart": "啟動時顯示機器人選單",
"triggerStart": "聊天發送時觸發", "triggerStart": "聊天發送時觸發",
@@ -779,5 +783,26 @@ export const languageChineseTraditional = {
"customFlags": "自定義修飾詞Flags", "customFlags": "自定義修飾詞Flags",
"enableCustomFlags": "啟用自定義修飾詞Flags", "enableCustomFlags": "啟用自定義修飾詞Flags",
"googleCloudTokenization": "Google Cloud Tokenization", "googleCloudTokenization": "Google Cloud Tokenization",
"presetChain": "預設鏈",
"legacyMediaFindings": "舊版媒體發現",
"staticsDisclaimer": "統計資料基於 2024 年 7 月之後的數據,可能不完全準確。",
"subtitles": "字幕",
"subtitlesWarning1": "您必須使用具有音訊/視訊輸入的模型才能使用此功能。",
"subtitlesWarning2": "您必須使用具有即時串流傳輸功能的模型才能使用此功能。",
"reset": "重置",
"assetMaxDifference": "資源最大差異",
"sourceLanguage": "原文語言",
"destinationLanguage": "目標語言",
"noWebGPU": "由於目前的瀏覽器或作業系統不支援 WebGPU效能將大幅下降。",
"menuSideBar": "選單側邊欄",
"home": "首頁",
"showSavingIcon": "顯示儲存圖示",
"pluginVersionWarn": "這是 {{plugin_version}} 版本的外掛程式,與當前 RisuAI 版本不相容。請更新外掛至 {{required_version}} 版本。",
"imageTranslation": "圖像翻譯",
"banCharacterset": "自動重新生成字符集",
"checkCorruption": "檢查損壞",
"showPromptComparison": "顯示提示比較",
"hypaV3Desc": "HypaMemory V3 是一個長期記憶系統,使用摘要資料和向量搜尋。",
"inlayErrorResponse": "嵌入錯誤回應",
"APIPool": "API 工具" "APIPool": "API 工具"
} }

View File

@@ -143,7 +143,9 @@
if(DBState.db.autoTranslateCachedOnly && DBState.db.translatorType === 'llm'){ if(DBState.db.autoTranslateCachedOnly && DBState.db.translatorType === 'llm'){
const cache = DBState.db.translateBeforeHTMLFormatting const cache = DBState.db.translateBeforeHTMLFormatting
? await getLLMCache(data) ? await getLLMCache(data)
: await getLLMCache(await ParseMarkdown(data, charArg, 'pretranslate', chatID, getCbsCondition())) : !DBState.db.legacyTranslation
? await getLLMCache(await ParseMarkdown(data, charArg, 'pretranslate', chatID, getCbsCondition()))
: await getLLMCache(await ParseMarkdown(data, charArg, mode, chatID, getCbsCondition()))
translateText = cache !== null translateText = cache !== null
} }

View File

@@ -871,19 +871,27 @@
<div class="sticky top-0 z-50 p-2 sm:p-3 bg-zinc-800"> <div class="sticky top-0 z-50 p-2 sm:p-3 bg-zinc-800">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div class="relative flex flex-1 items-center"> <div class="relative flex flex-1 items-center">
<input <form
class="w-full px-2 sm:px-4 py-2 sm:py-3 rounded border border-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-500 text-zinc-200 bg-zinc-900" class="w-full"
placeholder="Enter #N, ID, or search query" onsubmit={(e) => {
bind:this={searchUIState.ref} e.preventDefault();
bind:value={searchUIState.query} onSearch({ key: "Enter" } as KeyboardEvent);
oninput={() => {
if (searchUIState) {
searchUIState.currentIndex = -1;
searchUIState.results = [];
}
}} }}
onkeydown={(e) => onSearch(e)} >
/> <input
class="w-full px-2 sm:px-4 py-2 sm:py-3 rounded border border-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-500 text-zinc-200 bg-zinc-900"
placeholder="Enter #N, ID, or search query"
bind:this={searchUIState.ref}
bind:value={searchUIState.query}
oninput={() => {
if (searchUIState) {
searchUIState.currentIndex = -1;
searchUIState.results = [];
}
}}
onkeydown={(e) => onSearch(e)}
/>
</form>
{#if searchUIState.results.length > 0} {#if searchUIState.results.length > 0}
<span <span

View File

@@ -17,6 +17,9 @@
import CheckInput from "src/lib/UI/GUI/CheckInput.svelte"; import CheckInput from "src/lib/UI/GUI/CheckInput.svelte";
import TextAreaInput from "src/lib/UI/GUI/TextAreaInput.svelte"; import TextAreaInput from "src/lib/UI/GUI/TextAreaInput.svelte";
import { untrack } from "svelte"; import { untrack } from "svelte";
import { tokenizePreset } from "src/ts/process/prompt";
import { getCharToken } from "src/ts/tokenizer";
import { selectedCharID } from "src/ts/stores.svelte";
$effect.pre(() => { $effect.pre(() => {
DBState.db.NAIImgConfig ??= { DBState.db.NAIImgConfig ??= {
@@ -53,7 +56,7 @@
DBState.db.hypaV3Settings.similarMemoryRatio = 1 - newValue; DBState.db.hypaV3Settings.similarMemoryRatio = 1 - newValue;
} }
}) })
}) });
$effect(() => { $effect(() => {
const newValue = Math.min(DBState.db.hypaV3Settings.similarMemoryRatio, 1); const newValue = Math.min(DBState.db.hypaV3Settings.similarMemoryRatio, 1);
@@ -66,6 +69,24 @@
} }
}) })
}); });
async function getMaxMemoryRatio(): Promise<number> {
const promptTemplateToken = await tokenizePreset(DBState.db.promptTemplate);
const char = DBState.db.characters[$selectedCharID];
const charToken = await getCharToken(char);
const maxLoreToken = char.loreSettings?.tokenBudget ?? DBState.db.loreBookToken;
const maxResponse = DBState.db.maxResponse;
const requiredToken = promptTemplateToken + charToken.persistant + Math.min(charToken.dynamic, maxLoreToken) + maxResponse * 3;
const maxContext = DBState.db.maxContext;
if (maxContext === 0) {
return 0;
}
const maxMemoryRatio = Math.max((maxContext - requiredToken) / maxContext, 0);
return parseFloat(maxMemoryRatio.toFixed(2));
}
// End HypaV3 // End HypaV3
</script> </script>
<h2 class="mb-2 text-2xl font-bold mt-2">{language.otherBots}</h2> <h2 class="mb-2 text-2xl font-bold mt-2">{language.otherBots}</h2>
@@ -500,7 +521,13 @@
<span class="text-textcolor">{language.summarizationPrompt} <Help key="summarizationPrompt"/></span> <span class="text-textcolor">{language.summarizationPrompt} <Help key="summarizationPrompt"/></span>
<div class="mb-2"> <div class="mb-2">
<TextAreaInput size="sm" placeholder="Leave it blank to use default" bind:value={DBState.db.supaMemoryPrompt} /> <TextAreaInput size="sm" placeholder="Leave it blank to use default" bind:value={DBState.db.supaMemoryPrompt} />
</div> </div>
<span class="text-textcolor">Max Memory Tokens Ratio (Estimated)</span>
{#await getMaxMemoryRatio() then maxMemoryRatio}
<NumberInput marginBottom disabled size="sm" value={maxMemoryRatio} />
{:catch error}
<span class="text-textcolor">{error}</span>
{/await}
<span class="text-textcolor">Memory Tokens Ratio</span> <span class="text-textcolor">Memory Tokens Ratio</span>
<SliderInput marginBottom min={0} max={1} step={0.01} fixed={2} bind:value={DBState.db.hypaV3Settings.memoryTokensRatio} /> <SliderInput marginBottom min={0} max={1} step={0.01} fixed={2} bind:value={DBState.db.hypaV3Settings.memoryTokensRatio} />
<span class="text-textcolor">Extra Summarization Ratio</span> <span class="text-textcolor">Extra Summarization Ratio</span>

View File

@@ -1,6 +1,7 @@
import { runTrigger } from "./process/triggers"; import { runTrigger } from "./process/triggers";
import { sleep } from "./util"; import { sleep } from "./util";
import { getCurrentCharacter, getCurrentChat, setCurrentChat } from "./storage/database.svelte"; import { getCurrentCharacter, getCurrentChat, setCurrentChat } from "./storage/database.svelte";
import { runLuaButtonTrigger } from "./process/lua";
function nodeObserve(node:HTMLElement){ function nodeObserve(node:HTMLElement){
@@ -35,6 +36,15 @@ function nodeObserve(node:HTMLElement){
} }
if(btnEvent){ if(btnEvent){
node.addEventListener('click', async () => {
const currentChar = getCurrentCharacter()
if(currentChar.type === 'group'){
return;
}
await runLuaButtonTrigger(currentChar, btnEvent);
}, {
passive: true,
});
node.setAttribute('risu-observer', 'true'); node.setAttribute('risu-observer', 'true');
return return
} }

View File

@@ -457,6 +457,13 @@ export async function runLua(code:string, arg:{
} }
break break
} }
case 'onButtonClick':{
const func = luaEngine.global.get('onButtonClick')
if(func){
res = await func(accessKey, data)
}
break
}
case 'editRequest': case 'editRequest':
case 'editDisplay': case 'editDisplay':
case 'editInput': case 'editInput':
@@ -675,4 +682,25 @@ export async function runLuaEditTrigger<T extends any>(char:character|groupChat|
} catch (error) { } catch (error) {
return content return content
} }
}
export async function runLuaButtonTrigger(char:character|groupChat|simpleCharacterArgument, data:string):Promise<T>{
let runResult
try {
const triggers = char.type === 'group' ? getModuleTriggers() : char.triggerscript.concat(getModuleTriggers())
const lowLevelAccess = char.type !== 'simple' ? char.lowLevelAccess ?? false : false
for(let trigger of triggers){
if(trigger?.effect?.[0]?.type === 'triggerlua'){
runResult = await runLua(trigger.effect[0].code, {
char: char,
lowLevelAccess: lowLevelAccess,
mode: 'onButtonClick',
data: data
})
}
}
} catch (error) {
throw(error)
}
return runResult
} }