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:
@@ -2,6 +2,7 @@ import {
|
||||
UILanguage, UITheme, Styles, Controls,
|
||||
CaptionItem, FullConfig
|
||||
} from '../types'
|
||||
import { Log } from './Log'
|
||||
import { app, BrowserWindow } from 'electron'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
@@ -48,6 +49,7 @@ class AllConfig {
|
||||
uiTheme: UITheme = 'system';
|
||||
styles: Styles = {...defaultStyles};
|
||||
controls: Controls = {...defaultControls};
|
||||
lastLogIndex: number = -1;
|
||||
captionLog: CaptionItem[] = [];
|
||||
|
||||
constructor() {}
|
||||
@@ -61,7 +63,7 @@ class AllConfig {
|
||||
if(config.leftBarWidth) this.leftBarWidth = config.leftBarWidth
|
||||
if(config.styles) this.setStyles(config.styles)
|
||||
if(config.controls) this.setControls(config.controls)
|
||||
console.log('[INFO] Read Config from:', configPath)
|
||||
Log.info('Read Config from:', configPath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +77,7 @@ class AllConfig {
|
||||
}
|
||||
const configPath = path.join(app.getPath('userData'), 'config.json')
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2))
|
||||
console.log('[INFO] Write Config to:', configPath)
|
||||
Log.info('Write Config to:', configPath)
|
||||
}
|
||||
|
||||
public getFullConfig(): FullConfig {
|
||||
@@ -96,7 +98,7 @@ class AllConfig {
|
||||
this.styles[key] = args[key]
|
||||
}
|
||||
}
|
||||
console.log('[INFO] Set Styles:', this.styles)
|
||||
Log.info('Set Styles:', this.styles)
|
||||
}
|
||||
|
||||
public resetStyles() {
|
||||
@@ -105,7 +107,7 @@ class AllConfig {
|
||||
|
||||
public sendStyles(window: BrowserWindow) {
|
||||
window.webContents.send('both.styles.set', this.styles)
|
||||
console.log(`[INFO] Send Styles to #${window.id}:`, this.styles)
|
||||
Log.info(`Send Styles to #${window.id}:`, this.styles)
|
||||
}
|
||||
|
||||
public setControls(args: Object) {
|
||||
@@ -116,27 +118,28 @@ class AllConfig {
|
||||
}
|
||||
}
|
||||
this.controls.engineEnabled = engineEnabled
|
||||
console.log('[INFO] Set Controls:', this.controls)
|
||||
Log.info('Set Controls:', this.controls)
|
||||
}
|
||||
|
||||
public sendControls(window: BrowserWindow) {
|
||||
window.webContents.send('control.controls.set', this.controls)
|
||||
console.log(`[INFO] Send Controls to #${window.id}:`, this.controls)
|
||||
Log.info(`Send Controls to #${window.id}:`, this.controls)
|
||||
}
|
||||
|
||||
public updateCaptionLog(log: CaptionItem) {
|
||||
let command: 'add' | 'upd' = 'add'
|
||||
if(
|
||||
this.captionLog.length &&
|
||||
this.captionLog[this.captionLog.length - 1].index === log.index &&
|
||||
this.captionLog[this.captionLog.length - 1].time_s === log.time_s
|
||||
this.lastLogIndex === log.index
|
||||
) {
|
||||
this.captionLog.splice(this.captionLog.length - 1, 1, log)
|
||||
command = 'upd'
|
||||
}
|
||||
else {
|
||||
this.captionLog.push(log)
|
||||
this.lastLogIndex = log.index
|
||||
}
|
||||
this.captionLog[this.captionLog.length - 1].index = this.captionLog.length
|
||||
for(const window of BrowserWindow.getAllWindows()){
|
||||
this.sendCaptionLog(window, command)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import path from 'path'
|
||||
import { controlWindow } from '../ControlWindow'
|
||||
import { allConfig } from './AllConfig'
|
||||
import { i18n } from '../i18n'
|
||||
import { Log } from './Log'
|
||||
|
||||
export class CaptionEngine {
|
||||
appPath: string = ''
|
||||
@@ -14,7 +15,7 @@ export class CaptionEngine {
|
||||
|
||||
private getApp(): boolean {
|
||||
if (allConfig.controls.customized && allConfig.controls.customizedApp) {
|
||||
console.log('[INFO] Using customized engine')
|
||||
Log.info('Using customized engine')
|
||||
this.appPath = allConfig.controls.customizedApp
|
||||
this.command = allConfig.controls.customizedCommand.split(' ')
|
||||
}
|
||||
@@ -25,9 +26,7 @@ export class CaptionEngine {
|
||||
return false
|
||||
}
|
||||
let gummyName = 'main-gummy'
|
||||
if (process.platform === 'win32') {
|
||||
gummyName += '.exe'
|
||||
}
|
||||
if (process.platform === 'win32') { gummyName += '.exe' }
|
||||
this.command = []
|
||||
if (is.dev) {
|
||||
this.appPath = path.join(
|
||||
@@ -56,31 +55,33 @@ export class CaptionEngine {
|
||||
else if(allConfig.controls.engine === 'vosk'){
|
||||
allConfig.controls.customized = false
|
||||
let voskName = 'main-vosk'
|
||||
if (process.platform === 'win32') {
|
||||
voskName += '.exe'
|
||||
}
|
||||
if (process.platform === 'win32') { voskName += '.exe' }
|
||||
this.command = []
|
||||
if (is.dev) {
|
||||
this.appPath = path.join(
|
||||
app.getAppPath(),
|
||||
'engine', 'dist', voskName
|
||||
app.getAppPath(), 'engine',
|
||||
'subenv', 'Scripts', 'python.exe'
|
||||
)
|
||||
this.command.push(path.join(
|
||||
app.getAppPath(), 'engine', 'main-vosk.py'
|
||||
))
|
||||
}
|
||||
else {
|
||||
this.appPath = path.join(
|
||||
process.resourcesPath, 'engine', voskName
|
||||
)
|
||||
}
|
||||
this.command = []
|
||||
this.command.push('-a', allConfig.controls.audio ? '1' : '0')
|
||||
this.command.push('-m', `"${allConfig.controls.modelPath}"`)
|
||||
}
|
||||
console.log('[INFO] Engine Path:', this.appPath)
|
||||
console.log('[INFO] Engine Command:', this.command)
|
||||
Log.info('Engine Path:', this.appPath)
|
||||
Log.info('Engine Command:', this.command)
|
||||
return true
|
||||
}
|
||||
|
||||
public start() {
|
||||
if (this.processStatus !== 'stopped') {
|
||||
Log.warn('Caption engine status is not stopped, cannot start')
|
||||
return
|
||||
}
|
||||
if(!this.getApp()){ return }
|
||||
@@ -90,12 +91,12 @@ export class CaptionEngine {
|
||||
}
|
||||
catch (e) {
|
||||
controlWindow.sendErrorMessage(i18n('engine.start.error') + e)
|
||||
console.error('[ERROR] Error starting subprocess:', e)
|
||||
Log.error('Error starting engine:', e)
|
||||
return
|
||||
}
|
||||
|
||||
this.processStatus = 'running'
|
||||
console.log('[INFO] Caption Engine Started, PID:', this.process.pid)
|
||||
Log.info('Caption Engine Started, PID:', this.process.pid)
|
||||
|
||||
allConfig.controls.engineEnabled = true
|
||||
if(controlWindow.window){
|
||||
@@ -111,27 +112,23 @@ export class CaptionEngine {
|
||||
lines.forEach((line: string) => {
|
||||
if (line.trim()) {
|
||||
try {
|
||||
const caption = JSON.parse(line);
|
||||
if(caption.index === undefined) {
|
||||
console.log('[INFO] Engine Bad Output:', caption);
|
||||
}
|
||||
else allConfig.updateCaptionLog(caption);
|
||||
const data_obj = JSON.parse(line)
|
||||
handleEngineData(data_obj)
|
||||
} catch (e) {
|
||||
controlWindow.sendErrorMessage(i18n('engine.output.parse.error') + e)
|
||||
console.error('[ERROR] Error parsing JSON:', e);
|
||||
Log.error('Error parsing JSON:', e)
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.process.stderr.on('data', (data) => {
|
||||
this.process.stderr.on('data', (data: any) => {
|
||||
if(this.processStatus === 'stopping') return
|
||||
controlWindow.sendErrorMessage(i18n('engine.error') + data)
|
||||
console.error(`[ERROR] Subprocess Error: ${data}`);
|
||||
Log.error(`Engine Error: ${data}`);
|
||||
});
|
||||
|
||||
this.process.on('close', (code: any) => {
|
||||
console.log(`[INFO] Subprocess exited with code ${code}`);
|
||||
this.process = undefined;
|
||||
allConfig.controls.engineEnabled = false
|
||||
if(controlWindow.window){
|
||||
@@ -139,14 +136,14 @@ export class CaptionEngine {
|
||||
controlWindow.window.webContents.send('control.engine.stopped')
|
||||
}
|
||||
this.processStatus = 'stopped'
|
||||
console.log('[INFO] Caption engine process stopped')
|
||||
Log.info(`Engine exited with code ${code}`)
|
||||
});
|
||||
}
|
||||
|
||||
public stop() {
|
||||
if(this.processStatus !== 'running') return
|
||||
if (this.process.pid) {
|
||||
console.log('[INFO] Trying to stop process, PID:', this.process.pid)
|
||||
Log.info('Trying to stop process, PID:', this.process.pid)
|
||||
let cmd = `kill ${this.process.pid}`;
|
||||
if (process.platform === "win32") {
|
||||
cmd = `taskkill /pid ${this.process.pid} /t /f`
|
||||
@@ -154,7 +151,7 @@ export class CaptionEngine {
|
||||
exec(cmd, (error) => {
|
||||
if (error) {
|
||||
controlWindow.sendErrorMessage(i18n('engine.shutdown.error') + error)
|
||||
console.error(`[ERROR] Failed to kill process: ${error}`)
|
||||
Log.error(`Failed to kill process: ${error}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -166,11 +163,26 @@ export class CaptionEngine {
|
||||
controlWindow.window.webContents.send('control.engine.stopped')
|
||||
}
|
||||
this.processStatus = 'stopped'
|
||||
console.log('[INFO] Process PID undefined, caption engine process stopped')
|
||||
Log.info('Process PID undefined, caption engine process stopped')
|
||||
return
|
||||
}
|
||||
this.processStatus = 'stopping'
|
||||
console.log('[INFO] Caption engine process stopping')
|
||||
Log.info('Caption engine process stopping')
|
||||
}
|
||||
}
|
||||
|
||||
function handleEngineData(data: any) {
|
||||
if(data.command === 'caption') {
|
||||
allConfig.updateCaptionLog(data);
|
||||
}
|
||||
else if(data.command === 'print') {
|
||||
Log.info('Engine print:', data.content)
|
||||
}
|
||||
else if(data.command === 'info') {
|
||||
Log.info('Engine info:', data.content)
|
||||
}
|
||||
else if(data.command === 'usage') {
|
||||
Log.info('Caption engine usage: ', data.content)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
21
src/main/utils/Log.ts
Normal file
21
src/main/utils/Log.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
function getTimeString() {
|
||||
const now = new Date()
|
||||
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}`
|
||||
}
|
||||
|
||||
export class Log {
|
||||
static info(...msg: any[]){
|
||||
console.log(`[INFO ${getTimeString()}]`, ...msg)
|
||||
}
|
||||
|
||||
static warn(...msg: any[]){
|
||||
console.log(`[WARN ${getTimeString()}]`, ...msg)
|
||||
}
|
||||
|
||||
static error(...msg: any[]){
|
||||
console.log(`[ERROR ${getTimeString()}]`, ...msg)
|
||||
}
|
||||
}
|
||||
@@ -174,6 +174,12 @@ const columns = [
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
sorter: (a: CaptionItem, b: CaptionItem) => {
|
||||
if(a.index <= b.index) return -1
|
||||
return 1
|
||||
},
|
||||
sortDirections: ['descend'],
|
||||
defaultSortOrder: 'descend',
|
||||
},
|
||||
{
|
||||
title: 'time',
|
||||
@@ -184,8 +190,7 @@ const columns = [
|
||||
if(a.time_s <= b.time_s) return -1
|
||||
return 1
|
||||
},
|
||||
sortDirections: ['descend'],
|
||||
defaultSortOrder: 'descend',
|
||||
sortDirections: ['descend', 'ascend'],
|
||||
},
|
||||
{
|
||||
title: 'content',
|
||||
|
||||
Reference in New Issue
Block a user