feat: add process regex script option in HypaV3 modal
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { tick } from "svelte";
|
||||||
import {
|
import {
|
||||||
SettingsIcon,
|
SettingsIcon,
|
||||||
Trash2Icon,
|
Trash2Icon,
|
||||||
@@ -9,7 +10,6 @@
|
|||||||
ScissorsLineDashed,
|
ScissorsLineDashed,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
} from "lucide-svelte";
|
} from "lucide-svelte";
|
||||||
import { tick } from "svelte";
|
|
||||||
import TextAreaInput from "../../lib/UI/GUI/TextAreaInput.svelte";
|
import TextAreaInput from "../../lib/UI/GUI/TextAreaInput.svelte";
|
||||||
import {
|
import {
|
||||||
alertConfirm,
|
alertConfirm,
|
||||||
@@ -23,8 +23,13 @@
|
|||||||
settingsOpen,
|
settingsOpen,
|
||||||
SettingsMenuIndex,
|
SettingsMenuIndex,
|
||||||
} from "../../ts/stores.svelte";
|
} from "../../ts/stores.svelte";
|
||||||
import { summarize } from "../../ts/process/memory/hypav3";
|
|
||||||
import { type OpenAIChat } from "../../ts/process/index.svelte";
|
import { type OpenAIChat } from "../../ts/process/index.svelte";
|
||||||
|
import {
|
||||||
|
processScript,
|
||||||
|
processScriptFull,
|
||||||
|
risuChatParser,
|
||||||
|
} from "../../ts/process/scripts";
|
||||||
|
import { summarize } from "../../ts/process/memory/hypav3";
|
||||||
import { type Message } from "../../ts/storage/database.svelte";
|
import { type Message } from "../../ts/storage/database.svelte";
|
||||||
import { translateHTML } from "../../ts/translator/translator";
|
import { translateHTML } from "../../ts/translator/translator";
|
||||||
|
|
||||||
@@ -80,33 +85,6 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFirstMessage(): string | null {
|
|
||||||
const char = DBState.db.characters[$selectedCharID];
|
|
||||||
const chat = char.chats[DBState.db.characters[$selectedCharID].chatPage];
|
|
||||||
|
|
||||||
return chat.fmIndex === -1
|
|
||||||
? char.firstMessage
|
|
||||||
: char.alternateGreetings?.[chat.fmIndex]
|
|
||||||
? char.alternateGreetings[chat.fmIndex]
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMessageFromChatMemo(chatMemo: string | null): Message | null {
|
|
||||||
const char = DBState.db.characters[$selectedCharID];
|
|
||||||
const chat = char.chats[DBState.db.characters[$selectedCharID].chatPage];
|
|
||||||
const firstMessage = getFirstMessage();
|
|
||||||
|
|
||||||
if (!firstMessage) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chatMemo == null) {
|
|
||||||
return { role: "char", data: firstMessage };
|
|
||||||
}
|
|
||||||
|
|
||||||
return chat.message.find((m) => m.chatId === chatMemo) || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function toggleTranslate(
|
async function toggleTranslate(
|
||||||
summaryIndex: number,
|
summaryIndex: number,
|
||||||
regenerate?: boolean
|
regenerate?: boolean
|
||||||
@@ -167,16 +145,19 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const summary = hypaV3DataState.summaries[summaryIndex];
|
const summary = hypaV3DataState.summaries[summaryIndex];
|
||||||
const toSummarize: OpenAIChat[] = summary.chatMemos.map((chatMemo) => {
|
const toSummarize: OpenAIChat[] = await Promise.all(
|
||||||
const message = getMessageFromChatMemo(chatMemo);
|
summary.chatMemos.map(async (chatMemo) => {
|
||||||
|
// Processed message
|
||||||
|
const message = await getProcessedMessageFromChatMemo(chatMemo);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
role: (message.role === "char"
|
role: (message.role === "char"
|
||||||
? "assistant"
|
? "assistant"
|
||||||
: message.role) as OpenAIChat["role"],
|
: message.role) as OpenAIChat["role"],
|
||||||
content: message.data,
|
content: message.data,
|
||||||
};
|
};
|
||||||
});
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const summarizeResult = await summarize(toSummarize);
|
const summarizeResult = await summarize(toSummarize);
|
||||||
|
|
||||||
@@ -226,6 +207,65 @@
|
|||||||
summaryUIState.isRerolledTranslating = false;
|
summaryUIState.isRerolledTranslating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getProcessedMessageFromChatMemo(
|
||||||
|
chatMemo: string | null
|
||||||
|
): Promise<Message | null> {
|
||||||
|
const unprocessed = getMessageFromChatMemo(chatMemo);
|
||||||
|
|
||||||
|
if (!unprocessed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DBState.db.hypaV3Settings.processRegexScript
|
||||||
|
? await processRegexScript(unprocessed)
|
||||||
|
: unprocessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMessageFromChatMemo(chatMemo: string | null): Message | null {
|
||||||
|
const char = DBState.db.characters[$selectedCharID];
|
||||||
|
const chat = char.chats[DBState.db.characters[$selectedCharID].chatPage];
|
||||||
|
|
||||||
|
if (chatMemo == null) {
|
||||||
|
const firstMessage = getFirstMessage();
|
||||||
|
|
||||||
|
return firstMessage ? { role: "char", data: firstMessage } : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chat.message.find((m) => m.chatId === chatMemo) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFirstMessage(): string | null {
|
||||||
|
const char = DBState.db.characters[$selectedCharID];
|
||||||
|
const chat = char.chats[DBState.db.characters[$selectedCharID].chatPage];
|
||||||
|
|
||||||
|
return chat.fmIndex === -1
|
||||||
|
? char.firstMessage
|
||||||
|
: char.alternateGreetings?.[chat.fmIndex]
|
||||||
|
? char.alternateGreetings[chat.fmIndex]
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processRegexScript(msg: Message): Promise<Message> {
|
||||||
|
const char = DBState.db.characters[$selectedCharID];
|
||||||
|
const chat = char.chats[DBState.db.characters[$selectedCharID].chatPage];
|
||||||
|
const newData: string = (
|
||||||
|
await processScriptFull(
|
||||||
|
char,
|
||||||
|
risuChatParser(msg.data, { chara: char, role: msg.role }),
|
||||||
|
"editprocess",
|
||||||
|
-1,
|
||||||
|
{
|
||||||
|
chatRole: msg.role,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).data;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...msg,
|
||||||
|
data: newData,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function isMessageExpanded(
|
function isMessageExpanded(
|
||||||
summaryIndex: number,
|
summaryIndex: number,
|
||||||
chatMemo: string | null
|
chatMemo: string | null
|
||||||
@@ -265,7 +305,8 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = getMessageFromChatMemo(
|
// Processed message
|
||||||
|
const message = await getProcessedMessageFromChatMemo(
|
||||||
expandedMessageUIState.selectedChatMemo
|
expandedMessageUIState.selectedChatMemo
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -292,15 +333,33 @@
|
|||||||
expandedMessageUIState.isTranslating = false;
|
expandedMessageUIState.isTranslating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNextMessageToSummarize(): Message | null {
|
async function translate(
|
||||||
const char = DBState.db.characters[$selectedCharID];
|
text: string,
|
||||||
const chat = char.chats[DBState.db.characters[$selectedCharID].chatPage];
|
regenerate?: boolean
|
||||||
const firstMessage = getFirstMessage();
|
): Promise<string> {
|
||||||
|
try {
|
||||||
|
return await translateHTML(text, false, "", -1, regenerate);
|
||||||
|
} catch (error) {
|
||||||
|
return `Translation failed: ${error}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!firstMessage) {
|
async function getProcessedNextSummarizationTarget(): Promise<Message | null> {
|
||||||
|
const unprocessed = getNextSummarizationTarget();
|
||||||
|
|
||||||
|
if (!unprocessed) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return DBState.db.hypaV3Settings.processRegexScript
|
||||||
|
? await processRegexScript(unprocessed)
|
||||||
|
: unprocessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNextSummarizationTarget(): Message | null {
|
||||||
|
const char = DBState.db.characters[$selectedCharID];
|
||||||
|
const chat = char.chats[DBState.db.characters[$selectedCharID].chatPage];
|
||||||
|
|
||||||
// Summaries exist
|
// Summaries exist
|
||||||
if (hypaV3DataState.summaries.length > 0) {
|
if (hypaV3DataState.summaries.length > 0) {
|
||||||
const lastSummary = hypaV3DataState.summaries.at(-1);
|
const lastSummary = hypaV3DataState.summaries.at(-1);
|
||||||
@@ -317,8 +376,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No summaries
|
const firstMessage = getFirstMessage();
|
||||||
if (firstMessage?.trim() === "") {
|
|
||||||
|
// When no summaries exist OR couldn't find last connected message
|
||||||
|
// Check if first message is available
|
||||||
|
if (!firstMessage || firstMessage.trim() === "") {
|
||||||
if (chat.message.length > 0) {
|
if (chat.message.length > 0) {
|
||||||
return chat.message[0];
|
return chat.message[0];
|
||||||
}
|
}
|
||||||
@@ -327,25 +389,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// will summarize first message
|
// will summarize first message
|
||||||
return { role: "char", chatId: "first message", data: firstMessage };
|
return { role: "char", chatId: "first", data: firstMessage };
|
||||||
}
|
|
||||||
|
|
||||||
async function translate(
|
|
||||||
text: string,
|
|
||||||
regenerate?: boolean
|
|
||||||
): Promise<string> {
|
|
||||||
try {
|
|
||||||
return await translateHTML(text, false, "", -1, regenerate);
|
|
||||||
} catch (error) {
|
|
||||||
return `Translation failed: ${error}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isHypaV2ConversionPossible(): boolean {
|
function isHypaV2ConversionPossible(): boolean {
|
||||||
const char = DBState.db.characters[$selectedCharID];
|
const char = DBState.db.characters[$selectedCharID];
|
||||||
const chat = char.chats[DBState.db.characters[$selectedCharID].chatPage];
|
const chat = char.chats[DBState.db.characters[$selectedCharID].chatPage];
|
||||||
|
|
||||||
return chat.hypaV3Data?.summaries?.length === 0 && chat.hypaV2Data !== null;
|
return chat.hypaV3Data?.summaries?.length === 0 && chat.hypaV2Data != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertHypaV2ToV3(): { success: boolean; error?: string } {
|
function convertHypaV2ToV3(): { success: boolean; error?: string } {
|
||||||
@@ -559,30 +610,34 @@
|
|||||||
{#if hypaV3DataState.summaries.length === 0}
|
{#if hypaV3DataState.summaries.length === 0}
|
||||||
<!-- Conversion Section -->
|
<!-- Conversion Section -->
|
||||||
{#if isHypaV2ConversionPossible()}
|
{#if isHypaV2ConversionPossible()}
|
||||||
<div class="mt-4 flex flex-col items-center gap-2">
|
<div
|
||||||
<span class="text-textcolor2 text-center p-4"
|
class="flex flex-col p-4 rounded-lg border border-zinc-700 bg-zinc-800/50"
|
||||||
>No summaries yet, but you can convert HypaV2 data to V3.</span
|
>
|
||||||
>
|
<div class="mt-4 flex flex-col items-center gap-2">
|
||||||
<button
|
<span class="text-textcolor2 text-center p-4"
|
||||||
class="px-4 py-2 bg-zinc-800 text-zinc-200 rounded-md hover:bg-zinc-700 transition-colors"
|
>No summaries yet, but you may convert HypaV2 data to V3.</span
|
||||||
onclick={async () => {
|
>
|
||||||
const conversionResult = convertHypaV2ToV3();
|
<button
|
||||||
|
class="px-4 py-2 bg-zinc-800 text-zinc-200 rounded-md hover:bg-zinc-700 transition-colors"
|
||||||
|
onclick={async () => {
|
||||||
|
const conversionResult = convertHypaV2ToV3();
|
||||||
|
|
||||||
if (conversionResult.success) {
|
if (conversionResult.success) {
|
||||||
await alertNormalWait(
|
await alertNormalWait(
|
||||||
"Successfully converted HypaV2 data to V3"
|
"Successfully converted HypaV2 data to V3"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await alertNormalWait(
|
await alertNormalWait(
|
||||||
`Failed to convert HypaV2 data to V3: ${conversionResult.error}`
|
`Failed to convert HypaV2 data to V3: ${conversionResult.error}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
showHypaV3Alert();
|
showHypaV3Alert();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Convert to V3
|
Convert to V3
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="text-textcolor2 text-center p-4">No summaries yet</span
|
<span class="text-textcolor2 text-center p-4">No summaries yet</span
|
||||||
@@ -779,26 +834,32 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Selected Message Content (if selected) -->
|
<!-- Selected Message (if selected) -->
|
||||||
{#if expandedMessageUIState?.summaryIndex === i}
|
{#if expandedMessageUIState?.summaryIndex === i}
|
||||||
{@const message = getMessageFromChatMemo(
|
|
||||||
expandedMessageUIState.selectedChatMemo
|
|
||||||
)}
|
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
{#if message}
|
<!-- Processed Message -->
|
||||||
<!-- Role -->
|
{#await getProcessedMessageFromChatMemo(expandedMessageUIState.selectedChatMemo) then expandedMessage}
|
||||||
<div class="text-sm text-textcolor2 mb-2 block">
|
{#if expandedMessage}
|
||||||
{message.role}'s Message
|
<!-- Role -->
|
||||||
|
<div class="text-sm text-textcolor2 mb-2 block">
|
||||||
|
{expandedMessage.role}'s Message
|
||||||
|
</div>
|
||||||
|
<!-- Content -->
|
||||||
|
<div
|
||||||
|
class="p-2 max-h-48 overflow-y-auto bg-zinc-800 rounded-md whitespace-pre-wrap"
|
||||||
|
>
|
||||||
|
{expandedMessage.data}
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="text-sm text-red-500">
|
||||||
|
Message not found
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{:catch error}
|
||||||
|
<div class="text-sm text-red-500 mb-2">
|
||||||
|
Error loading expanded message: {error.message}
|
||||||
</div>
|
</div>
|
||||||
<!-- Content -->
|
{/await}
|
||||||
<div
|
|
||||||
class="p-2 max-h-48 overflow-y-auto bg-zinc-800 rounded-md whitespace-pre-wrap"
|
|
||||||
>
|
|
||||||
{message.data}
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<div class="text-sm text-red-500">Message not found</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<!-- Message Translation -->
|
<!-- Message Translation -->
|
||||||
{#if expandedMessageUIState.translation}
|
{#if expandedMessageUIState.translation}
|
||||||
@@ -822,15 +883,18 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<!-- Next message to be summarized -->
|
<!-- Next Summarization Target -->
|
||||||
{#if true}
|
{#await getProcessedNextSummarizationTarget() then nextMessage}
|
||||||
{@const nextMessage = getNextMessageToSummarize()}
|
|
||||||
{#if nextMessage}
|
{#if nextMessage}
|
||||||
|
{@const chatId =
|
||||||
|
nextMessage.chatId === "first"
|
||||||
|
? "First Message"
|
||||||
|
: nextMessage.chatId == null
|
||||||
|
? "No Message ID"
|
||||||
|
: nextMessage.chatId}
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<span class="text-sm text-textcolor2 mb-2 block">
|
<span class="text-sm text-textcolor2 mb-2 block">
|
||||||
HypaV3 will summarize [{nextMessage.chatId
|
HypaV3 will summarize [{chatId}]
|
||||||
? nextMessage.chatId
|
|
||||||
: "no message id"}]
|
|
||||||
</span>
|
</span>
|
||||||
<div
|
<div
|
||||||
class="p-2 max-h-48 overflow-y-auto bg-zinc-800 rounded-md whitespace-pre-wrap"
|
class="p-2 max-h-48 overflow-y-auto bg-zinc-800 rounded-md whitespace-pre-wrap"
|
||||||
@@ -838,11 +902,20 @@
|
|||||||
{nextMessage.data}
|
{nextMessage.data}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else if !getFirstMessage()}
|
|
||||||
<div class="text-sm text-red-500">
|
|
||||||
WARN: Selected first message is null
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
{:catch error}
|
||||||
|
<div class="text-sm text-red-500 mb-2">
|
||||||
|
Error loading next message: {error.message}
|
||||||
|
</div>
|
||||||
|
{/await}
|
||||||
|
|
||||||
|
<!-- No First Message -->
|
||||||
|
{#if !getFirstMessage()}
|
||||||
|
<div class="mt-4">
|
||||||
|
<div class="text-sm text-red-500 mb-2">
|
||||||
|
WARN: Selected first message is empty
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -519,7 +519,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex mb-2">
|
<div class="flex mb-2">
|
||||||
<Check name="Preserve Orphaned Memory" bind:check={DBState.db.hypaV3Settings.preserveOrphanedMemory} />
|
<Check name="Preserve Orphaned Memory" bind:check={DBState.db.hypaV3Settings.preserveOrphanedMemory} />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex mb-2">
|
||||||
|
<Check name="Process Regex Script (Modify Request Data)" bind:check={DBState.db.hypaV3Settings.processRegexScript} />
|
||||||
|
</div>
|
||||||
{:else if (DBState.db.supaModelType !== 'none' && DBState.db.hypav2 === false && DBState.db.hypaV3 === false)}
|
{:else if (DBState.db.supaModelType !== 'none' && DBState.db.hypav2 === false && DBState.db.hypaV3 === false)}
|
||||||
<span class="mb-2 text-textcolor2 text-sm text-wrap break-words max-w-full">{language.supaDesc}</span>
|
<span class="mb-2 text-textcolor2 text-sm text-wrap break-words max-w-full">{language.supaDesc}</span>
|
||||||
<span class="text-textcolor mt-4">{language.SuperMemory} {language.model}</span>
|
<span class="text-textcolor mt-4">{language.SuperMemory} {language.model}</span>
|
||||||
|
|||||||
@@ -477,7 +477,8 @@ export function setDatabase(data:Database){
|
|||||||
recentMemoryRatio: data.hypaV3Settings?.recentMemoryRatio ?? 0.4,
|
recentMemoryRatio: data.hypaV3Settings?.recentMemoryRatio ?? 0.4,
|
||||||
similarMemoryRatio: data.hypaV3Settings?.similarMemoryRatio ?? 0.4,
|
similarMemoryRatio: data.hypaV3Settings?.similarMemoryRatio ?? 0.4,
|
||||||
enableSimilarityCorrection: data.hypaV3Settings?.enableSimilarityCorrection ?? false,
|
enableSimilarityCorrection: data.hypaV3Settings?.enableSimilarityCorrection ?? false,
|
||||||
preserveOrphanedMemory: data.hypaV3Settings?.preserveOrphanedMemory ?? false
|
preserveOrphanedMemory: data.hypaV3Settings?.preserveOrphanedMemory ?? false,
|
||||||
|
processRegexScript: data.hypaV3Settings?.processRegexScript ?? false
|
||||||
}
|
}
|
||||||
changeLanguage(data.language)
|
changeLanguage(data.language)
|
||||||
setDatabaseLite(data)
|
setDatabaseLite(data)
|
||||||
@@ -890,6 +891,7 @@ export interface Database{
|
|||||||
similarMemoryRatio: number
|
similarMemoryRatio: number
|
||||||
enableSimilarityCorrection: boolean
|
enableSimilarityCorrection: boolean
|
||||||
preserveOrphanedMemory: boolean
|
preserveOrphanedMemory: boolean
|
||||||
|
processRegexScript: boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user