From 3d7738826c59e424bcdf4bf57e8d1d7047fb95eb Mon Sep 17 00:00:00 2001 From: sanio Date: Sun, 13 Jul 2025 10:18:29 +0900 Subject: [PATCH 1/3] delete legacy ask code --- src/features/ask/askService.js | 3 - src/preload.js | 9 +-- src/ui/ask/AskView.js | 83 +---------------------- src/window/windowManager.js | 119 ++++++++++++++------------------- 4 files changed, 53 insertions(+), 161 deletions(-) diff --git a/src/features/ask/askService.js b/src/features/ask/askService.js index 81c1439..abef353 100644 --- a/src/features/ask/askService.js +++ b/src/features/ask/askService.js @@ -231,9 +231,6 @@ class AskService { console.log(`[AskService] Stream reading was intentionally cancelled. Reason: ${signal.reason}`); } else { console.error('[AskService] Error while processing stream:', streamError); - if (askWin && !askWin.isDestroyed()) { - askWin.webContents.send('ask-response-stream-error', { error: streamError.message }); - } } } finally { this.state.isStreaming = false; diff --git a/src/preload.js b/src/preload.js index b2b1d62..9eee814 100644 --- a/src/preload.js +++ b/src/preload.js @@ -138,16 +138,9 @@ contextBridge.exposeInMainWorld('api', { removeOnAskStateUpdate: (callback) => ipcRenderer.removeListener('ask:stateUpdate', callback), // Listeners - onSendQuestionToRenderer: (callback) => ipcRenderer.on('ask:sendQuestionToRenderer', callback), - removeOnSendQuestionToRenderer: (callback) => ipcRenderer.removeListener('ask:sendQuestionToRenderer', callback), - onHideTextInput: (callback) => ipcRenderer.on('hide-text-input', callback), - removeOnHideTextInput: (callback) => ipcRenderer.removeListener('hide-text-input', callback), onShowTextInput: (callback) => ipcRenderer.on('ask:showTextInput', callback), removeOnShowTextInput: (callback) => ipcRenderer.removeListener('ask:showTextInput', callback), - onResponseChunk: (callback) => ipcRenderer.on('ask-response-chunk', callback), - removeOnResponseChunk: (callback) => ipcRenderer.removeListener('ask-response-chunk', callback), - onResponseStreamEnd: (callback) => ipcRenderer.on('ask-response-stream-end', callback), - removeOnResponseStreamEnd: (callback) => ipcRenderer.removeListener('ask-response-stream-end', callback), + onScrollResponseUp: (callback) => ipcRenderer.on('scroll-response-up', callback), removeOnScrollResponseUp: (callback) => ipcRenderer.removeListener('scroll-response-up', callback), onScrollResponseDown: (callback) => ipcRenderer.on('scroll-response-down', callback), diff --git a/src/ui/ask/AskView.js b/src/ui/ask/AskView.js index a3ae7e9..964c46b 100644 --- a/src/ui/ask/AskView.js +++ b/src/ui/ask/AskView.js @@ -719,15 +719,13 @@ export class AskView extends LitElement { this.headerText = 'AI Response'; this.headerAnimating = false; this.isStreaming = false; - // this.accumulatedResponse = ''; this.marked = null; this.hljs = null; this.DOMPurify = null; this.isLibrariesLoaded = false; - // this.handleStreamChunk = this.handleStreamChunk.bind(this); - // this.handleStreamEnd = this.handleStreamEnd.bind(this); + this.handleSendText = this.handleSendText.bind(this); this.handleTextKeydown = this.handleTextKeydown.bind(this); this.handleCopy = this.handleCopy.bind(this); @@ -770,12 +768,6 @@ export class AskView extends LitElement { }; if (window.api) { - window.api.askView.onSendQuestionToRenderer(this.handleQuestionFromAssistant); - window.api.askView.onHideTextInput(() => { - console.log('📤 Hide text input signal received'); - this.showTextInput = false; - this.requestUpdate(); - }); window.api.askView.onShowTextInput(() => { console.log('📤 Show text input signal received'); if (!this.showTextInput) { @@ -784,9 +776,6 @@ export class AskView extends LitElement { } }); - // window.api.askView.onResponseChunk(this.handleStreamChunk); - // window.api.askView.onResponseStreamEnd(this.handleStreamEnd); - window.api.askView.onScrollResponseUp(() => this.handleScroll('up')); window.api.askView.onScrollResponseDown(() => this.handleScroll('down')); window.api.askView.onAskStateUpdate((event, newState) => { @@ -824,11 +813,7 @@ export class AskView extends LitElement { if (window.api) { window.api.askView.removeOnAskStateUpdate(this.handleAskStateUpdate); - window.api.askView.removeOnSendQuestionToRenderer(this.handleQuestionFromAssistant); - window.api.askView.removeOnHideTextInput(this.handleHideTextInput); window.api.askView.removeOnShowTextInput(this.handleShowTextInput); - window.api.askView.removeOnResponseChunk(this.handleStreamChunk); - window.api.askView.removeOnResponseStreamEnd(this.handleStreamEnd); window.api.askView.removeOnScrollResponseUp(this.handleScroll); window.api.askView.removeOnScrollResponseDown(this.handleScroll); console.log('✅ AskView: IPC 이벤트 리스너 제거 필요'); @@ -917,9 +902,6 @@ export class AskView extends LitElement { this.isStreaming = false; this.headerText = 'AI Response'; this.showTextInput = true; - // this.accumulatedResponse = ''; - // this.requestUpdate(); - // this.renderContent(); } handleInputFocus() { @@ -986,33 +968,7 @@ export class AskView extends LitElement { } } - // --- 스트리밍 처리 핸들러 --- - // handleStreamChunk(event, { token }) { - // if (!this.isStreaming) { - // this.isStreaming = true; - // this.isLoading = false; - // this.accumulatedResponse = ''; - // const container = this.shadowRoot.getElementById('responseContainer'); - // if (container) container.innerHTML = ''; - // this.headerText = 'AI Response'; - // this.headerAnimating = false; - // this.requestUpdate(); - // } - // this.accumulatedResponse += token; - // this.renderContent(); - // } - // handleStreamEnd() { - // this.isStreaming = false; - // this.currentResponse = this.accumulatedResponse; - // if (this.headerText !== 'AI Response') { - // this.headerText = 'AI Response'; - // this.requestUpdate(); - // } - // this.renderContent(); - // } - - // ✨ 렌더링 로직 통합 renderContent() { const responseContainer = this.shadowRoot.getElementById('responseContainer'); if (!responseContainer) return; @@ -1029,7 +985,6 @@ export class AskView extends LitElement { return; } - // ✨ isStreaming이나 accumulatedResponse 대신 currentResponse를 직접 사용 let textToRender = this.fixIncompleteMarkdown(this.currentResponse); textToRender = this.fixIncompleteCodeBlocks(textToRender); @@ -1269,32 +1224,11 @@ export class AskView extends LitElement { textInput.value = ''; - // this.currentQuestion = text; - // this.lineCopyState = {}; - // this.showTextInput = false; - // this.isLoading = true; - // this.isStreaming = false; - // this.currentResponse = ''; - // this.accumulatedResponse = ''; - // this.startHeaderAnimation(); - // this.requestUpdate(); - // this.renderContent(); - if (window.api) { window.api.askView.sendMessage(text).catch(error => { console.error('Error sending text:', error); }); } - - // if (window.api) { - // window.api.askView.sendMessage(text).catch(error => { - // console.error('Error sending text:', error); - // this.isLoading = false; - // this.isStreaming = false; - // this.currentResponse = `Error: ${error.message}`; - // this.renderContent(); - // }); - // } } handleTextKeydown(e) { @@ -1312,21 +1246,6 @@ export class AskView extends LitElement { } } - // updated(changedProperties) { - // super.updated(changedProperties); - // if (changedProperties.has('isLoading')) { - // this.renderContent(); - // } - - // if (changedProperties.has('showTextInput') || changedProperties.has('isLoading')) { - // this.adjustWindowHeightThrottled(); - // } - - // if (changedProperties.has('showTextInput') && this.showTextInput) { - // this.focusTextInput(); - // } - // } - updated(changedProperties) { super.updated(changedProperties); diff --git a/src/window/windowManager.js b/src/window/windowManager.js index fe9403a..ed5e347 100644 --- a/src/window/windowManager.js +++ b/src/window/windowManager.js @@ -819,9 +819,9 @@ function setupIpcHandlers(movementManager) { ipcMain.handle('toggle-all-windows-visibility', () => toggleAllWindowsVisibility()); - ipcMain.handle('toggle-feature', async (event, featureName) => { - return toggleFeature(featureName); - }); + // ipcMain.handle('toggle-feature', async (event, featureName) => { + // return toggleFeature(featureName); + // }); ipcMain.on('animation-finished', (event) => { const win = BrowserWindow.fromWebContents(event.sender); @@ -838,27 +838,56 @@ function setupIpcHandlers(movementManager) { askWindow.webContents.send('window-hide-animation'); } }); - - - // ipcMain.handle('ask:sendQuestionToMain', (event, question) => { - // console.log('📨 Main process: Sending question to AskView', question); - // toggleFeature('ask', {ask: { questionText: question }}); - // return { success: true }; - // }); - - } -/** - * - * @param {'listen'|'ask'|'settings'} featureName - * @param {{ -* listen?: { targetVisibility?: 'show'|'hide' }, -* ask?: { targetVisibility?: 'show'|'hide', questionText?: string }, -* settings?: { targetVisibility?: 'show'|'hide' } -* }} [options={}] -*/ +// /** +// * +// * @param {'listen'|'ask'|'settings'} featureName +// * @param {{ +// * listen?: { targetVisibility?: 'show'|'hide' }, +// * ask?: { targetVisibility?: 'show'|'hide', questionText?: string }, +// * settings?: { targetVisibility?: 'show'|'hide' } +// * }} [options={}] +// */ +// async function toggleFeature(featureName, options = {}) { +// if (!windowPool.get(featureName) && currentHeaderState === 'main') { +// createFeatureWindows(windowPool.get('header')); +// } + +// if (featureName === 'ask') { +// let askWindow = windowPool.get('ask'); + +// if (!askWindow || askWindow.isDestroyed()) { +// console.log('[WindowManager] Ask window not found, creating new one'); +// return; +// } + +// const questionText = options?.ask?.questionText ?? null; +// const targetVisibility = options?.ask?.targetVisibility ?? null; +// if (askWindow.isVisible()) { +// if (questionText) { +// askWindow.webContents.send('ask:sendQuestionToRenderer', questionText); +// } else { +// updateLayout(); +// if (targetVisibility === 'show') { +// askWindow.webContents.send('ask:showTextInput'); +// } else { +// askWindow.webContents.send('window-hide-animation'); +// } +// } +// } else { +// console.log('[WindowManager] Showing hidden Ask window'); +// askWindow.show(); +// updateLayout(); +// if (questionText) { +// askWindow.webContents.send('ask:sendQuestionToRenderer', questionText); +// } +// askWindow.webContents.send('window-show-animation'); +// } +// } +// } + async function toggleFeature(featureName, options = {}) { if (!windowPool.get(featureName) && currentHeaderState === 'main') { createFeatureWindows(windowPool.get('header')); @@ -871,61 +900,15 @@ async function toggleFeature(featureName, options = {}) { console.log('[WindowManager] Ask window not found, creating new one'); return; } - - const questionText = options?.ask?.questionText ?? null; - const targetVisibility = options?.ask?.targetVisibility ?? null; if (askWindow.isVisible()) { - if (questionText) { - askWindow.webContents.send('ask:sendQuestionToRenderer', questionText); - } else { - updateLayout(); - if (targetVisibility === 'show') { - askWindow.webContents.send('ask:showTextInput'); - } else { - askWindow.webContents.send('window-hide-animation'); - } - } + askWindow.webContents.send('ask:showTextInput'); } else { console.log('[WindowManager] Showing hidden Ask window'); askWindow.show(); updateLayout(); - if (questionText) { - askWindow.webContents.send('ask:sendQuestionToRenderer', questionText); - } askWindow.webContents.send('window-show-animation'); } } - - if (featureName === 'settings') { - const settingsWindow = windowPool.get(featureName); - - if (settingsWindow) { - if (settingsWindow.isDestroyed()) { - console.error(`Window ${featureName} is destroyed, cannot toggle`); - return; - } - - if (settingsWindow.isVisible()) { - if (featureName === 'settings') { - settingsWindow.webContents.send('settings-window-hide-animation'); - } else { - settingsWindow.webContents.send('window-hide-animation'); - } - } else { - try { - settingsWindow.show(); - updateLayout(); - - settingsWindow.webContents.send('window-show-animation'); - } catch (e) { - console.error('Error showing window:', e); - } - } - } else { - console.error(`Window not found for feature: ${featureName}`); - console.error('Available windows:', Array.from(windowPool.keys())); - } - } } From 09aaf1f62df38caed688cb8ce92d1787a0c51a27 Mon Sep 17 00:00:00 2001 From: sanio Date: Sun, 13 Jul 2025 10:42:42 +0900 Subject: [PATCH 2/3] retrieve conversation history for askserice --- src/features/ask/askService.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/features/ask/askService.js b/src/features/ask/askService.js index abef353..8fbd7e9 100644 --- a/src/features/ask/askService.js +++ b/src/features/ask/askService.js @@ -4,6 +4,7 @@ const { getCurrentModelInfo, windowPool, captureScreenshot } = require('../../wi const sessionRepository = require('../common/repositories/session'); const askRepository = require('./repositories'); const { getSystemPrompt } = require('../common/prompts/promptBuilder'); +const listenService = require('../listen/listenService'); /** * @class @@ -34,15 +35,12 @@ class AskService { const { windowPool, updateLayout } = require('../../window/windowManager'); const askWindow = windowPool.get('ask'); - // 답변이 있거나 스트리밍 중일 때 const hasContent = this.state.isStreaming || (this.state.currentResponse && this.state.currentResponse.length > 0); if (askWindow.isVisible() && hasContent) { - // 창을 닫는 대신, 텍스트 입력창만 토글합니다. this.state.showTextInput = !this.state.showTextInput; - this._broadcastState(); // 변경된 상태 전파 + this._broadcastState(); } else { - // 기존의 창 보이기/숨기기 로직 if (askWindow.isVisible()) { askWindow.webContents.send('window-hide-animation'); this.state.isVisible = false; @@ -53,7 +51,6 @@ class AskService { updateLayout(); askWindow.webContents.send('window-show-animation'); } - // 창이 다시 열릴 때를 대비해 상태를 초기화하고 전파합니다. if (this.state.isVisible) { this.state.showTextInput = true; this._broadcastState(); @@ -80,7 +77,7 @@ class AskService { * @param {string} userPrompt * @returns {Promise<{success: boolean, response?: string, error?: string}>} */ - async sendMessage(userPrompt, conversationHistoryRaw=[]) { + async sendMessage(userPrompt) { if (this.abortController) { this.abortController.abort('New request received.'); } @@ -120,7 +117,20 @@ class AskService { const screenshotResult = await captureScreenshot({ quality: 'medium' }); const screenshotBase64 = screenshotResult.success ? screenshotResult.base64 : null; + let conversationHistoryRaw = []; + try { + const history = listenService.getConversationHistory(); + if (history && Array.isArray(history) && history.length > 0) { + console.log(`[AskService] Using conversation history from ListenService ${history.length} items).`); + conversationHistoryRaw = history; + } else { + console.log('[AskService] No active conversation history found in ListenService.'); + } + } catch (error) { + console.error('[AskService] Failed to get conversation history from ListenService:', error); + } const conversationHistory = this._formatConversationForPrompt(conversationHistoryRaw); + console.log(`[AskService] Using conversation history (${conversationHistory}`); const systemPrompt = getSystemPrompt('pickle_glass_analysis', conversationHistory, false); From bb9061316c110e3d1881858291e72cd66bccab78 Mon Sep 17 00:00:00 2001 From: sanio Date: Sun, 13 Jul 2025 10:47:16 +0900 Subject: [PATCH 3/3] fix legacy code --- src/preload.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/preload.js b/src/preload.js index 9eee814..8e0f5cc 100644 --- a/src/preload.js +++ b/src/preload.js @@ -141,10 +141,10 @@ contextBridge.exposeInMainWorld('api', { onShowTextInput: (callback) => ipcRenderer.on('ask:showTextInput', callback), removeOnShowTextInput: (callback) => ipcRenderer.removeListener('ask:showTextInput', callback), - onScrollResponseUp: (callback) => ipcRenderer.on('scroll-response-up', callback), - removeOnScrollResponseUp: (callback) => ipcRenderer.removeListener('scroll-response-up', callback), - onScrollResponseDown: (callback) => ipcRenderer.on('scroll-response-down', callback), - removeOnScrollResponseDown: (callback) => ipcRenderer.removeListener('scroll-response-down', callback) + onScrollResponseUp: (callback) => ipcRenderer.on('aks:scrollResponseUp', callback), + removeOnScrollResponseUp: (callback) => ipcRenderer.removeListener('aks:scrollResponseUp', callback), + onScrollResponseDown: (callback) => ipcRenderer.on('aks:scrollResponseDown', callback), + removeOnScrollResponseDown: (callback) => ipcRenderer.removeListener('aks:scrollResponseDown', callback) }, // src/ui/listen/ListenView.js