From b1633fdcff323abfa0aa5262f92b9964253e1d54 Mon Sep 17 00:00:00 2001 From: egg Date: Wed, 17 Dec 2025 07:43:35 +0800 Subject: [PATCH] feat: Display Whisper model status in frontend and add debug logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add activeWhisperConfig tracking in main.js to expose current Whisper settings - Expand get-sidecar-status IPC handler to return whisper config (model, device, compute, configSource) - Add Whisper status display in meeting-detail.html transcript panel header - Status updates every 5 seconds and shows: model, device, compute type, and ready state - Add comprehensive debug logging for config loading and whisper config resolution - Helps diagnose why config.json settings may not be passed correctly to sidecar 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- client/src/main.js | 46 +++++++++++++++++++++++----- client/src/pages/meeting-detail.html | 26 ++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/client/src/main.js b/client/src/main.js index 2e6ed30..3ff9914 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -9,6 +9,7 @@ let sidecarProcess; let sidecarReady = false; let streamingActive = false; let appConfig = null; +let activeWhisperConfig = null; /** * Load configuration from external config.json @@ -17,6 +18,11 @@ let appConfig = null; * - Packaged: /resources/config.json */ function loadConfig() { + console.log("=== Config Loading Debug ==="); + console.log("app.isPackaged:", app.isPackaged); + console.log("process.resourcesPath:", process.resourcesPath); + console.log("__dirname:", __dirname); + const configPaths = [ // Packaged app: resources folder app.isPackaged ? path.join(process.resourcesPath, "config.json") : null, @@ -26,13 +32,18 @@ function loadConfig() { path.join(__dirname, "config.json"), ].filter(Boolean); + console.log("Config search paths:", configPaths); + for (const configPath of configPaths) { + const exists = fs.existsSync(configPath); + console.log(`Checking: ${configPath} - exists: ${exists}`); try { - if (fs.existsSync(configPath)) { + if (exists) { const configData = fs.readFileSync(configPath, "utf-8"); appConfig = JSON.parse(configData); console.log("Config loaded from:", configPath); - console.log("Config:", appConfig); + console.log("Config content:", JSON.stringify(appConfig, null, 2)); + console.log("Whisper config:", appConfig.whisper); return appConfig; } } catch (error) { @@ -51,7 +62,8 @@ function loadConfig() { compute: "int8" } }; - console.log("Using default config:", appConfig); + console.log("WARNING: No config.json found, using defaults"); + console.log("Default config:", JSON.stringify(appConfig, null, 2)); return appConfig; } @@ -125,7 +137,15 @@ function startSidecar() { try { // Get Whisper configuration from config.json or environment variables + console.log("=== Whisper Config Resolution ==="); + console.log("appConfig:", appConfig); + console.log("appConfig?.whisper:", appConfig?.whisper); + const whisperConfig = appConfig?.whisper || {}; + console.log("whisperConfig (resolved):", whisperConfig); + console.log("process.env.WHISPER_MODEL:", process.env.WHISPER_MODEL); + console.log("whisperConfig.model:", whisperConfig.model); + const whisperEnv = { ...process.env, WHISPER_MODEL: process.env.WHISPER_MODEL || whisperConfig.model || "medium", @@ -133,12 +153,20 @@ function startSidecar() { WHISPER_COMPUTE: process.env.WHISPER_COMPUTE || whisperConfig.compute || "int8", }; - console.log("Starting sidecar with:", sidecarExecutable, sidecarArgs.join(" ")); - console.log("Whisper config:", { + // Store the active whisper config for status reporting + activeWhisperConfig = { model: whisperEnv.WHISPER_MODEL, device: whisperEnv.WHISPER_DEVICE, compute: whisperEnv.WHISPER_COMPUTE, - }); + configSource: appConfig?.whisper ? "config.json" : "defaults" + }; + + console.log("=== Final Whisper Environment ==="); + console.log("WHISPER_MODEL:", whisperEnv.WHISPER_MODEL); + console.log("WHISPER_DEVICE:", whisperEnv.WHISPER_DEVICE); + console.log("WHISPER_COMPUTE:", whisperEnv.WHISPER_COMPUTE); + console.log("Starting sidecar with:", sidecarExecutable, sidecarArgs.join(" ")); + console.log("Active Whisper config:", activeWhisperConfig); sidecarProcess = spawn(sidecarExecutable, sidecarArgs, { cwd: sidecarDir, @@ -239,7 +267,11 @@ ipcMain.handle("navigate", (event, page) => { }); ipcMain.handle("get-sidecar-status", () => { - return { ready: sidecarReady, streaming: streamingActive }; + return { + ready: sidecarReady, + streaming: streamingActive, + whisper: activeWhisperConfig + }; }); // === Streaming Mode IPC Handlers === diff --git a/client/src/pages/meeting-detail.html b/client/src/pages/meeting-detail.html index 4881391..8b71563 100644 --- a/client/src/pages/meeting-detail.html +++ b/client/src/pages/meeting-detail.html @@ -170,6 +170,7 @@
Transcript (逐字稿) + Loading...
@@ -281,6 +282,31 @@ const uploadProgressEl = document.getElementById('upload-progress'); const uploadProgressText = document.getElementById('upload-progress-text'); const uploadProgressFill = document.getElementById('upload-progress-fill'); + const whisperStatusEl = document.getElementById('whisper-status'); + + // Update Whisper status display + async function updateWhisperStatus() { + try { + const status = await window.electronAPI.getSidecarStatus(); + if (status.whisper) { + const readyIcon = status.ready ? '✅' : '⏳'; + whisperStatusEl.textContent = `${readyIcon} Model: ${status.whisper.model} | Device: ${status.whisper.device} | Compute: ${status.whisper.compute}`; + whisperStatusEl.title = `Config source: ${status.whisper.configSource || 'unknown'}`; + whisperStatusEl.style.color = status.ready ? '#28a745' : '#ffc107'; + } else { + whisperStatusEl.textContent = status.ready ? '✅ Ready' : '⏳ Loading...'; + whisperStatusEl.style.color = status.ready ? '#28a745' : '#ffc107'; + } + } catch (error) { + whisperStatusEl.textContent = '❌ Error'; + whisperStatusEl.style.color = '#dc3545'; + console.error('Failed to get sidecar status:', error); + } + } + + // Initial status check and periodic updates + updateWhisperStatus(); + const whisperStatusInterval = setInterval(updateWhisperStatus, 5000); // Load meeting data async function loadMeeting() {