Optimize chat rendering and performance with caching and lazy loading (#773)

# PR Checklist
- [ ] Have you checked if it works normally in all models? *Ignore this
if it doesn't use models.*
- [x] Have you checked if it works normally in all web, local, and node
hosted versions? If it doesn't, have you blocked it in those versions?
- [x] Have you added type definitions?

# Description
Enhance chat application efficiency by implementing caching for markdown
parsing and message forms, along with lazy loading and virtual scrolling
for improved performance in large chat histories. Introduce a cleanup
mechanism for cache management.
This commit is contained in:
kwaroran
2025-03-05 05:39:00 +09:00
committed by GitHub
4 changed files with 305 additions and 60 deletions

View File

@@ -16,26 +16,70 @@ export interface Messagec extends Message{
index: number
}
// Map to store message caches for each character
const messageFormCacheMap = new Map<number, Map<string, Messagec>>();
// Function to initialize the cache (called when changing characters)
export function clearMessageFormCache(charId?: number) {
if (charId !== undefined) {
messageFormCacheMap.delete(charId);
} else {
messageFormCacheMap.clear();
}
}
export function messageForm(arg:Message[], loadPages:number){
let db = getDatabase()
let selectedChar = get(selectedCharID)
// Map for message caching (maintained as a static variable)
const messageCache = messageFormCacheMap.get(selectedChar) || new Map<string, Messagec>();
function reformatContent(data:string){
return data.trim()
}
let a:Messagec[] = []
for(let i=0;i<arg.length;i++){
const m = arg[i]
a.unshift({
const startIndex = Math.max(0, arg.length - loadPages);
// Process only necessary messages (up to loadPages)
for(let i = arg.length - 1; i >= startIndex; i--){
const m = arg[i];
const cacheKey = `${m.role}-${i}-${m.chatId || 'none'}-${m.data.length}`;
// Use cached result if available
if (messageCache.has(cacheKey)) {
a.push(messageCache.get(cacheKey));
continue;
}
// Create new if not cached
const processed: Messagec = {
role: m.role,
data: reformatContent(m.data),
index: i,
saying: m.saying,
chatId: m.chatId ?? 'none',
generationInfo: m.generationInfo,
})
};
// Store in cache
messageCache.set(cacheKey, processed);
a.push(processed);
}
return a.slice(0, loadPages)
// Update cache map
messageFormCacheMap.set(selectedChar, messageCache);
// Limit cache size (maximum 1000 entries)
if (messageCache.size > 1000) {
const keys = Array.from(messageCache.keys());
for (let i = 0; i < keys.length - 1000; i++) {
messageCache.delete(keys[i]);
}
}
return a;
}
export function sleep(ms: number) {