Update to 1.24.0 (#161)

# 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
Update to 1.24.0
This commit is contained in:
kwaroran
2023-06-06 09:33:45 +09:00
committed by GitHub
13 changed files with 191 additions and 34 deletions

View File

@@ -8,7 +8,7 @@
},
"package": {
"productName": "RisuAI",
"version": "1.23.3"
"version": "1.24.0"
},
"tauri": {
"allowlist": {

View File

@@ -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<START>\n{{user}}: hi\n{{char}}: hello\n<START>\n{{user}}: hi\nHaruhi: hello\n```"
+ "\n\n```<START>```标记新对话的开始。",
@@ -81,9 +81,9 @@ export const languageChinese = {
utilityBot: "激活后,它会忽略主提示词。\n\n**不建议使用此选项。改为修改系统提示词。**",
loreSelective: "如果已切换选择模式则激活密钥和次级密钥都应有匹配项才能激活lorebook。",
loreRandomActivation: "如果启用了使用概率条件如果lorebook的其他条件都已满足每次发送聊天时lorebook将以“概率”设置的概率被激活。",
additionalAssets: "在你的聊天中显示的额外资。 \n\n - 使用 `{{raw::<asset name>}}` 作为路径。\n - 使用 `{{img::<asset name>}}` 作为图片",
additionalAssets: "在你的聊天中显示的额外资。 \n\n - 使用 `{{raw::<asset name>}}` 作为路径。\n - 使用 `{{img::<asset name>}}` 作为图片\n - use `{{video::<asset name>}}` to use as video\n - use `{{audio::<asset name>}}` 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: "使用概率条件",

View File

@@ -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::<asset name>}}` to use as path.\n - use `{{img::<asset name>}}` to use as image",
additionalAssets: "Additional assets to display in your chat. \n\n - use `{{raw::<asset name>}}` to use as path.\n - use `{{img::<asset name>}}` to use as image\n - use `{{video::<asset name>}}` to use as video\n - use `{{audio::<asset name>}}` 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::<asset name}}` for background music."
+ "\n\n Additionaly, you can use these with additional assets:"
+ "\n - `{{bg::<asset name>}}`: 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"
}

View File

@@ -275,5 +275,6 @@ export const languageKorean = {
talkness: "대화량",
active: "활성화",
loreRandomActivation: "확률 조건 사용",
activationProbability: "발동 확률"
activationProbability: "발동 확률",
backgroundHTML: "백그라운드 임베딩"
}

View File

@@ -0,0 +1,50 @@
<script lang="ts">
import { ParseMarkdown } from "src/ts/parser";
import { DataBase, type Database, type character, type groupChat } from "src/ts/storage/database";
import { selectedCharID } from "src/ts/stores";
import { onDestroy } from "svelte";
let backgroundHTML = ''
let lastdb:Database
let currentChar:character|groupChat
let selectedId = 0
function checkUpdate(){
if(selectedId > 0 && lastdb){
if(lastdb.characters[selectedId].backgroundHTML !== backgroundHTML){
backgroundHTML = lastdb.characters[selectedId].backgroundHTML
currentChar = lastdb.characters[selectedId]
}
}
else{
if(backgroundHTML !== ''){
backgroundHTML = ''
}
}
}
const unsubDatabase = DataBase.subscribe(v => {
lastdb = v
checkUpdate()
})
const unsubID = selectedCharID.subscribe(v => {
selectedId = v
checkUpdate()
})
onDestroy(() => {
unsubDatabase()
unsubID()
})
</script>
{#if backgroundHTML}
<div class="absolute top-0 left-0 w-full h-full">
{#await ParseMarkdown(backgroundHTML, currentChar, 'back') then md}
{@html md}
{/await}
</div>
{/if}

View File

@@ -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 @@
})()
</script>
{#if $DataBase.theme === ''}
<div class="flex-grow h-full min-w-0" style={bgImg}>
<div class="flex-grow h-full min-w-0 relative" style={bgImg}>
{#if $selectedCharID >= 0}
{#if $DataBase.characters[$selectedCharID].viewScreen !== 'none'}
<ResizeBox />
{/if}
{/if}
<BackgroundDom />
<DefaultChatScreen customStyle={bgImg.length > 2 ? `${externalStyles}`: ''} bind:openChatList/>
</div>
{:else if $DataBase.theme === 'waifu'}
<div class="flex-grow h-full flex justify-center" style="max-width:calc({$sideBarStore ? $SizeStore.w - 400 : $SizeStore.w}px);{bgImg.length < 4 ? wallPaper : bgImg}">
<div class="flex-grow h-full flex justify-center relative" style="max-width:calc({$sideBarStore ? $SizeStore.w - 400 : $SizeStore.w}px);{bgImg.length < 4 ? wallPaper : bgImg}">
<BackgroundDom />
{#if $selectedCharID >= 0}
{#if $DataBase.characters[$selectedCharID].viewScreen !== 'none'}
<div class="h-full mr-10 flex justify-end halfw" style:width="{42 * ($DataBase.waifuWidth2 / 100)}rem">
@@ -49,6 +53,7 @@
</div>
{:else if $DataBase.theme === 'waifuMobile'}
<div class="flex-grow h-full relative" style={bgImg.length < 4 ? wallPaper : bgImg}>
<BackgroundDom />
<div class="w-full h-1/3 absolute z-10 bottom-0 left-0">
<DefaultChatScreen customStyle={`${externalStyles}backdrop-filter: blur(4px);`} bind:openChatList/>
</div>

View File

@@ -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 @@
<span class="text-neutral-200">Palm2 {language.apiKey}</span>
<input class="text-neutral-200 mb-4 p-2 bg-transparent input-text focus:bg-selected text-sm" placeholder="..." bind:value={$DataBase.palmAPI}>
{/if}
{#if $DataBase.aiModel.startsWith('claude') || $DataBase.subModel.startsWith('claude')}
<span class="text-neutral-200">Claude {language.apiKey}</span>
<input class="text-neutral-200 mb-4 p-2 bg-transparent input-text focus:bg-selected text-sm" placeholder="..." bind:value={$DataBase.claudeAPIKey}>
{/if}
{#if $DataBase.aiModel === 'gpt35' || $DataBase.aiModel === 'gpt4' || $DataBase.subModel === 'gpt4' || $DataBase.subModel === 'gpt35'|| $DataBase.aiModel === 'gpt4_32k' || $DataBase.subModel === 'gpt4_32k'}
<span class="text-neutral-200">OpenAI {language.apiKey} <Help key="oaiapikey"/></span>
<input class="text-neutral-200 p-2 bg-transparent input-text focus:bg-selected text-sm" placeholder="sk-XXXXXXXXXXXXXXXXXXXX" bind:value={$DataBase.openAIKey}>

View File

@@ -553,6 +553,9 @@
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 text-xs resize-none h-20 focus:bg-selected" autocomplete="off" bind:value={currentChar.data.scenario}></textarea>
{/if}
<span class="text-neutral-200 mt-2">{language.backgroundHTML} <Help key="backgroundHTML" /></span>
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 text-xs resize-none h-20 focus:bg-selected" autocomplete="off" bind:value={currentChar.data.backgroundHTML}></textarea>
<span class="text-neutral-200">{language.creator}</span>
<input class="bg-transparent input-text mt-2 mb-2 text-gray-200 text-xs resize-none h-20 focus:bg-selected" autocomplete="off" bind:value={currentChar.data.additionalData.creator} />

View File

@@ -31,7 +31,7 @@
if(name.startsWith("horde:::")){
return name.replace(":::", " ")
}
return ''
return name
}
}
@@ -55,6 +55,12 @@
<button class="p-2 hover:text-green-500" on:click={() => {changeModel('gpt4')}}>GPT-4</button>
<button class="p-2 hover:text-green-500" on:click={() => {changeModel('gpt4_32k')}}>GPT-4 32K</button>
</Arcodion>
<Arcodion name="Anthropic Claude">
<button class="p-2 hover:text-green-500" on:click={() => {changeModel('claude-v1')}}>claude-v1</button>
<button class="p-2 hover:text-green-500" on:click={() => {changeModel('claude-v1-100k')}}>claude-v1-100k</button>
<button class="p-2 hover:text-green-500" on:click={() => {changeModel('claude-instant-v1')}}>claude-instant-v1</button>
<button class="p-2 hover:text-green-500" on:click={() => {changeModel('claude-instant-v1-100k')}}>claude-instant-v1-100k</button>
</Arcodion>
<button class="hover:bg-selected px-6 py-2 text-lg" on:click={() => {changeModel('textgen_webui')}}>Oobabooga WebUI</button>
<button class="hover:bg-selected px-6 py-2 text-lg" on:click={() => {changeModel('palm2')}}>Google PaLM2</button>
<button class="hover:bg-selected px-6 py-2 text-lg" on:click={() => {changeModel('kobold')}}>Kobold</button>

View File

@@ -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]}}}`,`<img src="${assetPath}" />`)
data = data.replaceAll(`{{raw::${asset[0]}}}`, assetPath).
replaceAll(`{{img::${asset[0]}}}`,`<img src="${assetPath}" />`)
.replaceAll(`{{video::${asset[0]}}}`,`<video autoplay loop><source src="${assetPath}" type="video/mp4"></video>`)
.replaceAll(`{{audio::${asset[0]}}}`,`<audio autoplay loop><source src="${assetPath}" type="audio/mpeg"></audio>`)
if(mode === 'back'){
data = data.replaceAll(`{{bg::${asset[0]}}}`, `<div style="width:100%;height:100%;background: linear-gradient(rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.8)),url(${assetPath}); background-size: cover;"></div>`)
}
}
}
}
@@ -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"]
})
}

View File

@@ -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<formated.length;i++){
if(arg.isGroupChat && formated[i].name){
formated[i].content = formated[i].name + ": " + formated[i].content
}
formated[i].name = undefined
}
let requestPrompt = formated.map((v) => {
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 ?? '')

View File

@@ -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{

View File

@@ -1 +1 @@
{"version":"1.23.3"}
{"version":"1.24.0"}