mirror of
https://github.com/HiMeditator/auto-caption.git
synced 2026-02-18 14:44:41 +08:00
refactor(main): 重构字幕引擎启动和错误处理逻辑
- 修改了字幕引擎的启动条件,增加了对环境变量和自定义应用的检查 - 优化了错误处理机制,通过控制窗口发送错误消息 - 在前端增加了错误通知功能
This commit is contained in:
@@ -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()
|
||||||
@@ -1,103 +1,119 @@
|
|||||||
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 = ''
|
||||||
command: string[] = []
|
command: string[] = []
|
||||||
process: any | undefined
|
process: any | undefined
|
||||||
|
|
||||||
private getApp() {
|
private getApp() {
|
||||||
if(controls.customized && controls.customizedApp){
|
if (controls.customized && controls.customizedApp) {
|
||||||
this.appPath = controls.customizedApp
|
this.appPath = controls.customizedApp
|
||||||
this.command = [ controls.customizedCommand ]
|
this.command = [controls.customizedCommand]
|
||||||
}
|
}
|
||||||
else if(controls.engine === 'gummy'){
|
else if (controls.engine === 'gummy') {
|
||||||
let gummyName = ''
|
controls.customized = false
|
||||||
if(process.platform === 'win32'){
|
let gummyName = ''
|
||||||
gummyName = 'main-gummy.exe'
|
if (process.platform === 'win32') {
|
||||||
}
|
gummyName = 'main-gummy.exe'
|
||||||
else if(process.platform === 'linux'){
|
}
|
||||||
gummyName = 'main-gummy'
|
else if (process.platform === 'linux') {
|
||||||
}
|
gummyName = 'main-gummy'
|
||||||
else{
|
}
|
||||||
throw new Error('Unsupported platform')
|
else {
|
||||||
}
|
controlWindow.sendErrorMessage('不支持的操作系统平台:' + process.platform)
|
||||||
if(is.dev){
|
throw new Error('Unsupported platform')
|
||||||
this.appPath = path.join(
|
}
|
||||||
app.getAppPath(),
|
if (is.dev) {
|
||||||
'python-subprocess', 'dist', gummyName
|
this.appPath = path.join(
|
||||||
)
|
app.getAppPath(),
|
||||||
}
|
'python-subprocess', 'dist', gummyName
|
||||||
else{
|
)
|
||||||
this.appPath = path.join(
|
}
|
||||||
process.resourcesPath,
|
else {
|
||||||
'python-subprocess', 'dist', gummyName
|
this.appPath = path.join(
|
||||||
)
|
process.resourcesPath,
|
||||||
}
|
'python-subprocess', 'dist', gummyName
|
||||||
this.command = []
|
)
|
||||||
this.command.push('-s', controls.sourceLang)
|
}
|
||||||
this.command.push('-t', controls.translation ? controls.targetLang : 'none')
|
this.command = []
|
||||||
this.command.push('-a', controls.audio ? '1' : '0')
|
this.command.push('-s', controls.sourceLang)
|
||||||
|
this.command.push('-t', controls.translation ? controls.targetLang : 'none')
|
||||||
|
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(window: BrowserWindow) {
|
||||||
|
if (this.process) {
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
this.getApp()
|
||||||
|
try {
|
||||||
|
this.process = spawn(this.appPath, this.command)
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
controlWindow.sendErrorMessage('字幕引擎启动失败:' + e)
|
||||||
|
console.error('[ERROR] Error starting subprocess:', e)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
public start() {
|
console.log('[INFO] Caption Engine Started: ', {
|
||||||
if (this.process) {
|
appPath: this.appPath,
|
||||||
this.stop();
|
command: this.command
|
||||||
|
})
|
||||||
|
|
||||||
|
controls.engineEnabled = true
|
||||||
|
sendControls(window)
|
||||||
|
window.webContents.send('control.engine.started')
|
||||||
|
|
||||||
|
this.process.stdout.on('data', (data) => {
|
||||||
|
const lines = data.toString().split('\n');
|
||||||
|
lines.forEach((line: string) => {
|
||||||
|
if (line.trim()) {
|
||||||
|
try {
|
||||||
|
const caption = JSON.parse(line);
|
||||||
|
addCaptionLog(caption);
|
||||||
|
} catch (e) {
|
||||||
|
controlWindow.sendErrorMessage('字幕引擎输出内容无法解析为 JSON 对象:' + e)
|
||||||
|
console.error('[ERROR] Error parsing JSON:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.getApp()
|
});
|
||||||
this.process = spawn(this.appPath, this.command)
|
});
|
||||||
controls.engineEnabled = true
|
|
||||||
|
|
||||||
console.log('[INFO] Caption Engine Started: ', {
|
this.process.stderr.on('data', (data) => {
|
||||||
appPath: this.appPath,
|
controlWindow.sendErrorMessage('字幕引擎错误:' + data)
|
||||||
command: this.command
|
console.error(`[ERROR] Subprocess Error: ${data}`);
|
||||||
})
|
});
|
||||||
|
|
||||||
this.process.stdout.on('data', (data) => {
|
this.process.on('close', (code: any) => {
|
||||||
const lines = data.toString().split('\n');
|
console.log(`[INFO] Subprocess exited with code ${code}`);
|
||||||
lines.forEach( (line: string) => {
|
this.process = undefined;
|
||||||
if (line.trim()) {
|
});
|
||||||
try {
|
}
|
||||||
const caption = JSON.parse(line);
|
|
||||||
addCaptionLog(caption);
|
public stop() {
|
||||||
} catch (e) {
|
if (this.process) {
|
||||||
console.error('Error parsing JSON:', e);
|
if (process.platform === "win32" && this.process.pid) {
|
||||||
}
|
exec(`taskkill /pid ${this.process.pid} /t /f`, (error) => {
|
||||||
}
|
if (error) {
|
||||||
});
|
controlWindow.sendErrorMessage('字幕引擎进程关闭失败:' + error)
|
||||||
});
|
console.error(`[ERROR] Failed to kill process: ${error}`);
|
||||||
|
}
|
||||||
this.process.stderr.on('data', (data) => {
|
|
||||||
console.error(`Python Error: ${data}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.process.on('close', (code: any) => {
|
|
||||||
console.log(`Python process exited with code ${code}`);
|
|
||||||
this.process = undefined;
|
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
this.process.kill('SIGKILL');
|
||||||
|
}
|
||||||
|
this.process = undefined;
|
||||||
|
controls.engineEnabled = false;
|
||||||
|
console.log('[INFO] Caption engine process stopped');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public stop() {
|
|
||||||
if (this.process) {
|
|
||||||
if (process.platform === "win32" && this.process.pid) {
|
|
||||||
exec(`taskkill /pid ${this.process.pid} /t /f`, (error) => {
|
|
||||||
if (error) {
|
|
||||||
console.error(`Failed to kill process: ${error}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.process.kill('SIGKILL');
|
|
||||||
}
|
|
||||||
this.process = undefined;
|
|
||||||
controls.engineEnabled = false;
|
|
||||||
console.log('[INFO] Caption engine process stopped');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -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, // 音频类型
|
||||||
|
|||||||
Reference in New Issue
Block a user