From 5b882f4e1372da91ab85549bc2b6d623370a5935 Mon Sep 17 00:00:00 2001
From: overcuriousity <anonauth@posteo.org>
Date: Thu, 18 Jul 2024 21:54:02 +0200
Subject: [PATCH] added persistent storage for the settings

---
 src/db/schema.ts                 | 11 +++++++++
 src/routes/index.ts              |  2 ++
 src/routes/settings.ts           | 38 ++++++++++++++++++++++++++++++++
 ui/components/ChatWindow.tsx     | 24 ++++++++++++++++++++
 ui/components/SettingsDialog.tsx | 24 +++++++++++---------
 5 files changed, 89 insertions(+), 10 deletions(-)
 create mode 100644 src/routes/settings.ts

diff --git a/src/db/schema.ts b/src/db/schema.ts
index 9eefa55..094852d 100644
--- a/src/db/schema.ts
+++ b/src/db/schema.ts
@@ -17,3 +17,14 @@ export const chats = sqliteTable('chats', {
   createdAt: text('createdAt').notNull(),
   focusMode: text('focusMode').notNull(),
 });
+
+export const settings = sqliteTable('settings', {
+  id: integer('id').primaryKey(),
+  chatModelProvider: text('chatModelProvider'),
+  chatModel: text('chatModel'),
+  embeddingModelProvider: text('embeddingModelProvider'),
+  embeddingModel: text('embeddingModel'),
+  openAIApiKey: text('openAIApiKey'),
+  openAIBaseURL: text('openAIBaseURL'),
+  // TODO: add user auth
+});
\ No newline at end of file
diff --git a/src/routes/index.ts b/src/routes/index.ts
index af928ab..a9a0264 100644
--- a/src/routes/index.ts
+++ b/src/routes/index.ts
@@ -5,6 +5,7 @@ import configRouter from './config';
 import modelsRouter from './models';
 import suggestionsRouter from './suggestions';
 import chatsRouter from './chats';
+import settingsRouter from './settings';
 
 const router = express.Router();
 
@@ -14,5 +15,6 @@ router.use('/config', configRouter);
 router.use('/models', modelsRouter);
 router.use('/suggestions', suggestionsRouter);
 router.use('/chats', chatsRouter);
+router.use('/settings', settingsRouter);
 
 export default router;
diff --git a/src/routes/settings.ts b/src/routes/settings.ts
new file mode 100644
index 0000000..4fc5967
--- /dev/null
+++ b/src/routes/settings.ts
@@ -0,0 +1,38 @@
+import express from 'express';
+import db from '../db';
+import { settings } from '../db/schema';
+
+const router = express.Router();
+
+router.post('/', async (req, res) => {
+  try {
+    const { chatModelProvider, chatModel, embeddingModelProvider, embeddingModel, openAIApiKey, openAIBaseURL } = req.body;
+    
+    // TODO: Add user authentication
+    
+    await db.insert(settings).values({
+      chatModelProvider,
+      chatModel,
+      embeddingModelProvider,
+      embeddingModel,
+      openAIApiKey,
+      openAIBaseURL,
+    }).execute();
+
+    res.status(200).json({ message: 'Settings saved successfully' });
+  } catch (err) {
+    res.status(500).json({ message: 'An error occurred while saving settings' });
+  }
+});
+
+router.get('/', async (req, res) => {
+  try {
+    // TODO: Add user authentication
+    const userSettings = await db.query.settings.findFirst();
+    res.status(200).json(userSettings);
+  } catch (err) {
+    res.status(500).json({ message: 'An error occurred while fetching settings' });
+  }
+});
+
+export default router;
\ No newline at end of file
diff --git a/ui/components/ChatWindow.tsx b/ui/components/ChatWindow.tsx
index f2c89a3..a0415e0 100644
--- a/ui/components/ChatWindow.tsx
+++ b/ui/components/ChatWindow.tsx
@@ -21,6 +21,25 @@ export type Message = {
   sources?: Document[];
 };
 
+
+const fetchSettings = async () => {
+  try {
+    const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/settings`);
+    const settings = await res.json();
+    
+    if (settings) {
+      localStorage.setItem('chatModelProvider', settings.chatModelProvider);
+      localStorage.setItem('chatModel', settings.chatModel);
+      localStorage.setItem('embeddingModelProvider', settings.embeddingModelProvider);
+      localStorage.setItem('embeddingModel', settings.embeddingModel);
+      localStorage.setItem('openAIApiKey', settings.openAIApiKey);
+      localStorage.setItem('openAIBaseURL', settings.openAIBaseURL);
+    }
+  } catch (err) {
+    console.error('Failed to fetch settings:', err);
+  }
+};
+
 const useSocket = (
   url: string,
   setIsWSReady: (ready: boolean) => void,
@@ -31,6 +50,8 @@ const useSocket = (
   useEffect(() => {
     if (!ws) {
       const connectWs = async () => {
+        await fetchSettings();
+
         let chatModel = localStorage.getItem('chatModel');
         let chatModelProvider = localStorage.getItem('chatModelProvider');
         let embeddingModel = localStorage.getItem('embeddingModel');
@@ -306,6 +327,9 @@ const ChatWindow = ({ id }: { id?: string }) => {
 
   const messagesRef = useRef<Message[]>([]);
 
+  useEffect(() => {
+    fetchSettings();
+  }, []);
   useEffect(() => {
     messagesRef.current = messages;
   }, [messages]);
diff --git a/ui/components/SettingsDialog.tsx b/ui/components/SettingsDialog.tsx
index 788469b..825553f 100644
--- a/ui/components/SettingsDialog.tsx
+++ b/ui/components/SettingsDialog.tsx
@@ -146,31 +146,35 @@ const SettingsDialog = ({
 
   const handleSubmit = async () => {
     setIsUpdating(true);
-
+  
     try {
-      await fetch(`${process.env.NEXT_PUBLIC_API_URL}/config`, {
+      await fetch(`${process.env.NEXT_PUBLIC_API_URL}/settings`, {
         method: 'POST',
         headers: {
           'Content-Type': 'application/json',
         },
-        body: JSON.stringify(config),
+        body: JSON.stringify({
+          chatModelProvider: selectedChatModelProvider,
+          chatModel: selectedChatModel,
+          embeddingModelProvider: selectedEmbeddingModelProvider,
+          embeddingModel: selectedEmbeddingModel,
+          openAIApiKey: customOpenAIApiKey,
+          openAIBaseURL: customOpenAIBaseURL,
+        }),
       });
-
+  
+      // Still keep localStorage for quick access on the client-side
       localStorage.setItem('chatModelProvider', selectedChatModelProvider!);
       localStorage.setItem('chatModel', selectedChatModel!);
-      localStorage.setItem(
-        'embeddingModelProvider',
-        selectedEmbeddingModelProvider!,
-      );
+      localStorage.setItem('embeddingModelProvider', selectedEmbeddingModelProvider!);
       localStorage.setItem('embeddingModel', selectedEmbeddingModel!);
       localStorage.setItem('openAIApiKey', customOpenAIApiKey!);
       localStorage.setItem('openAIBaseURL', customOpenAIBaseURL!);
     } catch (err) {
-      console.log(err);
+      console.error(err);
     } finally {
       setIsUpdating(false);
       setIsOpen(false);
-
       window.location.reload();
     }
   };