feat: add local activation for lorebook

This commit is contained in:
bangonicdd
2025-02-21 21:01:20 +09:00
parent 0a2e4fd04c
commit b10fccd3c4
5 changed files with 105 additions and 4 deletions

View File

@@ -1057,4 +1057,6 @@ export const languageEnglish = {
paste: "Paste",
depth: "Depth",
returnCSSError: "Return CSS Error",
alwaysActiveInChat: "Always Active (Current Chat)",
childLoreDesc: "This is a copy of Character lore that remains 'Always Active' until removed or manually deactivated in the original.",
}

View File

@@ -978,4 +978,6 @@ export const languageKorean = {
"copy": "복사",
"paste": "붙여넣기",
"depth": "깊이",
"alwaysActiveInChat": "언제나 활성화 (현재 챗)",
"childLoreDesc": "이것은 캐릭터 로어의 복사본이며, 삭제하거나 원본 로어에서 직접 비활성화하기 전에는 '언제나 활성화' 상태로 유지됩니다."
}

View File

@@ -1,8 +1,9 @@
<script lang="ts">
import { XIcon, LinkIcon, SunIcon } from "lucide-svelte";
import { XIcon, LinkIcon, SunIcon, BookCopyIcon } from "lucide-svelte";
import { v4 } from "uuid";
import { language } from "../../../lang";
import type { loreBook } from "../../../ts/storage/database.svelte";
import { alertConfirm } from "../../../ts/alert";
import { getCurrentCharacter, getCurrentChat, type loreBook } from "../../../ts/storage/database.svelte";
import { alertConfirm, alertMd } from "../../../ts/alert";
import Check from "../../UI/GUI/CheckInput.svelte";
import Help from "../../Others/Help.svelte";
import TextInput from "../../UI/GUI/TextInput.svelte";
@@ -34,10 +35,67 @@
return tokens
}
let tokens = $state(0)
function isLocallyActivated(book: loreBook){
return getCurrentChat()?.localLore.some(e =>
e.id === book.id &&
e.alwaysActive
)
}
function ActivateLocally(book: loreBook){
const chat = getCurrentChat()
let childLore: loreBook | undefined
if(!book.id){
book.id = v4()
}else{
childLore = chat.localLore.find(e => e.id === book.id)
}
if(childLore){
childLore.alwaysActive = true
}else{
childLore = {
key: '',
comment: '',
content: '',
mode: 'child',
insertorder: 100,
alwaysActive: true,
secondkey: '',
selective: false,
id: book.id,
}
chat.localLore.push(childLore)
}
}
function DeactivateLocally(book: loreBook){
const chat = getCurrentChat()
const childLore = chat?.localLore?.find(e => e.id === book.id)
if(childLore){
chat.localLore = chat.localLore.filter(e => e.id !== book.id)
}
}
function toggleLocalActive(check: boolean, book: loreBook){
if(check){
ActivateLocally(book)
}else{
DeactivateLocally(book)
}
}
function getParentLoreName(book: loreBook){
if(book.mode === 'child'){
const value = getCurrentCharacter()?.globalLore.find(e => e.id === book.id)
if(value){
return value.comment.length === 0 ? value.key.length === 0 ? "Unnamed Lore" : value.key : value.comment
}
}
}
</script>
<div class="w-full flex flex-col pt-2 mt-2 border-t border-t-selected first:pt-0 first:mt-0 first:border-0" data-risu-idx={idx}>
<div class="flex items-center transition-colors w-full p-1">
{#if value.mode !== 'child'}
<button class="endflex valuer border-darkborderc" onclick={() => {
value.secondkey = value.secondkey ?? ''
open = !open
@@ -70,11 +128,29 @@
if(!open){
onClose()
}
DeactivateLocally(value)
onRemove()
}
}}>
<XIcon size={20} />
</button>
{:else}
<button class="endflex valuer border-darkborderc" onclick={() => alertMd(language.childLoreDesc)}>
<BookCopyIcon size={20} class="mr-1" />
<span>{getParentLoreName(value)}</span>
</button>
<button class="valuer" onclick={async () => {
const d = await alertConfirm(language.removeConfirm + getParentLoreName(value))
if(d){
if(!open){
onClose()
}
onRemove()
}
}}>
<XIcon size={20} />
</button>
{/if}
</div>
{#if open}
<div class="border-0 outline-none w-full mt-2 flex flex-col mb-2">
@@ -120,6 +196,11 @@
<div class="flex items-center mt-4">
<Check bind:check={value.alwaysActive} name={language.alwaysActive}/>
</div>
{#if !value.alwaysActive && getCurrentCharacter()?.globalLore?.includes(value)}
<div class="flex items-center mt-2">
<Check check={isLocallyActivated(value)} onChange={(check: boolean) => toggleLocalActive(check, value)} name={language.alwaysActiveInChat}/>
</div>
{/if}
{#if !lorePlus && !value.useRegex}
<div class="flex items-center mt-2">
<Check bind:check={value.selective} name={language.selective}/>

View File

@@ -218,6 +218,21 @@ export async function loadLoreBookV3Prompt(){
all?:boolean
}[] = []
let fullWordMatching = fullWordMatchingSetting
if(fullLore[i].mode === 'child'){
activated = false
for(let j=0;j<i;j++){
if(fullLore[j].id === fullLore[i].id){
if(!activatedIndexes.includes(j)){
fullLore[i].comment = fullLore[j].comment
fullLore[i].content = fullLore[j].content
fullLore[i].alwaysActive = true
activated = true
}
break
}
}
}
const content = CCardLib.decorator.parse(fullLore[i].content, (name, arg) => {
switch(name){
case 'end':{

View File

@@ -937,7 +937,7 @@ export interface loreBook{
insertorder: number
comment: string
content: string
mode: 'multiple'|'constant'|'normal',
mode: 'multiple'|'constant'|'normal'|'child',
alwaysActive: boolean
selective:boolean
extentions?:{
@@ -950,6 +950,7 @@ export interface loreBook{
},
useRegex?:boolean
bookVersion?:number
id?:string
}
export interface character{