refactor(main): 重构字幕引擎启动和错误处理逻辑

- 修改了字幕引擎的启动条件,增加了对环境变量和自定义应用的检查
- 优化了错误处理机制,通过控制窗口发送错误消息
- 在前端增加了错误通知功能
This commit is contained in:
himeditator
2025-06-26 18:59:53 +08:00
parent c086725d98
commit 147e328d8c
3 changed files with 133 additions and 91 deletions

View File

@@ -90,8 +90,17 @@ class ControlWindow {
this.window?.webContents.send('control.engine.already') this.window?.webContents.send('control.engine.already')
} }
else { else {
captionEngine.start() if(
this.window?.webContents.send('control.engine.started') process.env.DASHSCOPE_API_KEY ||
(controls.customized && controls.customizedApp)
) {
if(this.window){
captionEngine.start(this.window)
}
}
else {
this.sendErrorMessage('没有检测到 DASHSCOPE_API_KEY 环境变量,如果要使用 gummy 引擎,需要在阿里云百炼平台获取 API Key 并添加到本机环境变量')
}
} }
}) })
// 停止字幕引擎 // 停止字幕引擎
@@ -104,6 +113,10 @@ class ControlWindow {
captionLog.splice(0) captionLog.splice(0)
}) })
} }
public sendErrorMessage(message: string) {
this.window?.webContents.send('control.error.send', message)
}
} }
export const controlWindow = new ControlWindow() export const controlWindow = new ControlWindow()

View File

@@ -1,8 +1,9 @@
import { spawn, exec } from 'child_process' import { spawn, exec } from 'child_process'
import { app } from 'electron' import { app, BrowserWindow } from 'electron'
import { is } from '@electron-toolkit/utils' import { is } from '@electron-toolkit/utils'
import path from 'path' import path from 'path'
import { addCaptionLog, controls } from './config' import { addCaptionLog, controls, sendControls } from './config'
import { controlWindow } from '../control'
export class CaptionEngine { export class CaptionEngine {
appPath: string = '' appPath: string = ''
@@ -15,6 +16,7 @@ export class CaptionEngine {
this.command = [controls.customizedCommand] this.command = [controls.customizedCommand]
} }
else if (controls.engine === 'gummy') { else if (controls.engine === 'gummy') {
controls.customized = false
let gummyName = '' let gummyName = ''
if (process.platform === 'win32') { if (process.platform === 'win32') {
gummyName = 'main-gummy.exe' gummyName = 'main-gummy.exe'
@@ -23,6 +25,7 @@ export class CaptionEngine {
gummyName = 'main-gummy' gummyName = 'main-gummy'
} }
else { else {
controlWindow.sendErrorMessage('不支持的操作系统平台:' + process.platform)
throw new Error('Unsupported platform') throw new Error('Unsupported platform')
} }
if (is.dev) { if (is.dev) {
@@ -42,24 +45,34 @@ export class CaptionEngine {
this.command.push('-t', controls.translation ? controls.targetLang : 'none') this.command.push('-t', controls.translation ? controls.targetLang : 'none')
this.command.push('-a', controls.audio ? '1' : '0') this.command.push('-a', controls.audio ? '1' : '0')
console.log('[INFO] engine', this.appPath) console.log('[INFO] Engine Path:', this.appPath)
console.log('[INFO] engine command',this.command) console.log('[INFO] Engine Command:', this.command)
} }
} }
public start() { public start(window: BrowserWindow) {
if (this.process) { if (this.process) {
this.stop(); this.stop();
} }
this.getApp() this.getApp()
try {
this.process = spawn(this.appPath, this.command) this.process = spawn(this.appPath, this.command)
controls.engineEnabled = true }
catch (e) {
controlWindow.sendErrorMessage('字幕引擎启动失败:' + e)
console.error('[ERROR] Error starting subprocess:', e)
return
}
console.log('[INFO] Caption Engine Started: ', { console.log('[INFO] Caption Engine Started: ', {
appPath: this.appPath, appPath: this.appPath,
command: this.command command: this.command
}) })
controls.engineEnabled = true
sendControls(window)
window.webContents.send('control.engine.started')
this.process.stdout.on('data', (data) => { this.process.stdout.on('data', (data) => {
const lines = data.toString().split('\n'); const lines = data.toString().split('\n');
lines.forEach((line: string) => { lines.forEach((line: string) => {
@@ -68,18 +81,20 @@ export class CaptionEngine {
const caption = JSON.parse(line); const caption = JSON.parse(line);
addCaptionLog(caption); addCaptionLog(caption);
} catch (e) { } catch (e) {
console.error('Error parsing JSON:', e); controlWindow.sendErrorMessage('字幕引擎输出内容无法解析为 JSON 对象:' + e)
console.error('[ERROR] Error parsing JSON:', e);
} }
} }
}); });
}); });
this.process.stderr.on('data', (data) => { this.process.stderr.on('data', (data) => {
console.error(`Python Error: ${data}`); controlWindow.sendErrorMessage('字幕引擎错误:' + data)
console.error(`[ERROR] Subprocess Error: ${data}`);
}); });
this.process.on('close', (code: any) => { this.process.on('close', (code: any) => {
console.log(`Python process exited with code ${code}`); console.log(`[INFO] Subprocess exited with code ${code}`);
this.process = undefined; this.process = undefined;
}); });
} }
@@ -89,7 +104,8 @@ export class CaptionEngine {
if (process.platform === "win32" && this.process.pid) { if (process.platform === "win32" && this.process.pid) {
exec(`taskkill /pid ${this.process.pid} /t /f`, (error) => { exec(`taskkill /pid ${this.process.pid} /t /f`, (error) => {
if (error) { if (error) {
console.error(`Failed to kill process: ${error}`); controlWindow.sendErrorMessage('字幕引擎进程关闭失败:' + error)
console.error(`[ERROR] Failed to kill process: ${error}`);
} }
}); });
} else { } else {

View File

@@ -1,6 +1,9 @@
import { ref } from 'vue' import { ref } from 'vue'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { notification } from 'ant-design-vue' import { notification } from 'ant-design-vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
import { h } from 'vue'
export const useCaptionControlStore = defineStore('captionControl', () => { export const useCaptionControlStore = defineStore('captionControl', () => {
const captionEngine = ref([ const captionEngine = ref([
@@ -109,6 +112,16 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
}); });
}) })
window.electron.ipcRenderer.on('control.error.send', (_, message) => {
notification.open({
message: '发生错误',
description: message,
duration: null,
placement: 'topLeft',
icon: () => h(ExclamationCircleOutlined, { style: 'color: #ff4d4f' })
});
})
return { return {
captionEngine, // 字幕引擎 captionEngine, // 字幕引擎
audioType, // 音频类型 audioType, // 音频类型