diff --git a/electron/main/Config/storeConfig.ts b/electron/main/Config/storeConfig.ts index 70d903a1..6a87ca61 100644 --- a/electron/main/Config/storeConfig.ts +++ b/electron/main/Config/storeConfig.ts @@ -4,6 +4,7 @@ export interface StoreSchema { preferences?: { // ... other preferences }; + openAIAPIKey?: string; }; // ... other top-level keys } @@ -12,7 +13,7 @@ export interface StoreSchema { export enum StoreKeys { UserDirectory = "user.directory", UserPreferences = "user.preferences", - // ... other keys + UserOpenAIAPIKey = "user.openAIAPIKey", } // Create a strongly-typed store instance diff --git a/electron/main/index.ts b/electron/main/index.ts index ef9848f4..7be34e69 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -142,7 +142,7 @@ async function createWindow() { // Apply electron-updater update(win); - registerLLMSessionHandlers(); + registerLLMSessionHandlers(store); registerDBSessionHandlers(dbTable); } @@ -330,6 +330,43 @@ ipcMain.on("set-user-directory", (event, userDirectory: string) => { event.returnValue = "success"; }); +ipcMain.on("set-openai-api-key", (event, apiKey: string) => { + console.log("setting openai api key", apiKey); + try { + if (!apiKey) { + throw new Error("API Key cannot be empty"); + } + store.set(StoreKeys.UserOpenAIAPIKey, apiKey); + registerLLMSessionHandlers(store); + } catch (error) { + console.error("Error setting openai api key", error); + } + // if (fileWatcher) { + // fileWatcher.close(); + // } + + // if (win) { + // startWatchingDirectory(win, userDirectory); + // updateFileListForRenderer(win, userDirectory, markdownExtensions); + // } + // maybeRePopulateTable(dbTable, userDirectory, markdownExtensions); + event.returnValue = "success"; +}); + +ipcMain.on("get-openai-api-key", (event) => { + const apiKey = store.get(StoreKeys.UserOpenAIAPIKey); + // if (fileWatcher) { + // fileWatcher.close(); + // } + + // if (win) { + // startWatchingDirectory(win, userDirectory); + // updateFileListForRenderer(win, userDirectory, markdownExtensions); + // } + // maybeRePopulateTable(dbTable, userDirectory, markdownExtensions); + event.returnValue = apiKey; +}); + ipcMain.on("get-user-directory", (event) => { const path = store.get(StoreKeys.UserDirectory); event.returnValue = path; diff --git a/electron/main/llm/llmSessionHandlers.ts b/electron/main/llm/llmSessionHandlers.ts index c7b15707..9ff57283 100644 --- a/electron/main/llm/llmSessionHandlers.ts +++ b/electron/main/llm/llmSessionHandlers.ts @@ -2,21 +2,22 @@ import { ipcMain, IpcMainInvokeEvent } from "electron"; import { LlamaCPPModelLoader, LlamaCPPSessionService } from "./models/LlamaCpp"; // Assuming SessionService is in the same directory import { ISessionService } from "./Types"; import { OpenAIModel, OpenAIModelSessionService } from "./models/GPT4"; +import { StoreKeys, StoreSchema } from "../Config/storeConfig"; +import Store from "electron-store"; // const modelLoader = new ModelLoader(); // Singleton // modelLoader.loadModel(); // Load model on startup -const openAIModel = new OpenAIModel( - "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" -); -openAIModel.loadModel(); -const llamaCPPModelLoader = new LlamaCPPModelLoader(); -llamaCPPModelLoader.loadModel(); -// const gpt4SessionService = new GPT4SessionService(gpt4Model, webContents); -// await gpt4SessionService.init(); const sessions: { [sessionId: string]: ISessionService } = {}; -export const registerLLMSessionHandlers = () => { +export const registerLLMSessionHandlers = (store: Store) => { + const apiKey: string = store.get(StoreKeys.UserOpenAIAPIKey); + const openAIModel = new OpenAIModel(apiKey); + openAIModel.loadModel(); + const llamaCPPModelLoader = new LlamaCPPModelLoader(); + llamaCPPModelLoader.loadModel(); + // const gpt4SessionService = new GPT4SessionService(gpt4Model, webContents); + // await gpt4SessionService.init(); ipcMain.handle( "createSession", async (event: IpcMainInvokeEvent, sessionId: string) => { @@ -45,6 +46,7 @@ export const registerLLMSessionHandlers = () => { ipcMain.handle( "initializeStreamingResponse", async (event: IpcMainInvokeEvent, sessionId: string, prompt: string) => { + console.log("INITIALIZING STREAMING RESPONSE"); const sessionService = sessions[sessionId]; if (!sessionService) { throw new Error(`Session ${sessionId} does not exist.`); diff --git a/electron/preload/index.ts b/electron/preload/index.ts index 94797fa4..560c843d 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -53,7 +53,9 @@ declare global { }; electronStore: { setUserDirectory: (path: string) => any; - getUserDirectory: () => any; + getUserDirectory: () => string; + setOpenAIAPIKey: (apiKey: string) => any; + getOpenAIAPIKey: () => string; }; } } @@ -79,6 +81,12 @@ contextBridge.exposeInMainWorld("electronStore", { setUserDirectory: (path: string) => { return ipcRenderer.sendSync("set-user-directory", path); }, + setOpenAIAPIKey: (apiKey: string) => { + return ipcRenderer.sendSync("set-openai-api-key", apiKey); + }, + getOpenAIAPIKey: () => { + return ipcRenderer.sendSync("get-openai-api-key"); + }, getUserDirectory: () => { return ipcRenderer.sendSync("get-user-directory"); }, diff --git a/src/components/FileEditorContainer.tsx b/src/components/FileEditorContainer.tsx index e59bce07..f25a5b51 100644 --- a/src/components/FileEditorContainer.tsx +++ b/src/components/FileEditorContainer.tsx @@ -5,6 +5,7 @@ import SimilarEntriesComponent from "./Similarity/SimilarFilesSidebar"; import TitleBar from "./TitleBar"; import ChatWithLLM from "./Chat/Chat"; import SettingsModal from "./Settings/SettingsModal"; +import LeftSidebar from "./LeftSidebar/LeftSidebar"; interface FileEditorContainerProps {} @@ -12,7 +13,6 @@ const FileEditorContainer: React.FC = ({}) => { const [editorContent, setEditorContent] = useState(""); const [selectedFilePath, setSelectedFilePath] = useState(null); const lastSavedContentRef = useRef(""); - const [isModalOpen, setModalOpen] = useState(false); const onFileSelect = async (path: string) => { // so here we can save the actual content too\\ @@ -28,21 +28,14 @@ const FileEditorContainer: React.FC = ({}) => {
-
+
+ +
+
- - setModalOpen(false)} - />
{selectedFilePath && (
diff --git a/src/components/LeftSidebar/LeftSidebar.tsx b/src/components/LeftSidebar/LeftSidebar.tsx new file mode 100644 index 00000000..29722d77 --- /dev/null +++ b/src/components/LeftSidebar/LeftSidebar.tsx @@ -0,0 +1,23 @@ +import React, { useState } from "react"; +import SettingsModal from "../Settings/SettingsModal"; +import { MdSettings } from "react-icons/md"; // Importing Material Design settings icon + +const LeftSidebar: React.FC = () => { + const [isModalOpen, setModalOpen] = useState(false); + + return ( +
+ + {/* */} + setModalOpen(false)} /> + {/*
*/} +
+ ); +}; + +export default LeftSidebar; diff --git a/src/components/Settings/SettingsModal.tsx b/src/components/Settings/SettingsModal.tsx index 2abff7fe..31c32696 100644 --- a/src/components/Settings/SettingsModal.tsx +++ b/src/components/Settings/SettingsModal.tsx @@ -1,24 +1,54 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; interface ModalProps { isOpen: boolean; onClose: () => void; + // onSaveKey: (key: string) => void; } -const SettingsModal: React.FC = ({ isOpen, onClose }) => { +const SettingsModal: React.FC = ({ + isOpen, + onClose, + // onSaveKey, +}) => { + const [openAIKey, setOpenAIKey] = useState(""); + + useEffect(() => { + const key = window.electronStore.getOpenAIAPIKey() || ""; // Fallback to empty string if undefined + setOpenAIKey(key); + }, []); + if (!isOpen) return null; + const handleSave = () => { + // onSaveKey(openAIKey); + window.electronStore.setOpenAIAPIKey(openAIKey); + onClose(); + }; + return (
- {/* {children} */} - hello +

OpenAI Key Settings

+ setOpenAIKey(e.target.value)} + /> +
);