Browse Source

chat history import/export added

Timothy J. Baek 1 năm trước cách đây
mục cha
commit
d00cc58511
4 tập tin đã thay đổi với 133 bổ sung11 xóa
  1. 11 0
      package-lock.json
  2. 1 0
      package.json
  3. 37 4
      src/lib/components/layout/Navbar.svelte
  4. 84 7
      src/routes/+page.svelte

+ 11 - 0
package-lock.json

@@ -9,6 +9,7 @@
 			"version": "0.0.1",
 			"dependencies": {
 				"@sveltejs/adapter-node": "^1.3.1",
+				"file-saver": "^2.0.5",
 				"highlight.js": "^11.9.0",
 				"idb": "^7.1.1",
 				"marked": "^9.1.0",
@@ -1902,6 +1903,11 @@
 				"node": "^10.12.0 || >=12.0.0"
 			}
 		},
+		"node_modules/file-saver": {
+			"version": "2.0.5",
+			"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
+			"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
+		},
 		"node_modules/fill-range": {
 			"version": "7.0.1",
 			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -5039,6 +5045,11 @@
 				"flat-cache": "^3.0.4"
 			}
 		},
+		"file-saver": {
+			"version": "2.0.5",
+			"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
+			"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
+		},
 		"fill-range": {
 			"version": "7.0.1",
 			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",

+ 1 - 0
package.json

@@ -33,6 +33,7 @@
 	"type": "module",
 	"dependencies": {
 		"@sveltejs/adapter-node": "^1.3.1",
+		"file-saver": "^2.0.5",
 		"highlight.js": "^11.9.0",
 		"idb": "^7.1.1",
 		"marked": "^9.1.0",

+ 37 - 4
src/lib/components/layout/Navbar.svelte

@@ -1,13 +1,34 @@
 <script lang="ts">
+	import { onMount } from 'svelte';
+
 	let show = false;
 	let navElement;
+	let importFileInputElement;
+	let importFiles;
 
 	export let title: string = 'Ollama Web UI';
 	export let chats = [];
 
 	export let createNewChat: Function;
 	export let loadChat: Function;
+	export let importChatHistory: Function;
+	export let exportChatHistory: Function;
 	export let deleteChatHistory: Function;
+
+	onMount(() => {});
+
+	$: if (importFiles) {
+		console.log(importFiles);
+
+		let reader = new FileReader();
+		reader.onload = (event) => {
+			let chats = JSON.parse(event.target.result);
+			console.log(chats);
+			importChatHistory(chats);
+		};
+
+		reader.readAsText(importFiles[0]);
+	}
 </script>
 
 <div
@@ -162,8 +183,15 @@
 			<hr class=" border-gray-800 mb-2 w-full" />
 
 			<div class="flex flex-col">
-				<!-- <div class="flex">
-					<button class=" flex rounded-md p-4 w-full hover:bg-gray-800 transition">
+				<div class="flex">
+					<input bind:this={importFileInputElement} bind:files={importFiles} type="file" hidden />
+					<button
+						class=" flex rounded-md p-4 w-full hover:bg-gray-800 transition"
+						on:click={() => {
+							importFileInputElement.click();
+							// importChatHistory();
+						}}
+					>
 						<div class=" self-center mr-3">
 							<svg
 								xmlns="http://www.w3.org/2000/svg"
@@ -182,7 +210,12 @@
 						</div>
 						<div class=" self-center">Import</div>
 					</button>
-					<button class=" flex rounded-md p-4 w-full hover:bg-gray-800 transition">
+					<button
+						class=" flex rounded-md p-4 w-full hover:bg-gray-800 transition"
+						on:click={() => {
+							exportChatHistory();
+						}}
+					>
 						<div class=" self-center mr-3">
 							<svg
 								xmlns="http://www.w3.org/2000/svg"
@@ -201,7 +234,7 @@
 						</div>
 						<div class=" self-center">Export</div>
 					</button>
-				</div> -->
+				</div>
 				<button
 					class=" flex rounded-md p-4 w-full hover:bg-gray-800 transition"
 					on:click={() => {

+ 84 - 7
src/routes/+page.svelte

@@ -4,6 +4,7 @@
 
 	import { v4 as uuidv4 } from 'uuid';
 	import { marked } from 'marked';
+	import { saveAs } from 'file-saver';
 	import hljs from 'highlight.js';
 	import 'highlight.js/styles/dark.min.css';
 
@@ -12,7 +13,6 @@
 
 	import { openDB, deleteDB } from 'idb';
 	import { ENDPOINT as SERVER_ENDPOINT } from '$lib/contants';
-	import Error from './+error.svelte';
 
 	export let data: PageData;
 	$: ({ models, OLLAMA_ENDPOINT } = data);
@@ -22,8 +22,8 @@
 	let db;
 
 	let selectedModel = '';
-	let systemPrompt = '';
-	let temperature = '';
+	let system = null;
+	let temperature = null;
 
 	let chats = [];
 	let chatId = uuidv4();
@@ -43,8 +43,8 @@
 			console.log(settings);
 
 			selectedModel = settings.model ?? '';
-			systemPrompt = settings.systemPrompt ?? '';
-			temperature = settings.temperature ?? '';
+			system = settings.system ?? null;
+			temperature = settings.temperature ?? null;
 		}
 
 		db = await openDB('Chats', 1, {
@@ -135,9 +135,21 @@
 
 	const createNewChat = () => {
 		if (messages.length > 0) {
+			chatId = uuidv4();
+
 			messages = [];
 			title = '';
-			chatId = uuidv4();
+			console.log(localStorage.settings.model);
+
+			let settings = localStorage.getItem('settings');
+			if (settings) {
+				settings = JSON.parse(settings);
+				console.log(settings);
+
+				selectedModel = settings.model ?? selectedModel;
+				system = settings.system ?? system;
+				temperature = settings.temperature ?? temperature;
+			}
 		}
 	};
 
@@ -146,6 +158,9 @@
 		messages = chat.messages;
 		title = chat.title;
 		chatId = chat.id;
+		selectedModel = chat.model ?? selectedModel;
+		system = chat.system ?? system;
+		temperature = chat.temperature ?? temperature;
 	};
 
 	const deleteChatHistory = async () => {
@@ -154,6 +169,31 @@
 		chats = await db.getAllFromIndex('chats', 'timestamp');
 	};
 
+	const importChatHistory = async (results) => {
+		for (const chat of results) {
+			console.log(chat);
+
+			await db.put('chats', {
+				id: chat.id,
+				model: chat.model,
+				system: chat.system,
+				options: chat.options,
+				title: chat.title,
+				timestamp: chat.timestamp,
+				messages: chat.messages
+			});
+		}
+		chats = await db.getAllFromIndex('chats', 'timestamp');
+
+		console.log(chats);
+	};
+
+	const exportChatHistory = async () => {
+		chats = await db.getAllFromIndex('chats', 'timestamp');
+		let blob = new Blob([JSON.stringify(chats)], { type: 'application/json' });
+		saveAs(blob, `chat-export-${Date.now()}.json`);
+	};
+
 	//////////////////////////
 	// Ollama functions
 	//////////////////////////
@@ -169,6 +209,11 @@
 			if (messages.length == 0) {
 				await db.put('chats', {
 					id: chatId,
+					model: selectedModel,
+					system: system,
+					options: {
+						temperature: temperature
+					},
 					title: 'New Chat',
 					timestamp: Date.now(),
 					messages: messages
@@ -205,6 +250,13 @@
 				body: JSON.stringify({
 					model: selectedModel,
 					prompt: user_prompt,
+					system: system ?? undefined,
+					options:
+						temperature != null
+							? {
+									temperature: temperature
+							  }
+							: undefined,
 					context:
 						messages.length > 3 && messages.at(-3).context != undefined
 							? messages.at(-3).context
@@ -257,6 +309,11 @@
 			await db.put('chats', {
 				id: chatId,
 				title: title,
+				model: selectedModel,
+				system: system,
+				options: {
+					temperature: temperature
+				},
 				timestamp: Date.now(),
 				messages: messages
 			});
@@ -289,6 +346,13 @@
 				body: JSON.stringify({
 					model: selectedModel,
 					prompt: lastUserMessage.content,
+					system: system ?? undefined,
+					options:
+						temperature != null
+							? {
+									temperature: temperature
+							  }
+							: undefined,
 					context:
 						messages.length > 3 && messages.at(-3).context != undefined
 							? messages.at(-3).context
@@ -337,6 +401,11 @@
 			await db.put('chats', {
 				id: chatId,
 				title: title,
+				model: selectedModel,
+				system: system,
+				options: {
+					temperature: temperature
+				},
 				timestamp: Date.now(),
 				messages: messages
 			});
@@ -378,7 +447,15 @@
 
 <div class="app text-gray-100">
 	<div class=" bg-gray-800 min-h-screen overflow-auto flex flex-row">
-		<Navbar {chats} {title} {loadChat} {createNewChat} {deleteChatHistory} />
+		<Navbar
+			{chats}
+			{title}
+			{loadChat}
+			{createNewChat}
+			{importChatHistory}
+			{exportChatHistory}
+			{deleteChatHistory}
+		/>
 
 		<div class="min-h-screen w-full flex justify-center">
 			<div class=" py-2.5 flex flex-col justify-between w-full">