feat: Display Whisper model status in frontend and add debug logging
- 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 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ let sidecarProcess;
|
|||||||
let sidecarReady = false;
|
let sidecarReady = false;
|
||||||
let streamingActive = false;
|
let streamingActive = false;
|
||||||
let appConfig = null;
|
let appConfig = null;
|
||||||
|
let activeWhisperConfig = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load configuration from external config.json
|
* Load configuration from external config.json
|
||||||
@@ -17,6 +18,11 @@ let appConfig = null;
|
|||||||
* - Packaged: <app>/resources/config.json
|
* - Packaged: <app>/resources/config.json
|
||||||
*/
|
*/
|
||||||
function loadConfig() {
|
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 = [
|
const configPaths = [
|
||||||
// Packaged app: resources folder
|
// Packaged app: resources folder
|
||||||
app.isPackaged ? path.join(process.resourcesPath, "config.json") : null,
|
app.isPackaged ? path.join(process.resourcesPath, "config.json") : null,
|
||||||
@@ -26,13 +32,18 @@ function loadConfig() {
|
|||||||
path.join(__dirname, "config.json"),
|
path.join(__dirname, "config.json"),
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
|
||||||
|
console.log("Config search paths:", configPaths);
|
||||||
|
|
||||||
for (const configPath of configPaths) {
|
for (const configPath of configPaths) {
|
||||||
|
const exists = fs.existsSync(configPath);
|
||||||
|
console.log(`Checking: ${configPath} - exists: ${exists}`);
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(configPath)) {
|
if (exists) {
|
||||||
const configData = fs.readFileSync(configPath, "utf-8");
|
const configData = fs.readFileSync(configPath, "utf-8");
|
||||||
appConfig = JSON.parse(configData);
|
appConfig = JSON.parse(configData);
|
||||||
console.log("Config loaded from:", configPath);
|
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;
|
return appConfig;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -51,7 +62,8 @@ function loadConfig() {
|
|||||||
compute: "int8"
|
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;
|
return appConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +137,15 @@ function startSidecar() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Get Whisper configuration from config.json or environment variables
|
// 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 || {};
|
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 = {
|
const whisperEnv = {
|
||||||
...process.env,
|
...process.env,
|
||||||
WHISPER_MODEL: process.env.WHISPER_MODEL || whisperConfig.model || "medium",
|
WHISPER_MODEL: process.env.WHISPER_MODEL || whisperConfig.model || "medium",
|
||||||
@@ -133,12 +153,20 @@ function startSidecar() {
|
|||||||
WHISPER_COMPUTE: process.env.WHISPER_COMPUTE || whisperConfig.compute || "int8",
|
WHISPER_COMPUTE: process.env.WHISPER_COMPUTE || whisperConfig.compute || "int8",
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("Starting sidecar with:", sidecarExecutable, sidecarArgs.join(" "));
|
// Store the active whisper config for status reporting
|
||||||
console.log("Whisper config:", {
|
activeWhisperConfig = {
|
||||||
model: whisperEnv.WHISPER_MODEL,
|
model: whisperEnv.WHISPER_MODEL,
|
||||||
device: whisperEnv.WHISPER_DEVICE,
|
device: whisperEnv.WHISPER_DEVICE,
|
||||||
compute: whisperEnv.WHISPER_COMPUTE,
|
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, {
|
sidecarProcess = spawn(sidecarExecutable, sidecarArgs, {
|
||||||
cwd: sidecarDir,
|
cwd: sidecarDir,
|
||||||
@@ -239,7 +267,11 @@ ipcMain.handle("navigate", (event, page) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle("get-sidecar-status", () => {
|
ipcMain.handle("get-sidecar-status", () => {
|
||||||
return { ready: sidecarReady, streaming: streamingActive };
|
return {
|
||||||
|
ready: sidecarReady,
|
||||||
|
streaming: streamingActive,
|
||||||
|
whisper: activeWhisperConfig
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// === Streaming Mode IPC Handlers ===
|
// === Streaming Mode IPC Handlers ===
|
||||||
|
|||||||
@@ -170,6 +170,7 @@
|
|||||||
<div class="panel">
|
<div class="panel">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<span>Transcript (逐字稿)</span>
|
<span>Transcript (逐字稿)</span>
|
||||||
|
<span id="whisper-status" style="font-size: 11px; color: #666; margin-left: 10px;" title="Whisper Model Info">Loading...</span>
|
||||||
<div class="recording-controls" style="padding: 0; display: flex; gap: 8px;">
|
<div class="recording-controls" style="padding: 0; display: flex; gap: 8px;">
|
||||||
<button class="btn btn-danger" id="record-btn">Start Recording</button>
|
<button class="btn btn-danger" id="record-btn">Start Recording</button>
|
||||||
<button class="btn btn-secondary" id="upload-audio-btn">Upload Audio</button>
|
<button class="btn btn-secondary" id="upload-audio-btn">Upload Audio</button>
|
||||||
@@ -281,6 +282,31 @@
|
|||||||
const uploadProgressEl = document.getElementById('upload-progress');
|
const uploadProgressEl = document.getElementById('upload-progress');
|
||||||
const uploadProgressText = document.getElementById('upload-progress-text');
|
const uploadProgressText = document.getElementById('upload-progress-text');
|
||||||
const uploadProgressFill = document.getElementById('upload-progress-fill');
|
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
|
// Load meeting data
|
||||||
async function loadMeeting() {
|
async function loadMeeting() {
|
||||||
|
|||||||
Reference in New Issue
Block a user