rough refactor done
This commit is contained in:
parent
586d44e57b
commit
d936af46a3
2
aec
2
aec
@ -1 +1 @@
|
||||
Subproject commit 9e11f4f95707714464194bdfc9db0222ec5c6163
|
||||
Subproject commit f00bb1fb948053c752b916adfee19f90644a0b2f
|
@ -9,6 +9,7 @@ const shortcutsService = require('../features/shortcuts/shortcutsService');
|
||||
|
||||
const askService = require('../features/ask/askService');
|
||||
const listenService = require('../features/listen/listenService');
|
||||
const permissionService = require('../features/common/services/permissionService');
|
||||
|
||||
module.exports = {
|
||||
// Renderer로부터의 요청을 수신
|
||||
@ -33,6 +34,14 @@ module.exports = {
|
||||
ipcMain.handle('save-shortcuts', async (event, newKeybinds) => await shortcutsService.handleSaveShortcuts(newKeybinds));
|
||||
|
||||
|
||||
// Permissions
|
||||
ipcMain.handle('check-system-permissions', async () => await permissionService.checkSystemPermissions());
|
||||
ipcMain.handle('request-microphone-permission', async () => await permissionService.requestMicrophonePermission());
|
||||
ipcMain.handle('open-system-preferences', async (event, section) => await permissionService.openSystemPreferences(section));
|
||||
ipcMain.handle('mark-permissions-completed', async () => await permissionService.markPermissionsAsCompleted());
|
||||
ipcMain.handle('check-permissions-completed', async () => await permissionService.checkPermissionsCompleted());
|
||||
|
||||
|
||||
// User/Auth
|
||||
ipcMain.handle('get-current-user', () => authService.getCurrentUser());
|
||||
ipcMain.handle('start-firebase-auth', async () => await authService.startFirebaseAuthFlow());
|
||||
@ -67,7 +76,6 @@ module.exports = {
|
||||
ipcMain.handle('ask:sendQuestionFromAsk', async (event, userPrompt) => await askService.sendMessage(userPrompt));
|
||||
ipcMain.handle('ask:sendQuestionFromSummary', async (event, userPrompt) => await askService.sendMessage(userPrompt));
|
||||
ipcMain.handle('ask:toggleAskButton', async () => await askService.toggleAskButton());
|
||||
ipcMain.handle('stop-screen-capture', async () => askService.handleStopScreenCapture());
|
||||
|
||||
// Listen
|
||||
ipcMain.handle('listen:sendMicAudio', async (event, { data, mimeType }) => await listenService.handleSendMicAudioContent(data, mimeType));
|
||||
@ -98,12 +106,11 @@ module.exports = {
|
||||
ipcMain.handle('model:validate-key', async (e, { provider, key }) => await modelStateService.handleValidateKey(provider, key));
|
||||
ipcMain.handle('model:get-all-keys', () => modelStateService.getAllApiKeys());
|
||||
ipcMain.handle('model:set-api-key', async (e, { provider, key }) => await modelStateService.setApiKey(provider, key));
|
||||
ipcMain.handle('model:remove-api-key', async (e, { provider }) => await modelStateService.handleRemoveApiKey(provider));
|
||||
ipcMain.handle('model:remove-api-key', async (e, provider) => await modelStateService.handleRemoveApiKey(provider));
|
||||
ipcMain.handle('model:get-selected-models', () => modelStateService.getSelectedModels());
|
||||
ipcMain.handle('model:set-selected-model', async (e, { type, modelId }) => await modelStateService.handleSetSelectedModel(type, modelId));
|
||||
ipcMain.handle('model:get-available-models', (e, { type }) => modelStateService.getAvailableModels(type));
|
||||
ipcMain.handle('model:are-providers-configured', () => modelStateService.areProvidersConfigured());
|
||||
ipcMain.handle('model:get-current-model-info', (e, { type }) => modelStateService.getCurrentModelInfo(type));
|
||||
ipcMain.handle('model:get-provider-config', () => modelStateService.getProviderConfig());
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// src/bridge/windowBridge.js
|
||||
const { ipcMain } = require('electron');
|
||||
const { ipcMain, BrowserWindow } = require('electron');
|
||||
const windowManager = require('../window/windowManager');
|
||||
|
||||
module.exports = {
|
||||
@ -15,6 +15,16 @@ module.exports = {
|
||||
ipcMain.handle('move-window-step', (event, direction) => windowManager.moveWindowStep(direction));
|
||||
ipcMain.on('close-shortcut-editor', () => windowManager.closeWindow('shortcut-settings'));
|
||||
|
||||
// Newly moved handlers from windowManager
|
||||
ipcMain.on('header-state-changed', (event, state) => windowManager.handleHeaderStateChanged(state));
|
||||
ipcMain.on('header-animation-finished', (event, state) => windowManager.handleHeaderAnimationFinished(state));
|
||||
ipcMain.handle('get-header-position', () => windowManager.getHeaderPosition());
|
||||
ipcMain.handle('move-header', (event, newX, newY) => windowManager.moveHeader(newX, newY));
|
||||
ipcMain.handle('move-header-to', (event, newX, newY) => windowManager.moveHeaderTo(newX, newY));
|
||||
ipcMain.handle('adjust-window-height', (event, targetHeight) => windowManager.adjustWindowHeight(event.sender, targetHeight));
|
||||
ipcMain.handle('toggle-all-windows-visibility', () => windowManager.toggleAllWindowsVisibility());
|
||||
ipcMain.on('animation-finished', (event) => windowManager.handleAnimationFinished(event.sender));
|
||||
ipcMain.handle('ask:closeAskWindow', () => windowManager.closeAskWindow());
|
||||
},
|
||||
|
||||
notifyFocusChange(win, isFocused) {
|
||||
|
@ -1,6 +1,18 @@
|
||||
const { BrowserWindow } = require('electron');
|
||||
const { createStreamingLLM } = require('../common/ai/factory');
|
||||
const { getCurrentModelInfo, windowPool, updateLayout } = require('../../window/windowManager');
|
||||
// Lazy require helper to avoid circular dependency issues
|
||||
const getWindowManager = () => require('../../window/windowManager');
|
||||
|
||||
const getWindowPool = () => {
|
||||
try {
|
||||
return getWindowManager().windowPool;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
const updateLayout = () => getWindowManager().updateLayout();
|
||||
const ensureAskWindowVisible = () => getWindowManager().ensureAskWindowVisible();
|
||||
|
||||
const sessionRepository = require('../common/repositories/session');
|
||||
const askRepository = require('./repositories');
|
||||
const { getSystemPrompt } = require('../common/prompts/promptBuilder');
|
||||
@ -10,6 +22,7 @@ const os = require('os');
|
||||
const util = require('util');
|
||||
const execFile = util.promisify(require('child_process').execFile);
|
||||
const { desktopCapturer } = require('electron');
|
||||
const modelStateService = require('../common/services/modelStateService');
|
||||
|
||||
// Try to load sharp, but don't fail if it's not available
|
||||
let sharp;
|
||||
@ -126,33 +139,33 @@ class AskService {
|
||||
}
|
||||
|
||||
_broadcastState() {
|
||||
const askWindow = windowPool.get('ask');
|
||||
const askWindow = getWindowPool()?.get('ask');
|
||||
if (askWindow && !askWindow.isDestroyed()) {
|
||||
askWindow.webContents.send('ask:stateUpdate', this.state);
|
||||
}
|
||||
}
|
||||
|
||||
async toggleAskButton() {
|
||||
const askWindow = windowPool.get('ask');
|
||||
const askWindow = getWindowPool()?.get('ask');
|
||||
|
||||
// 답변이 있거나 스트리밍 중일 때
|
||||
const hasContent = this.state.isStreaming || (this.state.currentResponse && this.state.currentResponse.length > 0);
|
||||
|
||||
if (askWindow.isVisible() && hasContent) {
|
||||
if (askWindow && askWindow.isVisible() && hasContent) {
|
||||
// 창을 닫는 대신, 텍스트 입력창만 토글합니다.
|
||||
this.state.showTextInput = !this.state.showTextInput;
|
||||
this._broadcastState(); // 변경된 상태 전파
|
||||
} else {
|
||||
// 기존의 창 보이기/숨기기 로직
|
||||
if (askWindow.isVisible()) {
|
||||
if (askWindow && askWindow.isVisible()) {
|
||||
askWindow.webContents.send('window-hide-animation');
|
||||
this.state.isVisible = false;
|
||||
} else {
|
||||
console.log('[AskService] Showing hidden Ask window');
|
||||
this.state.isVisible = true;
|
||||
askWindow.show();
|
||||
askWindow?.show();
|
||||
updateLayout();
|
||||
askWindow.webContents.send('window-show-animation');
|
||||
askWindow?.webContents.send('window-show-animation');
|
||||
}
|
||||
// 창이 다시 열릴 때를 대비해 상태를 초기화하고 전파합니다.
|
||||
if (this.state.isVisible) {
|
||||
@ -182,6 +195,8 @@ class AskService {
|
||||
* @returns {Promise<{success: boolean, response?: string, error?: string}>}
|
||||
*/
|
||||
async sendMessage(userPrompt, conversationHistoryRaw=[]) {
|
||||
ensureAskWindowVisible();
|
||||
|
||||
if (this.abortController) {
|
||||
this.abortController.abort('New request received.');
|
||||
}
|
||||
@ -212,7 +227,7 @@ class AskService {
|
||||
await askRepository.addAiMessage({ sessionId, role: 'user', content: userPrompt.trim() });
|
||||
console.log(`[AskService] DB: Saved user prompt to session ${sessionId}`);
|
||||
|
||||
const modelInfo = await getCurrentModelInfo(null, { type: 'llm' });
|
||||
const modelInfo = modelStateService.getCurrentModelInfo('llm');
|
||||
if (!modelInfo || !modelInfo.apiKey) {
|
||||
throw new Error('AI model or API key not configured.');
|
||||
}
|
||||
@ -252,7 +267,7 @@ class AskService {
|
||||
});
|
||||
|
||||
const response = await streamingLLM.streamChat(messages);
|
||||
const askWin = windowPool.get('ask');
|
||||
const askWin = getWindowPool()?.get('ask');
|
||||
|
||||
if (!askWin || askWin.isDestroyed()) {
|
||||
console.error("[AskService] Ask window is not available to send stream to.");
|
||||
@ -351,11 +366,6 @@ class AskService {
|
||||
}
|
||||
}
|
||||
|
||||
handleStopScreenCapture() {
|
||||
lastScreenshot = null;
|
||||
console.log('[AskService] Stopped screen capture and cleared cache.');
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
|
||||
const askService = new AskService();
|
||||
|
@ -82,7 +82,7 @@ async function createSTT({ apiKey, language = 'en', callbacks = {}, usePortkey =
|
||||
silence_duration_ms: 100,
|
||||
},
|
||||
input_audio_noise_reduction: {
|
||||
type: 'far_field'
|
||||
type: 'near_field'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -359,6 +359,7 @@ class ModelStateService {
|
||||
}
|
||||
|
||||
removeApiKey(provider) {
|
||||
console.log(`[ModelStateService] Removing API key for provider: ${provider}`);
|
||||
if (provider in this.state.apiKeys) {
|
||||
this.state.apiKeys[provider] = null;
|
||||
const llmProvider = this.getProviderForModel('llm', this.state.selectedModels.llm);
|
||||
@ -542,6 +543,7 @@ class ModelStateService {
|
||||
}
|
||||
|
||||
async handleRemoveApiKey(provider) {
|
||||
console.log(`[ModelStateService] handleRemoveApiKey: ${provider}`);
|
||||
const success = this.removeApiKey(provider);
|
||||
if (success) {
|
||||
const selectedModels = this.getSelectedModels();
|
||||
|
119
src/features/common/services/permissionService.js
Normal file
119
src/features/common/services/permissionService.js
Normal file
@ -0,0 +1,119 @@
|
||||
const { systemPreferences, shell, desktopCapturer } = require('electron');
|
||||
const permissionRepository = require('../repositories/permission');
|
||||
|
||||
class PermissionService {
|
||||
async checkSystemPermissions() {
|
||||
const permissions = {
|
||||
microphone: 'unknown',
|
||||
screen: 'unknown',
|
||||
needsSetup: true
|
||||
};
|
||||
|
||||
try {
|
||||
if (process.platform === 'darwin') {
|
||||
const micStatus = systemPreferences.getMediaAccessStatus('microphone');
|
||||
console.log('[Permissions] Microphone status:', micStatus);
|
||||
permissions.microphone = micStatus;
|
||||
|
||||
const screenStatus = systemPreferences.getMediaAccessStatus('screen');
|
||||
console.log('[Permissions] Screen status:', screenStatus);
|
||||
permissions.screen = screenStatus;
|
||||
|
||||
permissions.needsSetup = micStatus !== 'granted' || screenStatus !== 'granted';
|
||||
} else {
|
||||
permissions.microphone = 'granted';
|
||||
permissions.screen = 'granted';
|
||||
permissions.needsSetup = false;
|
||||
}
|
||||
|
||||
console.log('[Permissions] System permissions status:', permissions);
|
||||
return permissions;
|
||||
} catch (error) {
|
||||
console.error('[Permissions] Error checking permissions:', error);
|
||||
return {
|
||||
microphone: 'unknown',
|
||||
screen: 'unknown',
|
||||
needsSetup: true,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async requestMicrophonePermission() {
|
||||
if (process.platform !== 'darwin') {
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
try {
|
||||
const status = systemPreferences.getMediaAccessStatus('microphone');
|
||||
console.log('[Permissions] Microphone status:', status);
|
||||
if (status === 'granted') {
|
||||
return { success: true, status: 'granted' };
|
||||
}
|
||||
|
||||
const granted = await systemPreferences.askForMediaAccess('microphone');
|
||||
return {
|
||||
success: granted,
|
||||
status: granted ? 'granted' : 'denied'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[Permissions] Error requesting microphone permission:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async openSystemPreferences(section) {
|
||||
if (process.platform !== 'darwin') {
|
||||
return { success: false, error: 'Not supported on this platform' };
|
||||
}
|
||||
|
||||
try {
|
||||
if (section === 'screen-recording') {
|
||||
try {
|
||||
console.log('[Permissions] Triggering screen capture request to register app...');
|
||||
await desktopCapturer.getSources({
|
||||
types: ['screen'],
|
||||
thumbnailSize: { width: 1, height: 1 }
|
||||
});
|
||||
console.log('[Permissions] App registered for screen recording');
|
||||
} catch (captureError) {
|
||||
console.log('[Permissions] Screen capture request triggered (expected to fail):', captureError.message);
|
||||
}
|
||||
|
||||
// await shell.openExternal('x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture');
|
||||
}
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('[Permissions] Error opening system preferences:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async markPermissionsAsCompleted() {
|
||||
try {
|
||||
await permissionRepository.markPermissionsAsCompleted();
|
||||
console.log('[Permissions] Marked permissions as completed');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('[Permissions] Error marking permissions as completed:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async checkPermissionsCompleted() {
|
||||
try {
|
||||
const completed = await permissionRepository.checkPermissionsCompleted();
|
||||
console.log('[Permissions] Permissions completed status:', completed);
|
||||
return completed;
|
||||
} catch (error) {
|
||||
console.error('[Permissions] Error checking permissions completed status:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const permissionService = new PermissionService();
|
||||
module.exports = permissionService;
|
@ -1,6 +1,7 @@
|
||||
const { BrowserWindow } = require('electron');
|
||||
const { spawn } = require('child_process');
|
||||
const { createSTT } = require('../../common/ai/factory');
|
||||
const modelStateService = require('../../common/services/modelStateService');
|
||||
// const { getStoredApiKey, getStoredProvider, getCurrentModelInfo } = require('../../../window/windowManager');
|
||||
|
||||
const COMPLETION_DEBOUNCE_MS = 2000;
|
||||
@ -131,8 +132,7 @@ class SttService {
|
||||
async initializeSttSessions(language = 'en') {
|
||||
const effectiveLanguage = process.env.OPENAI_TRANSCRIBE_LANG || language || 'en';
|
||||
|
||||
const { getCurrentModelInfo } = require('../../../window/windowManager');
|
||||
const modelInfo = await getCurrentModelInfo(null, { type: 'stt' });
|
||||
const modelInfo = modelStateService.getCurrentModelInfo('stt');
|
||||
if (!modelInfo || !modelInfo.apiKey) {
|
||||
throw new Error('AI model or API key is not configured.');
|
||||
}
|
||||
@ -144,6 +144,7 @@ class SttService {
|
||||
console.log('[SttService] Ignoring message - session already closed');
|
||||
return;
|
||||
}
|
||||
console.log('[SttService] handleMyMessage', message);
|
||||
|
||||
if (this.modelInfo.provider === 'whisper') {
|
||||
// Whisper STT emits 'transcription' events with different structure
|
||||
@ -411,8 +412,7 @@ class SttService {
|
||||
let modelInfo = this.modelInfo;
|
||||
if (!modelInfo) {
|
||||
console.warn('[SttService] modelInfo not found, fetching on-the-fly as a fallback...');
|
||||
const { getCurrentModelInfo } = require('../../../window/windowManager');
|
||||
modelInfo = await getCurrentModelInfo(null, { type: 'stt' });
|
||||
modelInfo = modelStateService.getCurrentModelInfo('stt');
|
||||
}
|
||||
if (!modelInfo) {
|
||||
throw new Error('STT model info could not be retrieved.');
|
||||
@ -433,8 +433,7 @@ class SttService {
|
||||
let modelInfo = this.modelInfo;
|
||||
if (!modelInfo) {
|
||||
console.warn('[SttService] modelInfo not found, fetching on-the-fly as a fallback...');
|
||||
const { getCurrentModelInfo } = require('../../../window/windowManager');
|
||||
modelInfo = await getCurrentModelInfo(null, { type: 'stt' });
|
||||
modelInfo = modelStateService.getCurrentModelInfo('stt');
|
||||
}
|
||||
if (!modelInfo) {
|
||||
throw new Error('STT model info could not be retrieved.');
|
||||
@ -515,8 +514,7 @@ class SttService {
|
||||
let modelInfo = this.modelInfo;
|
||||
if (!modelInfo) {
|
||||
console.warn('[SttService] modelInfo not found, fetching on-the-fly as a fallback...');
|
||||
const { getCurrentModelInfo } = require('../../../window/windowManager');
|
||||
modelInfo = await getCurrentModelInfo(null, { type: 'stt' });
|
||||
modelInfo = modelStateService.getCurrentModelInfo('stt');
|
||||
}
|
||||
if (!modelInfo) {
|
||||
throw new Error('STT model info could not be retrieved.');
|
||||
|
@ -3,6 +3,7 @@ const { getSystemPrompt } = require('../../common/prompts/promptBuilder.js');
|
||||
const { createLLM } = require('../../common/ai/factory');
|
||||
const sessionRepository = require('../../common/repositories/session');
|
||||
const summaryRepository = require('./repositories');
|
||||
const modelStateService = require('../../common/services/modelStateService');
|
||||
// const { getStoredApiKey, getStoredProvider, getCurrentModelInfo } = require('../../../window/windowManager.js');
|
||||
|
||||
class SummaryService {
|
||||
@ -97,8 +98,7 @@ Please build upon this context while analyzing the new conversation segments.
|
||||
await sessionRepository.touch(this.currentSessionId);
|
||||
}
|
||||
|
||||
const { getCurrentModelInfo } = require('../../../window/windowManager');
|
||||
const modelInfo = await getCurrentModelInfo(null, { type: 'llm' });
|
||||
const modelInfo = modelStateService.getCurrentModelInfo('llm');
|
||||
if (!modelInfo || !modelInfo.apiKey) {
|
||||
throw new Error('AI model or API key is not configured.');
|
||||
}
|
||||
|
@ -374,6 +374,7 @@ async function removeApiKey() {
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[SettingsService] API key removed for all providers');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('[SettingsService] Error removing API key:', error);
|
||||
|
@ -1,6 +1,7 @@
|
||||
const { globalShortcut, screen } = require('electron');
|
||||
const shortcutsRepository = require('./repositories');
|
||||
const internalBridge = require('../../bridge/internalBridge');
|
||||
const askService = require('../ask/askService');
|
||||
|
||||
|
||||
class ShortcutsService {
|
||||
@ -210,8 +211,7 @@ class ShortcutsService {
|
||||
callback = () => this.toggleAllWindowsVisibility(this.windowPool);
|
||||
break;
|
||||
case 'nextStep':
|
||||
// Late require to prevent circular dependency
|
||||
callback = () => require('../../window/windowManager').toggleFeature('ask', {ask: { targetVisibility: 'show' }});
|
||||
callback = () => askService.toggleAskButton();
|
||||
break;
|
||||
case 'scrollUp':
|
||||
callback = () => {
|
||||
|
@ -276,12 +276,6 @@ contextBridge.exposeInMainWorld('api', {
|
||||
startMacosSystemAudio: () => ipcRenderer.invoke('listen:startMacosSystemAudio'),
|
||||
stopMacosSystemAudio: () => ipcRenderer.invoke('listen:stopMacosSystemAudio'),
|
||||
|
||||
// Screen Capture
|
||||
captureScreenshot: (options) => ipcRenderer.invoke('capture-screenshot', options),
|
||||
getCurrentScreenshot: () => ipcRenderer.invoke('get-current-screenshot'),
|
||||
startScreenCapture: () => ipcRenderer.invoke('start-screen-capture'),
|
||||
stopScreenCapture: () => ipcRenderer.invoke('stop-screen-capture'),
|
||||
|
||||
// Session Management
|
||||
isSessionActive: () => ipcRenderer.invoke('is-session-active'),
|
||||
|
||||
|
@ -38,13 +38,10 @@ const isMacOS = window.api.platform.isMacOS;
|
||||
|
||||
let mediaStream = null;
|
||||
let micMediaStream = null;
|
||||
let screenshotInterval = null;
|
||||
let audioContext = null;
|
||||
let audioProcessor = null;
|
||||
let systemAudioContext = null;
|
||||
let systemAudioProcessor = null;
|
||||
let currentImageQuality = 'medium';
|
||||
let lastScreenshotBase64 = null;
|
||||
|
||||
let systemAudioBuffer = [];
|
||||
const MAX_SYSTEM_BUFFER_SIZE = 10;
|
||||
@ -140,10 +137,6 @@ function runAecSync(micF32, sysF32) {
|
||||
return micF32;
|
||||
}
|
||||
|
||||
// ▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
|
||||
// 새로운 프레임 단위 처리 로직
|
||||
// ▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
|
||||
|
||||
const frameSize = 160; // AEC 모듈 초기화 시 설정한 프레임 크기
|
||||
const numFrames = Math.floor(micF32.length / frameSize);
|
||||
|
||||
@ -418,94 +411,10 @@ function setupSystemAudioProcessing(systemStream) {
|
||||
return { context: systemAudioContext, processor: systemProcessor };
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// Screenshot functions (exact from renderer.js)
|
||||
// ---------------------------
|
||||
async function captureScreenshot(imageQuality = 'medium', isManual = false) {
|
||||
console.log(`Capturing ${isManual ? 'manual' : 'automated'} screenshot...`);
|
||||
|
||||
// Check rate limiting for automated screenshots only
|
||||
if (!isManual && tokenTracker.shouldThrottle()) {
|
||||
console.log('Automated screenshot skipped due to rate limiting');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Request screenshot from main process
|
||||
const result = await window.api.listenCapture.captureScreenshot({
|
||||
quality: imageQuality,
|
||||
});
|
||||
|
||||
if (result.success && result.base64) {
|
||||
// Store the latest screenshot
|
||||
lastScreenshotBase64 = result.base64;
|
||||
|
||||
// Note: sendResult is not defined in the original, this was likely an error
|
||||
// Commenting out this section as it references undefined variable
|
||||
/*
|
||||
if (sendResult.success) {
|
||||
// Track image tokens after successful send
|
||||
const imageTokens = tokenTracker.calculateImageTokens(result.width || 1920, result.height || 1080);
|
||||
tokenTracker.addTokens(imageTokens, 'image');
|
||||
console.log(`📊 Image sent successfully - ${imageTokens} tokens used (${result.width}x${result.height})`);
|
||||
} else {
|
||||
console.error('Failed to send image:', sendResult.error);
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
console.error('Failed to capture screenshot:', result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error capturing screenshot:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function captureManualScreenshot(imageQuality = null) {
|
||||
console.log('Manual screenshot triggered');
|
||||
const quality = imageQuality || currentImageQuality;
|
||||
await captureScreenshot(quality, true);
|
||||
}
|
||||
|
||||
async function getCurrentScreenshot() {
|
||||
try {
|
||||
// First try to get a fresh screenshot from main process
|
||||
const result = await window.api.listenCapture.getCurrentScreenshot();
|
||||
|
||||
if (result.success && result.base64) {
|
||||
console.log('Got fresh screenshot from main process');
|
||||
return result.base64;
|
||||
}
|
||||
|
||||
// If no screenshot available, capture one now
|
||||
console.log('No screenshot available, capturing new one');
|
||||
const captureResult = await window.api.listenCapture.captureScreenshot({
|
||||
quality: currentImageQuality,
|
||||
});
|
||||
|
||||
if (captureResult.success && captureResult.base64) {
|
||||
lastScreenshotBase64 = captureResult.base64;
|
||||
return captureResult.base64;
|
||||
}
|
||||
|
||||
// Fallback to last stored screenshot
|
||||
if (lastScreenshotBase64) {
|
||||
console.log('Using cached screenshot');
|
||||
return lastScreenshotBase64;
|
||||
}
|
||||
|
||||
throw new Error('Failed to get screenshot');
|
||||
} catch (error) {
|
||||
console.error('Error getting current screenshot:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// Main capture functions (exact from renderer.js)
|
||||
// ---------------------------
|
||||
async function startCapture(screenshotIntervalSeconds = 5, imageQuality = 'medium') {
|
||||
// Store the image quality for manual screenshots
|
||||
currentImageQuality = imageQuality;
|
||||
|
||||
// Reset token tracker when starting new capture session
|
||||
tokenTracker.reset();
|
||||
@ -534,13 +443,6 @@ async function startCapture(screenshotIntervalSeconds = 5, imageQuality = 'mediu
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize screen capture in main process
|
||||
const screenResult = await window.api.listenCapture.startScreenCapture();
|
||||
if (!screenResult.success) {
|
||||
throw new Error('Failed to start screen capture: ' + screenResult.error);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
micMediaStream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: {
|
||||
@ -602,12 +504,6 @@ async function startCapture(screenshotIntervalSeconds = 5, imageQuality = 'mediu
|
||||
// Windows - capture mic and system audio separately using native loopback
|
||||
console.log('Starting Windows capture with native loopback audio...');
|
||||
|
||||
// Start screen capture in main process for screenshots
|
||||
const screenResult = await window.api.listenCapture.startScreenCapture();
|
||||
if (!screenResult.success) {
|
||||
throw new Error('Failed to start screen capture: ' + screenResult.error);
|
||||
}
|
||||
|
||||
// Ensure STT sessions are initialized before starting audio capture
|
||||
const sessionActive = await window.api.listenCapture.isSessionActive();
|
||||
if (!sessionActive) {
|
||||
@ -656,20 +552,6 @@ async function startCapture(screenshotIntervalSeconds = 5, imageQuality = 'mediu
|
||||
// Continue without system audio
|
||||
}
|
||||
}
|
||||
|
||||
// Start capturing screenshots - check if manual mode
|
||||
if (screenshotIntervalSeconds === 'manual' || screenshotIntervalSeconds === 'Manual') {
|
||||
console.log('Manual mode enabled - screenshots will be captured on demand only');
|
||||
// Don't start automatic capture in manual mode
|
||||
} else {
|
||||
// 스크린샷 기능 활성화 (chatModel에서 사용)
|
||||
const intervalMilliseconds = parseInt(screenshotIntervalSeconds) * 1000;
|
||||
screenshotInterval = setInterval(() => captureScreenshot(imageQuality), intervalMilliseconds);
|
||||
|
||||
// Capture first screenshot immediately
|
||||
setTimeout(() => captureScreenshot(imageQuality), 100);
|
||||
console.log(`📸 Screenshot capture enabled with ${screenshotIntervalSeconds}s interval`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error starting capture:', err);
|
||||
// Note: pickleGlass.e() is not available in this context, commenting out
|
||||
@ -678,11 +560,6 @@ async function startCapture(screenshotIntervalSeconds = 5, imageQuality = 'mediu
|
||||
}
|
||||
|
||||
function stopCapture() {
|
||||
if (screenshotInterval) {
|
||||
clearInterval(screenshotInterval);
|
||||
screenshotInterval = null;
|
||||
}
|
||||
|
||||
// Clean up microphone resources
|
||||
if (audioProcessor) {
|
||||
audioProcessor.disconnect();
|
||||
@ -713,11 +590,6 @@ function stopCapture() {
|
||||
micMediaStream = null;
|
||||
}
|
||||
|
||||
// Stop screen capture in main process
|
||||
window.api.listenCapture.stopScreenCapture().catch(err => {
|
||||
console.error('Error stopping screen capture:', err);
|
||||
});
|
||||
|
||||
// Stop macOS audio capture if running
|
||||
if (isMacOS) {
|
||||
window.api.listenCapture.stopMacosSystemAudio().catch(err => {
|
||||
@ -735,19 +607,14 @@ module.exports = {
|
||||
disposeAec, // 필요시 Rust 객체 파괴
|
||||
startCapture,
|
||||
stopCapture,
|
||||
captureManualScreenshot,
|
||||
getCurrentScreenshot,
|
||||
isLinux,
|
||||
isMacOS,
|
||||
};
|
||||
|
||||
// Expose functions to global scope for external access (exact from renderer.js)
|
||||
if (typeof window !== 'undefined') {
|
||||
window.captureManualScreenshot = captureManualScreenshot;
|
||||
window.listenCapture = module.exports;
|
||||
window.pickleGlass = window.pickleGlass || {};
|
||||
window.pickleGlass.startCapture = startCapture;
|
||||
window.pickleGlass.stopCapture = stopCapture;
|
||||
window.pickleGlass.captureManualScreenshot = captureManualScreenshot;
|
||||
window.pickleGlass.getCurrentScreenshot = getCurrentScreenshot;
|
||||
}
|
@ -693,6 +693,7 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
|
||||
async handleClearKey(provider) {
|
||||
console.log(`[SettingsView] handleClearKey: ${provider}`);
|
||||
this.saving = true;
|
||||
await window.api.settingsView.removeApiKey(provider);
|
||||
this.apiKeys = { ...this.apiKeys, [provider]: '' };
|
||||
@ -1097,13 +1098,6 @@ export class SettingsView extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
async handleClearApiKey() {
|
||||
console.log('Clear API Key clicked');
|
||||
await window.api.settingsView.removeApiKey();
|
||||
this.apiKey = null;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
handleQuit() {
|
||||
console.log('Quit clicked');
|
||||
window.api.settingsView.quitApplication();
|
||||
|
@ -1,4 +1,4 @@
|
||||
const { BrowserWindow, globalShortcut, ipcMain, screen, app, shell, desktopCapturer } = require('electron');
|
||||
const { BrowserWindow, globalShortcut, screen, app, shell } = require('electron');
|
||||
const WindowLayoutManager = require('./windowLayoutManager');
|
||||
const SmoothMovementManager = require('./smoothMovementManager');
|
||||
const path = require('node:path');
|
||||
@ -570,10 +570,7 @@ function createWindows() {
|
||||
}
|
||||
|
||||
function setupIpcHandlers(movementManager) {
|
||||
setupApiKeyIPC();
|
||||
|
||||
// quit-application handler moved to windowBridge.js to avoid duplication
|
||||
|
||||
screen.on('display-added', (event, newDisplay) => {
|
||||
console.log('[Display] New display added:', newDisplay.id);
|
||||
});
|
||||
@ -591,10 +588,9 @@ function setupIpcHandlers(movementManager) {
|
||||
// console.log('[Display] Display metrics changed:', display.id, changedMetrics);
|
||||
updateLayout();
|
||||
});
|
||||
}
|
||||
|
||||
// Content protection handlers moved to windowBridge.js to avoid duplication
|
||||
|
||||
ipcMain.on('header-state-changed', (event, state) => {
|
||||
const handleHeaderStateChanged = (state) => {
|
||||
console.log(`[WindowManager] Header state changed to: ${state}`);
|
||||
currentHeaderState = state;
|
||||
|
||||
@ -604,11 +600,9 @@ function setupIpcHandlers(movementManager) {
|
||||
destroyFeatureWindows();
|
||||
}
|
||||
internalBridge.emit('reregister-shortcuts');
|
||||
});
|
||||
};
|
||||
|
||||
// resize-header-window handler moved to windowBridge.js to avoid duplication
|
||||
|
||||
ipcMain.on('header-animation-finished', (event, state) => {
|
||||
const handleHeaderAnimationFinished = (state) => {
|
||||
const header = windowPool.get('header');
|
||||
if (!header || header.isDestroyed()) return;
|
||||
|
||||
@ -619,47 +613,42 @@ function setupIpcHandlers(movementManager) {
|
||||
console.log('[WindowManager] Header shown after animation.');
|
||||
updateLayout();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ipcMain.handle('get-header-position', () => {
|
||||
const getHeaderPosition = () => {
|
||||
const header = windowPool.get('header');
|
||||
if (header) {
|
||||
const [x, y] = header.getPosition();
|
||||
return { x, y };
|
||||
}
|
||||
return { x: 0, y: 0 };
|
||||
});
|
||||
};
|
||||
|
||||
ipcMain.handle('move-header', (event, newX, newY) => {
|
||||
const moveHeader = (newX, newY) => {
|
||||
const header = windowPool.get('header');
|
||||
if (header) {
|
||||
const currentY = newY !== undefined ? newY : header.getBounds().y;
|
||||
header.setPosition(newX, currentY, false);
|
||||
|
||||
updateLayout();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ipcMain.handle('move-header-to', (event, newX, newY) => {
|
||||
const moveHeaderTo = (newX, newY) => {
|
||||
const header = windowPool.get('header');
|
||||
if (header) {
|
||||
const targetDisplay = screen.getDisplayNearestPoint({ x: newX, y: newY });
|
||||
const { x: workAreaX, y: workAreaY, width, height } = targetDisplay.workArea;
|
||||
const headerBounds = header.getBounds();
|
||||
|
||||
// Only clamp if the new position would actually go out of bounds
|
||||
// This prevents progressive restriction of movement
|
||||
let clampedX = newX;
|
||||
let clampedY = newY;
|
||||
|
||||
// Check if we need to clamp X position
|
||||
if (newX < workAreaX) {
|
||||
clampedX = workAreaX;
|
||||
} else if (newX + headerBounds.width > workAreaX + width) {
|
||||
clampedX = workAreaX + width - headerBounds.width;
|
||||
}
|
||||
|
||||
// Check if we need to clamp Y position
|
||||
if (newY < workAreaY) {
|
||||
clampedY = workAreaY;
|
||||
} else if (newY + headerBounds.height > workAreaY + height) {
|
||||
@ -667,16 +656,12 @@ function setupIpcHandlers(movementManager) {
|
||||
}
|
||||
|
||||
header.setPosition(clampedX, clampedY, false);
|
||||
|
||||
updateLayout();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// move-window-step handler moved to windowBridge.js to avoid duplication
|
||||
|
||||
ipcMain.handle('adjust-window-height', (event, targetHeight) => {
|
||||
const senderWindow = BrowserWindow.fromWebContents(event.sender);
|
||||
const adjustWindowHeight = (sender, targetHeight) => {
|
||||
const senderWindow = BrowserWindow.fromWebContents(sender);
|
||||
if (senderWindow) {
|
||||
const wasResizable = senderWindow.isResizable();
|
||||
if (!wasResizable) {
|
||||
@ -702,276 +687,47 @@ function setupIpcHandlers(movementManager) {
|
||||
|
||||
updateLayout();
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('check-system-permissions', async () => {
|
||||
const { systemPreferences } = require('electron');
|
||||
const permissions = {
|
||||
microphone: 'unknown',
|
||||
screen: 'unknown',
|
||||
needsSetup: true
|
||||
};
|
||||
|
||||
try {
|
||||
if (process.platform === 'darwin') {
|
||||
// Check microphone permission on macOS
|
||||
const micStatus = systemPreferences.getMediaAccessStatus('microphone');
|
||||
console.log('[Permissions] Microphone status:', micStatus);
|
||||
permissions.microphone = micStatus;
|
||||
|
||||
// Check screen recording permission using the system API
|
||||
const screenStatus = systemPreferences.getMediaAccessStatus('screen');
|
||||
console.log('[Permissions] Screen status:', screenStatus);
|
||||
permissions.screen = screenStatus;
|
||||
|
||||
permissions.needsSetup = micStatus !== 'granted' || screenStatus !== 'granted';
|
||||
} else {
|
||||
permissions.microphone = 'granted';
|
||||
permissions.screen = 'granted';
|
||||
permissions.needsSetup = false;
|
||||
}
|
||||
|
||||
console.log('[Permissions] System permissions status:', permissions);
|
||||
return permissions;
|
||||
} catch (error) {
|
||||
console.error('[Permissions] Error checking permissions:', error);
|
||||
return {
|
||||
microphone: 'unknown',
|
||||
screen: 'unknown',
|
||||
needsSetup: true,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('request-microphone-permission', async () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
const { systemPreferences } = require('electron');
|
||||
try {
|
||||
const status = systemPreferences.getMediaAccessStatus('microphone');
|
||||
console.log('[Permissions] Microphone status:', status);
|
||||
if (status === 'granted') {
|
||||
return { success: true, status: 'granted' };
|
||||
}
|
||||
|
||||
// Req mic permission
|
||||
const granted = await systemPreferences.askForMediaAccess('microphone');
|
||||
return {
|
||||
success: granted,
|
||||
status: granted ? 'granted' : 'denied'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[Permissions] Error requesting microphone permission:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('open-system-preferences', async (event, section) => {
|
||||
if (process.platform !== 'darwin') {
|
||||
return { success: false, error: 'Not supported on this platform' };
|
||||
}
|
||||
|
||||
try {
|
||||
if (section === 'screen-recording') {
|
||||
// First trigger screen capture request to register the app in system preferences
|
||||
try {
|
||||
console.log('[Permissions] Triggering screen capture request to register app...');
|
||||
await desktopCapturer.getSources({
|
||||
types: ['screen'],
|
||||
thumbnailSize: { width: 1, height: 1 }
|
||||
});
|
||||
console.log('[Permissions] App registered for screen recording');
|
||||
} catch (captureError) {
|
||||
console.log('[Permissions] Screen capture request triggered (expected to fail):', captureError.message);
|
||||
}
|
||||
|
||||
// Then open system preferences
|
||||
// await shell.openExternal('x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture');
|
||||
}
|
||||
// if (section === 'microphone') {
|
||||
// await shell.openExternal('x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone');
|
||||
// }
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('[Permissions] Error opening system preferences:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('mark-permissions-completed', async () => {
|
||||
try {
|
||||
// This is a system-level setting, not user-specific.
|
||||
await permissionRepository.markPermissionsAsCompleted();
|
||||
console.log('[Permissions] Marked permissions as completed');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('[Permissions] Error marking permissions as completed:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('check-permissions-completed', async () => {
|
||||
try {
|
||||
const completed = await permissionRepository.checkPermissionsCompleted();
|
||||
console.log('[Permissions] Permissions completed status:', completed);
|
||||
return completed;
|
||||
} catch (error) {
|
||||
console.error('[Permissions] Error checking permissions completed status:', error);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('toggle-all-windows-visibility', () => toggleAllWindowsVisibility());
|
||||
|
||||
// ipcMain.handle('toggle-feature', async (event, featureName) => {
|
||||
// return toggleFeature(featureName);
|
||||
// });
|
||||
|
||||
ipcMain.on('animation-finished', (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
const handleAnimationFinished = (sender) => {
|
||||
const win = BrowserWindow.fromWebContents(sender);
|
||||
if (win && !win.isDestroyed()) {
|
||||
console.log(`[WindowManager] Hiding window after animation.`);
|
||||
win.hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
ipcMain.handle('ask:closeAskWindow', async () => {
|
||||
const closeAskWindow = () => {
|
||||
const askWindow = windowPool.get('ask');
|
||||
if (askWindow) {
|
||||
askWindow.webContents.send('window-hide-animation');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
async function ensureAskWindowVisible() {
|
||||
if (currentHeaderState !== 'main') {
|
||||
console.log('[WindowManager] Not in main state, skipping ensureAskWindowVisible');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// *
|
||||
// * @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'));
|
||||
}
|
||||
|
||||
if (featureName === 'ask') {
|
||||
let askWindow = windowPool.get('ask');
|
||||
|
||||
if (!askWindow || askWindow.isDestroyed()) {
|
||||
console.log('[WindowManager] Ask window not found, creating new one');
|
||||
return;
|
||||
createFeatureWindows(windowPool.get('header'), 'ask');
|
||||
askWindow = windowPool.get('ask');
|
||||
}
|
||||
if (askWindow.isVisible()) {
|
||||
askWindow.webContents.send('ask:showTextInput');
|
||||
} else {
|
||||
|
||||
if (!askWindow.isVisible()) {
|
||||
console.log('[WindowManager] Showing hidden Ask window');
|
||||
askWindow.show();
|
||||
updateLayout();
|
||||
askWindow.webContents.send('window-show-animation');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////// after_modelStateService ////////
|
||||
async function getStoredApiKey() {
|
||||
if (global.modelStateService) {
|
||||
const provider = await getStoredProvider();
|
||||
return global.modelStateService.getApiKey(provider);
|
||||
}
|
||||
return null; // Fallback
|
||||
}
|
||||
|
||||
async function getStoredProvider() {
|
||||
if (global.modelStateService) {
|
||||
return global.modelStateService.getCurrentProvider('llm');
|
||||
}
|
||||
return 'openai'; // Fallback
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {IpcMainInvokeEvent} event
|
||||
* @param {{type: 'llm' | 'stt'}}
|
||||
*/
|
||||
async function getCurrentModelInfo(event, { type }) {
|
||||
if (global.modelStateService && (type === 'llm' || type === 'stt')) {
|
||||
return global.modelStateService.getCurrentModelInfo(type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function setupApiKeyIPC() {
|
||||
const { ipcMain } = require('electron');
|
||||
|
||||
ipcMain.handle('get-stored-api-key', getStoredApiKey);
|
||||
ipcMain.handle('get-ai-provider', getStoredProvider);
|
||||
ipcMain.handle('get-current-model-info', getCurrentModelInfo);
|
||||
|
||||
ipcMain.handle('api-key-validated', async (event, data) => {
|
||||
console.warn("[DEPRECATED] 'api-key-validated' IPC was called. This logic is now handled by 'model:validate-key'.");
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
ipcMain.handle('remove-api-key', async () => {
|
||||
console.warn("[DEPRECATED] 'remove-api-key' IPC was called. This is now handled by 'model:remove-api-key'.");
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
console.log('[WindowManager] API key related IPC handlers have been updated for ModelStateService.');
|
||||
}
|
||||
//////// after_modelStateService ////////
|
||||
|
||||
|
||||
const closeWindow = (windowName) => {
|
||||
const win = windowPool.get(windowName);
|
||||
@ -985,10 +741,6 @@ module.exports = {
|
||||
createWindows,
|
||||
windowPool,
|
||||
fixedYPosition,
|
||||
getStoredApiKey,
|
||||
getStoredProvider,
|
||||
getCurrentModelInfo,
|
||||
toggleFeature, // Export toggleFeature so shortcutsService can use it
|
||||
toggleContentProtection,
|
||||
resizeHeaderWindow,
|
||||
getContentProtectionStatus,
|
||||
@ -999,4 +751,14 @@ module.exports = {
|
||||
openLoginPage,
|
||||
moveWindowStep,
|
||||
closeWindow,
|
||||
toggleAllWindowsVisibility,
|
||||
handleHeaderStateChanged,
|
||||
handleHeaderAnimationFinished,
|
||||
getHeaderPosition,
|
||||
moveHeader,
|
||||
moveHeaderTo,
|
||||
adjustWindowHeight,
|
||||
handleAnimationFinished,
|
||||
closeAskWindow,
|
||||
ensureAskWindowVisible,
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user