mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-24 23:06:51 +00:00
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -7611,6 +7611,12 @@ function MessageBubble({
|
||||
const [voiceWaveform, setVoiceWaveform] = useState<number[]>([])
|
||||
const voiceAutoDecryptTriggered = useRef(false)
|
||||
|
||||
|
||||
const [systemAlert, setSystemAlert] = useState<{
|
||||
title: string;
|
||||
message: React.ReactNode;
|
||||
} | null>(null)
|
||||
|
||||
// 转账消息双方名称
|
||||
const [transferPayerName, setTransferPayerName] = useState<string | undefined>(undefined)
|
||||
const [transferReceiverName, setTransferReceiverName] = useState<string | undefined>(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)。<br /><br />
|
||||
如果您使用的是 Linux 等自定义程度较高的系统,请检查 <code>sherpa-onnx</code> 的相关系统动态链接库 (如 glibc 等) 是否兼容。
|
||||
</>
|
||||
)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
setVoiceTranscriptError(true)
|
||||
voiceTranscriptRequestedRef.current = false
|
||||
}
|
||||
@@ -9699,6 +9720,31 @@ function MessageBubble({
|
||||
{isSelected && <Check size={14} strokeWidth={3} />}
|
||||
</div>
|
||||
)}
|
||||
{systemAlert && createPortal(
|
||||
<div className="modal-overlay" onClick={() => setSystemAlert(null)} style={{ zIndex: 99999 }}>
|
||||
<div className="delete-confirm-card" onClick={(e) => e.stopPropagation()} style={{ maxWidth: '400px' }}>
|
||||
<div className="confirm-icon">
|
||||
<AlertCircle size={32} color="var(--danger)" />
|
||||
</div>
|
||||
<div className="confirm-content">
|
||||
<h3>{systemAlert.title}</h3>
|
||||
<p style={{ marginTop: '12px', lineHeight: '1.6', fontSize: '14px', color: 'var(--text-secondary)' }}>
|
||||
{systemAlert.message}
|
||||
</p>
|
||||
</div>
|
||||
<div className="confirm-actions" style={{ justifyContent: 'center', marginTop: '24px' }}>
|
||||
<button
|
||||
className="btn-primary"
|
||||
onClick={() => setSystemAlert(null)}
|
||||
style={{ padding: '8px 32px' }}
|
||||
>
|
||||
确认
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
document.body
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user