Selaa lähdekoodia

feat: chat history db code refac for backend support

Timothy J. Baek 1 vuosi sitten
vanhempi
commit
c7b1fd1cd1

+ 1 - 9
src/lib/components/chat/Messages.svelte

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

+ 12 - 106
src/lib/components/layout/Sidebar.svelte

@@ -21,134 +21,40 @@
 
 	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 () => {
 		if (window.innerWidth > 1280) {
 			show = true;
 		}
 
-		await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
+		await chats.set(await $db.getChats());
 	});
 
 	const loadChat = async (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 chat = await $db.get('chats', id);
-		console.log(chat);
-
-		await $db.put('chats', {
-			...chat,
+		await $db.updateChatById(id, {
 			title: _title
 		});
-
 		title = _title;
-		await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
 	};
 
 	const deleteChat = async (id) => {
 		goto('/');
-
-		const chat = await $db.delete('chats', id);
-		console.log(chat);
-		await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
+		$db.deleteChatById(id);
 	};
 
 	const deleteChatHistory = async () => {
-		const tx = $db.transaction('chats', 'readwrite');
-		await Promise.all([tx.store.clear(), tx.done]);
-		await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
+		await $db.deleteAllChat();
 	};
 
-	const importChatHistory = async (chatHistory) => {
-		for (const chat of 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 importChats = async (chatHistory) => {
+		await $db.addChats(chatHistory);
 	};
 
-	const exportChatHistory = async () => {
-		await chats.set(await $db.getAllFromIndex('chats', 'timestamp'));
-		let blob = new Blob([JSON.stringify($chats)], { type: 'application/json' });
+	const exportChats = async () => {
+		let blob = new Blob([JSON.stringify(await $db.exportChats())], { type: 'application/json' });
 		saveAs(blob, `chat-export-${Date.now()}.json`);
 	};
 
@@ -159,7 +65,7 @@
 		reader.onload = (event) => {
 			let chats = JSON.parse(event.target.result);
 			console.log(chats);
-			importChatHistory(chats);
+			importChats(chats);
 		};
 
 		reader.readAsText(importFiles[0]);
@@ -238,7 +144,7 @@
 		</div>
 
 		<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">
 					<button
 						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"
 						on:click={() => {
 							importFileInputElement.click();
-							// importChatHistory();
+							// importChats();
 						}}
 					>
 						<div class=" self-center mr-3">
@@ -420,7 +326,7 @@
 					<button
 						class=" flex rounded-md py-3 px-3.5 w-full hover:bg-gray-900 transition"
 						on:click={() => {
-							exportChatHistory();
+							exportChats();
 						}}
 					>
 						<div class=" self-center mr-3">

+ 59 - 2
src/routes/(app)/+layout.svelte

@@ -3,7 +3,7 @@
 	import { onMount, tick } from 'svelte';
 	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 Sidebar from '$lib/components/layout/Sidebar.svelte';
@@ -77,7 +77,7 @@
 	};
 
 	const getDB = async () => {
-		return await openDB('Chats', 1, {
+		const _db = await openDB('Chats', 1, {
 			upgrade(db) {
 				const store = db.createObjectStore('chats', {
 					keyPath: 'id',
@@ -86,6 +86,63 @@
 				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 () => {

+ 9 - 23
src/routes/(app)/+page.svelte

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

+ 30 - 38
src/routes/(app)/c/[id]/+page.svelte

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