Revert #773 f7ea95aeea due to critical bug

This commit is contained in:
Kwaroran
2025-03-05 06:30:57 +09:00
parent 5026a96ce9
commit 17bd35e452
3 changed files with 55 additions and 256 deletions

View File

@@ -130,22 +130,9 @@
$effect.pre(() => { $effect.pre(() => {
blankMessage = (message === '{{none}}' || message === '{{blank}}' || message === '') && idx === -1 blankMessage = (message === '{{none}}' || message === '{{blank}}' || message === '') && idx === -1
}); });
// Static map for caching markdown parsing results
const markdownCache = new Map<string, string>();
const markParsing = async (data: string, charArg?: string | simpleCharacterArgument, mode?: "normal" | "back", chatID?: number, translateText?:boolean, tries?:number) => { const markParsing = async (data: string, charArg?: string | simpleCharacterArgument, mode?: "normal" | "back", chatID?: number, translateText?:boolean, tries?:number) => {
let lastParsedQueue = '' let lastParsedQueue = ''
try { try {
// Create cache key
const cacheKey = `${data}-${JSON.stringify(charArg)}-${mode}-${chatID}-${translateText}`;
// Use cached result if available and not retranslating
if (markdownCache.has(cacheKey) && !retranslate) {
lastParsedQueue = markdownCache.get(cacheKey);
lastCharArg = charArg;
lastChatId = chatID;
return lastParsedQueue;
}
if((!isEqual(lastCharArg, charArg)) || (chatID !== lastChatId)){ if((!isEqual(lastCharArg, charArg)) || (chatID !== lastChatId)){
lastParsedQueue = '' lastParsedQueue = ''
lastCharArg = charArg lastCharArg = charArg
@@ -197,7 +184,6 @@
const marked = await ParseMarkdown(data, charArg, mode, chatID, getCbsCondition()) const marked = await ParseMarkdown(data, charArg, mode, chatID, getCbsCondition())
lastParsedQueue = marked lastParsedQueue = marked
lastCharArg = charArg lastCharArg = charArg
markdownCache.set(cacheKey, marked);
return marked return marked
} }
else if(!DBState.db.legacyTranslation){ else if(!DBState.db.legacyTranslation){
@@ -207,7 +193,6 @@
translating = false translating = false
lastParsedQueue = translated lastParsedQueue = translated
lastCharArg = charArg lastCharArg = charArg
markdownCache.set(cacheKey, translated);
return translated return translated
} }
else{ else{
@@ -217,7 +202,6 @@
translating = false translating = false
lastParsedQueue = translated lastParsedQueue = translated
lastCharArg = charArg lastCharArg = charArg
markdownCache.set(cacheKey, translated);
return translated return translated
} }
} }
@@ -225,12 +209,12 @@
const marked = await ParseMarkdown(data, charArg, mode, chatID, getCbsCondition()) const marked = await ParseMarkdown(data, charArg, mode, chatID, getCbsCondition())
lastParsedQueue = marked lastParsedQueue = marked
lastCharArg = charArg lastCharArg = charArg
markdownCache.set(cacheKey, marked);
return marked return marked
} }
} catch (error) { } catch (error) {
//retry //retry
if(tries > 2){ if(tries > 2){
alertError(`Error while parsing chat message: ${translateText}, ${error.message}, ${error.stack}`) alertError(`Error while parsing chat message: ${translateText}, ${error.message}, ${error.stack}`)
return data return data
} }
@@ -241,17 +225,6 @@
} }
} }
// Limit cache size (runs periodically)
function cleanupMarkdownCache() {
if (markdownCache.size > 100) {
const keys = Array.from(markdownCache.keys());
// Delete the oldest 50 items
for (let i = 0; i < 50; i++) {
markdownCache.delete(keys[i]);
}
}
}
$effect.pre(() => { $effect.pre(() => {
displaya(message) displaya(message)
}); });
@@ -262,10 +235,6 @@
unsubscribers.push(ReloadGUIPointer.subscribe((v) => { unsubscribers.push(ReloadGUIPointer.subscribe((v) => {
displaya(message) displaya(message)
})) }))
// Clean up cache every 3 minutes
const cacheCleanupInterval = setInterval(cleanupMarkdownCache, 180000);
return () => clearInterval(cacheCleanupInterval);
}) })
onDestroy(()=>{ onDestroy(()=>{
@@ -344,22 +313,11 @@
style:line-height="{(DBState.db.lineHeight ?? 1.25) * (DBState.db.zoomsize / 100)}rem" style:line-height="{(DBState.db.lineHeight ?? 1.25) * (DBState.db.zoomsize / 100)}rem"
> >
{#key $ReloadGUIPointer} {#key $ReloadGUIPointer}
{#if message && message.length > 10000}
<!-- Delayed rendering for long messages -->
{#await new Promise(resolve => setTimeout(() => resolve(true), 10)) then _}
{#await markParsing(msgDisplay, character, 'normal', idx, translated)} {#await markParsing(msgDisplay, character, 'normal', idx, translated)}
{@html lastParsed} {@html lastParsed}
{:then md} {:then md}
{@html md} {@html md}
{/await} {/await}
{/await}
{:else}
{#await markParsing(msgDisplay, character, 'normal', idx, translated)}
{@html lastParsed}
{:then md}
{@html md}
{/await}
{/if}
{/key} {/key}
</span> </span>
{/if} {/if}

View File

@@ -5,7 +5,6 @@
import { CharEmotion, ShowVN, selectedCharID } from "../../ts/stores.svelte"; import { CharEmotion, ShowVN, selectedCharID } from "../../ts/stores.svelte";
import ResizeBox from './ResizeBox.svelte' import ResizeBox from './ResizeBox.svelte'
import DefaultChatScreen from "./DefaultChatScreen.svelte"; import DefaultChatScreen from "./DefaultChatScreen.svelte";
import { clearMessageFormCache } from "../../ts/util";
import defaultWallpaper from '../../etc/bg.jpg' import defaultWallpaper from '../../etc/bg.jpg'
import ChatList from "../Others/ChatList.svelte"; import ChatList from "../Others/ChatList.svelte";
import TransitionImage from "./TransitionImage.svelte"; import TransitionImage from "./TransitionImage.svelte";
@@ -15,7 +14,6 @@
import ModuleChatMenu from "../Setting/Pages/Module/ModuleChatMenu.svelte"; import ModuleChatMenu from "../Setting/Pages/Module/ModuleChatMenu.svelte";
let openChatList = $state(false) let openChatList = $state(false)
let openModuleList = $state(false) let openModuleList = $state(false)
let lastCharacterId = $state(-1);
const wallPaper = `background: url(${defaultWallpaper})` const wallPaper = `background: url(${defaultWallpaper})`
const externalStyles = const externalStyles =
@@ -33,25 +31,6 @@
} }
})() })()
}); });
$effect.pre(() => {
if ($selectedCharID !== lastCharacterId) {
if (lastCharacterId >= 0) {
clearMessageFormCache(lastCharacterId);
setTimeout(() => {
if (window.gc) {
try {
window.gc();
} catch (e) {
console.log("GC not available");
}
}
}, 100);
}
lastCharacterId = $selectedCharID;
}
});
</script> </script>
{#if $ShowVN} {#if $ShowVN}

View File

@@ -28,10 +28,6 @@
import { getInlayAsset } from 'src/ts/process/files/inlays'; import { getInlayAsset } from 'src/ts/process/files/inlays';
import PlaygroundMenu from '../Playground/PlaygroundMenu.svelte'; import PlaygroundMenu from '../Playground/PlaygroundMenu.svelte';
import { ConnectionOpenStore } from 'src/ts/sync/multiuser'; import { ConnectionOpenStore } from 'src/ts/sync/multiuser';
import { onMount, onDestroy } from "svelte";
import AutoresizeArea from "../UI/GUI/TextAreaResizable.svelte";
import { alertConfirm, alertClear } from "../../ts/alert";
import { clearMessageFormCache } from "../../ts/util";
let messageInput:string = $state('') let messageInput:string = $state('')
let messageInputTranslate:string = $state('') let messageInputTranslate:string = $state('')
@@ -46,107 +42,6 @@
let toggleStickers:boolean = $state(false) let toggleStickers:boolean = $state(false)
let fileInput:string[] = $state([]) let fileInput:string[] = $state([])
// Virtual scroll related states
let visibleStartIndex = $state(0);
let visibleEndIndex = $state(30);
let chatContainerRef: HTMLElement = $state(null);
let scrollPosition = $state(0);
let isScrolling = $state(false);
let scrollingTimeoutId: number;
// Data loading state
let isInitialLoading = $state(true);
// Function for optimization
function updateVisibleMessages(e?: Event) {
if (!chatContainerRef) return;
const el = chatContainerRef;
const scrollTop = el.scrollTop;
const containerHeight = el.clientHeight;
// Save scroll position
scrollPosition = scrollTop;
// Update scrolling state
isScrolling = true;
clearTimeout(scrollingTimeoutId);
scrollingTimeoutId = window.setTimeout(() => {
isScrolling = false;
}, 200);
// Optimized infinite scroll logic
const scrolled = el.scrollHeight - containerHeight + scrollTop;
if (scrolled < 100 && DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length > loadPages) {
loadPages += 15;
}
// Limit maximum number of messages to display if there are many
if (DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length > 200) {
// Load only the most recent 200 messages in memory
const messageCount = DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length;
visibleStartIndex = Math.max(0, messageCount - loadPages);
visibleEndIndex = messageCount;
} else {
visibleStartIndex = 0;
visibleEndIndex = loadPages;
}
}
// Asynchronous chat data loading function
async function loadChatDataAsync() {
isInitialLoading = true;
// Small delay to allow UI rendering
await new Promise(resolve => setTimeout(resolve, 0));
// Check character change and clear cache
if(lastCharId !== $selectedCharID) {
clearMessageFormCache(lastCharId);
lastCharId = $selectedCharID;
rerolls = [];
rerollid = -1;
}
// Process bulk data loading in background
await new Promise(resolve => setTimeout(resolve, 0));
// Process chat data asynchronously by chunks
const messages = DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message;
if (messages.length > 100) {
// Process large message sets in chunks asynchronously
const chunkSize = 30;
let processedChunks = 0;
for (let i = 0; i < messages.length; i += chunkSize) {
const chunk = messages.slice(i, i + chunkSize);
// Process each chunk
await new Promise(resolve => {
setTimeout(() => {
// Only prepare work here
// Actual rendering will be done later in messageForm
processedChunks++;
resolve(null);
}, 0);
});
// Determine initial load message count based on progress
loadPages = Math.min(messages.length, Math.max(30, processedChunks * chunkSize));
// Show all of the last 30 messages
if (i >= Math.max(0, messages.length - 30)) {
loadPages = messages.length;
}
}
} else {
loadPages = messages.length;
}
isInitialLoading = false;
updateVisibleMessages();
}
async function send(){ async function send(){
return sendMain(false) return sendMain(false)
} }
@@ -523,16 +418,6 @@
$effect.pre(() => { $effect.pre(() => {
currentCharacter = DBState.db.characters[$selectedCharID] currentCharacter = DBState.db.characters[$selectedCharID]
}); });
// Load chat data when character or chat page changes
$effect.pre(() => {
const charId = $selectedCharID;
const chatPage = DBState.db.characters[$selectedCharID]?.chatPage;
if (charId >= 0) {
loadChatDataAsync();
}
});
</script> </script>
<!-- svelte-ignore a11y_click_events_have_key_events --> <!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions --> <!-- svelte-ignore a11y_no_static_element_interactions -->
@@ -546,20 +431,13 @@
<PlaygroundMenu /> <PlaygroundMenu />
{/if} {/if}
{:else} {:else}
<div class="h-full w-full flex flex-col-reverse overflow-y-auto relative default-chat-screen" <div class="h-full w-full flex flex-col-reverse overflow-y-auto relative default-chat-screen" onscroll={(e) => {
bind:this={chatContainerRef} //@ts-ignore
onscroll={updateVisibleMessages}> const scrolled = (e.target.scrollHeight - e.target.clientHeight + e.target.scrollTop)
if(scrolled < 100 && DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length > loadPages){
<!-- Add loading screen --> loadPages += 15
{#if isInitialLoading} }
<div class="absolute inset-0 flex items-center justify-center bg-darkbg bg-opacity-30 z-10"> }}>
<div class="flex flex-col items-center">
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-textcolor"></div>
<p class="text-textcolor mt-4">{language.loading}</p>
</div>
</div>
{/if}
<div class="flex items-stretch mt-2 mb-2 w-full"> <div class="flex items-stretch mt-2 mb-2 w-full">
{#if DBState.db.useChatSticker && currentCharacter.type !== 'group'} {#if DBState.db.useChatSticker && currentCharacter.type !== 'group'}
<div onclick={()=>{toggleStickers = !toggleStickers}} <div onclick={()=>{toggleStickers = !toggleStickers}}
@@ -761,9 +639,7 @@
)} {send}/> )} {send}/>
{/if} {/if}
{#key loadPages}
{#each messageForm(DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message, loadPages) as chat, i} {#each messageForm(DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message, loadPages) as chat, i}
{#if !isScrolling || i < 20}
{#if chat.role === 'char'} {#if chat.role === 'char'}
{#if DBState.db.characters[$selectedCharID].type !== 'group'} {#if DBState.db.characters[$selectedCharID].type !== 'group'}
<Chat <Chat
@@ -806,21 +682,7 @@
messageGenerationInfo={chat.generationInfo} messageGenerationInfo={chat.generationInfo}
/> />
{/if} {/if}
{:else}
<!-- Simplified message placeholder for when scrolling -->
<div class="flex max-w-full justify-center opacity-30">
<div class="text-textcolor mt-1 ml-4 mr-4 mb-1 p-2 bg-transparent flex-grow border-t-gray-900 border-opacity-30 border-transparent flexium items-start max-w-full">
<div class="h-8 w-8 bg-textcolor2 rounded-full opacity-30"></div>
<span class="flex flex-col ml-4 w-full max-w-full min-w-0">
<div class="h-6 w-32 bg-textcolor2 rounded-md opacity-30 mb-2"></div>
<div class="h-4 w-full bg-textcolor2 rounded-md opacity-30"></div>
</span>
</div>
</div>
{/if}
{/each} {/each}
{/key}
{#if DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length <= loadPages} {#if DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length <= loadPages}
{#if DBState.db.characters[$selectedCharID].type !== 'group' } {#if DBState.db.characters[$selectedCharID].type !== 'group' }
<Chat <Chat