Update to 0.8.0 (#42)
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "RisuAI",
|
||||
"version": "0.7.9"
|
||||
"version": "0.8.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
|
||||
@@ -35,7 +35,7 @@ export const languageEnglish = {
|
||||
msgSound: "Plays *ding* sound when character responses",
|
||||
charDesc: "Brief description of the character. this effects characters response.",
|
||||
charFirstMessage: "First message of the character. this highly effects characters response.",
|
||||
charNote: "a note that strongly effects model behavior. works in current chat. also known as memory.",
|
||||
charNote: "a note that strongly effects model behavior. embbedded to current character. also known as UJB.",
|
||||
toggleNsfw: "toggles NSFW/jailbreak prompt on and off.",
|
||||
lorebook: "Lorebook is a user-made dictionary for AI. AI only sees it when where is an activation keys in the context.",
|
||||
loreName: "name of the lore. it dosen't effects the Ai.",
|
||||
@@ -54,13 +54,25 @@ export const languageEnglish = {
|
||||
regexScript: "Regex Script is a custom script that is embbedded to the character. it replaces string that matches IN to OUT.\n\nThere are three type options."
|
||||
+ "- **Modify Input** modifys user's input"
|
||||
+ "- **Modify Output** modifys character's output"
|
||||
+ "- **Modify Request Data** modifys current chat data when sent.\n\nIN must be a regex without flags and *\\*.\n\nOUT is a normal string."
|
||||
+ "- **Modify Request Data** modifys current chat data when sent.\n\nIN must be a regex without flags and without slashes in start and end.\n\nOUT is a normal string."
|
||||
+ "\n\n If OUT has {{data}} in string, it replaces to matched string."
|
||||
+ "\n\n If OUT starts with **@@**, it doesn't replaces the string, but instead does a special effect if matching string founds."
|
||||
+ "\n\n- @@emo (emotion name)\n\n if character is Emotion Images mode, sets (emotion name) as emotion and prevents default.",
|
||||
experimental: "This is a experimental setting. it might be unstable.",
|
||||
oogaboogaURL: "If your WebUI supports older version of api, your url should look *like https:.../run/textgen*\n\n"
|
||||
+ "If your WebUI supports newVersion of api, your url should look like *https://.../api/v1/generate* and use the api server as host, and add --api to arguments."
|
||||
+ "If your WebUI supports newVersion of api, your url should look like *https://.../api/v1/generate* and use the api server as host, and add --api to arguments.",
|
||||
exampleMessage: "Example conversations that effects output of the character. it dosen't uses tokens permanently."
|
||||
+ "\n\nExample format of conversations:"
|
||||
+ "\n\n```\n<START>\n{{user}}: hi\n{{char}}: hello\n<START>\n{{user}}: hi\nHaruhi: hello\n```"
|
||||
+ "\n\n```<START>``` Marks the beginning of a new conversation.",
|
||||
creatorQuotes: "Note that appearances on top of first message. Used to inform users about this character. It doesn't go into prompt.",
|
||||
systemPrompt: "A prompt that replaces main prompt in settings if its not blank.",
|
||||
chatNote: "a note that strongly effects model behavior. embbedded to current chat. also known as memory.",
|
||||
personality: "A brief description about character's personality. \n\n**It is not recommended to use this option. Describe it in character description instead.**",
|
||||
scenario: "A brief description about character's scenario. \n\n**It is not recommended to use this option. Describe it in character description instead.**",
|
||||
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."
|
||||
|
||||
},
|
||||
setup: {
|
||||
chooseProvider: "Choose AI Provider",
|
||||
@@ -211,6 +223,22 @@ export const languageEnglish = {
|
||||
editOutput: "Modfiy Output",
|
||||
editProcess: "Modfiy Request Data",
|
||||
loadLatest: "Load Latest Backup",
|
||||
loadOthers: "Load Other Backups"
|
||||
|
||||
loadOthers: "Load Other Backups",
|
||||
exampleMessage: "Example Message",
|
||||
creatorNotes: "Creator's Comment",
|
||||
systemPrompt: "System Prompt",
|
||||
characterNotes: "Character Notes",
|
||||
personality: "Personality",
|
||||
scenario: "Scenario",
|
||||
alternateGreetings: "Alternate Greetings",
|
||||
unrecommended: "Not Recommended",
|
||||
chatNotes: "Chat Notes",
|
||||
showUnrecommended: "Show Unrecommended Settings",
|
||||
altGreet: "Alternative First Messages",
|
||||
scripts: "Scripts",
|
||||
settings: "Settings",
|
||||
selective: "Selective",
|
||||
SecondaryKeys: 'Secondary keys',
|
||||
useGlobalSettings: "Use Global Settings",
|
||||
recursiveScanning: "Recursive Scanning"
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ export const languageKorean = {
|
||||
regexScript: "정규식 스크립트는 캐릭터에 종속된 커스텀 스크립트입니다. IN의 조건에 맞는 문자열을 OUT으로 변경합니다.\n\n타입은 세가지가 있습니다."
|
||||
+ "- **입력문 수정** 유저의 입력문을 수정합니다"
|
||||
+ "- **출력문 수정** 캐릭터의 출력문을 수정합니다"
|
||||
+ "- **리퀘스트 데이터 수정** 리퀘스트를 보낼 때 채팅 데이터를 수정합니다.\n\nIN은 flag와 *\\* 가 없는 Regex여야 합니다.\n\nOUT은 일반 문자열입니다."
|
||||
+ "- **리퀘스트 데이터 수정** 리퀘스트를 보낼 때 채팅 데이터를 수정합니다.\n\nIN은 flag가 없고, 양끝에 슬레시가 없는 Regex여야 합니다.\n\nOUT은 일반 문자열입니다."
|
||||
+ "\n\n 만약 OUT 문자열에 {{data}}가 있으면, 매칭된 문자열로 바뀝니다."
|
||||
+ "\n\n 만약 OUT이 @@로 시작된다면, 특수한 효과를 냅니다"
|
||||
+ "\n\n- @@emo (emotion name)\n\n 감정 이미지 모드일 시 (emotion name)을 감정으로 정하고 감정 처리를 하지 않습니다.",
|
||||
@@ -208,5 +208,22 @@ export const languageKorean = {
|
||||
editOutput: "출력문 수정",
|
||||
editProcess: "리퀘스트 데이터 수정",
|
||||
loadLatest: "가장 최근 백업 불러오기",
|
||||
loadOthers: "다른 백업 불러오기"
|
||||
loadOthers: "다른 백업 불러오기",
|
||||
exampleMessage: "예시 대화",
|
||||
creatorNotes: "제작자 코멘트",
|
||||
systemPrompt: "시스템 프롬프트",
|
||||
characterNotes: "캐릭터 노트",
|
||||
personality: "성격",
|
||||
scenario: "시나리오",
|
||||
alternateGreetings: "추가 첫 메시지",
|
||||
unrecommended: "비권장",
|
||||
chatNotes: "채팅 노트",
|
||||
showUnrecommended: "비권장 설정 보이기",
|
||||
altGreet: "추가 첫 메시지",
|
||||
scripts: "스크립트",
|
||||
settings: "설정",
|
||||
selective: "멀티플 키",
|
||||
SecondaryKeys: '두번째 키',
|
||||
useGlobalSettings: "글로벌 설정 사용",
|
||||
recursiveScanning: "재귀 검색"
|
||||
}
|
||||
@@ -10,13 +10,14 @@
|
||||
import { replacePlaceholders } from "../../ts/util";
|
||||
export let message = ''
|
||||
export let name = ''
|
||||
export let img = ''
|
||||
export let img:string|Promise<string> = ''
|
||||
export let idx = -1
|
||||
export let rerollIcon = false
|
||||
export let onReroll = () => {}
|
||||
export let unReroll = () => {}
|
||||
let translating = false
|
||||
let editMode = false
|
||||
export let altGreeting = false
|
||||
|
||||
let msgDisplay = ''
|
||||
|
||||
@@ -60,15 +61,13 @@
|
||||
|
||||
$: displaya(message)
|
||||
</script>
|
||||
<div class="flex">
|
||||
<div class="flex max-w-full">
|
||||
<div class="text-neutral-200 mt-2 p-2 bg-transparent flex-grow ml-4 mr-4 border-t-gray-900 border-opacity-30 border-transparent flexium items-start">
|
||||
{#if img === ''}
|
||||
<div class="rounded-md shadow-lg bg-gray-500 mt-2" style={`height:${$DataBase.iconsize * 3.5 / 100}rem;width:${$DataBase.iconsize * 3.5 / 100}rem`}>
|
||||
|
||||
</div>
|
||||
{:else}
|
||||
<div class="rounded-md shadow-lg bg-gray-500 mt-2" style={img + `height:${$DataBase.iconsize * 3.5 / 100}rem;width:${$DataBase.iconsize * 3.5 / 100}rem`} />
|
||||
{/if}
|
||||
{#await img}
|
||||
<div class="rounded-md shadow-lg bg-gray-500 mt-2" style={`height:${$DataBase.iconsize * 3.5 / 100}rem;width:${$DataBase.iconsize * 3.5 / 100}rem`} />
|
||||
{:then m}
|
||||
<div class="rounded-md shadow-lg bg-gray-500 mt-2" style={m + `height:${$DataBase.iconsize * 3.5 / 100}rem;width:${$DataBase.iconsize * 3.5 / 100}rem`} />
|
||||
{/await}
|
||||
<span class="flex flex-col ml-4 w-full">
|
||||
<div class="flexium items-center chat">
|
||||
<span class="chat text-xl unmargin">{name}</span>
|
||||
@@ -106,8 +105,8 @@
|
||||
<LanguagesIcon />
|
||||
</button>
|
||||
{/if}
|
||||
{#if rerollIcon}
|
||||
{#if $DataBase.swipe}
|
||||
{#if rerollIcon || altGreeting}
|
||||
{#if $DataBase.swipe || altGreeting}
|
||||
<button class="ml-2 hover:text-green-500 transition-colors" on:click={unReroll}>
|
||||
<ArrowLeft size={22}/>
|
||||
</button>
|
||||
|
||||
20
src/lib/ChatScreens/CreatorQuote.svelte
Normal file
20
src/lib/ChatScreens/CreatorQuote.svelte
Normal file
@@ -0,0 +1,20 @@
|
||||
<div class="flex w-full justify-center mt-4 max-w-100vw">
|
||||
<div class="w-5/6 max-w-80vw bg-darkbg rounded-md p-3 text-white text-sm">
|
||||
<h1 class="font-bold mb-2">{language.creatorNotes}
|
||||
<button class="float-right" on:click={onRemove}>
|
||||
<XIcon />
|
||||
</button>
|
||||
</h1>
|
||||
<div class="ml-2 max-w-full break-words text chat chattext prose prose-invert">
|
||||
{@html ParseMarkdown(quote)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script lang="ts">
|
||||
import { XIcon } from "lucide-svelte";
|
||||
import { language } from "src/lang";
|
||||
import { ParseMarkdown } from "src/ts/parser";
|
||||
|
||||
export let onRemove: () => void
|
||||
export let quote:string
|
||||
</script>
|
||||
@@ -13,6 +13,7 @@
|
||||
import {cloneDeep} from 'lodash'
|
||||
import { processScript } from "src/ts/process/scripts";
|
||||
import GithubStars from "../Others/GithubStars.svelte";
|
||||
import CreatorQuote from "./CreatorQuote.svelte";
|
||||
|
||||
let messageInput = ''
|
||||
let openMenu = false
|
||||
@@ -237,88 +238,81 @@
|
||||
{#each messageForm($DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].message, loadPages) as chat, i}
|
||||
{#if chat.role === 'char'}
|
||||
{#if $DataBase.characters[$selectedCharID].type !== 'group'}
|
||||
{#await getCharImage($DataBase.characters[$selectedCharID].image, 'css')}
|
||||
<Chat
|
||||
idx={chat.index}
|
||||
name={$DataBase.characters[$selectedCharID].name}
|
||||
message={chat.data}
|
||||
img={''}
|
||||
rerollIcon={i === 0}
|
||||
onReroll={reroll}
|
||||
unReroll={unReroll}
|
||||
/>
|
||||
{:then im}
|
||||
<Chat
|
||||
idx={chat.index}
|
||||
name={$DataBase.characters[$selectedCharID].name}
|
||||
message={chat.data}
|
||||
img={im}
|
||||
rerollIcon={i === 0}
|
||||
onReroll={reroll}
|
||||
unReroll={unReroll}
|
||||
|
||||
/>
|
||||
{/await}
|
||||
<Chat
|
||||
idx={chat.index}
|
||||
name={$DataBase.characters[$selectedCharID].name}
|
||||
message={chat.data}
|
||||
img={getCharImage($DataBase.characters[$selectedCharID].image, 'css')}
|
||||
rerollIcon={i === 0}
|
||||
onReroll={reroll}
|
||||
unReroll={unReroll}
|
||||
/>
|
||||
{:else}
|
||||
{#await getCharImage(findCharacterbyId(chat.saying).image, 'css')}
|
||||
<Chat
|
||||
idx={chat.index}
|
||||
name={findCharacterbyId(chat.saying).name}
|
||||
message={chat.data}
|
||||
rerollIcon={i === 0}
|
||||
onReroll={reroll}
|
||||
unReroll={unReroll}
|
||||
img={''}
|
||||
/>
|
||||
{:then im}
|
||||
<Chat
|
||||
idx={chat.index}
|
||||
name={findCharacterbyId(chat.saying).name}
|
||||
rerollIcon={i === 0}
|
||||
message={chat.data}
|
||||
onReroll={reroll}
|
||||
unReroll={unReroll}
|
||||
img={im}
|
||||
/>
|
||||
{/await}
|
||||
<Chat
|
||||
idx={chat.index}
|
||||
name={findCharacterbyId(chat.saying).name}
|
||||
rerollIcon={i === 0}
|
||||
message={chat.data}
|
||||
onReroll={reroll}
|
||||
unReroll={unReroll}
|
||||
img={getCharImage(findCharacterbyId(chat.saying).image, 'css')}
|
||||
/>
|
||||
{/if}
|
||||
{:else}
|
||||
{#await getCharImage($DataBase.userIcon, 'css')}
|
||||
<Chat
|
||||
idx={chat.index}
|
||||
name={$DataBase.username}
|
||||
message={chat.data}
|
||||
img={''}
|
||||
/>
|
||||
{:then im}
|
||||
<Chat
|
||||
idx={chat.index}
|
||||
name={$DataBase.username}
|
||||
message={chat.data}
|
||||
img={im}
|
||||
/>
|
||||
{/await}
|
||||
<Chat
|
||||
idx={chat.index}
|
||||
name={$DataBase.username}
|
||||
message={chat.data}
|
||||
img={getCharImage($DataBase.userIcon, 'css')}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{#if $DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].message.length <= loadPages}
|
||||
{#if $DataBase.characters[$selectedCharID].type !== 'group'}
|
||||
{#await getCharImage($DataBase.characters[$selectedCharID].image, 'css')}
|
||||
<Chat
|
||||
name={$DataBase.characters[$selectedCharID].name}
|
||||
message={ $DataBase.characters[$selectedCharID].firstMessage}
|
||||
img={''}
|
||||
idx={-1}
|
||||
/>
|
||||
{:then im}
|
||||
<Chat
|
||||
name={$DataBase.characters[$selectedCharID].name}
|
||||
message={ $DataBase.characters[$selectedCharID].firstMessage}
|
||||
img={im}
|
||||
idx={-1}
|
||||
/>
|
||||
{/await}
|
||||
<Chat
|
||||
name={$DataBase.characters[$selectedCharID].name}
|
||||
message={$DataBase.characters[$selectedCharID].firstMsgIndex === -1 ? $DataBase.characters[$selectedCharID].firstMessage :
|
||||
$DataBase.characters[$selectedCharID].alternateGreetings[$DataBase.characters[$selectedCharID].firstMsgIndex]}
|
||||
img={getCharImage($DataBase.characters[$selectedCharID].image, 'css')}
|
||||
idx={-1}
|
||||
altGreeting={$DataBase.characters[$selectedCharID].alternateGreetings.length > 0}
|
||||
onReroll={() => {
|
||||
const cha = $DataBase.characters[$selectedCharID]
|
||||
if(cha.type !== 'group'){
|
||||
if (cha.firstMsgIndex >= (cha.alternateGreetings.length - 1)){
|
||||
cha.firstMsgIndex = -1
|
||||
}
|
||||
else{
|
||||
cha.firstMsgIndex += 1
|
||||
}
|
||||
}
|
||||
$DataBase.characters[$selectedCharID] = cha
|
||||
}}
|
||||
unReroll={() => {
|
||||
const cha = $DataBase.characters[$selectedCharID]
|
||||
if(cha.type !== 'group'){
|
||||
if (cha.firstMsgIndex === -1){
|
||||
cha.firstMsgIndex = (cha.alternateGreetings.length - 1)
|
||||
}
|
||||
else{
|
||||
cha.firstMsgIndex -= 1
|
||||
}
|
||||
}
|
||||
$DataBase.characters[$selectedCharID] = cha
|
||||
}}
|
||||
/>
|
||||
{#if !$DataBase.characters[$selectedCharID].removedQuotes && $DataBase.characters[$selectedCharID].creatorNotes.length >= 2}
|
||||
<CreatorQuote quote={$DataBase.characters[$selectedCharID].creatorNotes} onRemove={() => {
|
||||
const cha = $DataBase.characters[$selectedCharID]
|
||||
if(cha.type !== 'group'){
|
||||
cha.removedQuotes = true
|
||||
}
|
||||
$DataBase.characters[$selectedCharID] = cha
|
||||
}} />
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if openMenu}
|
||||
<div class="absolute right-2 bottom-16 p-5 bg-darkbg flex flex-col gap-3 text-gray-200" on:click={(e) => {
|
||||
e.stopPropagation()
|
||||
|
||||
@@ -5,15 +5,20 @@
|
||||
}}>
|
||||
{#if key === "experimental"}
|
||||
<FlaskConicalIcon size={14} />
|
||||
{:else if unrecommended}
|
||||
<div class="text-red-500 hover:text-green-500">
|
||||
<AlertTriangle size={14} />
|
||||
</div>
|
||||
{:else}
|
||||
<HelpCircleIcon size={14} />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<script lang="ts">
|
||||
import { FlaskConicalIcon, HelpCircleIcon } from "lucide-svelte";
|
||||
import { AlertTriangle, FlaskConicalIcon, HelpCircleIcon } from "lucide-svelte";
|
||||
import { language } from "src/lang";
|
||||
import { alertMd } from "src/ts/alert";
|
||||
|
||||
export let unrecommended = false
|
||||
export let key: (keyof (typeof language.help))
|
||||
</script>
|
||||
@@ -3,7 +3,7 @@
|
||||
import { tokenize } from "../../ts/tokenizer";
|
||||
import { DataBase, type Database, type character, type groupChat } from "../../ts/database";
|
||||
import { selectedCharID } from "../../ts/stores";
|
||||
import { PlusIcon, SmileIcon, TrashIcon, UserIcon, ActivityIcon, BookIcon, LoaderIcon, User } from 'lucide-svelte'
|
||||
import { PlusIcon, SmileIcon, TrashIcon, UserIcon, ActivityIcon, BookIcon, LoaderIcon, User, DnaIcon, CurlyBracesIcon } from 'lucide-svelte'
|
||||
import Check from "../Others/Check.svelte";
|
||||
import { addCharEmotion, addingEmotion, getCharImage, rmCharEmotion, selectCharImg, makeGroupImage } from "../../ts/characters";
|
||||
import LoreBook from "./LoreBookSetting.svelte";
|
||||
@@ -22,13 +22,15 @@
|
||||
let tokens = {
|
||||
desc: 0,
|
||||
firstMsg: 0,
|
||||
localNote: 0
|
||||
localNote: 0,
|
||||
charaNote: 0
|
||||
}
|
||||
|
||||
let lasttokens = {
|
||||
desc: '',
|
||||
firstMsg: '',
|
||||
localNote: ''
|
||||
localNote: '',
|
||||
charaNote: ''
|
||||
}
|
||||
|
||||
async function loadTokenize(chara){
|
||||
@@ -45,12 +47,18 @@
|
||||
lasttokens.firstMsg = chara.firstMessage
|
||||
tokens.firstMsg = await tokenize(chara.firstMessage)
|
||||
}
|
||||
if(lasttokens.charaNote !== chara.postHistoryInstructions){
|
||||
lasttokens.charaNote = chara.postHistoryInstructions
|
||||
tokens.charaNote = await tokenize(chara.postHistoryInstructions)
|
||||
|
||||
}
|
||||
}
|
||||
if(lasttokens.localNote !== currentChar.data.chats[currentChar.data.chatPage].note){
|
||||
lasttokens.localNote = currentChar.data.chats[currentChar.data.chatPage].note
|
||||
tokens.localNote = await tokenize(currentChar.data.chats[currentChar.data.chatPage].note)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +156,11 @@
|
||||
<button class={subMenu === 3 ? 'text-gray-200' : 'text-gray-500'} on:click={() => {subMenu = 3;subberMenu = 0}}>
|
||||
<BookIcon />
|
||||
</button>
|
||||
{#if currentChar.type === 'character'}
|
||||
<button class={subMenu === 4 ? 'text-gray-200' : 'text-gray-500'} on:click={() => {subMenu = 4}}>
|
||||
<CurlyBracesIcon />
|
||||
</button>
|
||||
{/if}
|
||||
<button class={subMenu === 2 ? 'text-gray-200' : 'text-gray-500'} on:click={() => {subMenu = 2}}>
|
||||
<ActivityIcon />
|
||||
</button>
|
||||
@@ -163,6 +176,10 @@
|
||||
<span class="text-neutral-200">{language.firstMessage} <Help key="charFirstMessage"/></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.firstMessage}></textarea>
|
||||
<span class="text-gray-400 mb-6 text-sm">{tokens.firstMsg} {language.tokens}</span>
|
||||
<span class="text-neutral-200">{language.authorNote} <Help key="charNote"/></span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 resize-none h-20 focus:bg-selected text-xs" autocomplete="off" bind:value={currentChar.data.postHistoryInstructions}></textarea>
|
||||
<span class="text-gray-400 mb-6 text-sm">{tokens.charaNote} {language.tokens}</span>
|
||||
|
||||
{:else}
|
||||
<input class="text-neutral-200 mt-2 mb-4 p-2 bg-transparent input-text text-xl focus:bg-selected" placeholder="Group Name" bind:value={currentChar.data.name}>
|
||||
<span class="text-neutral-200">{language.character}</span>
|
||||
@@ -191,11 +208,13 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<span class="text-neutral-200">{language.chatNotes} <Help key="charNote"/></span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 resize-none h-20 focus:bg-selected text-xs" autocomplete="off" bind:value={currentChar.data.chats[currentChar.data.chatPage].note}></textarea>
|
||||
<span class="text-gray-400 mb-6 text-sm">{tokens.localNote} {language.tokens}</span>
|
||||
|
||||
|
||||
{/if}
|
||||
<span class="text-neutral-200">{language.authorNote} <Help key="charNote"/></span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 resize-none h-20 focus:bg-selected text-xs" autocomplete="off" bind:value={currentChar.data.chats[currentChar.data.chatPage].note}></textarea>
|
||||
<span class="text-gray-400 mb-6 text-sm">{tokens.localNote} {language.tokens}</span>
|
||||
|
||||
|
||||
<div class="flex mt-6 items-center">
|
||||
<Check bind:check={$DataBase.jailbreakToggle}/>
|
||||
<span class="text-neutral-200 ml-2">{language.jailbreakToggle}</span>
|
||||
@@ -356,9 +375,10 @@
|
||||
{:else if subMenu === 3}
|
||||
<h2 class="mb-2 text-2xl font-bold mt-2">{language.loreBook} <Help key="lorebook"/></h2>
|
||||
<LoreBook />
|
||||
{:else if subMenu === 2}
|
||||
<h2 class="mb-2 text-2xl font-bold mt-2">{language.advancedSettings}</h2>
|
||||
{#if currentChar.type !== 'group'}
|
||||
{:else if subMenu === 4}
|
||||
{#if currentChar.type === 'character'}
|
||||
<h2 class="mb-2 text-2xl font-bold mt-2">{language.scripts}</h2>
|
||||
|
||||
<span class="text-neutral-200 mt-2">Bias <Help key="bias"/></span>
|
||||
<table class="contain w-full max-w-full tabler mt-2">
|
||||
<tr>
|
||||
@@ -374,7 +394,7 @@
|
||||
</tr>
|
||||
{#if currentChar.data.bias.length === 0}
|
||||
<tr>
|
||||
<div class="text-gray-500">{language.noBias}</div>
|
||||
<div class="text-gray-500"> {language.noBias}</div>
|
||||
</tr>
|
||||
{/if}
|
||||
{#each currentChar.data.bias as bias, i}
|
||||
@@ -394,7 +414,9 @@
|
||||
}}><TrashIcon /></button>
|
||||
</tr>
|
||||
{/each}
|
||||
|
||||
</table>
|
||||
|
||||
<span class="text-neutral-200 mt-4">{language.regexScript} <Help key="regexScript"/></span>
|
||||
<table class="contain w-full max-w-full tabler mt-2 flex flex-col p-2 gap-2">
|
||||
{#if currentChar.data.customscript.length === 0}
|
||||
@@ -410,7 +432,7 @@
|
||||
}}/>
|
||||
{/each}
|
||||
</table>
|
||||
<th class="font-medium cursor-pointer hover:text-green-500" on:click={() => {
|
||||
<button class="font-medium cursor-pointer hover:text-green-500 mb-2" on:click={() => {
|
||||
if(currentChar.type === 'character'){
|
||||
let script = currentChar.data.customscript
|
||||
script.push({
|
||||
@@ -421,21 +443,95 @@
|
||||
})
|
||||
currentChar.data.customscript = script
|
||||
}
|
||||
}}><PlusIcon /></th>
|
||||
<div class="flex items-center mt-4">
|
||||
<Check bind:check={currentChar.data.utilityBot}/>
|
||||
<span>{language.utilityBot}</span>
|
||||
</div>
|
||||
}}><PlusIcon /></button>
|
||||
{/if}
|
||||
{:else if subMenu === 2}
|
||||
<h2 class="mb-2 text-2xl font-bold mt-2">{language.advancedSettings}</h2>
|
||||
{#if currentChar.type !== 'group'}
|
||||
<span class="text-neutral-200">{language.exampleMessage} <Help key="exampleMessage"/></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.exampleMessage}></textarea>
|
||||
|
||||
<span class="text-neutral-200">{language.creatorNotes} <Help key="creatorQuotes"/></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.creatorNotes} on:input={() => {
|
||||
currentChar.data.removedQuotes = false
|
||||
}}></textarea>
|
||||
|
||||
<span class="text-neutral-200">{language.systemPrompt} <Help key="systemPrompt"/></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.systemPrompt}></textarea>
|
||||
|
||||
<span class="text-neutral-200">{language.chatNotes} <Help key="chatNote"/></span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 resize-none h-20 focus:bg-selected text-xs" autocomplete="off" bind:value={currentChar.data.chats[currentChar.data.chatPage].note}></textarea>
|
||||
<span class="text-gray-400 mb-6 text-sm">{tokens.localNote} {language.tokens}</span>
|
||||
|
||||
{#if $DataBase.showUnrecommended || currentChar.data.personality.length > 3}
|
||||
<span class="text-neutral-200">{language.personality} <Help key="personality" unrecommended/></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.personality}></textarea>
|
||||
{/if}
|
||||
{#if $DataBase.showUnrecommended || currentChar.data.scenario.length > 3}
|
||||
<span class="text-neutral-200">{language.scenario} <Help key="scenario" unrecommended/></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.scenario}></textarea>
|
||||
{/if}
|
||||
|
||||
<span class="text-neutral-200 mt-2">{language.altGreet}</span>
|
||||
<table class="contain w-full max-w-full tabler mt-2">
|
||||
<tr>
|
||||
<th class="font-medium">{language.value}</th>
|
||||
<th class="font-medium cursor-pointer w-10">
|
||||
<button class="hover:text-green-500" on:click={() => {
|
||||
if(currentChar.type === 'character'){
|
||||
let alternateGreetings = currentChar.data.alternateGreetings
|
||||
alternateGreetings.push('')
|
||||
currentChar.data.alternateGreetings = alternateGreetings
|
||||
}
|
||||
}}>
|
||||
<PlusIcon />
|
||||
</button>
|
||||
</th>
|
||||
</tr>
|
||||
{#if currentChar.data.alternateGreetings.length === 0}
|
||||
<tr>
|
||||
<div class="text-gray-500"> No Messages</div>
|
||||
</tr>
|
||||
{/if}
|
||||
{#each currentChar.data.alternateGreetings as bias, i}
|
||||
<tr>
|
||||
<td class="font-medium truncate">
|
||||
<textarea class="text-neutral-200 mt-2 mb-4 p-2 bg-transparent input-text focus:bg-selected w-full resize-none" bind:value={currentChar.data.alternateGreetings[i]} placeholder="..." />
|
||||
</td>
|
||||
<th class="font-medium cursor-pointer w-10">
|
||||
<button class="hover:text-green-500" on:click={() => {
|
||||
if(currentChar.type === 'character'){
|
||||
currentChar.data.firstMsgIndex = -1
|
||||
let alternateGreetings = currentChar.data.alternateGreetings
|
||||
alternateGreetings.splice(i, 1)
|
||||
currentChar.data.alternateGreetings = alternateGreetings
|
||||
}
|
||||
}}>
|
||||
<TrashIcon />
|
||||
</button>
|
||||
</th>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
|
||||
|
||||
{#if $DataBase.showUnrecommended || currentChar.data.utilityBot}
|
||||
<div class="flex items-center mt-4">
|
||||
<Check bind:check={currentChar.data.utilityBot}/>
|
||||
<span>{language.utilityBot} <Help key="utilityBot" unrecommended/></span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<button on:click={async () => {
|
||||
exportChar($selectedCharID)
|
||||
}} class="text-neutral-200 mt-6 text-lg bg-transparent border-solid border-1 border-borderc p-4 hover:bg-green-500 transition-colors cursor-pointer">{language.exportCharacter}</button>
|
||||
|
||||
{:else}
|
||||
|
||||
<div class="flex mb-2 items-center">
|
||||
<Check bind:check={currentChar.data.useCharacterLore}/>
|
||||
<span class="text-neutral-200 ml-2">{language.useCharLorebook} <Help key="experimental"/></span>
|
||||
</div>
|
||||
<div class="flex mb-2 items-center">
|
||||
<Check bind:check={currentChar.data.useCharacterLore}/>
|
||||
<span class="text-neutral-200 ml-2">{language.useCharLorebook} <Help key="experimental"/></span>
|
||||
</div>
|
||||
|
||||
{/if}
|
||||
<button on:click={async () => {
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
<div class="w-full flex flex-col">
|
||||
<div class="flex items-center transition-colors w-full ">
|
||||
<button class="endflex valuer border-borderc" on:click={() => {
|
||||
value.secondkey = value.secondkey ?? ''
|
||||
open = !open
|
||||
}}>
|
||||
<span>{value.comment.length === 0 ? 'Unnamed Lore' : value.comment}</span>
|
||||
<span>{value.comment.length === 0 ? value.key.length === 0 ? "Unnamed Lore" : value.key : value.comment}</span>
|
||||
</button>
|
||||
<button class="valuer" on:click={async () => {
|
||||
const d = await alertConfirm(language.removeConfirm + value.comment)
|
||||
@@ -34,15 +35,25 @@
|
||||
<span class="text-neutral-200 mt-6">{language.activationKeys} <Help key="loreActivationKey"/></span>
|
||||
<span class="text-xs text-gray-500">{language.activationKeysInfo}</span>
|
||||
<input class="text-neutral-200 p-2 bg-transparent input-text focus:bg-selected text-sm" bind:value={value.key}>
|
||||
|
||||
{#if value.selective}
|
||||
<span class="text-neutral-200 mt-6">{language.SecondaryKeys}</span>
|
||||
<span class="text-xs text-gray-500">{language.activationKeysInfo}</span>
|
||||
<input class="text-neutral-200 p-2 bg-transparent input-text focus:bg-selected text-sm" bind:value={value.secondkey}>
|
||||
{/if}
|
||||
{/if}
|
||||
<span class="text-neutral-200 mt-4">{language.insertOrder} <Help key="loreorder"/></span>
|
||||
<input class="text-neutral-200 p-2 bg-transparent input-text focus:bg-selected text-sm" bind:value={value.insertorder} type="number" min={0} max={1000}>
|
||||
<span class="text-neutral-200 mt-4">{language.prompt}</span>
|
||||
<textarea class="bg-transparent input-text mt-2 text-gray-200 resize-none h-20 focus:bg-selected text-xs" autocomplete="off" bind:value={value.content}></textarea>
|
||||
<div class="flex items-center mt-4 mb-6">
|
||||
<div class="flex items-center mt-4">
|
||||
<Check bind:check={value.alwaysActive}/>
|
||||
<span>{language.alwaysActive}</span>
|
||||
</div>
|
||||
<div class="flex items-center mt-2 mb-6">
|
||||
<Check bind:check={value.selective}/>
|
||||
<span>{language.selective} <Help key="loreSelective"/></span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
import { language } from "../../lang";
|
||||
import {selectedCharID} from '../../ts/stores'
|
||||
import { DownloadIcon, FolderUpIcon, ImportIcon, PlusIcon } from "lucide-svelte";
|
||||
import { addLorebook, exportLoreBook, importLoreBook } from "../../ts/lorebook";
|
||||
import { addLorebook, exportLoreBook, importLoreBook } from "../../ts/process/lorebook";
|
||||
import LoreBookData from "./LoreBookData.svelte";
|
||||
import Check from "../Others/Check.svelte";
|
||||
let submenu = 0
|
||||
</script>
|
||||
|
||||
@@ -19,43 +20,77 @@
|
||||
}} class="flex-1 border-solid border-borderc border-1 border-l-transparent p-2 flex justify-center cursor-pointer" class:bg-selected={submenu === 1}>
|
||||
<span>{language.Chat}</span>
|
||||
</button>
|
||||
<button on:click={() => {
|
||||
submenu = 2
|
||||
}} class="flex-1 border-solid border-borderc border-1 border-l-transparent p-2 flex justify-center cursor-pointer" class:bg-selected={submenu === 2}>
|
||||
<span>{language.settings}</span>
|
||||
</button>
|
||||
</div>
|
||||
<span class="text-gray-500 mt-2 mb-6 text-sm">{submenu === 0 ? $DataBase.characters[$selectedCharID].type === 'group' ? language.groupLoreInfo : language.globalLoreInfo : language.localLoreInfo}</span>
|
||||
|
||||
<div class="border-solid border-borderc p-2 flex flex-col border-1">
|
||||
{#if submenu === 0}
|
||||
{#if $DataBase.characters[$selectedCharID].globalLore.length === 0}
|
||||
<span class="text-gray-500">No Lorebook</span>
|
||||
{:else}
|
||||
{#each $DataBase.characters[$selectedCharID].globalLore as book, i}
|
||||
{#if i !== 0}
|
||||
<div class="border-borderc mt-2 mb-2 w-full border-solid border-b-1 seperator"></div>
|
||||
{/if}
|
||||
<LoreBookData bind:value={$DataBase.characters[$selectedCharID].globalLore[i]} onRemove={() => {
|
||||
let lore = $DataBase.characters[$selectedCharID].globalLore
|
||||
lore.splice(i, 1)
|
||||
$DataBase.characters[$selectedCharID].globalLore = lore
|
||||
}}/>
|
||||
{/each}
|
||||
{#if submenu !== 2}
|
||||
<span class="text-gray-500 mt-2 mb-6 text-sm">{submenu === 0 ? $DataBase.characters[$selectedCharID].type === 'group' ? language.groupLoreInfo : language.globalLoreInfo : language.localLoreInfo}</span>
|
||||
<div class="border-solid border-borderc p-2 flex flex-col border-1">
|
||||
{#if submenu === 0}
|
||||
{#if $DataBase.characters[$selectedCharID].globalLore.length === 0}
|
||||
<span class="text-gray-500">No Lorebook</span>
|
||||
{:else}
|
||||
{#each $DataBase.characters[$selectedCharID].globalLore as book, i}
|
||||
{#if i !== 0}
|
||||
<div class="border-borderc mt-2 mb-2 w-full border-solid border-b-1 seperator"></div>
|
||||
{/if}
|
||||
<LoreBookData bind:value={$DataBase.characters[$selectedCharID].globalLore[i]} onRemove={() => {
|
||||
let lore = $DataBase.characters[$selectedCharID].globalLore
|
||||
lore.splice(i, 1)
|
||||
$DataBase.characters[$selectedCharID].globalLore = lore
|
||||
}}/>
|
||||
{/each}
|
||||
{/if}
|
||||
{:else if submenu === 1}
|
||||
{#if $DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].localLore.length === 0}
|
||||
<span class="text-gray-500">No Lorebook</span>
|
||||
{:else}
|
||||
{#each $DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].localLore as book, i}
|
||||
{#if i !== 0}
|
||||
<div class="border-borderc mt-2 mb-2 w-full border-solid border-b-1 seperator"></div>
|
||||
{/if}
|
||||
<LoreBookData bind:value={$DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].localLore[i]} onRemove={() => {
|
||||
let lore = $DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].localLore
|
||||
lore.splice(i, 1)
|
||||
$DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].localLore = lore
|
||||
}}/>
|
||||
{/each}
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
{#if $DataBase.characters[$selectedCharID].loreSettings}
|
||||
<div class="flex items-center mt-4">
|
||||
<Check check={false} onChange={() => {
|
||||
$DataBase.characters[$selectedCharID].loreSettings = undefined
|
||||
}}/>
|
||||
<span>{language.useGlobalSettings}</span>
|
||||
</div>
|
||||
<div class="flex items-center mt-4">
|
||||
<Check bind:check={$DataBase.characters[$selectedCharID].loreSettings.recursiveScanning}/>
|
||||
<span>{language.recursiveScanning}</span>
|
||||
</div>
|
||||
<span class="text-neutral-200 mt-4 mb-2">{language.loreBookDepth}</span>
|
||||
<input class="text-neutral-200 mb-4 p-2 bg-transparent input-text focus:bg-selected text-sm" type="number" min={0} max="20" bind:value={$DataBase.characters[$selectedCharID].loreSettings.scanDepth}>
|
||||
<span class="text-neutral-200">{language.loreBookToken}</span>
|
||||
<input class="text-neutral-200 mb-4 p-2 bg-transparent input-text focus:bg-selected text-sm" type="number" min={0} max="4096" bind:value={$DataBase.characters[$selectedCharID].loreSettings.tokenBudget}>
|
||||
{:else}
|
||||
{#if $DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].localLore.length === 0}
|
||||
<span class="text-gray-500">No Lorebook</span>
|
||||
{:else}
|
||||
{#each $DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].localLore as book, i}
|
||||
{#if i !== 0}
|
||||
<div class="border-borderc mt-2 mb-2 w-full border-solid border-b-1 seperator"></div>
|
||||
{/if}
|
||||
<LoreBookData bind:value={$DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].localLore[i]} onRemove={() => {
|
||||
let lore = $DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].localLore
|
||||
lore.splice(i, 1)
|
||||
$DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].localLore = lore
|
||||
}}/>
|
||||
{/each}
|
||||
{/if}
|
||||
<div class="flex items-center mt-4">
|
||||
<Check check={true} onChange={() => {
|
||||
$DataBase.characters[$selectedCharID].loreSettings = {
|
||||
tokenBudget: $DataBase.loreBookToken,
|
||||
scanDepth:$DataBase.loreBookDepth,
|
||||
recursiveScanning: false
|
||||
}
|
||||
}}/>
|
||||
<span>{language.useGlobalSettings}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
{#if submenu !== 2}
|
||||
|
||||
<div class="text-gray-500 mt-2 flex">
|
||||
<button on:click={() => {addLorebook(submenu)}} class="hover:text-neutral-200 cursor-pointer">
|
||||
@@ -72,7 +107,7 @@
|
||||
<FolderUpIcon />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/if}
|
||||
<style>
|
||||
.seperator{
|
||||
border-top: 0px;
|
||||
|
||||
@@ -499,7 +499,10 @@
|
||||
<Check bind:check={$DataBase.useSayNothing}/>
|
||||
<span>{language.sayNothing}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center mt-4">
|
||||
<Check bind:check={$DataBase.showUnrecommended}/>
|
||||
<span>{language.showUnrecommended}</span>
|
||||
</div>
|
||||
<button
|
||||
on:click={async () => {
|
||||
alertMd(getRequestLog())
|
||||
|
||||
@@ -47,6 +47,7 @@ html, body{
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { get } from "svelte/store"
|
||||
import { alertConfirm, alertError, alertNormal, alertStore } from "./alert"
|
||||
import { DataBase, defaultSdDataFunc, type character, saveImage, setDatabase, type customscript } from "./database"
|
||||
import { alertConfirm, alertError, alertNormal, alertSelect, alertStore } from "./alert"
|
||||
import { DataBase, defaultSdDataFunc, type character, saveImage, setDatabase, type customscript, type loreSettings, type loreBook } from "./database"
|
||||
import { checkNullish, selectSingleFile, sleep } from "./util"
|
||||
import { language } from "src/lang"
|
||||
import { encode as encodeMsgpack, decode as decodeMsgpack } from "@msgpack/msgpack";
|
||||
@@ -11,7 +11,6 @@ import { characterFormatUpdate } from "./characters"
|
||||
import { downloadFile, readImage } from "./globalApi"
|
||||
import { cloneDeep } from "lodash"
|
||||
|
||||
type CharacterBook = null
|
||||
|
||||
export async function importCharacter() {
|
||||
try {
|
||||
@@ -160,20 +159,11 @@ export async function characterHubImport() {
|
||||
|
||||
function convertOldTavernAndJSON(charaData:OldTavernChar, imgp:string|undefined = undefined):character{
|
||||
|
||||
let desc = charaData.description ?? ''
|
||||
|
||||
if(charaData.personality){
|
||||
desc += '\n\n' + charaData.personality
|
||||
}
|
||||
|
||||
if(charaData.scenario){
|
||||
desc += '\n\n' + charaData.scenario
|
||||
}
|
||||
|
||||
return {
|
||||
name: charaData.name ?? 'unknown name',
|
||||
firstMessage: charaData.first_mes ?? 'unknown first message',
|
||||
desc: desc,
|
||||
desc: charaData.description ?? '',
|
||||
notes: '',
|
||||
chats: [{
|
||||
message: [],
|
||||
@@ -191,13 +181,27 @@ function convertOldTavernAndJSON(charaData:OldTavernChar, imgp:string|undefined
|
||||
sdData: defaultSdDataFunc(),
|
||||
utilityBot: false,
|
||||
customscript: [],
|
||||
exampleMessage: charaData.mes_example
|
||||
exampleMessage: charaData.mes_example,
|
||||
creatorNotes:'',
|
||||
systemPrompt:'',
|
||||
postHistoryInstructions:'',
|
||||
alternateGreetings:[],
|
||||
tags:[],
|
||||
creator:"",
|
||||
characterVersion: 0,
|
||||
personality: charaData.personality ?? '',
|
||||
scenario:charaData.scenario ?? '',
|
||||
firstMsgIndex: -1
|
||||
}
|
||||
}
|
||||
|
||||
export async function exportChar(charaID:number) {
|
||||
const db = get(DataBase)
|
||||
let char:character = JSON.parse(JSON.stringify(db.characters[charaID]))
|
||||
let char = cloneDeep(db.characters[charaID])
|
||||
|
||||
if(char.type === 'group'){
|
||||
return
|
||||
}
|
||||
|
||||
if(!char.image){
|
||||
alertError('Image Required')
|
||||
@@ -208,6 +212,12 @@ export async function exportChar(charaID:number) {
|
||||
return
|
||||
}
|
||||
|
||||
const sel = await alertSelect(['Export as Spec V2','Export as Old RisuCard'])
|
||||
if(sel === '0'){
|
||||
exportSpecV2(char)
|
||||
return
|
||||
}
|
||||
|
||||
alertStore.set({
|
||||
type: 'wait',
|
||||
msg: 'Loading...'
|
||||
@@ -288,6 +298,7 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array):Promise<boole
|
||||
if(!card ||card.spec !== 'chara_card_v2'){
|
||||
return false
|
||||
}
|
||||
|
||||
const data = card.data
|
||||
const im = img ? await saveImage(PngMetadata.filter(img)) : undefined
|
||||
let db = get(DataBase)
|
||||
@@ -319,11 +330,45 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array):Promise<boole
|
||||
sdData = risuext.sdData ?? sdData
|
||||
}
|
||||
|
||||
const charbook = data.character_book
|
||||
let lorebook:loreBook[] = []
|
||||
let loresettings:undefined|loreSettings = undefined
|
||||
let loreExt:undefined|any = undefined
|
||||
if(charbook){
|
||||
if((!checkNullish(charbook.recursive_scanning)) &&
|
||||
(!checkNullish(charbook.scan_depth)) &&
|
||||
(!checkNullish(charbook.token_budget))){
|
||||
loresettings = {
|
||||
tokenBudget:charbook.token_budget,
|
||||
scanDepth:charbook.scan_depth,
|
||||
recursiveScanning: charbook.recursive_scanning
|
||||
}
|
||||
}
|
||||
|
||||
loreExt = charbook.extensions
|
||||
|
||||
for(const book of charbook.entries){
|
||||
lorebook.push({
|
||||
key: book.keys.join(', '),
|
||||
secondkey: book.secondary_keys?.join(', ') ?? '',
|
||||
insertorder: book.insertion_order,
|
||||
comment: book.name ?? book.comment ?? "",
|
||||
content: book.content,
|
||||
mode: "normal",
|
||||
alwaysActive: book.constant ?? false,
|
||||
selective: book.selective ?? false,
|
||||
extentions: book.extensions
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
let char:character = {
|
||||
name: data.name,
|
||||
firstMessage: data.first_mes,
|
||||
desc: data.description,
|
||||
notes: data.post_history_instructions,
|
||||
name: data.name ?? '',
|
||||
firstMessage: data.first_mes ?? '',
|
||||
desc: data.description ?? '',
|
||||
notes: '',
|
||||
chats: [{
|
||||
message: [],
|
||||
note: '',
|
||||
@@ -334,15 +379,34 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array):Promise<boole
|
||||
image: im,
|
||||
emotionImages: emotions,
|
||||
bias: bias,
|
||||
globalLore: [], //lorebook
|
||||
globalLore: lorebook, //lorebook
|
||||
viewScreen: viewScreen,
|
||||
chaId: uuidv4(),
|
||||
sdData: sdData,
|
||||
utilityBot: utilityBot,
|
||||
customscript: customScripts,
|
||||
exampleMessage: data.mes_example
|
||||
exampleMessage: data.mes_example ?? '',
|
||||
creatorNotes:data.creator_notes ?? '',
|
||||
systemPrompt:data.system_prompt ?? '',
|
||||
postHistoryInstructions:data.post_history_instructions ?? '',
|
||||
alternateGreetings:data.alternate_greetings ?? [],
|
||||
tags:data.tags ?? [],
|
||||
creator:data.creator ?? '',
|
||||
characterVersion: data.character_version ?? 0,
|
||||
personality:data.personality ?? '',
|
||||
scenario:data.scenario ?? '',
|
||||
firstMsgIndex: -1,
|
||||
removedQuotes: false,
|
||||
loreSettings: loresettings,
|
||||
loreExt: loreExt,
|
||||
additionalData: {
|
||||
tag: data.tags,
|
||||
creator: data.creator,
|
||||
character_version: data.character_version
|
||||
}
|
||||
}
|
||||
|
||||
db.characters.push(char)
|
||||
|
||||
setDatabase(db)
|
||||
|
||||
@@ -351,6 +415,103 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array):Promise<boole
|
||||
|
||||
}
|
||||
|
||||
export async function exportSpecV2(char:character) {
|
||||
let img = await readImage(char.image)
|
||||
|
||||
try{
|
||||
|
||||
let charBook:charBookEntry[] = []
|
||||
for(const lore of char.globalLore){
|
||||
charBook.push({
|
||||
keys: lore.key.split(',').map(r => r.trim()),
|
||||
secondary_keys: lore.selective ? lore.secondkey.split(',').map(r => r.trim()) : undefined,
|
||||
content: lore.content,
|
||||
extensions: lore.extentions ?? {},
|
||||
enabled: true,
|
||||
insertion_order: lore.insertorder,
|
||||
constant: lore.alwaysActive,
|
||||
selective:lore.selective,
|
||||
name: lore.comment,
|
||||
comment: lore.comment
|
||||
})
|
||||
}
|
||||
|
||||
const card:CharacterCardV2 = {
|
||||
spec: "chara_card_v2",
|
||||
spec_version: "2.0",
|
||||
data: {
|
||||
name: char.name,
|
||||
description: char.desc,
|
||||
personality: char.personality,
|
||||
scenario: char.scenario,
|
||||
first_mes: char.firstMessage,
|
||||
mes_example: char.exampleMessage,
|
||||
creator_notes: char.creatorNotes,
|
||||
system_prompt: char.systemPrompt,
|
||||
post_history_instructions: char.postHistoryInstructions,
|
||||
alternate_greetings: char.alternateGreetings,
|
||||
character_book: {
|
||||
scan_depth: char.loreSettings?.scanDepth,
|
||||
token_budget: char.loreSettings?.tokenBudget,
|
||||
recursive_scanning: char.loreSettings?.recursiveScanning,
|
||||
extensions: char.loreExt ?? {},
|
||||
entries: []
|
||||
},
|
||||
tags: char.additionalData?.tag ?? [],
|
||||
creator: char.additionalData?.creator ?? '',
|
||||
character_version: char.additionalData?.character_version ?? 0,
|
||||
extensions: {
|
||||
risuai: {
|
||||
emotions: char.emotionImages,
|
||||
bias: char.bias,
|
||||
viewScreen: char.viewScreen,
|
||||
customScripts: char.customscript,
|
||||
utilityBot: char.utilityBot,
|
||||
sdData: char.sdData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(card.data.extensions.risuai.emotions && card.data.extensions.risuai.emotions.length > 0){
|
||||
for(let i=0;i<card.data.extensions.risuai.emotions.length;i++){
|
||||
alertStore.set({
|
||||
type: 'wait',
|
||||
msg: `Loading... (Getting Emotions ${i} / ${card.data.extensions.risuai.emotions.length})`
|
||||
})
|
||||
const rData = await readImage(card.data.extensions.risuai.emotions[i][1])
|
||||
char.emotionImages[i][1] = Buffer.from(rData).toString('base64')
|
||||
}
|
||||
}
|
||||
|
||||
alertStore.set({
|
||||
type: 'wait',
|
||||
msg: 'Loading... (Writing Exif)'
|
||||
})
|
||||
|
||||
await sleep(10)
|
||||
img = PngMetadata.write(img, {
|
||||
'chara': Buffer.from(JSON.stringify(card)).toString('base64'),
|
||||
})
|
||||
|
||||
alertStore.set({
|
||||
type: 'wait',
|
||||
msg: 'Loading... (Writing)'
|
||||
})
|
||||
|
||||
char.image = ''
|
||||
await sleep(10)
|
||||
await downloadFile(`${char.name.replace(/[<>:"/\\|?*\.\,]/g, "")}_export.png`, img)
|
||||
|
||||
alertNormal(language.successExport)
|
||||
|
||||
}
|
||||
catch(e){
|
||||
alertError(`${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type CharacterCardV2 = {
|
||||
spec: 'chara_card_v2'
|
||||
@@ -396,3 +557,33 @@ interface OldTavernChar{
|
||||
scenario: ""
|
||||
talkativeness: "0.5"
|
||||
}
|
||||
type CharacterBook = {
|
||||
name?: string
|
||||
description?: string
|
||||
scan_depth?: number // agnai: "Memory: Chat History Depth"
|
||||
token_budget?: number // agnai: "Memory: Context Limit"
|
||||
recursive_scanning?: boolean // no agnai equivalent. whether entry content can trigger other entries
|
||||
extensions: Record<string, any>
|
||||
entries: Array<charBookEntry>
|
||||
}
|
||||
|
||||
interface charBookEntry{
|
||||
keys: Array<string>
|
||||
content: string
|
||||
extensions: Record<string, any>
|
||||
enabled: boolean
|
||||
insertion_order: number // if two entries inserted, lower "insertion order" = inserted higher
|
||||
|
||||
// FIELDS WITH NO CURRENT EQUIVALENT IN SILLY
|
||||
name?: string // not used in prompt engineering
|
||||
priority?: number // if token budget reached, lower priority value = discarded first
|
||||
|
||||
// FIELDS WITH NO CURRENT EQUIVALENT IN AGNAI
|
||||
id?: number // not used in prompt engineering
|
||||
comment?: string // not used in prompt engineering
|
||||
selective?: boolean // if `true`, require a key from both `keys` and `secondary_keys` to trigger the entry
|
||||
secondary_keys?: Array<string> // see field `selective`. ignored if selective == false
|
||||
constant?: boolean // if true, always inserted in the prompt (within budget limit)
|
||||
position?: 'before_char' | 'after_char' // whether the entry is placed before or after the character defs
|
||||
|
||||
}
|
||||
@@ -37,6 +37,7 @@ export function createNewGroup(){
|
||||
emotionImages: [],
|
||||
customscript: [],
|
||||
chaId: uuidv4(),
|
||||
firstMsgIndex: -1
|
||||
})
|
||||
setDatabase(db)
|
||||
return db.characters.length - 1
|
||||
@@ -269,6 +270,18 @@ export function characterFormatUpdate(index:number|character){
|
||||
if(checkNullish(cha.utilityBot)){
|
||||
cha.utilityBot = false
|
||||
}
|
||||
cha.alternateGreetings = cha.alternateGreetings ?? []
|
||||
cha.exampleMessage = cha.exampleMessage ?? ''
|
||||
cha.creatorNotes = cha.creatorNotes ?? ''
|
||||
cha.systemPrompt = cha.systemPrompt ?? ''
|
||||
cha.postHistoryInstructions = cha.postHistoryInstructions ?? ''
|
||||
cha.tags = cha.tags ?? []
|
||||
cha.creator = cha.creator ?? ''
|
||||
cha.characterVersion = cha.characterVersion ?? 0
|
||||
cha.personality = cha.personality ?? ''
|
||||
cha.scenario = cha.scenario ?? ''
|
||||
cha.firstMsgIndex = cha.firstMsgIndex ?? -1
|
||||
|
||||
}
|
||||
if(checkNullish(cha.customscript)){
|
||||
cha.customscript = []
|
||||
@@ -303,7 +316,17 @@ export function createBlankChar():character{
|
||||
sdData: defaultSdDataFunc(),
|
||||
utilityBot: false,
|
||||
customscript: [],
|
||||
exampleMessage: ''
|
||||
exampleMessage: '',
|
||||
creatorNotes:'',
|
||||
systemPrompt:'',
|
||||
postHistoryInstructions:'',
|
||||
alternateGreetings:[],
|
||||
tags:[],
|
||||
creator:"",
|
||||
characterVersion: 0,
|
||||
personality:"",
|
||||
scenario:"",
|
||||
firstMsgIndex: -1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { cloneDeep } from 'lodash';
|
||||
|
||||
export const DataBase = writable({} as any as Database)
|
||||
export const loadedStore = writable(false)
|
||||
export let appVer = '0.7.9'
|
||||
export let appVer = '0.8.0'
|
||||
|
||||
|
||||
export function setDatabase(data:Database){
|
||||
@@ -178,6 +178,9 @@ export function setDatabase(data:Database){
|
||||
if(checkNullish(data.requestproxy)){
|
||||
data.requestproxy = ''
|
||||
}
|
||||
if(checkNullish(data.showUnrecommended)){
|
||||
data.showUnrecommended = false
|
||||
}
|
||||
if(checkNullish(data.sdConfig)){
|
||||
data.sdConfig = {
|
||||
width:512,
|
||||
@@ -213,11 +216,14 @@ export interface customscript{
|
||||
|
||||
export interface loreBook{
|
||||
key:string
|
||||
secondkey:string
|
||||
insertorder: number
|
||||
comment: string
|
||||
content: string
|
||||
mode: 'multiple'|'constant'|'normal',
|
||||
alwaysActive: boolean
|
||||
selective:boolean
|
||||
extentions?:{}
|
||||
}
|
||||
|
||||
export interface character{
|
||||
@@ -238,8 +244,34 @@ export interface character{
|
||||
customscript: customscript[]
|
||||
utilityBot: boolean
|
||||
exampleMessage:string
|
||||
removedQuotes?:boolean
|
||||
creatorNotes:string
|
||||
systemPrompt:string
|
||||
postHistoryInstructions:string
|
||||
alternateGreetings:string[]
|
||||
tags:string[]
|
||||
creator:string
|
||||
characterVersion: number
|
||||
personality:string
|
||||
scenario:string
|
||||
firstMsgIndex:number
|
||||
loreSettings?:loreSettings
|
||||
loreExt?:any
|
||||
additionalData?: {
|
||||
tag?:string[]
|
||||
creator?:string
|
||||
character_version?:number
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export interface loreSettings{
|
||||
tokenBudget: number
|
||||
scanDepth:number
|
||||
recursiveScanning: boolean
|
||||
}
|
||||
|
||||
|
||||
export interface groupChat{
|
||||
type: 'group'
|
||||
image?:string
|
||||
@@ -255,6 +287,11 @@ export interface groupChat{
|
||||
emotionImages: [string, string][]
|
||||
customscript: customscript[],
|
||||
chaId: string
|
||||
alternateGreetings?: string[]
|
||||
creatorNotes?:string,
|
||||
removedQuotes?:boolean
|
||||
firstMsgIndex?:number,
|
||||
loreSettings?:loreSettings
|
||||
}
|
||||
|
||||
export interface botPreset{
|
||||
@@ -348,6 +385,7 @@ export interface Database{
|
||||
didFirstSetup: boolean
|
||||
requestmet: string
|
||||
requestproxy: string
|
||||
showUnrecommended:boolean
|
||||
}
|
||||
|
||||
|
||||
|
||||
62
src/ts/process/exampleMessages.ts
Normal file
62
src/ts/process/exampleMessages.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import type { OpenAIChat } from ".";
|
||||
import type { character } from "../database";
|
||||
import { replacePlaceholders } from "../util";
|
||||
|
||||
export function exampleMessage(char:character):OpenAIChat[]{
|
||||
if(char.exampleMessage === ''){
|
||||
return []
|
||||
}
|
||||
|
||||
const messages = char.exampleMessage.split('\n')
|
||||
let result:OpenAIChat[] = []
|
||||
let currentMessage:OpenAIChat
|
||||
|
||||
function add(){
|
||||
if(currentMessage){
|
||||
result.push(currentMessage)
|
||||
}
|
||||
}
|
||||
|
||||
for(const mes of messages){
|
||||
const trimed = mes.trim()
|
||||
const lowered = trimed.toLocaleLowerCase()
|
||||
|
||||
|
||||
if(lowered === '<start>'){
|
||||
add()
|
||||
result.push({
|
||||
role: "system",
|
||||
content: '[Start a new chat]'
|
||||
})
|
||||
}
|
||||
else if(lowered.startsWith('{{char}}:') || lowered.startsWith('<bot>:') || lowered.startsWith(`${char.name}:`)){
|
||||
add()
|
||||
currentMessage = {
|
||||
role: "assistant",
|
||||
content: trimed.split(':', 2)[1]
|
||||
}
|
||||
}
|
||||
else if(lowered.startsWith('{{user}}:') || lowered.startsWith('<user>:')){
|
||||
add()
|
||||
currentMessage = {
|
||||
role: "user",
|
||||
content: trimed.split(':', 2)[1]
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(currentMessage){
|
||||
currentMessage.content += "\n" + trimed
|
||||
}
|
||||
}
|
||||
}
|
||||
add()
|
||||
|
||||
result = result.map((r) => {
|
||||
return {
|
||||
role: r.role,
|
||||
content: replacePlaceholders(r.content, char.name)
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -4,11 +4,12 @@ import { CharEmotion, selectedCharID } from "../stores";
|
||||
import { tokenize, tokenizeNum } from "../tokenizer";
|
||||
import { language } from "../../lang";
|
||||
import { alertError } from "../alert";
|
||||
import { loadLoreBookPrompt } from "../lorebook";
|
||||
import { loadLoreBookPrompt } from "./lorebook";
|
||||
import { findCharacterbyId, replacePlaceholders } from "../util";
|
||||
import { requestChatData } from "./request";
|
||||
import { stableDiff } from "./stableDiff";
|
||||
import { processScript, processScriptFull } from "./scripts";
|
||||
import { exampleMessage } from "./exampleMessages";
|
||||
|
||||
export interface OpenAIChat{
|
||||
role: 'system'|'user'|'assistant'
|
||||
@@ -99,9 +100,11 @@ export async function sendChat(chatProcessIndex = -1):Promise<boolean> {
|
||||
}
|
||||
|
||||
if(!currentChar.utilityBot){
|
||||
const mainp = currentChar.systemPrompt.length > 3 ? currentChar.systemPrompt : db.mainPrompt
|
||||
|
||||
unformated.main.push({
|
||||
role: 'system',
|
||||
content: replacePlaceholders(db.mainPrompt + ((db.additionalPrompt === '' || (!db.promptPreprocess)) ? '' : `\n${db.additionalPrompt}`), currentChar.name)
|
||||
content: replacePlaceholders(mainp + ((db.additionalPrompt === '' || (!db.promptPreprocess)) ? '' : `\n${db.additionalPrompt}`), currentChar.name)
|
||||
})
|
||||
|
||||
if(db.jailbreakToggle){
|
||||
@@ -122,10 +125,30 @@ export async function sendChat(chatProcessIndex = -1):Promise<boolean> {
|
||||
content: replacePlaceholders(currentChat.note, currentChar.name)
|
||||
})
|
||||
|
||||
unformated.description.push({
|
||||
role: 'system',
|
||||
content: replacePlaceholders((db.promptPreprocess ? db.descriptionPrefix: '') + currentChar.desc, currentChar.name)
|
||||
})
|
||||
if(currentChar.postHistoryInstructions !== ''){
|
||||
unformated.authorNote.push({
|
||||
role: 'system',
|
||||
content: replacePlaceholders(currentChar.postHistoryInstructions, currentChar.name)
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
let description = replacePlaceholders((db.promptPreprocess ? db.descriptionPrefix: '') + currentChar.desc, currentChar.name)
|
||||
|
||||
if(currentChar.personality){
|
||||
description += replacePlaceholders("\n\nDescription of {{char}}: " + currentChar.personality,currentChar.name)
|
||||
}
|
||||
|
||||
if(currentChar.scenario){
|
||||
description += replacePlaceholders("\n\nCircumstances and context of the dialogue: " + currentChar.scenario,currentChar.name)
|
||||
}
|
||||
|
||||
unformated.description.push({
|
||||
role: 'system',
|
||||
content: description
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
unformated.lorebook.push({
|
||||
role: 'system',
|
||||
@@ -139,20 +162,12 @@ export async function sendChat(chatProcessIndex = -1):Promise<boolean> {
|
||||
}).join('\n\n')
|
||||
}).join('\n\n')) + db.maxResponse) + 150
|
||||
|
||||
let chats:OpenAIChat[] = []
|
||||
let chats:OpenAIChat[] = exampleMessage(currentChar)
|
||||
|
||||
if(nowChatroom.type === 'group'){
|
||||
chats.push({
|
||||
role: 'system',
|
||||
content: '[Start a new group chat]'
|
||||
})
|
||||
}
|
||||
else{
|
||||
chats.push({
|
||||
role: 'system',
|
||||
content: '[Start a new chat]'
|
||||
})
|
||||
}
|
||||
chats.push({
|
||||
role: 'system',
|
||||
content: '[Start a new chat]'
|
||||
})
|
||||
|
||||
chats.push({
|
||||
role: 'assistant',
|
||||
@@ -349,25 +364,6 @@ export async function sendChat(chatProcessIndex = -1):Promise<boolean> {
|
||||
}
|
||||
}
|
||||
}
|
||||
// const promptbody:OpenAIChat[] = [
|
||||
// {
|
||||
|
||||
// role:'system',
|
||||
// content: `assistant is a emotion extractor. user will input a prompt of a character, and assistant must output the emotion of a character.\n\n must chosen from this list: ${shuffleArray(emotionList).join(', ')} \noutput only one word.`
|
||||
// },
|
||||
// {
|
||||
// role: 'user',
|
||||
// content: `"Good morning, Master! Is there anything I can do for you today?"`
|
||||
// },
|
||||
// {
|
||||
// role: 'assistant',
|
||||
// content: 'happy'
|
||||
// },
|
||||
// {
|
||||
// role: 'user',
|
||||
// content: result
|
||||
// },
|
||||
// ]
|
||||
|
||||
const promptbody:OpenAIChat[] = [
|
||||
{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { get } from "svelte/store";
|
||||
import {selectedCharID} from './stores'
|
||||
import { DataBase, setDatabase, type loreBook } from "./database";
|
||||
import { tokenize } from "./tokenizer";
|
||||
import { selectSingleFile } from "./util";
|
||||
import { alertError, alertNormal } from "./alert";
|
||||
import { language } from "../lang";
|
||||
import { downloadFile } from "./globalApi";
|
||||
import {selectedCharID} from '../stores'
|
||||
import { DataBase, setDatabase, type loreBook } from "../database";
|
||||
import { tokenize } from "../tokenizer";
|
||||
import { selectSingleFile } from "../util";
|
||||
import { alertError, alertNormal } from "../alert";
|
||||
import { language } from "../../lang";
|
||||
import { downloadFile } from "../globalApi";
|
||||
|
||||
export function addLorebook(type:number) {
|
||||
let selectedID = get(selectedCharID)
|
||||
@@ -17,7 +17,9 @@ export function addLorebook(type:number) {
|
||||
content: '',
|
||||
mode: 'normal',
|
||||
insertorder: 100,
|
||||
alwaysActive: false
|
||||
alwaysActive: false,
|
||||
secondkey: "",
|
||||
selective: false
|
||||
})
|
||||
}
|
||||
else{
|
||||
@@ -28,16 +30,20 @@ export function addLorebook(type:number) {
|
||||
content: '',
|
||||
mode: 'normal',
|
||||
insertorder: 100,
|
||||
alwaysActive: false
|
||||
alwaysActive: false,
|
||||
secondkey: "",
|
||||
selective: false
|
||||
})
|
||||
}
|
||||
setDatabase(db)
|
||||
}
|
||||
|
||||
interface formatedLore{
|
||||
keys:string[]|'always'
|
||||
keys:string[]|'always',
|
||||
secondKey:string[]
|
||||
content: string
|
||||
order: number
|
||||
activatied: boolean
|
||||
}
|
||||
|
||||
const rmRegex = / |\n/g
|
||||
@@ -45,11 +51,14 @@ const rmRegex = / |\n/g
|
||||
export async function loadLoreBookPrompt(){
|
||||
const selectedID = get(selectedCharID)
|
||||
const db = get(DataBase)
|
||||
const page = db.characters[selectedID].chatPage
|
||||
const globalLore = db.characters[selectedID].globalLore
|
||||
const charLore = db.characters[selectedID].chats[page].localLore
|
||||
const char = db.characters[selectedID]
|
||||
const page = char.chatPage
|
||||
const globalLore = char.globalLore
|
||||
const charLore = char.chats[page].localLore
|
||||
const fullLore = globalLore.concat(charLore)
|
||||
const currentChat = db.characters[selectedID].chats[page].message
|
||||
const currentChat = char.chats[page].message
|
||||
const loreDepth = char.loreSettings?.scanDepth ?? db.loreBookDepth
|
||||
const loreToken = char.loreSettings?.tokenBudget ?? db.loreBookToken
|
||||
|
||||
let activatiedPrompt: string[] = []
|
||||
|
||||
@@ -61,8 +70,12 @@ export async function loadLoreBookPrompt(){
|
||||
keys: lore.alwaysActive ? 'always' : lore.key.replace(rmRegex, '').toLocaleLowerCase().split(',').filter((a) => {
|
||||
return a.length > 1
|
||||
}),
|
||||
secondKey: lore.selective ? lore.secondkey.replace(rmRegex, '').toLocaleLowerCase().split(',').filter((a) => {
|
||||
return a.length > 1
|
||||
}) : [],
|
||||
content: lore.content,
|
||||
order: lore.insertorder
|
||||
order: lore.insertorder,
|
||||
activatied: false
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -71,26 +84,58 @@ export async function loadLoreBookPrompt(){
|
||||
return b.order - a.order
|
||||
})
|
||||
|
||||
const formatedChat = currentChat.slice(currentChat.length - db.loreBookDepth,currentChat.length).map((msg) => {
|
||||
const formatedChat = currentChat.slice(currentChat.length - loreDepth,currentChat.length).map((msg) => {
|
||||
return msg.data
|
||||
}).join('||').replace(rmRegex,'').toLocaleLowerCase()
|
||||
|
||||
for(const lore of formatedLore){
|
||||
const totalTokens = await tokenize(activatiedPrompt.concat([lore.content]).join('\n\n'))
|
||||
if(totalTokens > db.loreBookToken){
|
||||
break
|
||||
}
|
||||
|
||||
if(lore.keys === 'always'){
|
||||
activatiedPrompt.push(lore.content)
|
||||
continue
|
||||
}
|
||||
|
||||
for(const key of lore.keys){
|
||||
if(formatedChat.includes(key)){
|
||||
activatiedPrompt.push(lore.content)
|
||||
let loreListUpdated = true
|
||||
|
||||
while(loreListUpdated){
|
||||
loreListUpdated = false
|
||||
for(let i=0;i<formatedLore.length;i++){
|
||||
const lore = formatedLore[i]
|
||||
if(lore.activatied){
|
||||
continue
|
||||
}
|
||||
const totalTokens = await tokenize(activatiedPrompt.concat([lore.content]).join('\n\n'))
|
||||
if(totalTokens > loreToken){
|
||||
break
|
||||
}
|
||||
|
||||
if(lore.keys === 'always'){
|
||||
activatiedPrompt.push(lore.content)
|
||||
lore.activatied = true
|
||||
loreListUpdated = true
|
||||
continue
|
||||
}
|
||||
|
||||
let firstKeyActivation = false
|
||||
for(const key of lore.keys){
|
||||
if(formatedChat.includes(key)){
|
||||
firstKeyActivation = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if(firstKeyActivation){
|
||||
if(lore.secondKey.length === 0){
|
||||
activatiedPrompt.push(lore.content)
|
||||
lore.activatied = true
|
||||
loreListUpdated = true
|
||||
continue
|
||||
}
|
||||
for(const key of lore.secondKey){
|
||||
if(formatedChat.includes(key)){
|
||||
activatiedPrompt.push(lore.content)
|
||||
lore.activatied = true
|
||||
loreListUpdated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!(char.loreSettings?.recursiveScanning)){
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +152,8 @@ export async function importLoreBook(mode:'global'|'local'){
|
||||
if(!lorebook){
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
const importedlore = JSON.parse(Buffer.from(lorebook).toString('utf-8'))
|
||||
@@ -129,10 +176,12 @@ export async function importLoreBook(mode:'global'|'local'){
|
||||
lore.push({
|
||||
key: currentLore.key.join(', '),
|
||||
insertorder: currentLore.order,
|
||||
comment: currentLore.comment.length < 1 ? 'Unnamed Imported Lore': currentLore.comment,
|
||||
comment: currentLore.comment.length < 1 ? 'Unnamed Imported Lore' : currentLore.comment,
|
||||
content: currentLore.content,
|
||||
mode: "normal",
|
||||
alwaysActive: currentLore.constant
|
||||
alwaysActive: currentLore.constant,
|
||||
secondkey: "",
|
||||
selective: false
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -20,13 +20,17 @@ export default {
|
||||
},
|
||||
maxWidth:{
|
||||
'half': '50%',
|
||||
'80p': '80%',
|
||||
'80vw': '80vw',
|
||||
'14': '3.5rem',
|
||||
'100vw': '100vw'
|
||||
},
|
||||
borderWidth: {
|
||||
'1': '1px',
|
||||
},
|
||||
width: {
|
||||
'2xl': '48rem',
|
||||
'3xl': '72rem',
|
||||
},
|
||||
minHeight:{
|
||||
'8': '2rem',
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":"0.7.9"}
|
||||
{"version":"0.8.0"}
|
||||
Reference in New Issue
Block a user