common service ipc moved to featureBridge
This commit is contained in:
		
							parent
							
								
									b2475c0940
								
							
						
					
					
						commit
						f60e73c08c
					
				@ -1,32 +1,72 @@
 | 
			
		||||
// src/bridge/featureBridge.js
 | 
			
		||||
const { ipcMain } = require('electron');
 | 
			
		||||
const { ipcMain, app } = require('electron');
 | 
			
		||||
const settingsService = require('../features/settings/settingsService');
 | 
			
		||||
const authService = require('../features/common/services/authService');
 | 
			
		||||
const whisperService = require('../features/common/services/whisperService');
 | 
			
		||||
const ollamaService = require('../features/common/services/ollamaService');
 | 
			
		||||
const modelStateService = require('../features/common/services/modelStateService');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  // Renderer로부터의 요청을 수신
 | 
			
		||||
  initialize() {
 | 
			
		||||
    ipcMain.handle('settings:getPresets', async () => {
 | 
			
		||||
      console.log('[FeatureBridge] settings:getPresets 호출됨');
 | 
			
		||||
      return await settingsService.getPresets();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('settings:get-auto-update', async () => {
 | 
			
		||||
      console.log('[FeatureBridge] settings:get-auto-update 호출됨');
 | 
			
		||||
      return await settingsService.getAutoUpdateSetting();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('settings:set-auto-update', async (event, isEnabled) => {
 | 
			
		||||
      console.log('[FeatureBridge] settings:set-auto-update 호출됨', isEnabled);
 | 
			
		||||
      return await settingsService.setAutoUpdateSetting(isEnabled);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // New IPC handler for loadInitialData
 | 
			
		||||
    ipcMain.handle('settings:loadInitialData', async () => {
 | 
			
		||||
      console.log('[FeatureBridge] settings:loadInitialData called');
 | 
			
		||||
      return await settingsService.loadInitialData();
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    console.log('[FeatureBridge] Initialized with settings handlers.');
 | 
			
		||||
    // Settings Service
 | 
			
		||||
    ipcMain.handle('settings:getPresets', async () => await settingsService.getPresets());
 | 
			
		||||
    ipcMain.handle('settings:get-auto-update', async () => await settingsService.getAutoUpdateSetting());
 | 
			
		||||
    ipcMain.handle('settings:set-auto-update', async (event, isEnabled) => await settingsService.setAutoUpdateSetting(isEnabled));  
 | 
			
		||||
    ipcMain.handle('settings:get-model-settings', async () => await settingsService.getModelSettings());
 | 
			
		||||
    ipcMain.handle('settings:validate-and-save-key', async (e, { provider, key }) => await settingsService.validateAndSaveKey(provider, key));
 | 
			
		||||
    ipcMain.handle('settings:clear-api-key', async (e, { provider }) => await settingsService.clearApiKey(provider));
 | 
			
		||||
    ipcMain.handle('settings:set-selected-model', async (e, { type, modelId }) => await settingsService.setSelectedModel(type, modelId));    
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('settings:get-ollama-status', async () => await settingsService.getOllamaStatus());
 | 
			
		||||
    ipcMain.handle('settings:ensure-ollama-ready', async () => await settingsService.ensureOllamaReady());
 | 
			
		||||
    ipcMain.handle('settings:shutdown-ollama', async () => await settingsService.shutdownOllama());
 | 
			
		||||
 | 
			
		||||
    // User/Auth
 | 
			
		||||
    ipcMain.handle('get-current-user', () => authService.getCurrentUser());
 | 
			
		||||
    ipcMain.handle('start-firebase-auth', async () => await authService.startFirebaseAuthFlow());
 | 
			
		||||
    ipcMain.handle('firebase-logout', async () => await authService.signOut());
 | 
			
		||||
 | 
			
		||||
    // App
 | 
			
		||||
    ipcMain.handle('quit-application', () => app.quit());
 | 
			
		||||
 | 
			
		||||
    // Whisper
 | 
			
		||||
    ipcMain.handle('whisper:download-model', async (event, modelId) => await whisperService.handleDownloadModel(event, modelId));
 | 
			
		||||
    ipcMain.handle('whisper:get-installed-models', async () => await whisperService.handleGetInstalledModels());
 | 
			
		||||
       
 | 
			
		||||
    // General
 | 
			
		||||
    ipcMain.handle('get-preset-templates', () => presetRepository.getPresetTemplates());
 | 
			
		||||
    ipcMain.handle('get-web-url', () => process.env.pickleglass_WEB_URL || 'http://localhost:3000');
 | 
			
		||||
 | 
			
		||||
    // Ollama
 | 
			
		||||
    ipcMain.handle('ollama:get-status', async () => await ollamaService.handleGetStatus());
 | 
			
		||||
    ipcMain.handle('ollama:install', async (event) => await ollamaService.handleInstall(event));
 | 
			
		||||
    ipcMain.handle('ollama:start-service', async (event) => await ollamaService.handleStartService(event));
 | 
			
		||||
    ipcMain.handle('ollama:ensure-ready', async () => await ollamaService.handleEnsureReady());
 | 
			
		||||
    ipcMain.handle('ollama:get-models', async () => await ollamaService.handleGetModels());
 | 
			
		||||
    ipcMain.handle('ollama:get-model-suggestions', async () => await ollamaService.handleGetModelSuggestions());
 | 
			
		||||
    ipcMain.handle('ollama:pull-model', async (event, modelName) => await ollamaService.handlePullModel(event, modelName));
 | 
			
		||||
    ipcMain.handle('ollama:is-model-installed', async (event, modelName) => await ollamaService.handleIsModelInstalled(modelName));
 | 
			
		||||
    ipcMain.handle('ollama:warm-up-model', async (event, modelName) => await ollamaService.handleWarmUpModel(modelName));
 | 
			
		||||
    ipcMain.handle('ollama:auto-warm-up', async () => await ollamaService.handleAutoWarmUp());
 | 
			
		||||
    ipcMain.handle('ollama:get-warm-up-status', async () => await ollamaService.handleGetWarmUpStatus());
 | 
			
		||||
    ipcMain.handle('ollama:shutdown', async (event, force = false) => await ollamaService.handleShutdown(event, force));
 | 
			
		||||
 | 
			
		||||
    // ModelStateService
 | 
			
		||||
    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: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());
 | 
			
		||||
 | 
			
		||||
    console.log('[FeatureBridge] Initialized with all feature handlers.');
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // Renderer로 상태를 전송
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
const { onAuthStateChanged, signInWithCustomToken, signOut } = require('firebase/auth');
 | 
			
		||||
const { BrowserWindow } = require('electron');
 | 
			
		||||
const { BrowserWindow, shell } = require('electron');
 | 
			
		||||
const { getFirebaseAuth } = require('./firebaseClient');
 | 
			
		||||
const fetch = require('node-fetch');
 | 
			
		||||
const encryptionService = require('./encryptionService');
 | 
			
		||||
@ -131,6 +131,19 @@ class AuthService {
 | 
			
		||||
        return this.initializationPromise;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async startFirebaseAuthFlow() {
 | 
			
		||||
        try {
 | 
			
		||||
            const webUrl = process.env.pickleglass_WEB_URL || 'http://localhost:3000';
 | 
			
		||||
            const authUrl = `${webUrl}/login?mode=electron`;
 | 
			
		||||
            console.log(`[AuthService] Opening Firebase auth URL in browser: ${authUrl}`);
 | 
			
		||||
            await shell.openExternal(authUrl);
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[AuthService] Failed to open Firebase auth URL:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async signInWithCustomToken(token) {
 | 
			
		||||
        const auth = getFirebaseAuth();
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,6 @@ class ModelStateService {
 | 
			
		||||
    async initialize() {
 | 
			
		||||
        console.log('[ModelStateService] Initializing...');
 | 
			
		||||
        await this._loadStateForCurrentUser();
 | 
			
		||||
        this.setupIpcHandlers();
 | 
			
		||||
        console.log('[ModelStateService] Initialization complete');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -329,10 +328,11 @@ class ModelStateService {
 | 
			
		||||
        this._logCurrentSelection();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setApiKey(provider, key) {
 | 
			
		||||
    async setApiKey(provider, key) {
 | 
			
		||||
        if (provider in this.state.apiKeys) {
 | 
			
		||||
            this.state.apiKeys[provider] = key;
 | 
			
		||||
            this._saveState();
 | 
			
		||||
            this._autoSelectAvailableModels();
 | 
			
		||||
            await this._saveState();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
@ -523,10 +523,7 @@ class ModelStateService {
 | 
			
		||||
        if (result.success) {
 | 
			
		||||
            // Use 'local' as placeholder for local services
 | 
			
		||||
            const finalKey = (provider === 'ollama' || provider === 'whisper') ? 'local' : key;
 | 
			
		||||
            this.setApiKey(provider, finalKey);
 | 
			
		||||
            // After setting the key, auto-select models
 | 
			
		||||
            this._autoSelectAvailableModels();
 | 
			
		||||
            this._saveState(); // Ensure state is saved after model selection
 | 
			
		||||
            await this.setApiKey(provider, finalKey);
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
@ -569,26 +566,6 @@ class ModelStateService {
 | 
			
		||||
        return { provider, model, apiKey };
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    setupIpcHandlers() {
 | 
			
		||||
        ipcMain.handle('model:validate-key', async (e, { provider, key }) => this.handleValidateKey(provider, key));
 | 
			
		||||
        ipcMain.handle('model:get-all-keys', () => this.getAllApiKeys());
 | 
			
		||||
        ipcMain.handle('model:set-api-key', async (e, { provider, key }) => {
 | 
			
		||||
            const success = this.setApiKey(provider, key);
 | 
			
		||||
            if (success) {
 | 
			
		||||
                this._autoSelectAvailableModels();
 | 
			
		||||
                await this._saveState();
 | 
			
		||||
            }
 | 
			
		||||
            return success;
 | 
			
		||||
        });
 | 
			
		||||
        ipcMain.handle('model:remove-api-key', async (e, { provider }) => this.handleRemoveApiKey(provider));
 | 
			
		||||
        ipcMain.handle('model:get-selected-models', () => this.getSelectedModels());
 | 
			
		||||
        ipcMain.handle('model:set-selected-model', async (e, { type, modelId }) => this.handleSetSelectedModel(type, modelId));
 | 
			
		||||
        ipcMain.handle('model:get-available-models', (e, { type }) => this.getAvailableModels(type));
 | 
			
		||||
        ipcMain.handle('model:are-providers-configured', () => this.areProvidersConfigured());
 | 
			
		||||
        ipcMain.handle('model:get-current-model-info', (e, { type }) => this.getCurrentModelInfo(type));
 | 
			
		||||
 | 
			
		||||
        ipcMain.handle('model:get-provider-config', () => this.getProviderConfig());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Export singleton instance
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ const { app } = require('electron');
 | 
			
		||||
const LocalAIServiceBase = require('./localAIServiceBase');
 | 
			
		||||
const { spawnAsync } = require('../utils/spawnHelper');
 | 
			
		||||
const { DOWNLOAD_CHECKSUMS } = require('../config/checksums');
 | 
			
		||||
const ollamaModelRepository = require('../repositories/ollamaModel');
 | 
			
		||||
 | 
			
		||||
class OllamaService extends LocalAIServiceBase {
 | 
			
		||||
    constructor() {
 | 
			
		||||
@ -822,6 +823,183 @@ class OllamaService extends LocalAIServiceBase {
 | 
			
		||||
        
 | 
			
		||||
        return models;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleGetStatus() {
 | 
			
		||||
        try {
 | 
			
		||||
            const installed = await this.isInstalled();
 | 
			
		||||
            if (!installed) {
 | 
			
		||||
                return { success: true, installed: false, running: false, models: [] };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const running = await this.isServiceRunning();
 | 
			
		||||
            if (!running) {
 | 
			
		||||
                return { success: true, installed: true, running: false, models: [] };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const models = await this.getAllModelsWithStatus();
 | 
			
		||||
            return { success: true, installed: true, running: true, models };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Error getting status:', error);
 | 
			
		||||
            return { success: false, error: error.message, installed: false, running: false, models: [] };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleInstall(event) {
 | 
			
		||||
        try {
 | 
			
		||||
            const onProgress = (data) => {
 | 
			
		||||
                event.sender.send('ollama:install-progress', data);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            await this.autoInstall(onProgress);
 | 
			
		||||
 | 
			
		||||
            if (!await this.isServiceRunning()) {
 | 
			
		||||
                onProgress({ stage: 'starting', message: 'Starting Ollama service...', progress: 0 });
 | 
			
		||||
                await this.startService();
 | 
			
		||||
                onProgress({ stage: 'starting', message: 'Ollama service started.', progress: 100 });
 | 
			
		||||
            }
 | 
			
		||||
            event.sender.send('ollama:install-complete', { success: true });
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to install:', error);
 | 
			
		||||
            event.sender.send('ollama:install-complete', { success: false, error: error.message });
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleStartService(event) {
 | 
			
		||||
        try {
 | 
			
		||||
            if (!await this.isServiceRunning()) {
 | 
			
		||||
                console.log('[OllamaService] Starting Ollama service...');
 | 
			
		||||
                await this.startService();
 | 
			
		||||
            }
 | 
			
		||||
            event.sender.send('ollama:install-complete', { success: true });
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to start service:', error);
 | 
			
		||||
            event.sender.send('ollama:install-complete', { success: false, error: error.message });
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleEnsureReady() {
 | 
			
		||||
        try {
 | 
			
		||||
            if (await this.isInstalled() && !await this.isServiceRunning()) {
 | 
			
		||||
                console.log('[OllamaService] Ollama installed but not running, starting service...');
 | 
			
		||||
                await this.startService();
 | 
			
		||||
            }
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to ensure ready:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleGetModels() {
 | 
			
		||||
        try {
 | 
			
		||||
            const models = await this.getAllModelsWithStatus();
 | 
			
		||||
            return { success: true, models };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to get models:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleGetModelSuggestions() {
 | 
			
		||||
        try {
 | 
			
		||||
            const suggestions = await this.getModelSuggestions();
 | 
			
		||||
            return { success: true, suggestions };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to get model suggestions:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handlePullModel(event, modelName) {
 | 
			
		||||
        try {
 | 
			
		||||
            console.log(`[OllamaService] Starting model pull: ${modelName}`);
 | 
			
		||||
 | 
			
		||||
            await ollamaModelRepository.updateInstallStatus(modelName, false, true);
 | 
			
		||||
 | 
			
		||||
            const progressHandler = (data) => {
 | 
			
		||||
                if (data.model === modelName) {
 | 
			
		||||
                    event.sender.send('ollama:pull-progress', data);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            const completeHandler = (data) => {
 | 
			
		||||
                if (data.model === modelName) {
 | 
			
		||||
                    console.log(`[OllamaService] Model ${modelName} pull completed`);
 | 
			
		||||
                    this.removeListener('pull-progress', progressHandler);
 | 
			
		||||
                    this.removeListener('pull-complete', completeHandler);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.on('pull-progress', progressHandler);
 | 
			
		||||
            this.on('pull-complete', completeHandler);
 | 
			
		||||
 | 
			
		||||
            await this.pullModel(modelName);
 | 
			
		||||
 | 
			
		||||
            await ollamaModelRepository.updateInstallStatus(modelName, true, false);
 | 
			
		||||
 | 
			
		||||
            console.log(`[OllamaService] Model ${modelName} pull successful`);
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to pull model:', error);
 | 
			
		||||
            await ollamaModelRepository.updateInstallStatus(modelName, false, false);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleIsModelInstalled(modelName) {
 | 
			
		||||
        try {
 | 
			
		||||
            const installed = await this.isModelInstalled(modelName);
 | 
			
		||||
            return { success: true, installed };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to check model installation:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleWarmUpModel(modelName) {
 | 
			
		||||
        try {
 | 
			
		||||
            const success = await this.warmUpModel(modelName);
 | 
			
		||||
            return { success };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to warm up model:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleAutoWarmUp() {
 | 
			
		||||
        try {
 | 
			
		||||
            const success = await this.autoWarmUpSelectedModel();
 | 
			
		||||
            return { success };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to auto warm-up:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleGetWarmUpStatus() {
 | 
			
		||||
        try {
 | 
			
		||||
            const status = this.getWarmUpStatus();
 | 
			
		||||
            return { success: true, status };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to get warm-up status:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleShutdown(event, force = false) {
 | 
			
		||||
        try {
 | 
			
		||||
            console.log(`[OllamaService] Manual shutdown requested (force: ${force})`);
 | 
			
		||||
            const success = await this.shutdown(force);
 | 
			
		||||
            return { success };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[OllamaService] Failed to shutdown Ollama:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Export singleton instance
 | 
			
		||||
 | 
			
		||||
@ -169,6 +169,47 @@ class WhisperService extends LocalAIServiceBase {
 | 
			
		||||
        console.log(`[WhisperService] Model ${modelId} downloaded successfully`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleDownloadModel(event, modelId) {
 | 
			
		||||
        try {
 | 
			
		||||
            console.log(`[WhisperService] Handling download for model: ${modelId}`);
 | 
			
		||||
 | 
			
		||||
            if (!this.isInitialized) {
 | 
			
		||||
                await this.initialize();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const progressHandler = (data) => {
 | 
			
		||||
                if (data.modelId === modelId && event && event.sender) {
 | 
			
		||||
                    event.sender.send('whisper:download-progress', data);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            this.on('downloadProgress', progressHandler);
 | 
			
		||||
            
 | 
			
		||||
            try {
 | 
			
		||||
                await this.ensureModelAvailable(modelId);
 | 
			
		||||
            } finally {
 | 
			
		||||
                this.removeListener('downloadProgress', progressHandler);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error(`[WhisperService] Failed to handle download for model ${modelId}:`, error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleGetInstalledModels() {
 | 
			
		||||
        try {
 | 
			
		||||
            if (!this.isInitialized) {
 | 
			
		||||
                await this.initialize();
 | 
			
		||||
            }
 | 
			
		||||
            const models = await this.getInstalledModels();
 | 
			
		||||
            return { success: true, models };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[WhisperService] Failed to get installed models:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async getModelPath(modelId) {
 | 
			
		||||
        if (!this.isInitialized || !this.modelsDir) {
 | 
			
		||||
 | 
			
		||||
@ -423,17 +423,6 @@ function initialize() {
 | 
			
		||||
    // cleanup 
 | 
			
		||||
    windowNotificationManager.cleanup();
 | 
			
		||||
    
 | 
			
		||||
    // IPC handlers for model settings
 | 
			
		||||
    ipcMain.handle('settings:get-model-settings', getModelSettings);
 | 
			
		||||
    ipcMain.handle('settings:validate-and-save-key', (e, { provider, key }) => validateAndSaveKey(provider, key));
 | 
			
		||||
    ipcMain.handle('settings:clear-api-key', (e, { provider }) => clearApiKey(provider));
 | 
			
		||||
    ipcMain.handle('settings:set-selected-model', (e, { type, modelId }) => setSelectedModel(type, modelId));
 | 
			
		||||
 | 
			
		||||
    // IPC handlers for Ollama management
 | 
			
		||||
    ipcMain.handle('settings:get-ollama-status', getOllamaStatus);
 | 
			
		||||
    ipcMain.handle('settings:ensure-ollama-ready', ensureOllamaReady);
 | 
			
		||||
    ipcMain.handle('settings:shutdown-ollama', shutdownOllama);
 | 
			
		||||
    
 | 
			
		||||
    console.log('[SettingsService] Initialized and ready.');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										301
									
								
								src/index.js
									
									
									
									
									
								
							
							
						
						
									
										301
									
								
								src/index.js
									
									
									
									
									
								
							@ -26,7 +26,6 @@ const askService = require('./features/ask/askService');
 | 
			
		||||
const settingsService = require('./features/settings/settingsService');
 | 
			
		||||
const sessionRepository = require('./features/common/repositories/session');
 | 
			
		||||
const modelStateService = require('./features/common/services/modelStateService');
 | 
			
		||||
const sqliteClient = require('./features/common/services/sqliteClient');
 | 
			
		||||
const featureBridge = require('./bridge/featureBridge');
 | 
			
		||||
 | 
			
		||||
// Global variables
 | 
			
		||||
@ -200,11 +199,8 @@ app.whenReady().then(async () => {
 | 
			
		||||
 | 
			
		||||
        listenService.initialize();
 | 
			
		||||
        askService.initialize();
 | 
			
		||||
        settingsService.initialize();
 | 
			
		||||
        featureBridge.initialize();  // 추가: featureBridge 초기화
 | 
			
		||||
        setupGeneralIpcHandlers();
 | 
			
		||||
        setupOllamaIpcHandlers();
 | 
			
		||||
        setupWhisperIpcHandlers();
 | 
			
		||||
        setupWebDataHandlers();
 | 
			
		||||
 | 
			
		||||
        // Initialize Ollama models in database
 | 
			
		||||
        await ollamaModelRepository.initializeDefaultModels();
 | 
			
		||||
@ -318,301 +314,6 @@ app.on('activate', () => {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function setupWhisperIpcHandlers() {
 | 
			
		||||
    const whisperService = require('./features/common/services/whisperService');
 | 
			
		||||
    
 | 
			
		||||
    // Forward download progress events to renderer
 | 
			
		||||
    whisperService.on('downloadProgress', (data) => {
 | 
			
		||||
        const windows = BrowserWindow.getAllWindows();
 | 
			
		||||
        windows.forEach(window => {
 | 
			
		||||
            window.webContents.send('whisper:download-progress', data);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    // IPC handlers for Whisper operations
 | 
			
		||||
    ipcMain.handle('whisper:download-model', async (event, modelId) => {
 | 
			
		||||
        try {
 | 
			
		||||
            console.log(`[Whisper IPC] Starting download for model: ${modelId}`);
 | 
			
		||||
            
 | 
			
		||||
            // Ensure WhisperService is initialized first
 | 
			
		||||
            if (!whisperService.isInitialized) {
 | 
			
		||||
                console.log('[Whisper IPC] Initializing WhisperService...');
 | 
			
		||||
                await whisperService.initialize();
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Set up progress listener
 | 
			
		||||
            const progressHandler = (data) => {
 | 
			
		||||
                if (data.modelId === modelId) {
 | 
			
		||||
                    event.sender.send('whisper:download-progress', data);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            whisperService.on('downloadProgress', progressHandler);
 | 
			
		||||
            
 | 
			
		||||
            try {
 | 
			
		||||
                await whisperService.ensureModelAvailable(modelId);
 | 
			
		||||
                console.log(`[Whisper IPC] Model ${modelId} download completed successfully`);
 | 
			
		||||
            } finally {
 | 
			
		||||
                // Cleanup listener
 | 
			
		||||
                whisperService.removeListener('downloadProgress', progressHandler);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error(`[Whisper IPC] Failed to download model ${modelId}:`, error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    ipcMain.handle('whisper:get-installed-models', async () => {
 | 
			
		||||
        try {
 | 
			
		||||
            // Ensure WhisperService is initialized first
 | 
			
		||||
            if (!whisperService.isInitialized) {
 | 
			
		||||
                console.log('[Whisper IPC] Initializing WhisperService for model list...');
 | 
			
		||||
                await whisperService.initialize();
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            const models = await whisperService.getInstalledModels();
 | 
			
		||||
            return { success: true, models };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Whisper IPC] Failed to get installed models:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setupGeneralIpcHandlers() {
 | 
			
		||||
    const userRepository = require('./features/common/repositories/user');
 | 
			
		||||
    const presetRepository = require('./features/common/repositories/preset');
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('get-user-presets', () => {
 | 
			
		||||
        // The adapter injects the UID.
 | 
			
		||||
        return presetRepository.getPresets();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('get-preset-templates', () => {
 | 
			
		||||
        return presetRepository.getPresetTemplates();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('start-firebase-auth', async () => {
 | 
			
		||||
        try {
 | 
			
		||||
            const authUrl = `http://localhost:${WEB_PORT}/login?mode=electron`;
 | 
			
		||||
            console.log(`[Auth] Opening Firebase auth URL in browser: ${authUrl}`);
 | 
			
		||||
            await shell.openExternal(authUrl);
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Auth] Failed to open Firebase auth URL:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('get-web-url', () => {
 | 
			
		||||
        return process.env.pickleglass_WEB_URL || 'http://localhost:3000';
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('get-current-user', () => {
 | 
			
		||||
        return authService.getCurrentUser();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // --- Web UI Data Handlers (New) ---
 | 
			
		||||
    setupWebDataHandlers();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setupOllamaIpcHandlers() {
 | 
			
		||||
    // Ollama status and installation
 | 
			
		||||
    ipcMain.handle('ollama:get-status', async () => {
 | 
			
		||||
        try {
 | 
			
		||||
            const installed = await ollamaService.isInstalled();
 | 
			
		||||
            const running = installed ? await ollamaService.isServiceRunning() : false;
 | 
			
		||||
            const models = await ollamaService.getAllModelsWithStatus();
 | 
			
		||||
            
 | 
			
		||||
            return { 
 | 
			
		||||
                installed, 
 | 
			
		||||
                running, 
 | 
			
		||||
                models,
 | 
			
		||||
                success: true 
 | 
			
		||||
            };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to get status:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('ollama:install', async (event) => {
 | 
			
		||||
        try {
 | 
			
		||||
            const onProgress = (data) => {
 | 
			
		||||
                event.sender.send('ollama:install-progress', data);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            await ollamaService.autoInstall(onProgress);
 | 
			
		||||
            
 | 
			
		||||
            if (!await ollamaService.isServiceRunning()) {
 | 
			
		||||
                onProgress({ stage: 'starting', message: 'Starting Ollama service...', progress: 0 });
 | 
			
		||||
                await ollamaService.startService();
 | 
			
		||||
                onProgress({ stage: 'starting', message: 'Ollama service started.', progress: 100 });
 | 
			
		||||
            }
 | 
			
		||||
            event.sender.send('ollama:install-complete', { success: true });
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to install:', error);
 | 
			
		||||
            event.sender.send('ollama:install-complete', { success: false, error: error.message });
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('ollama:start-service', async (event) => {
 | 
			
		||||
        try {
 | 
			
		||||
            if (!await ollamaService.isServiceRunning()) {
 | 
			
		||||
                console.log('[Ollama IPC] Starting Ollama service...');
 | 
			
		||||
                await ollamaService.startService();
 | 
			
		||||
            }
 | 
			
		||||
            event.sender.send('ollama:install-complete', { success: true });
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to start service:', error);
 | 
			
		||||
            event.sender.send('ollama:install-complete', { success: false, error: error.message });
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Ensure Ollama is ready (starts service if installed but not running)
 | 
			
		||||
    ipcMain.handle('ollama:ensure-ready', async () => {
 | 
			
		||||
        try {
 | 
			
		||||
            if (await ollamaService.isInstalled() && !await ollamaService.isServiceRunning()) {
 | 
			
		||||
                console.log('[Ollama IPC] Ollama installed but not running, starting service...');
 | 
			
		||||
                await ollamaService.startService();
 | 
			
		||||
            }
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to ensure ready:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Get all models with their status
 | 
			
		||||
    ipcMain.handle('ollama:get-models', async () => {
 | 
			
		||||
        try {
 | 
			
		||||
            const models = await ollamaService.getAllModelsWithStatus();
 | 
			
		||||
            return { success: true, models };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to get models:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Get model suggestions for autocomplete
 | 
			
		||||
    ipcMain.handle('ollama:get-model-suggestions', async () => {
 | 
			
		||||
        try {
 | 
			
		||||
            const suggestions = await ollamaService.getModelSuggestions();
 | 
			
		||||
            return { success: true, suggestions };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to get model suggestions:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Pull/install a specific model
 | 
			
		||||
    ipcMain.handle('ollama:pull-model', async (event, modelName) => {
 | 
			
		||||
        try {
 | 
			
		||||
            console.log(`[Ollama IPC] Starting model pull: ${modelName}`);
 | 
			
		||||
            
 | 
			
		||||
            // Update DB status to installing
 | 
			
		||||
            await ollamaModelRepository.updateInstallStatus(modelName, false, true);
 | 
			
		||||
            
 | 
			
		||||
            // Set up progress listener for real-time updates
 | 
			
		||||
            const progressHandler = (data) => {
 | 
			
		||||
                if (data.model === modelName) {
 | 
			
		||||
                    event.sender.send('ollama:pull-progress', data);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            const completeHandler = (data) => {
 | 
			
		||||
                if (data.model === modelName) {
 | 
			
		||||
                    console.log(`[Ollama IPC] Model ${modelName} pull completed`);
 | 
			
		||||
                    // Clean up listeners
 | 
			
		||||
                    ollamaService.removeListener('pull-progress', progressHandler);
 | 
			
		||||
                    ollamaService.removeListener('pull-complete', completeHandler);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            ollamaService.on('pull-progress', progressHandler);
 | 
			
		||||
            ollamaService.on('pull-complete', completeHandler);
 | 
			
		||||
            
 | 
			
		||||
            // Pull the model using REST API
 | 
			
		||||
            await ollamaService.pullModel(modelName);
 | 
			
		||||
            
 | 
			
		||||
            // Update DB status to installed
 | 
			
		||||
            await ollamaModelRepository.updateInstallStatus(modelName, true, false);
 | 
			
		||||
            
 | 
			
		||||
            console.log(`[Ollama IPC] Model ${modelName} pull successful`);
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to pull model:', error);
 | 
			
		||||
            // Reset status on error
 | 
			
		||||
            await ollamaModelRepository.updateInstallStatus(modelName, false, false);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Check if a specific model is installed
 | 
			
		||||
    ipcMain.handle('ollama:is-model-installed', async (event, modelName) => {
 | 
			
		||||
        try {
 | 
			
		||||
            const installed = await ollamaService.isModelInstalled(modelName);
 | 
			
		||||
            return { success: true, installed };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to check model installation:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Warm up a specific model
 | 
			
		||||
    ipcMain.handle('ollama:warm-up-model', async (event, modelName) => {
 | 
			
		||||
        try {
 | 
			
		||||
            const success = await ollamaService.warmUpModel(modelName);
 | 
			
		||||
            return { success };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to warm up model:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Auto warm-up currently selected model
 | 
			
		||||
    ipcMain.handle('ollama:auto-warm-up', async () => {
 | 
			
		||||
        try {
 | 
			
		||||
            const success = await ollamaService.autoWarmUpSelectedModel();
 | 
			
		||||
            return { success };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to auto warm-up:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Get warm-up status for debugging
 | 
			
		||||
    ipcMain.handle('ollama:get-warm-up-status', async () => {
 | 
			
		||||
        try {
 | 
			
		||||
            const status = ollamaService.getWarmUpStatus();
 | 
			
		||||
            return { success: true, status };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to get warm-up status:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Shutdown Ollama service manually
 | 
			
		||||
    ipcMain.handle('ollama:shutdown', async (event, force = false) => {
 | 
			
		||||
        try {
 | 
			
		||||
            console.log(`[Ollama IPC] Manual shutdown requested (force: ${force})`);
 | 
			
		||||
            const success = await ollamaService.shutdown(force);
 | 
			
		||||
            return { success };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error('[Ollama IPC] Failed to shutdown Ollama:', error);
 | 
			
		||||
            return { success: false, error: error.message };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    console.log('[Ollama IPC] Handlers registered');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setupWebDataHandlers() {
 | 
			
		||||
    const sessionRepository = require('./features/common/repositories/session');
 | 
			
		||||
    const sttRepository = require('./features/listen/stt/repositories');
 | 
			
		||||
 | 
			
		||||
@ -588,10 +588,6 @@ function loadAndRegisterShortcuts(movementManager) {
 | 
			
		||||
function setupIpcHandlers(movementManager) {
 | 
			
		||||
    setupApiKeyIPC();
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('quit-application', () => {
 | 
			
		||||
        app.quit();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    screen.on('display-added', (event, newDisplay) => {
 | 
			
		||||
        console.log('[Display] New display added:', newDisplay.id);
 | 
			
		||||
    });
 | 
			
		||||
@ -698,14 +694,6 @@ function setupIpcHandlers(movementManager) {
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('open-login-page', () => {
 | 
			
		||||
        const webUrl = process.env.pickleglass_WEB_URL || 'http://localhost:3000';
 | 
			
		||||
        const personalizeUrl = `${webUrl}/personalize?desktop=true`;
 | 
			
		||||
        shell.openExternal(personalizeUrl);
 | 
			
		||||
        console.log('Opening personalization page:', personalizeUrl);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('resize-header-window', (event, { width, height }) => {
 | 
			
		||||
        const header = windowPool.get('header');
 | 
			
		||||
        if (header) {
 | 
			
		||||
@ -908,12 +896,6 @@ function setupIpcHandlers(movementManager) {
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('firebase-logout', async () => {
 | 
			
		||||
        console.log('[WindowManager] Received request to log out.');
 | 
			
		||||
        
 | 
			
		||||
        await authService.signOut();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('check-system-permissions', async () => {
 | 
			
		||||
        const { systemPreferences } = require('electron');
 | 
			
		||||
        const permissions = {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user