diff --git a/electron/services/keyServiceLinux.ts b/electron/services/keyServiceLinux.ts index 1d9e10b..3af9ddf 100644 --- a/electron/services/keyServiceLinux.ts +++ b/electron/services/keyServiceLinux.ts @@ -4,6 +4,7 @@ import { existsSync, readdirSync, statSync, readFileSync } from 'fs' import { execFile, exec } from 'child_process' import { promisify } from 'util' import { createRequire } from 'module'; +import { spawn } from 'child_process' const require = createRequire(import.meta.url); const execFileAsync = promisify(execFile) @@ -51,12 +52,37 @@ export class KeyServiceLinux { await new Promise(r => setTimeout(r, 1000)) onStatus?.('正在尝试拉起微信...', 0) - const startCmds = [ - 'nohup wechat >/dev/null 2>&1 &', - 'nohup wechat-bin >/dev/null 2>&1 &', - 'nohup xwechat >/dev/null 2>&1 &' + + const cleanEnv = { ...process.env }; + delete cleanEnv.ELECTRON_RUN_AS_NODE; + delete cleanEnv.ELECTRON_NO_ATTACH_CONSOLE; + delete cleanEnv.APPDIR; + delete cleanEnv.APPIMAGE; + + const wechatBins = [ + 'wechat', + 'wechat-bin', + 'xwechat', + '/opt/wechat/wechat', + '/usr/bin/wechat', + '/opt/apps/com.tencent.wechat/files/wechat' ] - for (const cmd of startCmds) execAsync(cmd).catch(() => {}) + + for (const binName of wechatBins) { + try { + const child = spawn(binName, [], { + detached: true, + stdio: 'ignore', + env: cleanEnv + }); + + child.on('error', () => {}); + + child.unref(); + } catch (e) { + + } + } onStatus?.('等待微信进程出现...', 0) let pid = 0 diff --git a/electron/services/voiceTranscribeService.ts b/electron/services/voiceTranscribeService.ts index cc75828..107cbc5 100644 --- a/electron/services/voiceTranscribeService.ts +++ b/electron/services/voiceTranscribeService.ts @@ -273,8 +273,20 @@ export class VoiceTranscribeService { }) worker.on('error', (err: Error) => resolve({ success: false, error: String(err) })) - worker.on('exit', (code: number) => { - if (code !== 0) resolve({ success: false, error: `Worker exited with code ${code}` }) + worker.on('exit', (code: number | null, signal: string | null) => { + if (code === null || signal === 'SIGSEGV') { + + console.error(`[VoiceTranscribe] Worker 异常崩溃,信号: ${signal}。可能是由于底层 C++ 运行库在当前系统上发生段错误。`); + resolve({ + success: false, + error: 'SEGFAULT_ERROR' + }); + return; + } + + if (code !== 0) { + resolve({ success: false, error: `Worker exited with code ${code}` }); + } }) } catch (error) { diff --git a/src/pages/ChatPage.tsx b/src/pages/ChatPage.tsx index d6faca4..07ef637 100644 --- a/src/pages/ChatPage.tsx +++ b/src/pages/ChatPage.tsx @@ -7611,6 +7611,12 @@ function MessageBubble({ const [voiceWaveform, setVoiceWaveform] = useState([]) const voiceAutoDecryptTriggered = useRef(false) + + const [systemAlert, setSystemAlert] = useState<{ + title: string; + message: React.ReactNode; + } | null>(null) + // 转账消息双方名称 const [transferPayerName, setTransferPayerName] = useState(undefined) const [transferReceiverName, setTransferReceiverName] = useState(undefined) @@ -8290,9 +8296,9 @@ function MessageBubble({ } const result = await window.electronAPI.chat.getVoiceTranscript( - session.username, - String(message.localId), - message.createTime + session.username, + String(message.localId), + message.createTime ) if (result.success) { @@ -8300,6 +8306,21 @@ function MessageBubble({ voiceTranscriptCache.set(voiceTranscriptCacheKey, transcriptText) setVoiceTranscript(transcriptText) } else { + if (result.error === 'SEGFAULT_ERROR') { + console.warn('[ChatPage] 捕获到语音引擎底层段错误'); + + setSystemAlert({ + title: '引擎崩溃提示', + message: ( + <> + 语音识别引擎发生底层崩溃 (Segmentation Fault)。

+ 如果您使用的是 Linux 等自定义程度较高的系统,请检查 sherpa-onnx 的相关系统动态链接库 (如 glibc 等) 是否兼容。 + + ) + }); + + } + setVoiceTranscriptError(true) voiceTranscriptRequestedRef.current = false } @@ -9699,6 +9720,31 @@ function MessageBubble({ {isSelected && } )} + {systemAlert && createPortal( +
setSystemAlert(null)} style={{ zIndex: 99999 }}> +
e.stopPropagation()} style={{ maxWidth: '400px' }}> +
+ +
+
+

{systemAlert.title}

+

+ {systemAlert.message} +

+
+
+ +
+
+
, + document.body + )} )