diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index eed9e561..a14d92b5 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "RisuAI", - "version": "1.23.3" + "version": "1.24.0" }, "tauri": { "allowlist": { diff --git a/src/lang/cn.ts b/src/lang/cn.ts index e1a3b8ba..ac34c54e 100644 --- a/src/lang/cn.ts +++ b/src/lang/cn.ts @@ -69,7 +69,7 @@ export const languageChinese = { experimental: "这是一个实验性功能。可能不稳定。", oogaboogaURL: "如果你的WebUI支持api的旧版本,你的url应该看起来*像https:.../run/textgen*\n\n" + "如果你的WebUI支持api的新版本,你的url应该看起来像*https://.../api/v1/generate*并且使用api服务器作为主机,并在参数中添加 --api。", - exampleMessage: "影响角色输出的示例对话。它不会永久性地使用令牌。" + exampleMessage: "影响角色输出的示例对话。它不会永久性地使用token。" + "\n\n对话的示例格式:" + "\n\n```\n\n{{user}}: hi\n{{char}}: hello\n\n{{user}}: hi\nHaruhi: hello\n```" + "\n\n``````标记新对话的开始。", @@ -81,9 +81,9 @@ export const languageChinese = { utilityBot: "激活后,它会忽略主提示词。\n\n**不建议使用此选项。改为修改系统提示词。**", loreSelective: "如果已切换选择模式,则激活密钥和次级密钥都应有匹配项才能激活lorebook。", loreRandomActivation: "如果启用了使用概率条件,如果lorebook的其他条件都已满足,每次发送聊天时,lorebook将以“概率”设置的概率被激活。", - additionalAssets: "在你的聊天中显示的额外资产。 \n\n - 使用 `{{raw::}}` 作为路径。\n - 使用 `{{img::}}` 作为图片", + additionalAssets: "在你的聊天中显示的额外资源。 \n\n - 使用 `{{raw::}}` 作为路径。\n - 使用 `{{img::}}` 作为图片\n - use `{{video::}}` to use as video\n - use `{{audio::}}` to use as audio (recommended to put in Background HTML)", superMemory: "SuperMemory 通过给 AI 提供总结数据使你的角色记忆更多信息。\n\n" - + "SuperMemory 模型是一个总结文本的模型。推荐使用达芬奇,除非是具有超过2000个令牌的高度总结能力的未过滤模型,否则不推荐使用辅助模型。\n\n" + + "SuperMemory 模型是一个总结文本的模型。推荐使用Davinci,除非是具有超过2000个token数的高度总结能力的成人模型,否则不推荐使用辅助模型。\n\n" + "SuperMemory 提示词决定了应发送什么提示词进行总结。如果你留空,它将使用默认提示词。建议留空。\n\n" + "在所有设置都完成后,你可以在角色的设置中启用它。", replaceGlobalNote: "如果不为空,将当前的全局笔记替换为此。", @@ -113,7 +113,7 @@ export const languageChinese = { jailbreakPrompt: "NSFW(成人模式)/越狱提示词", globalNote: "全局注释", autoSuggest: "自动建议", - tokens: '令牌', + tokens: 'token数', maxContextSize: '最大上下文大小', maxResponseSize: '最大响应大小', temperature: '温度', @@ -125,7 +125,7 @@ export const languageChinese = { authorNote: "作者注释", firstMessage: '第一条消息', description: '描述', - jailbreakToggle: '切换NSFW(成人模式)/越狱', + jailbreakToggle: '开启NSFW(成人模式)/越狱', charIcon: "角色图标", characterDisplay: "角色展示", viewScreen: '额外角色屏幕', @@ -139,7 +139,7 @@ export const languageChinese = { value: "值", reroll: '重新生成', chatList: '聊天列表', - removeChat: "移除此消息?", + removeChat: "删除此消息?", loreBook: 'lorebook', character: "角色", Chat: "聊天", @@ -147,17 +147,17 @@ export const languageChinese = { group: "群组", groupLoreInfo: "群组lorebook应用于群组中的所有聊天。", localLoreInfo: "聊天lorebook仅应用于当前聊天。", - removeConfirm: "你真的想移除:", - removeConfirm2: "你真的真的想移除:", + removeConfirm: "你真的想删除:", + removeConfirm2: "你真的真的想删除:", exportConfirm: "你想要导出这个吗?", insertOrder: '插入顺序', activationKeys: '激活键', activationKeysInfo: '用逗号分隔', prompt: '提示词', loreBookDepth: "lorebook搜索深度", - loreBookToken: "lorebook最大令牌", - removeCharacter: "移除角色", - removeGroup: "移除群组", + loreBookToken: "lorebook最大token数", + removeCharacter: "删除角色", + removeGroup: "删除群组", exportCharacter: "导出角色", userSetting: "用户设置", username: '你的名字', @@ -223,8 +223,8 @@ export const languageChinese = { currentImageGeneration: "当前图像生成数据", promptPreprocess: "使用提示词预处理", SwipeRegenerate: "使用滑动重新生成", - instantRemove: "当消息被移除时,立即移除随后的消息", - instantRemoveConfirm: "你想移除单条消息吗?如果你选择否,那么随后的消息也将被移除。", + instantRemove: "当消息被删除时,立即删除随后的消息", + instantRemoveConfirm: "你想删除单条消息吗?如果你选择否,那么随后的消息也将被删除。", textColor: "文本颜色", classicRisu: "经典的Risu", highcontrast: "高对比度", @@ -233,7 +233,7 @@ export const languageChinese = { utilityBot: "实用机器人", ShowLog: "显示请求日志", waifuWidth2: "虚拟角色大小", - sayNothing: "当没有输入字符串时,输入'什么都不说'", + sayNothing: "当没有输入字符串时,输入'Say Nothing'", regexScript: "正则表达式脚本", type: "类型", editInput: "修改输入", editOutput: "修改输出", @@ -260,7 +260,7 @@ export const languageChinese = { creator: "创作者", CharVersion: "角色版本", Speech: "语音", - ToggleSuperMemory: "切换超级记忆", + ToggleSuperMemory: "开启超级记忆", SuperMemory: "超级记忆", useExperimental: "启用实验性功能", showMemoryLimit: "显示记忆限制", @@ -269,7 +269,7 @@ export const languageChinese = { chatBot: '聊天机器人', otherBots: '其他机器人', user: "用户", - additionalAssets: "额外资产", + additionalAssets: "额外资源", editDisplay: "修改显示", community: "社区", textBackgrounds: "自定义文本屏幕颜色", @@ -278,7 +278,7 @@ export const languageChinese = { textScreenBorder: "文本屏幕边框", ttsReadOnlyQuoted: "仅朗读引用", ttsStop: "停止TTS", - askRemoval: "询问移除", + askRemoval: "删除消息前确认", replaceGlobalNote: "替换全局备注", charLoreBook: '角色lorebook', globalLoreBook: '全局lorebook', @@ -293,7 +293,7 @@ export const languageChinese = { askReRollAutoSuggestions: "重新生成自动建议", creatingSuggestions: "正在生成建议...", orderByOrder: "按顺序交谈", - removeFromGroup: "你真的要将{{char}}从群组中移除吗?", + removeFromGroup: "你真的要将{{char}}从群组中删除吗?", talkness: "健谈程度", active: "活跃", loreRandomActivation: "使用概率条件", diff --git a/src/lang/en.ts b/src/lang/en.ts index 5e46dfa9..c5e5ec2b 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -80,12 +80,15 @@ export const languageEnglish = { utilityBot: "When activated, it ignores main prompt. \n\n**It is not recommended to use this option. Modifiy system prompt instead.**", loreSelective: "If Selective mode is toggled, both Activation Key and Secondary key should have a match to activate the lore.", loreRandomActivation: "If Use Probability Condition is abled, if the lore's other conditions are all met, the lore will be activated with a set probability which is set by 'Probability' each time a chat is sent.", - additionalAssets: "Additional assets to display in your chat. \n\n - use `{{raw::}}` to use as path.\n - use `{{img::}}` to use as image", + additionalAssets: "Additional assets to display in your chat. \n\n - use `{{raw::}}` to use as path.\n - use `{{img::}}` to use as image\n - use `{{video::}}` to use as video\n - use `{{audio::}}` to use as audio\n - recommended to put in Background HTML", 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.", - replaceGlobalNote: "If its not blank, it replaces current global note to this." + replaceGlobalNote: "If its not blank, it replaces current global note to this.", + backgroundHTML: "A Markdown/HTML Data that would be injected to the background of chat screen.\n\n you can also use additional assets. for example, you can use `{{audio::}}`: inject the background as asset" }, setup: { chooseProvider: "Choose AI Provider", @@ -300,5 +303,6 @@ export const languageEnglish = { activationProbability: "Probability", shareCloud: "Share to RisuRealm", hub: "RisuRealm", - tags: "Tags" + tags: "Tags", + backgroundHTML: "Background Embedding" } \ No newline at end of file diff --git a/src/lang/ko.ts b/src/lang/ko.ts index ac5bb1ca..9049a5c6 100644 --- a/src/lang/ko.ts +++ b/src/lang/ko.ts @@ -275,5 +275,6 @@ export const languageKorean = { talkness: "대화량", active: "활성화", loreRandomActivation: "확률 조건 사용", - activationProbability: "발동 확률" + activationProbability: "발동 확률", + backgroundHTML: "백그라운드 임베딩" } \ No newline at end of file diff --git a/src/lib/ChatScreens/BackgroundDom.svelte b/src/lib/ChatScreens/BackgroundDom.svelte new file mode 100644 index 00000000..193e6dea --- /dev/null +++ b/src/lib/ChatScreens/BackgroundDom.svelte @@ -0,0 +1,50 @@ + + + +{#if backgroundHTML} +
+ {#await ParseMarkdown(backgroundHTML, currentChar, 'back') then md} + {@html md} + {/await} +
+{/if} \ No newline at end of file diff --git a/src/lib/ChatScreens/ChatScreen.svelte b/src/lib/ChatScreens/ChatScreen.svelte index beb6f00c..808feacf 100644 --- a/src/lib/ChatScreens/ChatScreen.svelte +++ b/src/lib/ChatScreens/ChatScreen.svelte @@ -7,6 +7,7 @@ import defaultWallpaper from '../../etc/bg.jpg' import ChatList from "../Others/ChatList.svelte"; import TransitionImage from "./TransitionImage.svelte"; + import BackgroundDom from "./BackgroundDom.svelte"; let openChatList = false const wallPaper = `background: url(${defaultWallpaper})` @@ -26,16 +27,19 @@ })() {#if $DataBase.theme === ''} -
+
+ {#if $selectedCharID >= 0} {#if $DataBase.characters[$selectedCharID].viewScreen !== 'none'} {/if} {/if} + 2 ? `${externalStyles}`: ''} bind:openChatList/>
{:else if $DataBase.theme === 'waifu'} -
+
+ {#if $selectedCharID >= 0} {#if $DataBase.characters[$selectedCharID].viewScreen !== 'none'}
@@ -49,6 +53,7 @@
{:else if $DataBase.theme === 'waifuMobile'}
+
diff --git a/src/lib/Setting/Pages/BotSettings.svelte b/src/lib/Setting/Pages/BotSettings.svelte index 700d719e..33a1b07e 100644 --- a/src/lib/Setting/Pages/BotSettings.svelte +++ b/src/lib/Setting/Pages/BotSettings.svelte @@ -79,6 +79,13 @@ $DataBase.maxContext = 4000 $DataBase.maxResponse = 500 } + else if(v.startsWith('claude')){ + $DataBase.maxContext = 7500 + $DataBase.maxResponse = 500 + if(v.endsWith('100k')){ + $DataBase.maxContext = 99000 + } + } else{ $DataBase.maxContext = 1500 $DataBase.maxResponse = 200 @@ -94,6 +101,11 @@ Palm2 {language.apiKey} {/if} + +{#if $DataBase.aiModel.startsWith('claude') || $DataBase.subModel.startsWith('claude')} + Claude {language.apiKey} + +{/if} {#if $DataBase.aiModel === 'gpt35' || $DataBase.aiModel === 'gpt4' || $DataBase.subModel === 'gpt4' || $DataBase.subModel === 'gpt35'|| $DataBase.aiModel === 'gpt4_32k' || $DataBase.subModel === 'gpt4_32k'} OpenAI {language.apiKey} diff --git a/src/lib/SideBars/CharConfig.svelte b/src/lib/SideBars/CharConfig.svelte index 14ae070e..5f3894b8 100644 --- a/src/lib/SideBars/CharConfig.svelte +++ b/src/lib/SideBars/CharConfig.svelte @@ -553,6 +553,9 @@ {/if} + {language.backgroundHTML} + + {language.creator} diff --git a/src/lib/UI/ModelList.svelte b/src/lib/UI/ModelList.svelte index fb89d73a..ddcd9d8a 100644 --- a/src/lib/UI/ModelList.svelte +++ b/src/lib/UI/ModelList.svelte @@ -31,7 +31,7 @@ if(name.startsWith("horde:::")){ return name.replace(":::", " ") } - return '' + return name } } @@ -55,6 +55,12 @@ + + + + + + diff --git a/src/ts/parser.ts b/src/ts/parser.ts index c21e1fb4..25ef1dd7 100644 --- a/src/ts/parser.ts +++ b/src/ts/parser.ts @@ -26,7 +26,13 @@ DOMPurify.addHook("uponSanitizeElement", (node: HTMLElement, data) => { } }); -export async function ParseMarkdown(data:string, char:(character | groupChat) = null) { +DOMPurify.addHook("uponSanitizeAttribute", (node, data) => { + if(data.attrName === 'style'){ + data.attrValue = data.attrValue.replace(/(absolute)|(z-index)|(fixed)/g, '') + } +}) + +export async function ParseMarkdown(data:string, char:(character | groupChat) = null, mode:'normal'|'back' = 'normal') { if(char && char.type !== 'group'){ if(char.customscript){ data = processScript(char, data, 'editdisplay') @@ -34,7 +40,13 @@ export async function ParseMarkdown(data:string, char:(character | groupChat) = if(char.additionalAssets){ for(const asset of char.additionalAssets){ const assetPath = await getFileSrc(asset[1]) - data = data.replaceAll(`{{raw::${asset[0]}}}`, assetPath).replaceAll(`{{img::${asset[0]}}}`,``) + data = data.replaceAll(`{{raw::${asset[0]}}}`, assetPath). + replaceAll(`{{img::${asset[0]}}}`,``) + .replaceAll(`{{video::${asset[0]}}}`,``) + .replaceAll(`{{audio::${asset[0]}}}`,``) + if(mode === 'back'){ + data = data.replaceAll(`{{bg::${asset[0]}}}`, `
`) + } } } } @@ -46,7 +58,8 @@ export async function ParseMarkdown(data:string, char:(character | groupChat) = export function parseMarkdownSafe(data:string) { return DOMPurify.sanitize(safeConvertor.makeHtml(data), { - FORBID_TAGS: ["a", "style"] + FORBID_TAGS: ["a", "style"], + FORBID_ATTR: ["style"] }) } diff --git a/src/ts/process/request.ts b/src/ts/process/request.ts index 14167231..7ebc7917 100644 --- a/src/ts/process/request.ts +++ b/src/ts/process/request.ts @@ -48,7 +48,8 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' const db = get(DataBase) let result = '' let formated = arg.formated - let maxTokens = db.maxResponse + let maxTokens = arg.maxTokens ??db.maxResponse + let temperature = arg.temperature ?? (db.temperature / 100) let bias = arg.bias let currentChar = arg.currentChar const replacer = model === 'model' ? db.forceReplaceUrl : db.forceReplaceUrl2 @@ -70,7 +71,7 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' model: aiModel === 'gpt35' ? 'gpt-3.5-turbo' : aiModel === 'gpt4' ? 'gpt-4' : 'gpt-4-32k', messages: formated, - temperature: arg.temperature ?? (db.temperature / 100), + temperature: temperature, max_tokens: arg.maxTokens ?? maxTokens, presence_penalty: arg.PresensePenalty ?? (db.PresensePenalty / 100), frequency_penalty: arg.frequencyPenalty ?? (db.frequencyPenalty / 100), @@ -460,6 +461,65 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' } } default:{ + if(aiModel.startsWith('claude')){ + for(let i=0;i { + let prefix = '' + switch (v.role){ + case "assistant": + prefix = "\n\nAssistant: " + break + case "user": + prefix = "\n\nHuman: " + break + case "system": + prefix = "\n\nSystem: " + break + } + return prefix + v.content + }).join('') + '\n\nAssistant: ' + + console.log(requestPrompt) + + const da = await globalFetch('https://api.anthropic.com/v1/complete', { + method: "POST", + body: { + prompt : "\n\nHuman: " + requestPrompt, + model: aiModel, + max_tokens_to_sample: maxTokens, + stop_sequences: ["\n\nHuman:", "\n\nSystem:", "\n\nAssistant:"], + temperature: temperature, + }, + headers: { + "Content-Type": "application/json", + "x-api-key": db.claudeAPIKey + } + }) + + if((!da.ok) || (da.data.error)){ + return { + type: 'fail', + result: `${JSON.stringify(da.data)}` + } + } + + const res = da.data + + console.log(res) + return { + type: "success", + result: res.completion, + } + + } if(aiModel.startsWith("horde:::")){ const proompt = stringlizeChat(formated, currentChar?.name ?? '') diff --git a/src/ts/storage/database.ts b/src/ts/storage/database.ts index 9384b390..7742a4d5 100644 --- a/src/ts/storage/database.ts +++ b/src/ts/storage/database.ts @@ -8,7 +8,7 @@ import { defaultAutoSuggestPrompt, defaultJailbreak, defaultMainPrompt } from '. export const DataBase = writable({} as any as Database) export const loadedStore = writable(false) -export let appVer = '1.23.3' +export let appVer = '1.24.0' export function setDatabase(data:Database){ if(checkNullish(data.characters)){ @@ -335,6 +335,7 @@ export interface character{ additionalAssets?:[string, string][] ttsReadOnlyQuoted?:boolean replaceGlobalNote:string + backgroundHTML?:string } @@ -371,6 +372,7 @@ export interface groupChat{ ttsMode?:string suggestMessages?:string[] orderByOrder?:boolean + backgroundHTML?:string } export interface botPreset{ @@ -498,7 +500,8 @@ export interface Database{ koboldURL:string advancedBotSettings:boolean useAutoSuggestions:boolean - autoSuggestPrompt:string + autoSuggestPrompt:string, + claudeAPIKey:string } interface hordeConfig{ diff --git a/version.json b/version.json index 75bb7d98..b55dafdf 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"version":"1.23.3"} \ No newline at end of file +{"version":"1.24.0"} \ No newline at end of file