From 2876c7a539383738e18486bc6f6d9f69ba3e6bae Mon Sep 17 00:00:00 2001 From: Forrest Date: Sun, 18 Jan 2026 17:12:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(voice-transcribe):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=AF=AD=E9=9F=B3=E8=BD=AC=E5=86=99=E6=B5=81=E7=A8=8B=E5=B9=B6?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E6=95=B0=E6=8D=AE=E5=BA=93=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 createTime 参数到语音转写接口,支持更精确的消息定位 - 实现 media.db 列表缓存机制(5分钟TTL),减少重复查询开销 - 添加 media.db 表结构信息缓存,提升数据库操作效率 - 优化语音缓存目录获取逻辑,支持自定义缓存路径配置 - 重构语音数据获取实现,绕过WCDB的buggy getVoiceData方法 - 移除冗余的调试日志,提升代码整洁度 - 删除不再使用的 silk_v3_decoder.exe 文件 - 优化数据库连接流程,后台预热缓存提升响应速度 --- electron/main.ts | 4 +- electron/preload.ts | 2 +- electron/services/chatService.ts | 616 ++++++++++++++------ electron/services/imageDecryptService.ts | 9 +- electron/services/voiceTranscribeService.ts | 3 + electron/services/wcdbCore.ts | 14 +- resources/silk_v3_decoder.exe | Bin 179037 -> 0 bytes src/pages/ChatPage.tsx | 11 +- src/types/electron.d.ts | 2 +- 9 files changed, 474 insertions(+), 187 deletions(-) delete mode 100644 resources/silk_v3_decoder.exe diff --git a/electron/main.ts b/electron/main.ts index 8cade14..5cec754 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -446,8 +446,8 @@ function registerIpcHandlers() { return chatService.resolveVoiceCache(sessionId, msgId) }) - ipcMain.handle('chat:getVoiceTranscript', async (event, sessionId: string, msgId: string) => { - return chatService.getVoiceTranscript(sessionId, msgId, (text) => { + ipcMain.handle('chat:getVoiceTranscript', async (event, sessionId: string, msgId: string, createTime?: number) => { + return chatService.getVoiceTranscript(sessionId, msgId, createTime, (text) => { event.sender.send('chat:voiceTranscriptPartial', { msgId, text }) }) }) diff --git a/electron/preload.ts b/electron/preload.ts index 775e19a..c3aaf4a 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -109,7 +109,7 @@ contextBridge.exposeInMainWorld('electronAPI', { getVoiceData: (sessionId: string, msgId: string, createTime?: number, serverId?: string | number) => ipcRenderer.invoke('chat:getVoiceData', sessionId, msgId, createTime, serverId), resolveVoiceCache: (sessionId: string, msgId: string) => ipcRenderer.invoke('chat:resolveVoiceCache', sessionId, msgId), - getVoiceTranscript: (sessionId: string, msgId: string) => ipcRenderer.invoke('chat:getVoiceTranscript', sessionId, msgId), + getVoiceTranscript: (sessionId: string, msgId: string, createTime?: number) => ipcRenderer.invoke('chat:getVoiceTranscript', sessionId, msgId, createTime), onVoiceTranscriptPartial: (callback: (payload: { msgId: string; text: string }) => void) => { const listener = (_: any, payload: { msgId: string; text: string }) => callback(payload) ipcRenderer.on('chat:voiceTranscriptPartial', listener) diff --git a/electron/services/chatService.ts b/electron/services/chatService.ts index cfe251b..19594c4 100644 --- a/electron/services/chatService.ts +++ b/electron/services/chatService.ts @@ -83,7 +83,18 @@ class ChatService { private voiceWavCache = new Map() private voiceTranscriptCache = new Map() private voiceTranscriptPending = new Map>() + private mediaDbsCache: string[] | null = null + private mediaDbsCacheTime = 0 + private readonly mediaDbsCacheTtl = 300000 // 5分钟 private readonly voiceCacheMaxEntries = 50 + // 缓存 media.db 的表结构信息 + private mediaDbSchemaCache = new Map() constructor() { this.configService = new ConfigService() @@ -140,6 +151,10 @@ class ChatService { } this.connected = true + + // 预热 listMediaDbs 缓存(后台异步执行,不阻塞连接) + this.warmupMediaDbsCache() + return { success: true } } catch (e) { console.error('ChatService: 连接数据库失败:', e) @@ -147,6 +162,21 @@ class ChatService { } } + /** + * 预热 media 数据库列表缓存(后台异步执行) + */ + private async warmupMediaDbsCache(): Promise { + try { + const result = await wcdbService.listMediaDbs() + if (result.success && result.data) { + this.mediaDbsCache = result.data as string[] + this.mediaDbsCacheTime = Date.now() + } + } catch (e) { + // 静默失败,不影响主流程 + } + } + private async ensureConnected(): Promise<{ success: boolean; error?: string }> { if (this.connected && wcdbService.isReady()) { return { success: true } @@ -382,8 +412,6 @@ class ChatService { const needNewCursor = !state || offset === 0 || state.batchSize !== batchSize if (needNewCursor) { - console.log(`[ChatService] 创建新游标: sessionId=${sessionId}, offset=${offset}, batchSize=${batchSize}`) - // 关闭旧游标 if (state) { try { @@ -440,7 +468,6 @@ class ChatService { } // 获取当前批次的消息 - console.log(`[ChatService] 获取消息批次: cursor=${state.cursor}, fetched=${state.fetched}`) const batch = await wcdbService.fetchMessageBatch(state.cursor) if (!batch.success) { console.error('[ChatService] 获取消息批次失败:', batch.error) @@ -1691,21 +1718,17 @@ class ChatService { // 增加 'self' 作为兜底标识符,微信有时将个人信息存储在 'self' 记录中 const fetchList = Array.from(new Set([myWxid, cleanedWxid, 'self'])) - console.log(`[ChatService] 尝试获取个人头像, wxids: ${JSON.stringify(fetchList)}`) const result = await wcdbService.getAvatarUrls(fetchList) if (result.success && result.map) { // 按优先级尝试匹配 const avatarUrl = result.map[myWxid] || result.map[cleanedWxid] || result.map['self'] if (avatarUrl) { - console.log(`[ChatService] 成功获取个人头像: ${avatarUrl.substring(0, 50)}...`) return { success: true, avatarUrl } } - console.warn(`[ChatService] 未能在 contact.db 中找到个人头像, 请求列表: ${JSON.stringify(fetchList)}`) return { success: true, avatarUrl: undefined } } - console.error(`[ChatService] 查询个人头像失败: ${result.error || '未知错误'}`) return { success: true, avatarUrl: undefined } } catch (e) { console.error('ChatService: 获取当前用户头像失败:', e) @@ -1716,6 +1739,19 @@ class ChatService { /** * 获取表情包缓存目录 */ + /** + * 获取语音缓存目录 + */ + private getVoiceCacheDir(): string { + const cachePath = this.configService.get('cachePath') + if (cachePath) { + return join(cachePath, 'Voices') + } + // 回退到默认目录 + const documentsPath = app.getPath('documents') + return join(documentsPath, 'WeFlow', 'Voices') + } + private getEmojiCacheDir(): string { const cachePath = this.configService.get('cachePath') if (cachePath) { @@ -2085,12 +2121,6 @@ class ChatService { return { success: false, error: '未找到消息' } } const msg = msgResult.message - console.info('[ChatService][Image] request', { - sessionId, - localId: msg.localId, - imageMd5: msg.imageMd5, - imageDatName: msg.imageDatName - }) // 2. 确定搜索的基础名 const baseName = msg.imageMd5 || msg.imageDatName || String(msg.localId) @@ -2107,7 +2137,6 @@ class ChatService { const datPath = await this.findDatFile(actualAccountDir, baseName, sessionId) if (!datPath) return { success: false, error: '未找到图片源文件 (.dat)' } - console.info('[ChatService][Image] dat path', datPath) // 4. 获取解密密钥 const xorKeyRaw = this.configService.get('imageXorKey') @@ -2135,7 +2164,6 @@ class ChatService { const aesKey = this.asciiKey16(trimmed) decrypted = this.decryptDatV4(data, xorKey, aesKey) } - console.info('[ChatService][Image] decrypted bytes', decrypted.length) // 返回 base64 return { success: true, data: decrypted.toString('base64') } @@ -2146,44 +2174,30 @@ class ChatService { } /** - * getVoiceData (优化的 C++ 实现 + 文件缓存) + * getVoiceData (绕过WCDB的buggy getVoiceData,直接用execQuery读取) */ async getVoiceData(sessionId: string, msgId: string, createTime?: number, serverId?: string | number): Promise<{ success: boolean; data?: string; error?: string }> { - + const startTime = Date.now() try { const localId = parseInt(msgId, 10) if (isNaN(localId)) { return { success: false, error: '无效的消息ID' } } - // 检查文件缓存 - const cacheKey = this.getVoiceCacheKey(sessionId, msgId) - const cachedFile = this.getVoiceCacheFilePath(cacheKey) - if (existsSync(cachedFile)) { - try { - const wavData = readFileSync(cachedFile) - console.info('[ChatService][Voice] 使用缓存文件:', cachedFile) - return { success: true, data: wavData.toString('base64') } - } catch (e) { - console.error('[ChatService][Voice] 读取缓存失败:', e) - // 继续重新解密 - } - } - - // 1. 确定 createTime 和 svrId let msgCreateTime = createTime - let msgSvrId: string | number = serverId || 0 + let senderWxid: string | null = null - // 如果提供了传来的参数,验证其有效性 - if (!msgCreateTime || msgCreateTime === 0) { + // 如果前端没传 createTime,才需要查询消息(这个很慢) + if (!msgCreateTime) { + const t1 = Date.now() const msgResult = await this.getMessageByLocalId(sessionId, localId) + const t2 = Date.now() + console.log(`[Voice] getMessageByLocalId: ${t2 - t1}ms`) + if (msgResult.success && msgResult.message) { const msg = msgResult.message as any - msgCreateTime = msg.createTime || msg.create_time - // 尝试获取各种可能的 server id 列名 (只有在没有传入 serverId 时才查找) - if (!msgSvrId || msgSvrId === 0) { - msgSvrId = msg.serverId || msg.svr_id || msg.msg_svr_id || msg.message_id || 0 - } + msgCreateTime = msg.createTime + senderWxid = msg.senderUsername || null } } @@ -2191,54 +2205,84 @@ class ChatService { return { success: false, error: '未找到消息时间戳' } } - // 2. 构建查找候选 (sessionId, myWxid) + // 使用 sessionId + createTime 作为缓存key + const cacheKey = `${sessionId}_${msgCreateTime}` + + // 检查 WAV 内存缓存 + const wavCache = this.voiceWavCache.get(cacheKey) + if (wavCache) { + console.log(`[Voice] 内存缓存命中,总耗时: ${Date.now() - startTime}ms`) + return { success: true, data: wavCache.toString('base64') } + } + + // 检查 WAV 文件缓存 + const voiceCacheDir = this.getVoiceCacheDir() + const wavFilePath = join(voiceCacheDir, `${cacheKey}.wav`) + if (existsSync(wavFilePath)) { + try { + const wavData = readFileSync(wavFilePath) + // 同时缓存到内存 + this.cacheVoiceWav(cacheKey, wavData) + console.log(`[Voice] 文件缓存命中,总耗时: ${Date.now() - startTime}ms`) + return { success: true, data: wavData.toString('base64') } + } catch (e) { + console.error('[Voice] 读取缓存文件失败:', e) + } + } + + // 构建查找候选 const candidates: string[] = [] - if (sessionId) candidates.push(sessionId) const myWxid = this.configService.get('myWxid') as string + + // 如果有 senderWxid,优先使用(群聊中最重要) + if (senderWxid) { + candidates.push(senderWxid) + } + + // sessionId(1对1聊天时是对方wxid,群聊时是群id) + if (sessionId && !candidates.includes(sessionId)) { + candidates.push(sessionId) + } + + // 我的wxid(兜底) if (myWxid && !candidates.includes(myWxid)) { candidates.push(myWxid) } - - - // 3. 调用 C++ 接口获取语音 (Hex) - const voiceRes = await wcdbService.getVoiceData(sessionId, msgCreateTime, candidates, localId, msgSvrId) - if (!voiceRes.success || !voiceRes.hex) { - return { success: false, error: voiceRes.error || '未找到语音数据' } + const t3 = Date.now() + // 从数据库读取 silk 数据 + const silkData = await this.getVoiceDataFromMediaDb(msgCreateTime, candidates) + const t4 = Date.now() + console.log(`[Voice] getVoiceDataFromMediaDb: ${t4 - t3}ms`) + + if (!silkData) { + return { success: false, error: '未找到语音数据' } } - - - // 4. Hex 转 Buffer (Silk) - const silkData = Buffer.from(voiceRes.hex, 'hex') - - // 5. 使用 silk-wasm 解码 - try { - const pcmData = await this.decodeSilkToPcm(silkData, 24000) - if (!pcmData) { - return { success: false, error: 'Silk 解码失败' } - } - - // PCM -> WAV - const wavData = this.createWavBuffer(pcmData, 24000) - - // 保存到文件缓存 - try { - this.saveVoiceCache(cacheKey, wavData) - console.info('[ChatService][Voice] 已保存缓存:', cachedFile) - } catch (e) { - console.error('[ChatService][Voice] 保存缓存失败:', e) - // 不影响返回 - } - - // 缓存 WAV 数据 (内存缓存) - this.cacheVoiceWav(cacheKey, wavData) - - return { success: true, data: wavData.toString('base64') } - } catch (e) { - console.error('[ChatService][Voice] decoding error:', e) - return { success: false, error: '语音解码失败: ' + String(e) } + const t5 = Date.now() + // 使用 silk-wasm 解码 + const pcmData = await this.decodeSilkToPcm(silkData, 24000) + const t6 = Date.now() + console.log(`[Voice] decodeSilkToPcm: ${t6 - t5}ms`) + + if (!pcmData) { + return { success: false, error: 'Silk 解码失败' } } + + const t7 = Date.now() + // PCM -> WAV + const wavData = this.createWavBuffer(pcmData, 24000) + const t8 = Date.now() + console.log(`[Voice] createWavBuffer: ${t8 - t7}ms`) + + // 缓存 WAV 数据到内存 + this.cacheVoiceWav(cacheKey, wavData) + + // 缓存 WAV 数据到文件(异步,不阻塞返回) + this.cacheVoiceWavToFile(cacheKey, wavData) + + console.log(`[Voice] 总耗时: ${Date.now() - startTime}ms`) + return { success: true, data: wavData.toString('base64') } } catch (e) { console.error('ChatService: getVoiceData 失败:', e) return { success: false, error: String(e) } @@ -2246,26 +2290,228 @@ class ChatService { } /** - * 检查语音是否已有缓存 + * 缓存 WAV 数据到文件(异步) + */ + private async cacheVoiceWavToFile(cacheKey: string, wavData: Buffer): Promise { + try { + const voiceCacheDir = this.getVoiceCacheDir() + if (!existsSync(voiceCacheDir)) { + mkdirSync(voiceCacheDir, { recursive: true }) + } + + const wavFilePath = join(voiceCacheDir, `${cacheKey}.wav`) + writeFileSync(wavFilePath, wavData) + } catch (e) { + console.error('[Voice] 缓存文件失败:', e) + } + } + + /** + * 通过 WCDB 的 execQuery 直接查询 media.db(绕过有bug的getVoiceData接口) + * 策略:批量查询 + 多种兜底方案 + */ + private async getVoiceDataFromMediaDb(createTime: number, candidates: string[]): Promise { + const startTime = Date.now() + try { + const t1 = Date.now() + // 获取所有 media 数据库(永久缓存,直到应用重启) + let mediaDbFiles: string[] + if (this.mediaDbsCache) { + mediaDbFiles = this.mediaDbsCache + console.log(`[Voice] listMediaDbs (缓存): 0ms`) + } else { + const mediaDbsResult = await wcdbService.listMediaDbs() + const t2 = Date.now() + console.log(`[Voice] listMediaDbs: ${t2 - t1}ms`) + + if (!mediaDbsResult.success || !mediaDbsResult.data || mediaDbsResult.data.length === 0) { + return null + } + + mediaDbFiles = mediaDbsResult.data as string[] + this.mediaDbsCache = mediaDbFiles // 永久缓存 + } + + // 在所有 media 数据库中查找 + for (const dbPath of mediaDbFiles) { + try { + // 检查缓存 + let schema = this.mediaDbSchemaCache.get(dbPath) + + if (!schema) { + const t3 = Date.now() + // 第一次查询,获取表结构并缓存 + const tablesResult = await wcdbService.execQuery('media', dbPath, + "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'VoiceInfo%'" + ) + const t4 = Date.now() + console.log(`[Voice] 查询VoiceInfo表: ${t4 - t3}ms`) + + if (!tablesResult.success || !tablesResult.rows || tablesResult.rows.length === 0) { + continue + } + + const voiceTable = tablesResult.rows[0].name + + const t5 = Date.now() + const columnsResult = await wcdbService.execQuery('media', dbPath, + `PRAGMA table_info('${voiceTable}')` + ) + const t6 = Date.now() + console.log(`[Voice] 查询表结构: ${t6 - t5}ms`) + + if (!columnsResult.success || !columnsResult.rows) { + continue + } + + // 创建列名映射(原始名称 -> 小写名称) + const columnMap = new Map() + for (const c of columnsResult.rows) { + const name = String(c.name || '') + if (name) { + columnMap.set(name.toLowerCase(), name) + } + } + + // 查找数据列(使用原始列名) + const dataColumnLower = ['voice_data', 'buf', 'voicebuf', 'data'].find(n => columnMap.has(n)) + const dataColumn = dataColumnLower ? columnMap.get(dataColumnLower) : undefined + + if (!dataColumn) { + continue + } + + // 查找 chat_name_id 列 + const chatNameIdColumnLower = ['chat_name_id', 'chatnameid', 'chat_nameid'].find(n => columnMap.has(n)) + const chatNameIdColumn = chatNameIdColumnLower ? columnMap.get(chatNameIdColumnLower) : undefined + + // 查找时间列 + const timeColumnLower = ['create_time', 'createtime', 'time'].find(n => columnMap.has(n)) + const timeColumn = timeColumnLower ? columnMap.get(timeColumnLower) : undefined + + const t7 = Date.now() + // 查找 Name2Id 表 + const name2IdTablesResult = await wcdbService.execQuery('media', dbPath, + "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'Name2Id%'" + ) + const t8 = Date.now() + console.log(`[Voice] 查询Name2Id表: ${t8 - t7}ms`) + + const name2IdTable = (name2IdTablesResult.success && name2IdTablesResult.rows && name2IdTablesResult.rows.length > 0) + ? name2IdTablesResult.rows[0].name + : undefined + + schema = { + voiceTable, + dataColumn, + chatNameIdColumn, + timeColumn, + name2IdTable + } + + // 缓存表结构 + this.mediaDbSchemaCache.set(dbPath, schema) + } + + // 策略1: 通过 chat_name_id + create_time 查找(最准确) + if (schema.chatNameIdColumn && schema.timeColumn && schema.name2IdTable) { + const t9 = Date.now() + // 批量获取所有 candidates 的 chat_name_id(减少查询次数) + const candidatesStr = candidates.map(c => `'${c.replace(/'/g, "''")}'`).join(',') + const name2IdResult = await wcdbService.execQuery('media', dbPath, + `SELECT user_name, rowid FROM ${schema.name2IdTable} WHERE user_name IN (${candidatesStr})` + ) + const t10 = Date.now() + console.log(`[Voice] 查询chat_name_id: ${t10 - t9}ms`) + + if (name2IdResult.success && name2IdResult.rows && name2IdResult.rows.length > 0) { + // 构建 chat_name_id 列表 + const chatNameIds = name2IdResult.rows.map((r: any) => r.rowid) + const chatNameIdsStr = chatNameIds.join(',') + + const t11 = Date.now() + // 一次查询所有可能的语音 + const voiceResult = await wcdbService.execQuery('media', dbPath, + `SELECT ${schema.dataColumn} AS data FROM ${schema.voiceTable} WHERE ${schema.chatNameIdColumn} IN (${chatNameIdsStr}) AND ${schema.timeColumn} = ${createTime} LIMIT 1` + ) + const t12 = Date.now() + console.log(`[Voice] 策略1查询语音: ${t12 - t11}ms`) + + if (voiceResult.success && voiceResult.rows && voiceResult.rows.length > 0) { + const row = voiceResult.rows[0] + const silkData = this.decodeVoiceBlob(row.data) + if (silkData) { + console.log(`[Voice] getVoiceDataFromMediaDb总耗时: ${Date.now() - startTime}ms`) + return silkData + } + } + } + } + + // 策略2: 只通过 create_time 查找(兜底) + if (schema.timeColumn) { + const t13 = Date.now() + const voiceResult = await wcdbService.execQuery('media', dbPath, + `SELECT ${schema.dataColumn} AS data FROM ${schema.voiceTable} WHERE ${schema.timeColumn} = ${createTime} LIMIT 1` + ) + const t14 = Date.now() + console.log(`[Voice] 策略2查询语音: ${t14 - t13}ms`) + + if (voiceResult.success && voiceResult.rows && voiceResult.rows.length > 0) { + const row = voiceResult.rows[0] + const silkData = this.decodeVoiceBlob(row.data) + if (silkData) { + console.log(`[Voice] getVoiceDataFromMediaDb总耗时: ${Date.now() - startTime}ms`) + return silkData + } + } + } + + // 策略3: 时间范围查找(±5秒,处理时间戳不精确的情况) + if (schema.timeColumn) { + const t15 = Date.now() + const voiceResult = await wcdbService.execQuery('media', dbPath, + `SELECT ${schema.dataColumn} AS data FROM ${schema.voiceTable} WHERE ${schema.timeColumn} BETWEEN ${createTime - 5} AND ${createTime + 5} ORDER BY ABS(${schema.timeColumn} - ${createTime}) LIMIT 1` + ) + const t16 = Date.now() + console.log(`[Voice] 策略3查询语音: ${t16 - t15}ms`) + + if (voiceResult.success && voiceResult.rows && voiceResult.rows.length > 0) { + const row = voiceResult.rows[0] + const silkData = this.decodeVoiceBlob(row.data) + if (silkData) { + console.log(`[Voice] getVoiceDataFromMediaDb总耗时: ${Date.now() - startTime}ms`) + return silkData + } + } + } + } catch (e) { + // 静默失败,继续尝试下一个数据库 + } + } + + return null + } catch (e) { + return null + } + } + + /** + * 检查语音是否已有缓存(只检查内存,不查询数据库) */ async resolveVoiceCache(sessionId: string, msgId: string): Promise<{ success: boolean; hasCache: boolean; data?: string }> { try { + // 直接用 msgId 生成 cacheKey,不查询数据库 + // 注意:这里的 cacheKey 可能不准确(因为没有 createTime),但只是用来快速检查缓存 + // 如果缓存未命中,用户点击时会重新用正确的 cacheKey 查询 const cacheKey = this.getVoiceCacheKey(sessionId, msgId) - // 1. 检查内存缓存 + // 检查内存缓存 const inMemory = this.voiceWavCache.get(cacheKey) if (inMemory) { return { success: true, hasCache: true, data: inMemory.toString('base64') } } - // 2. 检查文件缓存 - const cachedFile = this.getVoiceCacheFilePath(cacheKey) - if (existsSync(cachedFile)) { - const wavData = readFileSync(cachedFile) - this.cacheVoiceWav(cacheKey, wavData) // 回甜内存 - return { success: true, hasCache: true, data: wavData.toString('base64') } - } - return { success: true, hasCache: false } } catch (e) { return { success: false, hasCache: false } @@ -2460,60 +2706,133 @@ class ChatService { async getVoiceTranscript( sessionId: string, msgId: string, + createTime?: number, onPartial?: (text: string) => void ): Promise<{ success: boolean; transcript?: string; error?: string }> { - const cacheKey = this.getVoiceCacheKey(sessionId, msgId) - const cached = this.voiceTranscriptCache.get(cacheKey) - if (cached) { - return { success: true, transcript: cached } - } - - const pending = this.voiceTranscriptPending.get(cacheKey) - if (pending) { - return pending - } - - const task = (async () => { - try { - let wavData = this.voiceWavCache.get(cacheKey) - if (!wavData) { - // 获取消息详情以拿到 createTime 和 serverId - let cTime: number | undefined - let sId: string | number | undefined - const msgResult = await this.getMessageById(sessionId, parseInt(msgId, 10)) - if (msgResult.success && msgResult.message) { - cTime = msgResult.message.createTime - sId = msgResult.message.serverId - } - - const voiceResult = await this.getVoiceData(sessionId, msgId, cTime, sId) - if (!voiceResult.success || !voiceResult.data) { - return { success: false, error: voiceResult.error || '语音解码失败' } - } - wavData = Buffer.from(voiceResult.data, 'base64') + const startTime = Date.now() + console.log(`[Transcribe] 开始转写: sessionId=${sessionId}, msgId=${msgId}, createTime=${createTime}`) + + try { + let msgCreateTime = createTime + let serverId: string | number | undefined + + // 如果前端没传 createTime,才需要查询消息(这个很慢) + if (!msgCreateTime) { + const t1 = Date.now() + const msgResult = await this.getMessageById(sessionId, parseInt(msgId, 10)) + const t2 = Date.now() + console.log(`[Transcribe] getMessageById: ${t2 - t1}ms`) + + if (msgResult.success && msgResult.message) { + msgCreateTime = msgResult.message.createTime + serverId = msgResult.message.serverId + console.log(`[Transcribe] 获取到 createTime=${msgCreateTime}, serverId=${serverId}`) } - - const result = await voiceTranscribeService.transcribeWavBuffer(wavData, (text) => { - onPartial?.(text) - }) - if (result.success && result.transcript) { - this.cacheVoiceTranscript(cacheKey, result.transcript) - } - return result - } catch (error) { - return { success: false, error: String(error) } - } finally { - this.voiceTranscriptPending.delete(cacheKey) } - })() - this.voiceTranscriptPending.set(cacheKey, task) - return task + if (!msgCreateTime) { + console.error(`[Transcribe] 未找到消息时间戳`) + return { success: false, error: '未找到消息时间戳' } + } + + // 使用正确的 cacheKey(包含 createTime) + const cacheKey = this.getVoiceCacheKey(sessionId, msgId, msgCreateTime) + console.log(`[Transcribe] cacheKey=${cacheKey}`) + + // 检查转写缓存 + const cached = this.voiceTranscriptCache.get(cacheKey) + if (cached) { + console.log(`[Transcribe] 缓存命中,总耗时: ${Date.now() - startTime}ms`) + return { success: true, transcript: cached } + } + + // 检查是否正在转写 + const pending = this.voiceTranscriptPending.get(cacheKey) + if (pending) { + console.log(`[Transcribe] 正在转写中,等待结果`) + return pending + } + + const task = (async () => { + try { + // 检查内存中是否有 WAV 数据 + let wavData = this.voiceWavCache.get(cacheKey) + if (wavData) { + console.log(`[Transcribe] WAV内存缓存命中,大小: ${wavData.length} bytes`) + } else { + // 检查文件缓存 + const voiceCacheDir = this.getVoiceCacheDir() + const wavFilePath = join(voiceCacheDir, `${cacheKey}.wav`) + if (existsSync(wavFilePath)) { + try { + wavData = readFileSync(wavFilePath) + console.log(`[Transcribe] WAV文件缓存命中,大小: ${wavData.length} bytes`) + // 同时缓存到内存 + this.cacheVoiceWav(cacheKey, wavData) + } catch (e) { + console.error(`[Transcribe] 读取缓存文件失败:`, e) + } + } + } + + if (!wavData) { + console.log(`[Transcribe] WAV缓存未命中,调用 getVoiceData`) + const t3 = Date.now() + // 调用 getVoiceData 获取并解码 + const voiceResult = await this.getVoiceData(sessionId, msgId, msgCreateTime, serverId) + const t4 = Date.now() + console.log(`[Transcribe] getVoiceData: ${t4 - t3}ms, success=${voiceResult.success}`) + + if (!voiceResult.success || !voiceResult.data) { + console.error(`[Transcribe] 语音解码失败: ${voiceResult.error}`) + return { success: false, error: voiceResult.error || '语音解码失败' } + } + wavData = Buffer.from(voiceResult.data, 'base64') + console.log(`[Transcribe] WAV数据大小: ${wavData.length} bytes`) + } + + // 转写 + console.log(`[Transcribe] 开始调用 transcribeWavBuffer`) + const t5 = Date.now() + const result = await voiceTranscribeService.transcribeWavBuffer(wavData, (text) => { + console.log(`[Transcribe] 部分结果: ${text}`) + onPartial?.(text) + }) + const t6 = Date.now() + console.log(`[Transcribe] transcribeWavBuffer: ${t6 - t5}ms, success=${result.success}`) + + if (result.success && result.transcript) { + console.log(`[Transcribe] 转写成功: ${result.transcript}`) + this.cacheVoiceTranscript(cacheKey, result.transcript) + } else { + console.error(`[Transcribe] 转写失败: ${result.error}`) + } + + console.log(`[Transcribe] 总耗时: ${Date.now() - startTime}ms`) + return result + } catch (error) { + console.error(`[Transcribe] 异常:`, error) + return { success: false, error: String(error) } + } finally { + this.voiceTranscriptPending.delete(cacheKey) + } + })() + + this.voiceTranscriptPending.set(cacheKey, task) + return task + } catch (error) { + console.error(`[Transcribe] 外层异常:`, error) + return { success: false, error: String(error) } + } } - private getVoiceCacheKey(sessionId: string, msgId: string): string { + private getVoiceCacheKey(sessionId: string, msgId: string, createTime?: number): string { + // 优先使用 createTime 作为key,避免不同会话中localId相同导致的混乱 + if (createTime) { + return `${sessionId}_${createTime}` + } return `${sessionId}_${msgId}` } @@ -2525,32 +2844,6 @@ class ChatService { } } - /** - * 获取语音缓存文件路径 - */ - private getVoiceCacheFilePath(cacheKey: string): string { - const cachePath = this.configService.get('cachePath') as string | undefined - let baseDir: string - if (cachePath && cachePath.trim()) { - baseDir = join(cachePath, 'Voices') - } else { - const documentsPath = app.getPath('documents') - baseDir = join(documentsPath, 'WeFlow', 'Voices') - } - if (!existsSync(baseDir)) { - mkdirSync(baseDir, { recursive: true }) - } - return join(baseDir, `${cacheKey}.wav`) - } - - /** - * 保存语音到文件缓存 - */ - private saveVoiceCache(cacheKey: string, wavData: Buffer): void { - const filePath = this.getVoiceCacheFilePath(cacheKey) - writeFileSync(filePath, wavData) - } - private cacheVoiceTranscript(cacheKey: string, transcript: string): void { this.voiceTranscriptCache.set(cacheKey, transcript) if (this.voiceTranscriptCache.size > this.voiceCacheMaxEntries) { @@ -2561,8 +2854,6 @@ class ChatService { async getMessageById(sessionId: string, localId: number): Promise<{ success: boolean; message?: Message; error?: string }> { try { - console.info('[ChatService] getMessageById (SQL)', { sessionId, localId }) - // 1. 获取该会话所在的消息表 // 注意:这里使用 getMessageTableStats 而不是 getMessageTables,因为前者包含 db_path const tableStats = await wcdbService.getMessageTableStats(sessionId) @@ -2585,7 +2876,6 @@ class ChatService { const message = this.parseMessage(row) if (message.localId !== 0) { - console.info('[ChatService] getMessageById hit', { tableName, localId: message.localId }) return { success: true, message } } } diff --git a/electron/services/imageDecryptService.ts b/electron/services/imageDecryptService.ts index 7b6dab8..aae33f9 100644 --- a/electron/services/imageDecryptService.ts +++ b/electron/services/imageDecryptService.ts @@ -68,14 +68,7 @@ export class ImageDecryptService { const metaStr = meta ? ` ${JSON.stringify(meta)}` : '' const logLine = `[${timestamp}] [ImageDecrypt] ${message}${metaStr}\n` - // 同时输出到控制台 - if (meta) { - console.info(message, meta) - } else { - console.info(message) - } - - // 写入日志文件 + // 只写入文件,不输出到控制台 this.writeLog(logLine) } diff --git a/electron/services/voiceTranscribeService.ts b/electron/services/voiceTranscribeService.ts index a23d0d2..5f594c2 100644 --- a/electron/services/voiceTranscribeService.ts +++ b/electron/services/voiceTranscribeService.ts @@ -224,13 +224,16 @@ export class VoiceTranscribeService { let finalTranscript = '' worker.on('message', (msg: any) => { + console.log('[VoiceTranscribe] Worker 消息:', msg) if (msg.type === 'partial') { onPartial?.(msg.text) } else if (msg.type === 'final') { finalTranscript = msg.text + console.log('[VoiceTranscribe] 最终文本:', finalTranscript) resolve({ success: true, transcript: finalTranscript }) worker.terminate() } else if (msg.type === 'error') { + console.error('[VoiceTranscribe] Worker 错误:', msg.error) resolve({ success: false, error: msg.error }) worker.terminate() } diff --git a/electron/services/wcdbCore.ts b/electron/services/wcdbCore.ts index 1949e74..7f8f32c 100644 --- a/electron/services/wcdbCore.ts +++ b/electron/services/wcdbCore.ts @@ -110,7 +110,7 @@ export class WcdbCore { private writeLog(message: string, force = false): void { if (!force && !this.isLogEnabled()) return const line = `[${new Date().toISOString()}] ${message}` - console.log(`[WCDB] ${line}`) + // 移除控制台日志,只写入文件 try { const base = this.userDataPath || process.env.WCDB_LOG_DIR || process.cwd() const dir = join(base, 'logs') @@ -620,7 +620,7 @@ export class WcdbCore { try { this.wcdbSetMyWxid(this.handle, wxid) } catch (e) { - console.warn('设置 wxid 失败:', e) + // 静默失败 } } if (this.isLogEnabled()) { @@ -799,7 +799,6 @@ export class WcdbCore { await new Promise(resolve => setImmediate(resolve)) if (result !== 0 || !outPtr[0]) { - console.warn(`[wcdbCore] getAvatarUrls DLL调用失败: result=${result}, usernames=${toFetch.length}`) if (Object.keys(resultMap).length > 0) { return { success: true, map: resultMap, error: `获取头像失败: ${result}` } } @@ -807,25 +806,18 @@ export class WcdbCore { } const jsonStr = this.decodeJsonPtr(outPtr[0]) if (!jsonStr) { - console.error('[wcdbCore] getAvatarUrls 解析JSON失败') return { success: false, error: '解析头像失败' } } const map = JSON.parse(jsonStr) as Record - let successCount = 0 - let emptyCount = 0 for (const username of toFetch) { const url = map[username] if (url && url.trim()) { resultMap[username] = url // 只缓存有效的URL this.avatarUrlCache.set(username, { url, updatedAt: now }) - successCount++ - } else { - emptyCount++ - // 不缓存空URL,下次可以重新尝试 } + // 不缓存空URL,下次可以重新尝试 } - console.log(`[wcdbCore] getAvatarUrls 成功: ${successCount}个, 空结果: ${emptyCount}个, 总请求: ${toFetch.length}`) return { success: true, map: resultMap } } catch (e) { console.error('[wcdbCore] getAvatarUrls 异常:', e) diff --git a/resources/silk_v3_decoder.exe b/resources/silk_v3_decoder.exe deleted file mode 100644 index f61275121a8d8bbe9da20f635190be636404d248..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 179037 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 X^k&9fDA-s?V@b=6#__oFz>oh2Y#tB& diff --git a/src/pages/ChatPage.tsx b/src/pages/ChatPage.tsx index 74e655c..1e11914 100644 --- a/src/pages/ChatPage.tsx +++ b/src/pages/ChatPage.tsx @@ -1784,7 +1784,16 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat, o throw error } - const result = await window.electronAPI.chat.getVoiceTranscript(session.username, String(message.localId)) + const result = await window.electronAPI.chat.getVoiceTranscript( + session.username, + String(message.localId), + message.createTime + ) + console.log('[ChatPage] 调用转写:', { + sessionId: session.username, + msgId: message.localId, + createTime: message.createTime + }) if (result.success) { const transcriptText = (result.transcript || '').trim() voiceTranscriptCache.set(voiceTranscriptCacheKey, transcriptText) diff --git a/src/types/electron.d.ts b/src/types/electron.d.ts index 65cff90..34ee49d 100644 --- a/src/types/electron.d.ts +++ b/src/types/electron.d.ts @@ -96,7 +96,7 @@ export interface ElectronAPI { getImageData: (sessionId: string, msgId: string) => Promise<{ success: boolean; data?: string; error?: string }> getVoiceData: (sessionId: string, msgId: string, createTime?: number, serverId?: string | number) => Promise<{ success: boolean; data?: string; error?: string }> resolveVoiceCache: (sessionId: string, msgId: string) => Promise<{ success: boolean; hasCache: boolean; data?: string }> - getVoiceTranscript: (sessionId: string, msgId: string) => Promise<{ success: boolean; transcript?: string; error?: string }> + getVoiceTranscript: (sessionId: string, msgId: string, createTime?: number) => Promise<{ success: boolean; transcript?: string; error?: string }> onVoiceTranscriptPartial: (callback: (payload: { msgId: string; text: string }) => void) => () => void }