mirror of
https://github.com/HiMeditator/auto-caption.git
synced 2026-02-04 04:14:42 +08:00
feat(engine): 优化 Vosk 字幕引擎支持
- 实现文件夹选择功能,用于选择 Vosk 模型路径 - 在 EngineControl 组件中添加模型路径选择按钮和相关提示 - 在 EngineStatus 组件中增加对空模型路径的检查和错误提示
This commit is contained in:
@@ -1 +1 @@
|
||||
from .process import mergeChunkChannels, resampleRawChunk
|
||||
from .process import mergeChunkChannels, resampleRawChunk, resampleMonoChunk
|
||||
|
||||
@@ -50,7 +50,7 @@ def resampleRawChunk(chunk, channels, orig_sr, target_sr, mode="sinc_best"):
|
||||
|
||||
def resampleMonoChunk(chunk, orig_sr, target_sr, mode="sinc_best"):
|
||||
"""
|
||||
将当前单通道进行重采样
|
||||
将当前单通道音频块进行重采样
|
||||
|
||||
Args:
|
||||
chunk: (bytes)单通道音频数据块
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
- [x] 添加复制字幕到剪贴板功能 *2025/07/08*
|
||||
- [x] 适配 macOS 平台 *2025/07/08*
|
||||
- [x] 添加字幕文字描边 *2025/07/09*
|
||||
- [x] 添加基于 Vosk 的字幕引擎 *2025/07/09*
|
||||
|
||||
## 待完成
|
||||
|
||||
- [ ] 添加 Ollama 模型用于本地字幕引擎的翻译
|
||||
- [ ] 更新 README 和用户手册(字幕引擎构建、Vosk 模型获取和使用)
|
||||
- [ ] 添加本地字幕引擎
|
||||
- [ ] 添加基于 Vosk 的字幕引擎
|
||||
- [ ] 验证 / 添加基于 FunASR 的字幕引擎
|
||||
- [ ] 减小软件不必要的体积
|
||||
|
||||
|
||||
@@ -44,6 +44,19 @@
|
||||
- 发送:无数据
|
||||
- 接收:`string`
|
||||
|
||||
### `control.folder.select`
|
||||
|
||||
**介绍:** 打开文件夹选择器,并将用户选择的文件夹路径返回给前端
|
||||
|
||||
**发起方:** 前端控制窗口
|
||||
|
||||
**接收方:** 后端控制窗口实例
|
||||
|
||||
**数据类型:**
|
||||
|
||||
- 发送:无数据
|
||||
- 接收:`string`
|
||||
|
||||
## 前端 ==> 后端
|
||||
|
||||
### `control.uiLanguage.change`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { shell, BrowserWindow, ipcMain, nativeTheme } from 'electron'
|
||||
import { shell, BrowserWindow, ipcMain, nativeTheme, dialog } from 'electron'
|
||||
import path from 'path'
|
||||
import { is } from '@electron-toolkit/utils'
|
||||
import icon from '../../build/icon.png?asset'
|
||||
@@ -72,6 +72,15 @@ class ControlWindow {
|
||||
return allConfig.uiTheme
|
||||
})
|
||||
|
||||
ipcMain.handle('control.folder.select', async () => {
|
||||
const result = await dialog.showOpenDialog({
|
||||
properties: ['openDirectory']
|
||||
});
|
||||
|
||||
if (result.canceled) return "";
|
||||
return result.filePaths[0];
|
||||
})
|
||||
|
||||
ipcMain.on('control.uiLanguage.change', (_, args) => {
|
||||
allConfig.uiLanguage = args
|
||||
if(captionWindow.window){
|
||||
|
||||
@@ -51,7 +51,12 @@
|
||||
|
||||
<a-card size="small" :title="$t('engine.showMore')" v-show="showMore">
|
||||
<div class="input-item">
|
||||
<span class="input-label">{{ $t('engine.apikey') }}</span>
|
||||
<a-popover>
|
||||
<template #content>
|
||||
<p class="label-hover-info">{{ $t('engine.apikeyInfo') }}</p>
|
||||
</template>
|
||||
<span class="input-label info-label">{{ $t('engine.apikey') }}</span>
|
||||
</a-popover>
|
||||
<a-input
|
||||
class="input-area"
|
||||
type="password"
|
||||
@@ -59,9 +64,19 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span class="input-label">{{ $t('engine.modelPath') }}</span>
|
||||
<a-popover>
|
||||
<template #content>
|
||||
<p class="label-hover-info">{{ $t('engine.modelPathInfo') }}</p>
|
||||
</template>
|
||||
<span class="input-label info-label">{{ $t('engine.modelPath') }}</span>
|
||||
</a-popover>
|
||||
<span
|
||||
class="input-folder"
|
||||
@click="selectFolderPath"
|
||||
><span><FolderOpenOutlined /></span></span>
|
||||
<a-input
|
||||
class="input-area"
|
||||
style="width:calc(100% - 140px);"
|
||||
v-model:value="currentModelPath"
|
||||
/>
|
||||
</div>
|
||||
@@ -106,7 +121,7 @@ import { storeToRefs } from 'pinia'
|
||||
import { useGeneralSettingStore } from '@renderer/stores/generalSetting'
|
||||
import { useEngineControlStore } from '@renderer/stores/engineControl'
|
||||
import { notification } from 'ant-design-vue'
|
||||
import { InfoCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { FolderOpenOutlined ,InfoCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
@@ -168,6 +183,13 @@ function cancelChange(){
|
||||
currentCustomizedCommand.value = engineControl.customizedCommand
|
||||
}
|
||||
|
||||
function selectFolderPath() {
|
||||
window.electron.ipcRenderer.invoke('control.folder.select').then((folderPath) => {
|
||||
if(!folderPath) return
|
||||
currentModelPath.value = folderPath
|
||||
})
|
||||
}
|
||||
|
||||
watch(changeSignal, (val) => {
|
||||
if(val == true) {
|
||||
cancelChange();
|
||||
@@ -190,6 +212,35 @@ watch(currentEngine, (val) => {
|
||||
<style scoped>
|
||||
@import url(../assets/input.css);
|
||||
|
||||
.label-hover-info {
|
||||
margin-top: 10px;
|
||||
max-width: min(36vw, 380px);
|
||||
}
|
||||
|
||||
.info-label {
|
||||
color: #1677ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.input-folder {
|
||||
display:inline-block;
|
||||
width: 40px;
|
||||
font-size:1.38em;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s;
|
||||
}
|
||||
|
||||
.input-folder>span {
|
||||
padding: 0 4px;
|
||||
border: 2px solid #1677ff;
|
||||
color: #1677ff;
|
||||
border-radius: 30%;
|
||||
}
|
||||
|
||||
.input-folder:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.customize-note {
|
||||
padding: 10px 10px 0;
|
||||
color: red;
|
||||
|
||||
@@ -106,6 +106,11 @@ function openCaptionWindow() {
|
||||
}
|
||||
|
||||
function startEngine() {
|
||||
console.log(`@@${engineControl.modelPath}##`)
|
||||
if(engineControl.modelPath.trim() === '') {
|
||||
engineControl.emptyModelPathErr()
|
||||
return
|
||||
}
|
||||
window.electron.ipcRenderer.send('control.engine.start')
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ export default {
|
||||
"custom": "Type: Custom engine, engine path: ",
|
||||
"args": ", command arguments: ",
|
||||
"pidInfo": ", caption engine process PID: ",
|
||||
"empty": "Model Path is Empty",
|
||||
"emptyInfo": "The Vosk model path is empty. Please set the Vosk model path in the additional settings of the subtitle engine settings.",
|
||||
"stopped": "Caption Engine Stopped",
|
||||
"stoppedInfo": "The caption engine has stopped. You can click the 'Start Caption Engine' button to restart it.",
|
||||
"error": "An error occurred",
|
||||
@@ -48,6 +50,9 @@ export default {
|
||||
"enableTranslation": "Translation",
|
||||
"showMore": "More Settings",
|
||||
"apikey": "API KEY",
|
||||
"modelPath": "Model Path",
|
||||
"apikeyInfo": "API KEY required for the Gummy subtitle engine, which needs to be obtained from the Alibaba Cloud Bailing platform. For more details, see the project user manual.",
|
||||
"modelPathInfo": "The folder path of the model required by the Vosk subtitle engine. You need to download the required model to your local machine in advance. For more details, see the project user manual.",
|
||||
"customEngine": "Custom Engine",
|
||||
custom: {
|
||||
"title": "Custom Caption Engine",
|
||||
|
||||
@@ -17,6 +17,8 @@ export default {
|
||||
"custom": "タイプ:カスタムエンジン、エンジンパス:",
|
||||
"args": "、コマンド引数:",
|
||||
"pidInfo": "、字幕エンジンプロセス PID:",
|
||||
"empty": "モデルパスが空です",
|
||||
"emptyInfo": "Vosk モデルのパスが空です。字幕エンジン設定の追加設定で Vosk モデルのパスを設定してください。",
|
||||
"stopped": "字幕エンジンが停止しました",
|
||||
"stoppedInfo": "字幕エンジンが停止しました。再起動するには「字幕エンジンを開始」ボタンをクリックしてください。",
|
||||
"error": "エラーが発生しました",
|
||||
@@ -48,6 +50,9 @@ export default {
|
||||
"enableTranslation": "翻訳",
|
||||
"showMore": "詳細設定",
|
||||
"apikey": "API KEY",
|
||||
"modelPath": "モデルパス",
|
||||
"apikeyInfo": "Gummy 字幕エンジンに必要な API KEY は、アリババクラウド百煉プラットフォームから取得する必要があります。詳細情報はプロジェクトのユーザーマニュアルをご覧ください。",
|
||||
"modelPathInfo": "Vosk 字幕エンジンに必要なモデルのフォルダパスです。必要なモデルを事前にローカルマシンにダウンロードする必要があります。詳細情報はプロジェクトのユーザーマニュアルをご覧ください。",
|
||||
"customEngine": "カスタムエンジン",
|
||||
custom: {
|
||||
"title": "カスタムキャプションエンジン",
|
||||
|
||||
@@ -17,6 +17,8 @@ export default {
|
||||
"custom": "类型:自定义引擎,引擎路径:",
|
||||
"args": ",命令参数:",
|
||||
"pidInfo": ",字幕引擎进程 PID:",
|
||||
"empty": "模型路径为空",
|
||||
"emptyInfo": "Vosk 模型模型路径为空,请在字幕引擎设置的更多设置中设置 Vosk 模型的路径。",
|
||||
"stopped": "字幕引擎停止",
|
||||
"stoppedInfo": "字幕引擎已经停止,可点击“启动字幕引擎”按钮重新启动",
|
||||
"error": "发生错误",
|
||||
@@ -49,6 +51,8 @@ export default {
|
||||
"showMore": "更多设置",
|
||||
"apikey": "API KEY",
|
||||
"modelPath": "模型路径",
|
||||
"apikeyInfo": "Gummy 字幕引擎需要的 API KEY,需要在阿里云百炼平台获取。详细信息见项目用户手册。",
|
||||
"modelPathInfo": "Vosk 字幕引擎需要的模型的文件夹路径,需要提前下载需要的模型到本地。信息详情见项目用户手册。",
|
||||
"customEngine": "自定义引擎",
|
||||
custom: {
|
||||
"title": "自定义字幕引擎",
|
||||
|
||||
@@ -62,6 +62,13 @@ export const useEngineControlStore = defineStore('engineControl', () => {
|
||||
changeSignal.value = true
|
||||
}
|
||||
|
||||
function emptyModelPathErr() {
|
||||
notification.open({
|
||||
message: t('noti.empty'),
|
||||
description: t('noti.emptyInfo')
|
||||
});
|
||||
}
|
||||
|
||||
window.electron.ipcRenderer.on('control.controls.set', (_, controls: Controls) => {
|
||||
setControls(controls)
|
||||
})
|
||||
@@ -120,6 +127,7 @@ export const useEngineControlStore = defineStore('engineControl', () => {
|
||||
customizedCommand, // 自定义字幕引擎的命令
|
||||
setControls, // 设置引擎配置
|
||||
sendControlsChange, // 发送最新控制消息到后端
|
||||
emptyModelPathErr, // 模型路径为空时显示警告
|
||||
changeSignal, // 配置改变信号
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user