mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2025-11-10 10:27:03 +00:00
* init version * fix auto scroll * bring back copy btn * bring back thought process * add lint and format check on CI * remove lang from html tag * allow multiple generations at the same time * lint and format combined * fix unused var * improve MarkdownDisplay * fix more latex * fix code block cannot be selected while generating
139 lines
3.9 KiB
TypeScript
139 lines
3.9 KiB
TypeScript
// coversations is stored in localStorage
|
|
// format: { [convId]: { id: string, lastModified: number, messages: [...] } }
|
|
|
|
import { CONFIG_DEFAULT } from '../Config';
|
|
import { Conversation, Message } from './types';
|
|
|
|
const event = new EventTarget();
|
|
|
|
type CallbackConversationChanged = (convId: string) => void;
|
|
let onConversationChangedHandlers: [
|
|
CallbackConversationChanged,
|
|
EventListener,
|
|
][] = [];
|
|
const dispatchConversationChange = (convId: string) => {
|
|
event.dispatchEvent(
|
|
new CustomEvent('conversationChange', { detail: { convId } })
|
|
);
|
|
};
|
|
|
|
// convId is a string prefixed with 'conv-'
|
|
const StorageUtils = {
|
|
/**
|
|
* manage conversations
|
|
*/
|
|
getAllConversations(): Conversation[] {
|
|
const res = [];
|
|
for (const key in localStorage) {
|
|
if (key.startsWith('conv-')) {
|
|
res.push(JSON.parse(localStorage.getItem(key) ?? '{}'));
|
|
}
|
|
}
|
|
res.sort((a, b) => b.lastModified - a.lastModified);
|
|
return res;
|
|
},
|
|
/**
|
|
* can return null if convId does not exist
|
|
*/
|
|
getOneConversation(convId: string): Conversation | null {
|
|
return JSON.parse(localStorage.getItem(convId) || 'null');
|
|
},
|
|
/**
|
|
* if convId does not exist, create one
|
|
*/
|
|
appendMsg(convId: string, msg: Message): void {
|
|
if (msg.content === null) return;
|
|
const conv = StorageUtils.getOneConversation(convId) || {
|
|
id: convId,
|
|
lastModified: Date.now(),
|
|
messages: [],
|
|
};
|
|
conv.messages.push(msg);
|
|
conv.lastModified = Date.now();
|
|
localStorage.setItem(convId, JSON.stringify(conv));
|
|
dispatchConversationChange(convId);
|
|
},
|
|
/**
|
|
* Get new conversation id
|
|
*/
|
|
getNewConvId(): string {
|
|
return `conv-${Date.now()}`;
|
|
},
|
|
/**
|
|
* remove conversation by id
|
|
*/
|
|
remove(convId: string): void {
|
|
localStorage.removeItem(convId);
|
|
dispatchConversationChange(convId);
|
|
},
|
|
/**
|
|
* remove all conversations
|
|
*/
|
|
filterAndKeepMsgs(
|
|
convId: string,
|
|
predicate: (msg: Message) => boolean
|
|
): void {
|
|
const conv = StorageUtils.getOneConversation(convId);
|
|
if (!conv) return;
|
|
conv.messages = conv.messages.filter(predicate);
|
|
conv.lastModified = Date.now();
|
|
localStorage.setItem(convId, JSON.stringify(conv));
|
|
dispatchConversationChange(convId);
|
|
},
|
|
/**
|
|
* remove last message from conversation
|
|
*/
|
|
popMsg(convId: string): Message | undefined {
|
|
const conv = StorageUtils.getOneConversation(convId);
|
|
if (!conv) return;
|
|
const msg = conv.messages.pop();
|
|
conv.lastModified = Date.now();
|
|
if (conv.messages.length === 0) {
|
|
StorageUtils.remove(convId);
|
|
} else {
|
|
localStorage.setItem(convId, JSON.stringify(conv));
|
|
}
|
|
dispatchConversationChange(convId);
|
|
return msg;
|
|
},
|
|
|
|
// event listeners
|
|
onConversationChanged(callback: CallbackConversationChanged) {
|
|
const fn = (e: Event) => callback((e as CustomEvent).detail.convId);
|
|
onConversationChangedHandlers.push([callback, fn]);
|
|
event.addEventListener('conversationChange', fn);
|
|
},
|
|
offConversationChanged(callback: CallbackConversationChanged) {
|
|
const fn = onConversationChangedHandlers.find(([cb, _]) => cb === callback);
|
|
if (fn) {
|
|
event.removeEventListener('conversationChange', fn[1]);
|
|
}
|
|
onConversationChangedHandlers = [];
|
|
},
|
|
|
|
// manage config
|
|
getConfig(): typeof CONFIG_DEFAULT {
|
|
const savedVal = JSON.parse(localStorage.getItem('config') || '{}');
|
|
// to prevent breaking changes in the future, we always provide default value for missing keys
|
|
return {
|
|
...CONFIG_DEFAULT,
|
|
...savedVal,
|
|
};
|
|
},
|
|
setConfig(config: typeof CONFIG_DEFAULT) {
|
|
localStorage.setItem('config', JSON.stringify(config));
|
|
},
|
|
getTheme(): string {
|
|
return localStorage.getItem('theme') || 'auto';
|
|
},
|
|
setTheme(theme: string) {
|
|
if (theme === 'auto') {
|
|
localStorage.removeItem('theme');
|
|
} else {
|
|
localStorage.setItem('theme', theme);
|
|
}
|
|
},
|
|
};
|
|
|
|
export default StorageUtils;
|