feat: 增加了音频输入选项,并优化了字幕引擎的构建和运行流程。

- 新增了系统音频输入(麦克风)的选择功能
- 重构了字幕引擎的构建流程,使用 PyInstaller 打包为可执行文件
- 优化了字幕引擎的启动和停止逻辑
- 更新了用户界面,增加了音频选择的控制选项
- 修改了相关的文件路径和构建配置
This commit is contained in:
himeditator
2025-06-21 23:22:19 +08:00
parent 7030aaaae3
commit 42237a229c
15 changed files with 268 additions and 63 deletions

View File

@@ -2,6 +2,7 @@ import { app, BrowserWindow } from 'electron'
import { electronApp, optimizer } from '@electron-toolkit/utils'
import { controlWindow } from './control'
import { captionWindow } from './caption'
import { captionEngine } from './utils/config'
app.whenReady().then(() => {
electronApp.setAppUserModelId('com.himeditator.autocaption')
@@ -22,6 +23,10 @@ app.whenReady().then(() => {
})
})
app.on('will-quit', async () => {
captionEngine.stop()
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()

View File

@@ -23,6 +23,7 @@ export interface Controls {
sourceLang: string,
targetLang: string,
engine: string,
audio: 0 | 1,
translation: boolean,
customized: boolean,
customizedApp: string,

View File

@@ -22,6 +22,7 @@ export const controls: Controls = {
sourceLang: 'en',
targetLang: 'zh',
engine: 'gummy',
audio: 0,
engineEnabled: false,
translation: true,
customized: false,
@@ -74,6 +75,7 @@ export function setControls(args: any) {
controls.sourceLang = args.sourceLang
controls.targetLang = args.targetLang
controls.engine = args.engine
controls.audio = args.audio
controls.translation = args.translation
controls.customized = args.customized
controls.customizedApp = args.customizedApp

View File

@@ -1,5 +1,6 @@
import { spawn } from 'child_process'
import { spawn, exec } from 'child_process'
import { app } from 'electron'
import { is } from '@electron-toolkit/utils'
import path from 'path'
import { addCaptionLog, controls } from './config'
@@ -14,24 +15,29 @@ export class CaptionEngine {
this.command = [ controls.customizedCommand ]
}
else if(controls.engine === 'gummy'){
this.appPath = path.join(
app.getAppPath(),
'python-subprocess', 'subenv', 'Scripts', 'python.exe'
)
if(is.dev){
this.appPath = path.join(
app.getAppPath(),
'python-subprocess', 'dist', 'main-gummy.exe'
)
}
else{
this.appPath = path.join(
process.resourcesPath,
'python-subprocess', 'dist', 'main-gummy.exe'
)
}
this.command = []
this.command.push(path.join(
app.getAppPath(),
'python-subprocess', 'main.py'
))
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(this.appPath)
console.log(this.command)
console.log('[INFO] engine', this.appPath)
console.log('[INFO] engine command',this.command)
}
}
public start() {
public start() {
if (this.process) {
this.stop();
}
@@ -70,7 +76,15 @@ export class CaptionEngine {
public stop() {
if (this.process) {
this.process.kill();
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');

View File

@@ -29,6 +29,14 @@
:options="captionEngine"
></a-select>
</div>
<div class="control-item">
<span class="control-label">音频选择</span>
<a-select
class="control-input"
v-model:value="currentAudio"
:options="audioType"
></a-select>
</div>
<div class="control-item">
<span class="control-label">启用翻译</span>
<a-switch v-model:checked="currentTranslation" />
@@ -62,13 +70,15 @@
import { ref, computed, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useCaptionControlStore } from '@renderer/stores/captionControl'
import { notification } from 'ant-design-vue'
const captionControl = useCaptionControlStore()
const { captionEngine, changeSignal } = storeToRefs(captionControl)
const { captionEngine, audioType, changeSignal } = storeToRefs(captionControl)
const currentSourceLang = ref('auto')
const currentTargetLang = ref('zh')
const currentEngine = ref('gummy')
const currentAudio = ref<0 | 1>(0)
const currentTranslation = ref<boolean>(false)
const currentCustomized = ref<boolean>(false)
@@ -88,6 +98,7 @@ function applyChange(){
captionControl.sourceLang = currentSourceLang.value
captionControl.targetLang = currentTargetLang.value
captionControl.engine = currentEngine.value
captionControl.audio = currentAudio.value
captionControl.translation = currentTranslation.value
captionControl.customized = currentCustomized.value
@@ -95,12 +106,18 @@ function applyChange(){
captionControl.customizedCommand = currentCustomizedCommand.value
captionControl.sendControlChange()
notification.open({
message: '字幕控制已更改',
description: '如果字幕引擎已经启动,需要关闭后重启才会生效'
});
}
function cancelChange(){
currentSourceLang.value = captionControl.sourceLang
currentTargetLang.value = captionControl.targetLang
currentEngine.value = captionControl.engine
currentAudio.value = captionControl.audio
currentTranslation.value = captionControl.translation
currentCustomized.value = captionControl.customized

View File

@@ -16,11 +16,23 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
]
},
])
const audioType = ref([
{
value: 0,
label: '系统音频输出(扬声器)'
},
{
value: 1,
label: '系统音频输入(麦克风)'
}
])
const engineEnabled = ref(false)
const sourceLang = ref<string>('en')
const targetLang = ref<string>('zh')
const engine = ref<string>('gummy')
const audio = ref<0 | 1>(0)
const translation = ref<boolean>(true)
const customized = ref<boolean>(false)
const customizedApp = ref<string>('')
@@ -34,6 +46,7 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
sourceLang: sourceLang.value,
targetLang: targetLang.value,
engine: engine.value,
audio: audio.value,
translation: translation.value,
customized: customized.value,
customizedApp: customizedApp.value,
@@ -54,6 +67,7 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
sourceLang.value = controls.sourceLang
targetLang.value = controls.targetLang
engine.value = controls.engine
audio.value = controls.audio
translation.value = controls.translation
customized.value = controls.customized
customizedApp.value = controls.customizedApp
@@ -73,7 +87,8 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
engineEnabled.value = true
notification.open({
message: '字幕引擎启动',
description: `原语言:${sourceLang.value},是否翻译:${translation.value?'是':'否'}` +
description: `原语言:${sourceLang.value},是否翻译:${translation.value?'是':'否'}` +
`字幕引擎:${engine.value},音频类型:${audio.value ? '输入音频' : '输出音频'}` +
(translation.value ? `,翻译语言:${targetLang.value}` : '')
});
})
@@ -88,10 +103,12 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
return {
captionEngine, // 字幕引擎
audioType, // 音频类型
engineEnabled, // 字幕引擎是否启用
sourceLang, // 源语言
targetLang, // 目标语言
engine, // 字幕引擎
audio, // 选择音频
translation, // 是否启用翻译
customized, // 是否使用自定义字幕引擎
customizedApp, // 自定义字幕引擎的应用程序