From 5fcec6d346cec377089dbbcc75b60fcc165b6a35 Mon Sep 17 00:00:00 2001 From: seven Date: Thu, 18 Apr 2024 02:10:52 +0800 Subject: [PATCH] feat: receive message for openai #48 Signed-off-by: seven --- src/electron/chatBotApi.ts | 31 +++++++++--- src/electron/main.ts | 64 +++++++++++++----------- src/electron/preload.ts | 2 + src/layout/components/tool-bar-right.vue | 3 +- src/store/chatStore.ts | 51 ++++++++++++++----- src/vite-env.d.ts | 16 ++++++ 6 files changed, 120 insertions(+), 47 deletions(-) diff --git a/src/electron/chatBotApi.ts b/src/electron/chatBotApi.ts index 9574f49..c9e7a30 100644 --- a/src/electron/chatBotApi.ts +++ b/src/electron/chatBotApi.ts @@ -53,24 +53,44 @@ const chatBotApi = { assistantId, threadId, question, + mainWindow, }: { openai: OpenAI; assistantId: string; threadId: string; question: string; + mainWindow: Electron.BrowserWindow; }) => { await openai.beta.threads.messages.create(threadId, { role: 'user', content: question }); openai.beta.threads.runs .stream(threadId, { assistant_id: assistantId }) - .on('textCreated', text => console.log('textCreated, text:', text)) - .on('textDelta', (textDelta, snapshot) => - console.log('textDelta, textDelta:', JSON.stringify({ textDelta, snapshot })), + .on('messageCreated', message => + mainWindow.webContents.send('chat-bot-api-message-delta', { + msgEvent: 'messageCreated', + message, + }), + ) + .on('messageDelta', (delta, snapshot) => { + console.log('messageDelta, delta:', delta, 'snapshot:', snapshot); + mainWindow.webContents.send('chat-bot-api-message-delta', { + msgEvent: 'messageDelta', + delta, + }); + }) + .on('messageDone', message => + mainWindow.webContents.send('chat-bot-api-message-delta', { + msgEvent: 'messageDone', + message, + }), ); }, }; -const registerChatBotApiListener = (ipcMain: Electron.IpcMain) => { +const registerChatBotApiListener = ( + ipcMain: Electron.IpcMain, + mainWindow: Electron.BrowserWindow, +) => { let openai: OpenAI; ipcMain.handle( @@ -79,7 +99,6 @@ const registerChatBotApiListener = (ipcMain: Electron.IpcMain) => { _, { method, question, apiKey, prompt, model, assistantId, threadId }: ChatBotApiInput, ) => { - console.log(`chatBotApi method: ${method}`); if (method === ChatBotApiMethods.INITIALIZE) { openai = createOpenaiClient({ apiKey }); @@ -95,7 +114,7 @@ const registerChatBotApiListener = (ipcMain: Electron.IpcMain) => { if (!openai) { openai = createOpenaiClient({ apiKey }); } - await chatBotApi.ask({ openai, assistantId, threadId, question: question }); + await chatBotApi.ask({ openai, assistantId, threadId, question: question, mainWindow }); } }, ); diff --git a/src/electron/main.ts b/src/electron/main.ts index 1a85347..1bcf338 100644 --- a/src/electron/main.ts +++ b/src/electron/main.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, ipcMain, shell } from 'electron'; +import { app, BrowserWindow, ipcMain, IpcMain, shell } from 'electron'; import path from 'path'; import { createMenu } from './menu'; import { debug } from '../common'; @@ -30,19 +30,22 @@ const loadDevTools = async () => { } }; -const createWindow = async () => { - // Create the browser window. - const mainWindow = new BrowserWindow({ - width: 1200, - minWidth: 900, - height: 750, - minHeight: 600, - webPreferences: { - preload: path.join(__dirname, 'preload.js'), - webSecurity: false, - }, - icon: path.resolve(__dirname, '../../dockit.png'), - }); +const registerListeners = (ipcMain: IpcMain, mainWindow: BrowserWindow) => { + registerStoreApiListener(ipcMain); + registerSourceFileApiListener(ipcMain); + registerFetchApiListener(ipcMain); + registerChatBotApiListener(ipcMain, mainWindow); + + ipcMain.handle('versions', () => ({ + node: process.versions.chrome, + chrome: process.versions.chrome, + electron: process.versions.electron, + version: app.getVersion(), + name: app.getName(), + })); +}; + +const renderMainWindow = async (mainWindow: BrowserWindow) => { createMenu(mainWindow); // and load the index.html of the app. if (MAIN_WINDOW_VITE_DEV_SERVER_URL) { @@ -65,21 +68,30 @@ const createWindow = async () => { path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`), ); } +}; - ipcMain.handle('versions', () => ({ - node: process.versions.chrome, - chrome: process.versions.chrome, - electron: process.versions.electron, - version: app.getVersion(), - name: app.getName(), - })); +const createWindow = () => { + // Create the browser window. + return new BrowserWindow({ + width: 1200, + minWidth: 900, + height: 750, + minHeight: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js'), + webSecurity: false, + }, + icon: path.resolve(__dirname, '../../dockit.png'), + }); }; // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.on('ready', async () => { - await createWindow(); + const mainWindow = createWindow(); + await renderMainWindow(mainWindow); + registerListeners(ipcMain, mainWindow); await loadDevTools(); }); @@ -96,7 +108,8 @@ app.on('window-all-closed', () => { // dock icon is clicked and there are no other windows open. app.on('activate', async () => { if (BrowserWindow.getAllWindows().length === 0) { - await createWindow(); + const mainWindow = createWindow(); + await renderMainWindow(mainWindow); } }); @@ -107,10 +120,5 @@ ipcMain.on('open-link', (_event, link: string) => { shell.openExternal(link); }); -registerStoreApiListener(ipcMain); -registerSourceFileApiListener(ipcMain); -registerFetchApiListener(ipcMain); -registerChatBotApiListener(ipcMain); - // In this file you can include the rest of your app's specific main process // code. You can also put them in separate files and import them here. diff --git a/src/electron/preload.ts b/src/electron/preload.ts index a5267bf..29d59ee 100644 --- a/src/electron/preload.ts +++ b/src/electron/preload.ts @@ -46,4 +46,6 @@ contextBridge.exposeInMainWorld('chatBotApi', { threadId: string; }) => ipcRenderer.invoke('chatBotApi', { method: 'ASK', question, apiKey, assistantId, threadId }), + onMessageReceived: (callback: (value: unknown) => void) => + ipcRenderer.on('chat-bot-api-message-delta', (_event, value) => callback(value)), }); diff --git a/src/layout/components/tool-bar-right.vue b/src/layout/components/tool-bar-right.vue index 4876891..749500a 100644 --- a/src/layout/components/tool-bar-right.vue +++ b/src/layout/components/tool-bar-right.vue @@ -88,7 +88,7 @@ import { ChatMessageRole, useChatStore } from '../../store'; import { storeToRefs } from 'pinia'; const chatStore = useChatStore(); -const { sendMessage } = chatStore; +const { sendMessage, fetchChats } = chatStore; const { chats } = storeToRefs(chatStore); const selectedItemId = ref(-1); const chatBot = ref({ active: false }); @@ -145,6 +145,7 @@ onMounted(() => { onUnmounted(() => { window.removeEventListener('resize', updateHeight); }); +fetchChats();