feat: chat history db code refac for backend support

This commit is contained in:
Timothy J. Baek 2023-11-21 09:39:11 -08:00
parent 14fb5a9b5c
commit c7b1fd1cd1
5 changed files with 111 additions and 178 deletions

View file

@ -20,7 +20,6 @@
export let messages = []; export let messages = [];
$: if (messages && messages.length > 0 && (messages.at(-1).done ?? false)) { $: if (messages && messages.length > 0 && (messages.at(-1).done ?? false)) {
console.log('message done: rendering');
(async () => { (async () => {
await tick(); await tick();
renderLatex(); renderLatex();
@ -32,7 +31,6 @@
const createCopyCodeBlockButton = () => { const createCopyCodeBlockButton = () => {
// use a class selector if available // use a class selector if available
let blocks = document.querySelectorAll('pre'); let blocks = document.querySelectorAll('pre');
console.log(blocks);
blocks.forEach((block) => { blocks.forEach((block) => {
// only add button if browser supports Clipboard API // only add button if browser supports Clipboard API
@ -195,8 +193,6 @@
}; };
const rateMessage = async (messageIdx, rating) => { const rateMessage = async (messageIdx, rating) => {
const chat = await $db.get('chats', chatId);
messages = messages.map((message, idx) => { messages = messages.map((message, idx) => {
if (messageIdx === idx) { if (messageIdx === idx) {
message.rating = rating; message.rating = rating;
@ -204,14 +200,10 @@
return message; return message;
}); });
await $db.put('chats', { $db.updateChatById(chatId, {
...chat,
timestamp: Date.now(),
messages: messages, messages: messages,
history: history history: history
}); });
console.log(messages);
}; };
const showPreviousMessage = async (message) => { const showPreviousMessage = async (message) => {

View file

@ -21,134 +21,40 @@
let showDropdown = false; let showDropdown = false;
let _chats = $chats.map((item, idx) => $chats[$chats.length - 1 - idx]);
$: if ($chats) {
// Reverse Order
_chats = $chats.map((item, idx) => $chats[$chats.length - 1 - idx]);
}
onMount(async () => { onMount(async () => {
if (window.innerWidth > 1280) { if (window.innerWidth > 1280) {
show = true; show = true;
} }
await chats.set(await $db.getAllFromIndex('chats', 'timestamp')); await chats.set(await $db.getChats());
}); });
const loadChat = async (id) => { const loadChat = async (id) => {
goto(`/c/${id}`); goto(`/c/${id}`);
// const chat = await db.get('chats', id);
// console.log(chat);
// if (chatId !== chat.id) {
// if ('history' in chat && chat.history !== undefined) {
// history = chat.history;
// } else {
// let _history = {
// messages: {},
// currentId: null
// };
// let parentMessageId = null;
// let messageId = null;
// for (const message of chat.messages) {
// messageId = uuidv4();
// if (parentMessageId !== null) {
// _history.messages[parentMessageId].childrenIds = [
// ..._history.messages[parentMessageId].childrenIds,
// messageId
// ];
// }
// _history.messages[messageId] = {
// ...message,
// id: messageId,
// parentId: parentMessageId,
// childrenIds: []
// };
// parentMessageId = messageId;
// }
// _history.currentId = messageId;
// history = _history;
// }
// if ('models' in chat && chat.models !== undefined) {
// selectedModels = chat.models ?? selectedModels;
// } else {
// selectedModels = [chat.model ?? ''];
// }
// console.log(history);
// title = chat.title;
// chatId = chat.id;
// settings.system = chat.system ?? settings.system;
// settings.temperature = chat.temperature ?? settings.temperature;
// autoScroll = true;
// await tick();
// if (messages.length > 0) {
// history.messages[messages.at(-1).id].done = true;
// }
// }
}; };
const editChatTitle = async (id, _title) => { const editChatTitle = async (id, _title) => {
const chat = await $db.get('chats', id); await $db.updateChatById(id, {
console.log(chat);
await $db.put('chats', {
...chat,
title: _title title: _title
}); });
title = _title; title = _title;
await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
}; };
const deleteChat = async (id) => { const deleteChat = async (id) => {
goto('/'); goto('/');
$db.deleteChatById(id);
const chat = await $db.delete('chats', id);
console.log(chat);
await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
}; };
const deleteChatHistory = async () => { const deleteChatHistory = async () => {
const tx = $db.transaction('chats', 'readwrite'); await $db.deleteAllChat();
await Promise.all([tx.store.clear(), tx.done]);
await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
}; };
const importChatHistory = async (chatHistory) => { const importChats = async (chatHistory) => {
for (const chat of chatHistory) { await $db.addChats(chatHistory);
console.log(chat);
await $db.put('chats', {
id: chat.id,
model: chat.model,
models: chat.models,
system: chat.system,
options: chat.options,
title: chat.title,
timestamp: chat.timestamp,
messages: chat.messages,
history: chat.history
});
}
await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
console.log(chats);
}; };
const exportChatHistory = async () => { const exportChats = async () => {
await chats.set(await $db.getAllFromIndex('chats', 'timestamp')); let blob = new Blob([JSON.stringify(await $db.exportChats())], { type: 'application/json' });
let blob = new Blob([JSON.stringify($chats)], { type: 'application/json' });
saveAs(blob, `chat-export-${Date.now()}.json`); saveAs(blob, `chat-export-${Date.now()}.json`);
}; };
@ -159,7 +65,7 @@
reader.onload = (event) => { reader.onload = (event) => {
let chats = JSON.parse(event.target.result); let chats = JSON.parse(event.target.result);
console.log(chats); console.log(chats);
importChatHistory(chats); importChats(chats);
}; };
reader.readAsText(importFiles[0]); reader.readAsText(importFiles[0]);
@ -238,7 +144,7 @@
</div> </div>
<div class="pl-2.5 my-3 flex-1 flex flex-col space-y-1 overflow-y-auto"> <div class="pl-2.5 my-3 flex-1 flex flex-col space-y-1 overflow-y-auto">
{#each _chats as chat, i} {#each $chats as chat, i}
<div class=" w-full pr-2 relative"> <div class=" w-full pr-2 relative">
<button <button
class=" w-full flex justify-between rounded-md px-3 py-2 hover:bg-gray-900 {chat.id === class=" w-full flex justify-between rounded-md px-3 py-2 hover:bg-gray-900 {chat.id ===
@ -396,7 +302,7 @@
class=" flex rounded-md py-3 px-3.5 w-full hover:bg-gray-900 transition" class=" flex rounded-md py-3 px-3.5 w-full hover:bg-gray-900 transition"
on:click={() => { on:click={() => {
importFileInputElement.click(); importFileInputElement.click();
// importChatHistory(); // importChats();
}} }}
> >
<div class=" self-center mr-3"> <div class=" self-center mr-3">
@ -420,7 +326,7 @@
<button <button
class=" flex rounded-md py-3 px-3.5 w-full hover:bg-gray-900 transition" class=" flex rounded-md py-3 px-3.5 w-full hover:bg-gray-900 transition"
on:click={() => { on:click={() => {
exportChatHistory(); exportChats();
}} }}
> >
<div class=" self-center mr-3"> <div class=" self-center mr-3">

View file

@ -3,7 +3,7 @@
import { onMount, tick } from 'svelte'; import { onMount, tick } from 'svelte';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { config, user, showSettings, settings, models, db } from '$lib/stores'; import { config, user, showSettings, settings, models, db, chats } from '$lib/stores';
import SettingsModal from '$lib/components/chat/SettingsModal.svelte'; import SettingsModal from '$lib/components/chat/SettingsModal.svelte';
import Sidebar from '$lib/components/layout/Sidebar.svelte'; import Sidebar from '$lib/components/layout/Sidebar.svelte';
@ -77,7 +77,7 @@
}; };
const getDB = async () => { const getDB = async () => {
return await openDB('Chats', 1, { const _db = await openDB('Chats', 1, {
upgrade(db) { upgrade(db) {
const store = db.createObjectStore('chats', { const store = db.createObjectStore('chats', {
keyPath: 'id', keyPath: 'id',
@ -86,6 +86,63 @@
store.createIndex('timestamp', 'timestamp'); store.createIndex('timestamp', 'timestamp');
} }
}); });
return {
db: _db,
getChatById: async function (id) {
return await this.db.get('chats', id);
},
getChats: async function () {
let chats = await this.db.getAllFromIndex('chats', 'timestamp');
chats = chats.map((item, idx) => ({
title: chats[chats.length - 1 - idx].title,
id: chats[chats.length - 1 - idx].id
}));
return chats;
},
exportChats: async function () {
let chats = await this.db.getAllFromIndex('chats', 'timestamp');
chats = chats.map((item, idx) => chats[chats.length - 1 - idx]);
return chats;
},
addChats: async function (_chats) {
for (const chat of _chats) {
console.log(chat);
await this.addChat(chat);
}
await chats.set(await this.db.getChats());
},
addChat: async function (chat) {
await this.db.put('chats', {
...chat
});
},
createNewChat: async function (chat) {
await this.addChat({ ...chat, timestamp: Date.now() });
await chats.set(await this.db.getChats());
},
updateChatById: async function (id, updated) {
const chat = await this.getChatById(id);
await this.db.put('chats', {
...chat,
...updated,
timestamp: Date.now()
});
await chats.set(await this.db.getChats());
},
deleteChatById: async function (id) {
await this.db.delete('chats', id);
await chats.set(await this.db.getChats());
},
deleteAllChat: async function () {
const tx = this.db.transaction('chats', 'readwrite');
await Promise.all([tx.store.clear(), tx.done]);
await chats.set(await this.db.getChats());
}
};
}; };
onMount(async () => { onMount(async () => {

View file

@ -71,8 +71,6 @@
////////////////////////// //////////////////////////
const sendPrompt = async (userPrompt, parentId) => { const sendPrompt = async (userPrompt, parentId) => {
await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
await Promise.all( await Promise.all(
selectedModels.map(async (model) => { selectedModels.map(async (model) => {
if (model.includes('gpt-')) { if (model.includes('gpt-')) {
@ -83,9 +81,7 @@
}) })
); );
await chats.set(await $db.getAllFromIndex('chats', 'timestamp')); await chats.set(await $db.getChats());
console.log(history);
}; };
const sendPromptOllama = async (model, userPrompt, parentId) => { const sendPromptOllama = async (model, userPrompt, parentId) => {
@ -189,8 +185,7 @@
window.scrollTo({ top: document.body.scrollHeight }); window.scrollTo({ top: document.body.scrollHeight });
} }
await $db.put('chats', { await $db.updateChatById($chatId, {
id: $chatId,
title: title === '' ? 'New Chat' : title, title: title === '' ? 'New Chat' : title,
models: selectedModels, models: selectedModels,
system: $settings.system ?? undefined, system: $settings.system ?? undefined,
@ -202,8 +197,7 @@
top_p: $settings.top_p ?? undefined top_p: $settings.top_p ?? undefined
}, },
messages: messages, messages: messages,
history: history, history: history
timestamp: Date.now()
}); });
} }
@ -316,11 +310,9 @@
window.scrollTo({ top: document.body.scrollHeight }); window.scrollTo({ top: document.body.scrollHeight });
} }
await $db.put('chats', { await $db.updateChatById($chatId, {
id: $chatId,
title: title === '' ? 'New Chat' : title, title: title === '' ? 'New Chat' : title,
models: selectedModels, models: selectedModels,
system: $settings.system ?? undefined, system: $settings.system ?? undefined,
options: { options: {
seed: $settings.seed ?? undefined, seed: $settings.seed ?? undefined,
@ -330,8 +322,7 @@
top_p: $settings.top_p ?? undefined top_p: $settings.top_p ?? undefined
}, },
messages: messages, messages: messages,
history: history, history: history
timestamp: Date.now()
}); });
} }
@ -344,7 +335,6 @@
if (messages.length == 2) { if (messages.length == 2) {
window.history.replaceState(history.state, '', `/c/${$chatId}`); window.history.replaceState(history.state, '', `/c/${$chatId}`);
await setChatTitle($chatId, userPrompt); await setChatTitle($chatId, userPrompt);
} }
} }
@ -362,7 +352,6 @@
document.getElementById('chat-textarea').style.height = ''; document.getElementById('chat-textarea').style.height = '';
let userMessageId = uuidv4(); let userMessageId = uuidv4();
let userMessage = { let userMessage = {
id: userMessageId, id: userMessageId,
parentId: messages.length !== 0 ? messages.at(-1).id : null, parentId: messages.length !== 0 ? messages.at(-1).id : null,
@ -381,7 +370,7 @@
prompt = ''; prompt = '';
if (messages.length == 0) { if (messages.length == 0) {
await $db.put('chats', { await $db.createNewChat({
id: $chatId, id: $chatId,
title: 'New Chat', title: 'New Chat',
models: selectedModels, models: selectedModels,
@ -394,8 +383,7 @@
top_p: $settings.top_p ?? undefined top_p: $settings.top_p ?? undefined
}, },
messages: messages, messages: messages,
history: history, history: history
timestamp: Date.now()
}); });
} }
@ -459,9 +447,8 @@
}; };
const setChatTitle = async (_chatId, _title) => { const setChatTitle = async (_chatId, _title) => {
const chat = await $db.get('chats', _chatId); await $db.updateChatById(_chatId, { title: _title });
await $db.put('chats', { ...chat, title: _title }); if (_chatId === $chatId) {
if (chat.id === $chatId) {
title = _title; title = _title;
} }
}; };
@ -469,7 +456,6 @@
<svelte:window <svelte:window
on:scroll={(e) => { on:scroll={(e) => {
console.log(e);
autoScroll = window.innerHeight + window.scrollY >= document.body.offsetHeight - 40; autoScroll = window.innerHeight + window.scrollY >= document.body.offsetHeight - 40;
}} }}
/> />

View file

@ -42,21 +42,27 @@
messages = _messages; messages = _messages;
} }
onMount(async () => { // onMount(async () => {
let chat = await loadChat(); // let chat = await loadChat();
await tick(); // await tick();
if (chat) { // if (chat) {
loaded = true; // loaded = true;
} else { // } else {
await goto('/'); // await goto('/');
} // }
}); // });
$: if ($page.params.id) { $: if ($page.params.id) {
console.log($page.params.id);
(async () => { (async () => {
await loadChat(); let chat = await loadChat();
await tick();
if (chat) {
loaded = true;
} else {
await goto('/');
}
})(); })();
} }
@ -66,7 +72,7 @@
const loadChat = async () => { const loadChat = async () => {
await chatId.set($page.params.id); await chatId.set($page.params.id);
const chat = await $db.get('chats', $chatId); const chat = await $db.getChatById($chatId);
if (chat) { if (chat) {
console.log(chat); console.log(chat);
@ -76,10 +82,8 @@
(chat?.history ?? undefined) !== undefined (chat?.history ?? undefined) !== undefined
? chat.history ? chat.history
: convertMessagesToHistory(chat.messages); : convertMessagesToHistory(chat.messages);
console.log(history);
title = chat.title; title = chat.title;
await settings.set({ await settings.set({
...$settings, ...$settings,
system: chat.system ?? $settings.system, system: chat.system ?? $settings.system,
@ -104,8 +108,6 @@
////////////////////////// //////////////////////////
const sendPrompt = async (userPrompt, parentId) => { const sendPrompt = async (userPrompt, parentId) => {
await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
await Promise.all( await Promise.all(
selectedModels.map(async (model) => { selectedModels.map(async (model) => {
if (model.includes('gpt-')) { if (model.includes('gpt-')) {
@ -116,9 +118,7 @@
}) })
); );
await chats.set(await $db.getAllFromIndex('chats', 'timestamp')); await chats.set(await $db.getChats());
console.log(history);
}; };
const sendPromptOllama = async (model, userPrompt, parentId) => { const sendPromptOllama = async (model, userPrompt, parentId) => {
@ -222,8 +222,7 @@
window.scrollTo({ top: document.body.scrollHeight }); window.scrollTo({ top: document.body.scrollHeight });
} }
await $db.put('chats', { await $db.updateChatById($chatId, {
id: $chatId,
title: title === '' ? 'New Chat' : title, title: title === '' ? 'New Chat' : title,
models: selectedModels, models: selectedModels,
system: $settings.system ?? undefined, system: $settings.system ?? undefined,
@ -235,8 +234,7 @@
top_p: $settings.top_p ?? undefined top_p: $settings.top_p ?? undefined
}, },
messages: messages, messages: messages,
history: history, history: history
timestamp: Date.now()
}); });
} }
@ -247,6 +245,7 @@
} }
if (messages.length == 2 && messages.at(1).content !== '') { if (messages.length == 2 && messages.at(1).content !== '') {
window.history.replaceState(history.state, '', `/c/${$chatId}`);
await generateChatTitle($chatId, userPrompt); await generateChatTitle($chatId, userPrompt);
} }
}; };
@ -348,11 +347,9 @@
window.scrollTo({ top: document.body.scrollHeight }); window.scrollTo({ top: document.body.scrollHeight });
} }
await $db.put('chats', { await $db.updateChatById($chatId, {
id: $chatId,
title: title === '' ? 'New Chat' : title, title: title === '' ? 'New Chat' : title,
models: selectedModels, models: selectedModels,
system: $settings.system ?? undefined, system: $settings.system ?? undefined,
options: { options: {
seed: $settings.seed ?? undefined, seed: $settings.seed ?? undefined,
@ -362,8 +359,7 @@
top_p: $settings.top_p ?? undefined top_p: $settings.top_p ?? undefined
}, },
messages: messages, messages: messages,
history: history, history: history
timestamp: Date.now()
}); });
} }
@ -375,6 +371,7 @@
} }
if (messages.length == 2) { if (messages.length == 2) {
window.history.replaceState(history.state, '', `/c/${$chatId}`);
await setChatTitle($chatId, userPrompt); await setChatTitle($chatId, userPrompt);
} }
} }
@ -392,7 +389,6 @@
document.getElementById('chat-textarea').style.height = ''; document.getElementById('chat-textarea').style.height = '';
let userMessageId = uuidv4(); let userMessageId = uuidv4();
let userMessage = { let userMessage = {
id: userMessageId, id: userMessageId,
parentId: messages.length !== 0 ? messages.at(-1).id : null, parentId: messages.length !== 0 ? messages.at(-1).id : null,
@ -411,7 +407,7 @@
prompt = ''; prompt = '';
if (messages.length == 0) { if (messages.length == 0) {
await $db.put('chats', { await $db.createNewChat({
id: $chatId, id: $chatId,
title: 'New Chat', title: 'New Chat',
models: selectedModels, models: selectedModels,
@ -424,8 +420,7 @@
top_p: $settings.top_p ?? undefined top_p: $settings.top_p ?? undefined
}, },
messages: messages, messages: messages,
history: history, history: history
timestamp: Date.now()
}); });
} }
@ -489,9 +484,8 @@
}; };
const setChatTitle = async (_chatId, _title) => { const setChatTitle = async (_chatId, _title) => {
const chat = await $db.get('chats', _chatId); await $db.updateChatById(_chatId, { title: _title });
await $db.put('chats', { ...chat, title: _title }); if (_chatId === $chatId) {
if (chat.id === $chatId) {
title = _title; title = _title;
} }
}; };
@ -499,8 +493,6 @@
<svelte:window <svelte:window
on:scroll={(e) => { on:scroll={(e) => {
console.log(e);
autoScroll = window.innerHeight + window.scrollY >= document.body.offsetHeight - 40; autoScroll = window.innerHeight + window.scrollY >= document.body.offsetHeight - 40;
}} }}
/> />