mirror of
https://github.com/HiMeditator/auto-caption.git
synced 2026-02-13 02:54:48 +08:00
feat(engine): 优化字幕引擎通信和控制逻辑,优化窗口信息展示
- 优化错误处理和引擎重启逻辑 - 添加字幕引擎强制终止功能 - 调整通知和错误提示的显示位置 - 优化日志记录精度到毫秒级
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { spawn } from 'child_process'
|
||||
import { exec, spawn } from 'child_process'
|
||||
import { app } from 'electron'
|
||||
import { is } from '@electron-toolkit/utils'
|
||||
import path from 'path'
|
||||
@@ -13,11 +13,11 @@ export class CaptionEngine {
|
||||
command: string[] = []
|
||||
process: any | undefined
|
||||
client: net.Socket | undefined
|
||||
status: 'running' | 'stopping' | 'stopped' = 'stopped'
|
||||
status: 'running' | 'starting' | 'stopping' | 'stopped' = 'stopped'
|
||||
|
||||
private getApp(): boolean {
|
||||
if (allConfig.controls.customized) {
|
||||
Log.info('Using customized engine')
|
||||
Log.info('Using customized caption engine')
|
||||
this.appPath = allConfig.controls.customizedApp
|
||||
this.command = allConfig.controls.customizedCommand.split(' ')
|
||||
}
|
||||
@@ -30,14 +30,14 @@ export class CaptionEngine {
|
||||
}
|
||||
this.command = []
|
||||
if (is.dev) {
|
||||
// this.appPath = path.join(
|
||||
// app.getAppPath(), 'engine',
|
||||
// 'subenv', 'Scripts', 'python.exe'
|
||||
// )
|
||||
// this.command.push(path.join(
|
||||
// app.getAppPath(), 'engine', 'main.py'
|
||||
// ))
|
||||
this.appPath = path.join(app.getAppPath(), 'engine', 'dist', 'main.exe')
|
||||
this.appPath = path.join(
|
||||
app.getAppPath(), 'engine',
|
||||
'subenv', 'Scripts', 'python.exe'
|
||||
)
|
||||
this.command.push(path.join(
|
||||
app.getAppPath(), 'engine', 'main.py'
|
||||
))
|
||||
// this.appPath = path.join(app.getAppPath(), 'engine', 'dist', 'main.exe')
|
||||
}
|
||||
else {
|
||||
this.appPath = path.join(process.resourcesPath, 'engine', 'main.exe')
|
||||
@@ -73,6 +73,14 @@ export class CaptionEngine {
|
||||
Log.info('Connected to caption engine server');
|
||||
});
|
||||
this.status = 'running'
|
||||
allConfig.controls.engineEnabled = true
|
||||
if(controlWindow.window){
|
||||
allConfig.sendControls(controlWindow.window)
|
||||
controlWindow.window.webContents.send(
|
||||
'control.engine.started',
|
||||
this.process.pid
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public sendCommand(command: string, content: string = "") {
|
||||
@@ -93,19 +101,11 @@ export class CaptionEngine {
|
||||
if(!this.getApp()){ return }
|
||||
|
||||
this.process = spawn(this.appPath, this.command)
|
||||
Log.info('Caption Engine Started, PID:', this.process.pid)
|
||||
|
||||
allConfig.controls.engineEnabled = true
|
||||
if(controlWindow.window){
|
||||
allConfig.sendControls(controlWindow.window)
|
||||
controlWindow.window.webContents.send(
|
||||
'control.engine.started',
|
||||
this.process.pid
|
||||
)
|
||||
}
|
||||
|
||||
this.status = 'starting'
|
||||
Log.info('Caption Engine Starting, PID:', this.process.pid)
|
||||
|
||||
this.process.stdout.on('data', (data: any) => {
|
||||
const lines = data.toString().split('\n');
|
||||
const lines = data.toString().split('\n')
|
||||
lines.forEach((line: string) => {
|
||||
if (line.trim()) {
|
||||
try {
|
||||
@@ -120,13 +120,18 @@ export class CaptionEngine {
|
||||
});
|
||||
|
||||
this.process.stderr.on('data', (data: any) => {
|
||||
if(this.status === 'stopping') return
|
||||
controlWindow.sendErrorMessage(i18n('engine.error') + data)
|
||||
Log.error(`Engine Error: ${data}`);
|
||||
const lines = data.toString().split('\n')
|
||||
lines.forEach((line: string) => {
|
||||
if(line.trim()){
|
||||
controlWindow.sendErrorMessage(/*i18n('engine.error') +*/ line)
|
||||
console.error(line)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
this.process.on('close', (code: any) => {
|
||||
this.process = undefined;
|
||||
this.client = undefined
|
||||
allConfig.controls.engineEnabled = false
|
||||
if(controlWindow.window){
|
||||
allConfig.sendControls(controlWindow.window)
|
||||
@@ -150,25 +155,52 @@ export class CaptionEngine {
|
||||
this.status = 'stopping'
|
||||
Log.info('Caption engine process stopping...')
|
||||
}
|
||||
|
||||
public kill(){
|
||||
if(this.status !== 'running'){
|
||||
Log.warn('Engine is not running, current status:', this.status)
|
||||
return
|
||||
}
|
||||
if (this.process.pid) {
|
||||
Log.warn('Trying to kill engine process, PID:', this.process.pid)
|
||||
if(this.client){
|
||||
this.client.destroy()
|
||||
this.client = undefined
|
||||
}
|
||||
let cmd = `kill ${this.process.pid}`;
|
||||
if (process.platform === "win32") {
|
||||
cmd = `taskkill /pid ${this.process.pid} /t /f`
|
||||
}
|
||||
exec(cmd)
|
||||
}
|
||||
this.status = 'stopping'
|
||||
}
|
||||
}
|
||||
|
||||
function handleEngineData(data: any) {
|
||||
if(data.command === 'ready'){
|
||||
if(data.command === 'connect'){
|
||||
captionEngine.connect()
|
||||
}
|
||||
else if(data.command === 'kill') {
|
||||
if(captionEngine.status !== 'stopped') {
|
||||
Log.warn('Error occurred, trying to kill Gummy engine...')
|
||||
captionEngine.kill()
|
||||
}
|
||||
}
|
||||
else if(data.command === 'caption') {
|
||||
allConfig.updateCaptionLog(data);
|
||||
}
|
||||
else if(data.command === 'print') {
|
||||
console.log(data.content)
|
||||
// Log.info('Engine Print:', data.content)
|
||||
Log.info('Engine Print:', data.content)
|
||||
}
|
||||
else if(data.command === 'info') {
|
||||
Log.info('Engine Info:', data.content)
|
||||
}
|
||||
else if(data.command === 'usage') {
|
||||
console.error(data.content)
|
||||
// Log.info('Gummy Engine Usage: ', data.content)
|
||||
Log.info('Gummy Engine Usage: ', data.content)
|
||||
}
|
||||
else {
|
||||
Log.warn('Unknown command:', data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ function getTimeString() {
|
||||
const HH = String(now.getHours()).padStart(2, '0')
|
||||
const MM = String(now.getMinutes()).padStart(2, '0')
|
||||
const SS = String(now.getSeconds()).padStart(2, '0')
|
||||
return `${HH}:${MM}:${SS}`
|
||||
const MS = String(now.getMilliseconds()).padStart(3, '0')
|
||||
return `${HH}:${MM}:${SS}.${MS}`
|
||||
}
|
||||
|
||||
export class Log {
|
||||
|
||||
@@ -282,7 +282,8 @@ function applyStyle(){
|
||||
|
||||
captionStyle.sendStylesChange();
|
||||
|
||||
notification.open({
|
||||
notification.open({
|
||||
placement: 'topLeft',
|
||||
message: t('noti.styleChange'),
|
||||
description: t('noti.styleInfo')
|
||||
});
|
||||
|
||||
@@ -164,6 +164,7 @@ function applyChange(){
|
||||
engineControl.sendControlsChange()
|
||||
|
||||
notification.open({
|
||||
placement: 'topLeft',
|
||||
message: t('noti.engineChange'),
|
||||
description: t('noti.changeInfo')
|
||||
});
|
||||
|
||||
@@ -61,12 +61,14 @@
|
||||
>{{ $t('status.openCaption') }}</a-button>
|
||||
<a-button
|
||||
class="control-button"
|
||||
:disabled="engineEnabled"
|
||||
:loading="pending && !engineEnabled"
|
||||
:disabled="pending || engineEnabled"
|
||||
@click="startEngine"
|
||||
>{{ $t('status.startEngine') }}</a-button>
|
||||
<a-button
|
||||
danger class="control-button"
|
||||
:disabled="!engineEnabled"
|
||||
:loading="pending && engineEnabled"
|
||||
:disabled="pending || !engineEnabled"
|
||||
@click="stopEngine"
|
||||
>{{ $t('status.stopEngine') }}</a-button>
|
||||
</div>
|
||||
@@ -119,13 +121,14 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { EngineInfo } from '@renderer/types'
|
||||
import { ref } from 'vue'
|
||||
import { ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useCaptionLogStore } from '@renderer/stores/captionLog'
|
||||
import { useEngineControlStore } from '@renderer/stores/engineControl'
|
||||
import { GithubOutlined, InfoCircleOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
const showAbout = ref(false)
|
||||
const pending = ref(false)
|
||||
|
||||
const captionLog = useCaptionLogStore()
|
||||
const { captionData } = storeToRefs(captionLog)
|
||||
@@ -143,6 +146,7 @@ function openCaptionWindow() {
|
||||
}
|
||||
|
||||
function startEngine() {
|
||||
pending.value = true
|
||||
if(engineControl.engine === 'vosk' && engineControl.modelPath.trim() === '') {
|
||||
engineControl.emptyModelPathErr()
|
||||
return
|
||||
@@ -151,6 +155,7 @@ function startEngine() {
|
||||
}
|
||||
|
||||
function stopEngine() {
|
||||
pending.value = true
|
||||
window.electron.ipcRenderer.send('control.engine.stop')
|
||||
}
|
||||
|
||||
@@ -164,6 +169,9 @@ function getEngineInfo() {
|
||||
})
|
||||
}
|
||||
|
||||
watch(engineEnabled, () => {
|
||||
pending.value = false
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -64,6 +64,7 @@ export const useEngineControlStore = defineStore('engineControl', () => {
|
||||
|
||||
function emptyModelPathErr() {
|
||||
notification.open({
|
||||
placement: 'topLeft',
|
||||
message: t('noti.empty'),
|
||||
description: t('noti.emptyInfo')
|
||||
});
|
||||
@@ -80,6 +81,7 @@ export const useEngineControlStore = defineStore('engineControl', () => {
|
||||
(translation.value ? `${t('noti.tLang')}${targetLang.value}` : '');
|
||||
const str1 = `${t('noti.custom')}${customizedApp.value}${t('noti.args')}${customizedCommand.value}`;
|
||||
notification.open({
|
||||
placement: 'topLeft',
|
||||
message: t('noti.started'),
|
||||
description:
|
||||
(customized.value ? str1 : str0) +
|
||||
@@ -89,6 +91,7 @@ export const useEngineControlStore = defineStore('engineControl', () => {
|
||||
|
||||
window.electron.ipcRenderer.on('control.engine.stopped', () => {
|
||||
notification.open({
|
||||
placement: 'topLeft',
|
||||
message: t('noti.stopped'),
|
||||
description: t('noti.stoppedInfo')
|
||||
});
|
||||
@@ -99,7 +102,6 @@ export const useEngineControlStore = defineStore('engineControl', () => {
|
||||
message: t('noti.error'),
|
||||
description: message,
|
||||
duration: null,
|
||||
placement: 'topLeft',
|
||||
icon: () => h(ExclamationCircleOutlined, { style: 'color: #ff4d4f' })
|
||||
});
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user