Merge branch 'refactor/0712_ask' of https://github.com/pickle-com/glass into refactor/0712_ask
This commit is contained in:
commit
9ec8df0548
@ -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);
|
||||
|
||||
@ -231,9 +241,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;
|
||||
|
@ -138,20 +138,13 @@ 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),
|
||||
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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -897,9 +897,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);
|
||||
@ -916,27 +916,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'));
|
||||
@ -949,61 +978,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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user