diff --git a/electron/preload.ts b/electron/preload.ts index 0470246..3c50915 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -184,10 +184,10 @@ contextBridge.exposeInMainWorld('electronAPI', { }, whisper: { - downloadModel: (payload: { modelName: string; downloadDir?: string; source?: string }) => - ipcRenderer.invoke('whisper:downloadModel', payload), - getModelStatus: (payload: { modelName: string; downloadDir?: string }) => - ipcRenderer.invoke('whisper:getModelStatus', payload), + downloadModel: () => + ipcRenderer.invoke('whisper:downloadModel'), + getModelStatus: () => + ipcRenderer.invoke('whisper:getModelStatus'), onDownloadProgress: (callback: (payload: { modelName: string; downloadedBytes: number; totalBytes?: number; percent?: number }) => void) => { ipcRenderer.on('whisper:downloadProgress', (_, payload) => callback(payload)) return () => ipcRenderer.removeAllListeners('whisper:downloadProgress') diff --git a/electron/services/exportService.ts b/electron/services/exportService.ts index 9e985bc..a3bfa4e 100644 --- a/electron/services/exportService.ts +++ b/electron/services/exportService.ts @@ -1,4 +1,4 @@ -import * as fs from 'fs' +import * as fs from 'fs' import * as path from 'path' import * as http from 'http' import * as https from 'https' @@ -364,7 +364,6 @@ class ExportService { return `[${callType}]` } catch (e) { - console.error('[ExportService] Failed to parse VOIP message:', e) return '[通话]' } } @@ -417,8 +416,7 @@ class ExportService { if (localType === 3 && options.exportImages) { const result = await this.exportImage(msg, sessionId, mediaDir) if (result) { - console.log('[ExportService] 图片导出成功:', result.relativePath) - } + } return result } @@ -438,8 +436,7 @@ class ExportService { if (localType === 47 && options.exportEmojis) { const result = await this.exportEmoji(msg, sessionId, mediaDir) if (result) { - console.log('[ExportService] 表情导出成功:', result.relativePath) - } + } return result } @@ -461,12 +458,9 @@ class ExportService { const imageDatName = msg.imageDatName if (!imageMd5 && !imageDatName) { - console.log('[ExportService] 图片消息缺少 md5 和 datName:', msg.localId) return null } - console.log('[ExportService] 导出图片:', { localId: msg.localId, imageMd5, imageDatName, sessionId }) - const result = await imageDecryptService.decryptImage({ sessionId, imageMd5, @@ -524,7 +518,6 @@ class ExportService { return null } catch (e) { - console.error('[ExportService] 导出图片失败:', e) return null } } @@ -545,19 +538,15 @@ class ExportService { // 如果已存在则跳过 if (fs.existsSync(destPath)) { - console.log('[ExportService] 语音已存在:', destPath) return { relativePath: `media/voices/${fileName}`, kind: 'voice' } } - console.log('[ExportService] 导出语音:', { localId: msg.localId, sessionId }) - // 调用 chatService 获取语音数据 const voiceResult = await chatService.getVoiceData(sessionId, msgId) if (!voiceResult.success || !voiceResult.data) { - console.log('[ExportService] 获取语音数据失败:', voiceResult.error) return null } @@ -565,13 +554,11 @@ class ExportService { const wavBuffer = Buffer.from(voiceResult.data, 'base64') fs.writeFileSync(destPath, wavBuffer) - console.log('[ExportService] 语音导出成功:', destPath) return { relativePath: `media/voices/${fileName}`, kind: 'voice' } } catch (e) { - console.error('[ExportService] 导出语音失败:', e) return null } } @@ -587,7 +574,6 @@ class ExportService { } return '[语音消息 - 转文字失败]' } catch (e) { - console.error('[ExportService] 语音转文字失败:', e) return '[语音消息 - 转文字失败]' } } @@ -625,7 +611,6 @@ class ExportService { // 如果已存在则跳过 if (fs.existsSync(destPath)) { - console.log('[ExportService] 表情已存在:', destPath) return { relativePath: `media/emojis/${fileName}`, kind: 'emoji' @@ -634,22 +619,18 @@ class ExportService { // 下载表情 if (emojiUrl) { - console.log('[ExportService] 开始下载表情:', emojiUrl) const downloaded = await this.downloadFile(emojiUrl, destPath) if (downloaded) { - console.log('[ExportService] 表情下载成功:', destPath) return { relativePath: `media/emojis/${fileName}`, kind: 'emoji' } } else { - console.log('[ExportService] 表情下载失败:', emojiUrl) - } + } } return null } catch (e) { - console.error('[ExportService] 导出表情失败:', e) return null } } @@ -823,13 +804,11 @@ class ExportService { // 图片消息 imageMd5 = this.extractImageMd5(content) imageDatName = this.extractImageDatName(content) - console.log('[ExportService] 提取图片字段:', { localId, imageMd5, imageDatName }) - } else if (localType === 47 && content) { + } else if (localType === 47 && content) { // 动画表情 emojiCdnUrl = this.extractEmojiUrl(content) emojiMd5 = this.extractEmojiMd5(content) - console.log('[ExportService] 提取表情字段:', { localId, emojiMd5, emojiCdnUrl: emojiCdnUrl?.substring(0, 100) }) - } + } rows.push({ localId, @@ -1233,7 +1212,6 @@ class ExportService { return { success: true } } catch (e) { - console.error('ExportService: 导出失败:', e) return { success: false, error: String(e) } } } @@ -1348,7 +1326,6 @@ class ExportService { return { success: true } } catch (e) { - console.error('ExportService: 导出失败:', e) return { success: false, error: String(e) } } } @@ -1570,14 +1547,7 @@ class ExportService { // 调试日志 if (msg.localType === 3 || msg.localType === 47) { - console.log('[ExportService] 媒体消息填充表格:', { - localId: msg.localId, - localType: msg.localType, - hasMediaItem: !!mediaItem, - mediaRelativePath: mediaItem?.relativePath, - contentValue: contentValue?.substring(0, 100) - }) - } + } worksheet.getCell(currentRow, 1).value = i + 1 worksheet.getCell(currentRow, 2).value = this.formatTimestamp(msg.createTime) @@ -1628,8 +1598,6 @@ class ExportService { return { success: true } } catch (e) { - console.error('ExportService: 导出 Excel 失败:', e) - // 处理文件被占用的错误 if (e instanceof Error) { if (e.message.includes('EBUSY') || e.message.includes('resource busy') || e.message.includes('locked')) { @@ -1721,3 +1689,4 @@ class ExportService { } export const exportService = new ExportService() + diff --git a/electron/services/voiceTranscribeService.ts b/electron/services/voiceTranscribeService.ts index 1a9d65d..56b2088 100644 --- a/electron/services/voiceTranscribeService.ts +++ b/electron/services/voiceTranscribeService.ts @@ -1,4 +1,4 @@ -import { app } from 'electron' +import { app } from 'electron' import { existsSync, mkdirSync, statSync, unlinkSync, createWriteStream } from 'fs' import { join } from 'path' import * as https from 'https' @@ -98,7 +98,6 @@ export class VoiceTranscribeService { sizeBytes: totalSize } } catch (error) { - console.error('[VoiceTranscribe] getModelStatus error:', error) return { success: false, error: String(error) } } } @@ -125,7 +124,6 @@ export class VoiceTranscribeService { const vadPath = this.resolveModelPath((SENSEVOICE_MODEL.files as any).vad) // 下载模型文件 (40%) - console.info('[VoiceTranscribe] 开始下载模型文件...') await this.downloadToFile( MODEL_DOWNLOAD_URLS.model, modelPath, @@ -142,7 +140,6 @@ export class VoiceTranscribeService { ) // 下载 tokens 文件 (30%) - console.info('[VoiceTranscribe] 开始下载 tokens 文件...') await this.downloadToFile( MODEL_DOWNLOAD_URLS.tokens, tokensPath, @@ -160,7 +157,6 @@ export class VoiceTranscribeService { ) // 下载 vad 文件 (30%) - console.info('[VoiceTranscribe] 开始下载 VAD 文件...') await this.downloadToFile( (MODEL_DOWNLOAD_URLS as any).vad, vadPath, @@ -178,10 +174,8 @@ export class VoiceTranscribeService { } ) - console.info('[VoiceTranscribe] 模型下载完成') return { success: true, modelPath, tokensPath } } catch (error) { - console.error('[VoiceTranscribe] 下载失败:', error) const modelPath = this.resolveModelPath(SENSEVOICE_MODEL.files.model) const tokensPath = this.resolveModelPath(SENSEVOICE_MODEL.files.tokens) const vadPath = this.resolveModelPath((SENSEVOICE_MODEL.files as any).vad) @@ -221,8 +215,6 @@ export class VoiceTranscribeService { // main.js 和 transcribeWorker.js 同在 dist-electron 目录下 const workerPath = join(__dirname, 'transcribeWorker.js') - console.info('[VoiceTranscribe] 启动后台 Worker 转写...', { workerPath }) - const worker = new Worker(workerPath, { workerData: { modelPath, @@ -248,7 +240,6 @@ export class VoiceTranscribeService { }) worker.on('error', (err: Error) => { - console.error('[VoiceTranscribe] Worker error:', err) resolve({ success: false, error: String(err) }) }) @@ -260,7 +251,6 @@ export class VoiceTranscribeService { }) } catch (error) { - console.error('[VoiceTranscribe] 启动 Worker 失败:', error) resolve({ success: false, error: String(error) }) } }) @@ -350,10 +340,10 @@ export class VoiceTranscribeService { // sherpa-onnx 的 recognizer 可能需要手动释放 this.recognizer = null } catch (error) { - console.error('[VoiceTranscribe] 释放识别器失败:', error) - } + } } } } export const voiceTranscribeService = new VoiceTranscribeService() + diff --git a/electron/services/wcdbService.ts b/electron/services/wcdbService.ts index fd14ae1..7f750c3 100644 --- a/electron/services/wcdbService.ts +++ b/electron/services/wcdbService.ts @@ -58,11 +58,13 @@ export class WcdbService { }) this.worker.on('error', (err) => { - console.error('WCDB Worker 错误:', err) + // Worker error }) this.worker.on('exit', (code) => { - if (code !== 0) console.error(`WCDB Worker 异常退出,退出码: ${code}`) + if (code !== 0) { + // Worker exited with error + } this.worker = null }) @@ -73,7 +75,7 @@ export class WcdbService { this.setLogEnabled(this.logEnabled) } catch (e) { - console.error('创建 WCDB Worker 失败:', e) + // Failed to create worker } } @@ -97,7 +99,7 @@ export class WcdbService { setPaths(resourcesPath: string, userDataPath: string): void { this.resourcesPath = resourcesPath this.userDataPath = userDataPath - this.callWorker('setPaths', { resourcesPath, userDataPath }).catch(console.error) + this.callWorker('setPaths', { resourcesPath, userDataPath }).catch(() => {}) } /** @@ -105,7 +107,7 @@ export class WcdbService { */ setLogEnabled(enabled: boolean): void { this.logEnabled = enabled - this.callWorker('setLogEnabled', { enabled }).catch(console.error) + this.callWorker('setLogEnabled', { enabled }).catch(() => {}) } /** diff --git a/electron/transcribeWorker.ts b/electron/transcribeWorker.ts index d892b44..9b1efd2 100644 --- a/electron/transcribeWorker.ts +++ b/electron/transcribeWorker.ts @@ -1,4 +1,4 @@ -import { parentPort, workerData } from 'worker_threads' +import { parentPort, workerData } from 'worker_threads' import * as fs from 'fs' interface WorkerParams { @@ -9,37 +9,23 @@ interface WorkerParams { } async function run() { - console.info('[TranscribeWorker] Worker process starting...'); - if (!parentPort) { - console.error('[TranscribeWorker] Critical Error: parentPort is null'); return; } try { - console.info('[TranscribeWorker] Loading sherpa-onnx-node...'); // 动态加载以捕获可能的加载错误(如 C++ 运行库缺失等) let sherpa: any; try { sherpa = require('sherpa-onnx-node'); - console.info('[TranscribeWorker] sherpa-onnx-node loaded successfully.'); - } catch (requireError) { - console.error('[TranscribeWorker] Failed to load sherpa-onnx-node:', requireError); + } catch (requireError) { parentPort.postMessage({ type: 'error', error: 'Failed to load speech engine: ' + String(requireError) }); return; } const { modelPath, tokensPath, wavData: rawWavData, sampleRate } = workerData as WorkerParams const wavData = Buffer.from(rawWavData); - console.info('[TranscribeWorker] Params received:', { - modelPath, - tokensPath, - sampleRate, - wavDataLength: wavData?.length - }); - // 1. 初始化识别器 (SenseVoiceSmall) - console.info('[TranscribeWorker] Initializing OfflineRecognizer...'); const recognizerConfig = { modelConfig: { senseVoice: { @@ -52,12 +38,8 @@ async function run() { } } const recognizer = new sherpa.OfflineRecognizer(recognizerConfig) - console.info('[TranscribeWorker] OfflineRecognizer initialized.'); - // 2. 初始化 VAD (用于流式输出效果) const vadPath = modelPath.replace('model.int8.onnx', 'silero_vad.onnx'); - console.info('[TranscribeWorker] VAD Path:', vadPath); - const vadConfig = { sileroVad: { model: vadPath, @@ -73,8 +55,6 @@ async function run() { // 检查 VAD 模型是否存在,如果不存在则退回到全量识别 if (!fs.existsSync(vadPath)) { - console.warn('[TranscribeWorker] VAD model not found, falling back to full transcription.'); - const pcmData = wavData.slice(44) const samples = new Float32Array(pcmData.length / 2) for (let i = 0; i < samples.length; i++) { @@ -86,15 +66,11 @@ async function run() { recognizer.decode(stream) const result = recognizer.getResult(stream) - console.info('[TranscribeWorker] Full transcription result:', result.text); parentPort.postMessage({ type: 'final', text: result.text }) return } - console.info('[TranscribeWorker] Initializing Vad...'); const vad = new sherpa.Vad(vadConfig, 60) // 60s max - console.info('[TranscribeWorker] VAD initialized.'); - // 3. 处理音频数据 const pcmData = wavData.slice(44) const samples = new Float32Array(pcmData.length / 2) @@ -107,7 +83,6 @@ async function run() { let offset = 0 let accumulatedText = '' - console.info('[TranscribeWorker] Starting processing loop...'); let segmentCount = 0; while (offset < samples.length) { @@ -120,9 +95,6 @@ async function run() { while (!vad.isEmpty()) { const segment = vad.front(false) - // Log segment detection - console.info(`[TranscribeWorker] VAD Segment detected. Duration: ${segment.samples.length / sampleRate}s`); - const stream = recognizer.createStream() stream.acceptWaveform({ sampleRate, samples: segment.samples }) recognizer.decode(stream) @@ -133,7 +105,6 @@ async function run() { if (text.length > 0) { accumulatedText += (accumulatedText ? ' ' : '') + text segmentCount++; - console.info(`[TranscribeWorker] Partial update #${segmentCount}: "${text}" -> Total: "${accumulatedText.substring(0, 50)}..."`); parentPort.postMessage({ type: 'partial', text: accumulatedText }) } } @@ -149,26 +120,23 @@ async function run() { vad.flush(); while (!vad.isEmpty()) { const segment = vad.front(false); - console.info(`[TranscribeWorker] Final VAD Segment detected. Duration: ${segment.samples.length / sampleRate}s`); const stream = recognizer.createStream() stream.acceptWaveform({ sampleRate, samples: segment.samples }) recognizer.decode(stream) const result = recognizer.getResult(stream) if (result.text) { accumulatedText += (accumulatedText ? ' ' : '') + result.text.trim() - console.info(`[TranscribeWorker] Final partial update: "${result.text.trim()}"`); parentPort.postMessage({ type: 'partial', text: accumulatedText }) } vad.pop(); } - console.info('[TranscribeWorker] Loop finished. Final text length:', accumulatedText.length); parentPort.postMessage({ type: 'final', text: accumulatedText }) } catch (error) { - console.error('[TranscribeWorker] Fatal error:', error); parentPort.postMessage({ type: 'error', error: String(error) }) } } run(); + diff --git a/package-lock.json b/package-lock.json index c8ba91e..a38e504 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "weflow", - "version": "1.1.2", + "version": "1.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "weflow", - "version": "1.1.2", + "version": "1.2.0", "hasInstallScript": true, "dependencies": { "better-sqlite3": "^12.5.0", diff --git a/src/pages/ChatPage.scss b/src/pages/ChatPage.scss index 75d986b..0fa1664 100644 --- a/src/pages/ChatPage.scss +++ b/src/pages/ChatPage.scss @@ -1412,7 +1412,7 @@ .voice-transcript.sent { background: rgba(255, 255, 255, 0.9); - color: var(--text-primary); + color: #333333; border-color: transparent; } diff --git a/src/pages/ExportPage.tsx b/src/pages/ExportPage.tsx index 0125074..f60a588 100644 --- a/src/pages/ExportPage.tsx +++ b/src/pages/ExportPage.tsx @@ -160,7 +160,7 @@ function ExportPage() { exportImages: options.exportMedia && options.exportImages, exportVoices: options.exportMedia && options.exportVoices, exportEmojis: options.exportMedia && options.exportEmojis, - exportVoiceAsText: options.exportMedia && options.exportVoiceAsText, + exportVoiceAsText: options.exportVoiceAsText, // 独立于 exportMedia dateRange: options.useAllTime ? null : options.dateRange ? { start: Math.floor(options.dateRange.start.getTime() / 1000), // 将结束日期设置为当天的 23:59:59,以包含当天的所有消息 @@ -444,15 +444,14 @@ function ExportPage() {
-