mirror of
https://github.com/HiMeditator/auto-caption.git
synced 2026-02-04 04:14:42 +08:00
feat(engine): 添加字幕引擎资源消耗监控功能
- 在控制窗口添加引擎状态显示,包括 PID、PPID、CPU 使用率、内存使用量和运行时间 - 优化字幕记录导出和复制功能,支持选择导出内容类型
This commit is contained in:
@@ -14,10 +14,11 @@
|
||||
- [x] 字幕窗口右上角图标改为竖向排布 *2025/07/14*
|
||||
- [x] 可以调整字幕时间轴 *2025/07/14*
|
||||
- [x] 可以导出 srt 格式的字幕记录 *2025/07/14*
|
||||
- [x] 可以获取字幕引擎的系统资源消耗情况 *2025/07/15*
|
||||
|
||||
## 待完成
|
||||
|
||||
- [ ] 可以获取字幕引擎的系统资源消耗情况
|
||||
- [ ] 探索更多的语音转文字模型
|
||||
|
||||
## 后续计划
|
||||
|
||||
|
||||
@@ -57,6 +57,19 @@
|
||||
- 发送:无数据
|
||||
- 接收:`string`
|
||||
|
||||
### `control.engine.info`
|
||||
|
||||
**介绍:** 获取字幕引擎的资源消耗情况
|
||||
|
||||
**发起方:** 前端控制窗口
|
||||
|
||||
**接收方:** 后端控制窗口实例
|
||||
|
||||
**数据类型:**
|
||||
|
||||
- 发送:无数据
|
||||
- 接收:`EngineInfo`
|
||||
|
||||
## 前端 ==> 后端
|
||||
|
||||
### `control.uiLanguage.change`
|
||||
|
||||
14
package-lock.json
generated
14
package-lock.json
generated
@@ -12,6 +12,7 @@
|
||||
"@electron-toolkit/preload": "^3.0.1",
|
||||
"@electron-toolkit/utils": "^4.0.0",
|
||||
"ant-design-vue": "^4.2.6",
|
||||
"pidusage": "^4.0.1",
|
||||
"pinia": "^3.0.2",
|
||||
"vue-i18n": "^11.1.9",
|
||||
"vue-router": "^4.5.1"
|
||||
@@ -7742,6 +7743,18 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pidusage": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pidusage/-/pidusage-4.0.1.tgz",
|
||||
"integrity": "sha512-yCH2dtLHfEBnzlHUJymR/Z1nN2ePG3m392Mv8TFlTP1B0xkpMQNHAnfkY0n2tAi6ceKO6YWhxYfZ96V4vVkh/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/pinia": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/pinia/-/pinia-3.0.2.tgz",
|
||||
@@ -8292,7 +8305,6 @@
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"@electron-toolkit/preload": "^3.0.1",
|
||||
"@electron-toolkit/utils": "^4.0.0",
|
||||
"ant-design-vue": "^4.2.6",
|
||||
"pidusage": "^4.0.1",
|
||||
"pinia": "^3.0.2",
|
||||
"vue-i18n": "^11.1.9",
|
||||
"vue-router": "^4.5.1"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { shell, BrowserWindow, ipcMain, nativeTheme, dialog } from 'electron'
|
||||
import path from 'path'
|
||||
import { EngineInfo } from './types'
|
||||
import pidusage from 'pidusage'
|
||||
import { is } from '@electron-toolkit/utils'
|
||||
import icon from '../../build/icon.png?asset'
|
||||
import { captionWindow } from './CaptionWindow'
|
||||
@@ -81,6 +83,20 @@ class ControlWindow {
|
||||
return result.filePaths[0];
|
||||
})
|
||||
|
||||
ipcMain.handle('control.engine.info', async () => {
|
||||
const info: EngineInfo = {
|
||||
pid: 0, ppid: 0, cpu: 0, mem: 0, elapsed: 0
|
||||
}
|
||||
if(captionEngine.processStatus !== 'running') return info
|
||||
const stats = await pidusage(captionEngine.process.pid)
|
||||
info.pid = stats.pid
|
||||
info.ppid = stats.ppid
|
||||
info.cpu = stats.cpu
|
||||
info.mem = stats.memory
|
||||
info.elapsed = stats.elapsed
|
||||
return info
|
||||
})
|
||||
|
||||
ipcMain.on('control.uiLanguage.change', (_, args) => {
|
||||
allConfig.uiLanguage = args
|
||||
if(captionWindow.window){
|
||||
|
||||
@@ -54,3 +54,11 @@ export interface FullConfig {
|
||||
controls: Controls,
|
||||
captionLog: CaptionItem[]
|
||||
}
|
||||
|
||||
export interface EngineInfo {
|
||||
pid: number,
|
||||
ppid: number,
|
||||
cpu: number,
|
||||
mem: number,
|
||||
elapsed: number
|
||||
}
|
||||
@@ -59,6 +59,14 @@
|
||||
<a-radio-button value="json">.json</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span class="input-label">{{ $t('log.exportContent') }}</span>
|
||||
<a-radio-group v-model:value="contentOption">
|
||||
<a-radio-button value="both">{{ $t('log.both') }}</a-radio-button>
|
||||
<a-radio-button value="source">{{ $t('log.source') }}</a-radio-button>
|
||||
<a-radio-button value="target">{{ $t('log.translation') }}</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
<a-button
|
||||
style="margin-right: 20px;"
|
||||
@@ -76,7 +84,7 @@
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span class="input-label">{{ $t('log.copyContent') }}</span>
|
||||
<a-radio-group v-model:value="copyOption">
|
||||
<a-radio-group v-model:value="contentOption">
|
||||
<a-radio-button value="both">{{ $t('log.both') }}</a-radio-button>
|
||||
<a-radio-button value="source">{{ $t('log.source') }}</a-radio-button>
|
||||
<a-radio-button value="target">{{ $t('log.translation') }}</a-radio-button>
|
||||
@@ -86,7 +94,6 @@
|
||||
<a-button
|
||||
style="margin-right: 20px;"
|
||||
@click="copyCaptions"
|
||||
:disabled="captionData.length === 0"
|
||||
>{{ $t('log.copy') }}</a-button>
|
||||
</a-popover>
|
||||
<a-button
|
||||
@@ -138,7 +145,7 @@ const { captionData } = storeToRefs(captionLog)
|
||||
const exportFormat = ref('srt')
|
||||
const showIndex = ref(true)
|
||||
const copyTime = ref(true)
|
||||
const copyOption = ref('both')
|
||||
const contentOption = ref('both')
|
||||
|
||||
const baseHH = ref<number>(0)
|
||||
const baseMM = ref<number>(0)
|
||||
@@ -228,7 +235,9 @@ function getExportData() {
|
||||
const item = captionData.value[i]
|
||||
content += `${i+1}\n`
|
||||
content += `${item.time_s} --> ${item.time_t}\n`.replace(/\./g, ',')
|
||||
content += `${item.text}\n${item.translation}\n\n`
|
||||
if(contentOption.value === 'both') content += `${item.text}\n${item.translation}\n\n`
|
||||
else if(contentOption.value === 'source') content += `${item.text}\n\n`
|
||||
else content += `${item.translation}\n\n`
|
||||
}
|
||||
return content
|
||||
}
|
||||
@@ -239,8 +248,8 @@ function copyCaptions() {
|
||||
const item = captionData.value[i]
|
||||
if(showIndex.value) content += `${i+1}\n`
|
||||
if(copyTime.value) content += `${item.time_s} --> ${item.time_t}\n`.replace(/\./g, ',')
|
||||
if(copyOption.value === 'both') content += `${item.text}\n${item.translation}\n\n`
|
||||
else if(copyOption.value === 'source') content += `${item.text}\n\n`
|
||||
if(contentOption.value === 'both') content += `${item.text}\n${item.translation}\n\n`
|
||||
else if(contentOption.value === 'source') content += `${item.text}\n\n`
|
||||
else content += `${item.translation}\n\n`
|
||||
}
|
||||
navigator.clipboard.writeText(content)
|
||||
|
||||
@@ -7,12 +7,38 @@
|
||||
:value="(customized && customizedApp)?$t('status.customized'):engine"
|
||||
/>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-statistic
|
||||
:title="$t('status.status')"
|
||||
:value="engineEnabled?$t('status.started'):$t('status.stopped')"
|
||||
/>
|
||||
</a-col>
|
||||
<a-popover :title="$t('status.engineStatus')">
|
||||
<template #content>
|
||||
<a-row class="engine-status">
|
||||
<a-col :flex="1" :title="$t('status.pid')" style="cursor:pointer;">
|
||||
<div class="engine-status-title">pid</div>
|
||||
<div>{{ pid }}</div>
|
||||
</a-col>
|
||||
<a-col :flex="1" :title="$t('status.ppid')" style="cursor:pointer;">
|
||||
<div class="engine-status-title">ppid</div>
|
||||
<div>{{ ppid }}</div>
|
||||
</a-col>
|
||||
<a-col :flex="1" :title="$t('status.cpu')" style="cursor:pointer;">
|
||||
<div class="engine-status-title">cpu</div>
|
||||
<div>{{ cpu.toFixed(1) }}%</div>
|
||||
</a-col>
|
||||
<a-col :flex="1" :title="$t('status.mem')" style="cursor:pointer;">
|
||||
<div class="engine-status-title">mem</div>
|
||||
<div>{{ (mem/1024/1024).toFixed(2) }}MB</div>
|
||||
</a-col>
|
||||
<a-col :flex="1" :title="$t('status.elapsed')" style="cursor:pointer;">
|
||||
<div class="engine-status-title">elapsed</div>
|
||||
<div>{{ (elapsed/1000).toFixed(0) }}s</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
<a-col :span="6" @mouseenter="getEngineInfo" style="cursor: pointer;">
|
||||
<a-statistic
|
||||
:title="$t('status.status')"
|
||||
:value="engineEnabled?$t('status.started'):$t('status.stopped')"
|
||||
/>
|
||||
</a-col>
|
||||
</a-popover>
|
||||
<a-col :span="6">
|
||||
<a-statistic :title="$t('status.logNumber')" :value="captionData.length" />
|
||||
</a-col>
|
||||
@@ -88,6 +114,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { EngineInfo } from '@renderer/types'
|
||||
import { ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useCaptionLogStore } from '@renderer/stores/captionLog'
|
||||
@@ -101,6 +128,12 @@ const { captionData } = storeToRefs(captionLog)
|
||||
const engineControl = useEngineControlStore()
|
||||
const { engineEnabled, engine, customized, customizedApp } = storeToRefs(engineControl)
|
||||
|
||||
const pid = ref(0)
|
||||
const ppid = ref(0)
|
||||
const cpu = ref(0)
|
||||
const mem = ref(0)
|
||||
const elapsed = ref(0)
|
||||
|
||||
function openCaptionWindow() {
|
||||
window.electron.ipcRenderer.send('control.captionWindow.activate')
|
||||
}
|
||||
@@ -116,9 +149,32 @@ function startEngine() {
|
||||
function stopEngine() {
|
||||
window.electron.ipcRenderer.send('control.engine.stop')
|
||||
}
|
||||
|
||||
function getEngineInfo() {
|
||||
window.electron.ipcRenderer.invoke('control.engine.info').then((data: EngineInfo) => {
|
||||
pid.value = data.pid
|
||||
ppid.value = data.ppid
|
||||
cpu.value = data.cpu
|
||||
mem.value = data.mem
|
||||
elapsed.value = data.elapsed
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.engine-status {
|
||||
width: max(420px, 36vw);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.engine-status-title {
|
||||
font-size: 12px;
|
||||
color: var(--tag-color);
|
||||
}
|
||||
|
||||
.about-tag {
|
||||
color: var(--tag-color);
|
||||
margin-bottom: 16px;
|
||||
|
||||
@@ -91,6 +91,12 @@ export default {
|
||||
},
|
||||
status: {
|
||||
"engine": "Caption Engine",
|
||||
"engineStatus": "Caption Engine Status",
|
||||
"pid": "Process ID",
|
||||
"ppid": "Parent Process ID",
|
||||
"cpu": "CPU Usage",
|
||||
"mem": "Memory Usage",
|
||||
"elapsed": "Running Time",
|
||||
"customized": "Customized",
|
||||
"status": "Engine Status",
|
||||
"started": "Started",
|
||||
@@ -115,24 +121,25 @@ export default {
|
||||
},
|
||||
log: {
|
||||
"title": "Caption Log",
|
||||
"changeTime": "Modify Caption Time",
|
||||
"changeTime": "Modify Time",
|
||||
"baseTime": "First Caption Start Time",
|
||||
"hour": "Hour",
|
||||
"min": "Minute",
|
||||
"sec": "Second",
|
||||
"ms": "Millisecond",
|
||||
"export": "Export Caption Log",
|
||||
"copy": "Copy to Clipboard",
|
||||
"export": "Export Log",
|
||||
"copy": "Copy Log",
|
||||
"exportOptions": "Export Options",
|
||||
"exportFormat": "Format",
|
||||
"exportContent": "Content",
|
||||
"copyOptions": "Copy Options",
|
||||
"addIndex": "Add Index",
|
||||
"copyTime": "Copy Time",
|
||||
"copyContent": "Content",
|
||||
"both": "Original and Translation",
|
||||
"source": "Original Only",
|
||||
"translation": "Translation Only",
|
||||
"both": "Both",
|
||||
"source": "Original",
|
||||
"translation": "Translation",
|
||||
"copySuccess": "Subtitle copied to clipboard",
|
||||
"clear": "Clear Caption Log"
|
||||
"clear": "Clear Log"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,12 @@ export default {
|
||||
},
|
||||
status: {
|
||||
"engine": "字幕エンジン",
|
||||
"engineStatus": "字幕エンジンの状態",
|
||||
"pid": "プロセス ID",
|
||||
"ppid": "親プロセス ID",
|
||||
"cpu": "CPU 使用率",
|
||||
"mem": "メモリ使用量",
|
||||
"elapsed": "稼働時間",
|
||||
"customized": "カスタマイズ済み",
|
||||
"status": "エンジン状態",
|
||||
"started": "開始済み",
|
||||
@@ -115,24 +121,25 @@ export default {
|
||||
},
|
||||
log: {
|
||||
"title": "字幕ログ",
|
||||
"changeTime": "字幕時間を変更",
|
||||
"changeTime": "時間を変更",
|
||||
"baseTime": "最初の字幕開始時間",
|
||||
"hour": "時",
|
||||
"min": "分",
|
||||
"sec": "秒",
|
||||
"ms": "ミリ秒",
|
||||
"export": "エクスポート",
|
||||
"copy": "クリップボードにコピー",
|
||||
"copy": "ログをコピー",
|
||||
"exportOptions": "エクスポートオプション",
|
||||
"exportFormat": "形式",
|
||||
"exportContent": "内容",
|
||||
"copyOptions": "コピー設定",
|
||||
"addIndex": "順序番号",
|
||||
"copyTime": "時間",
|
||||
"copyContent": "内容",
|
||||
"both": "原文と翻訳",
|
||||
"source": "原文のみ",
|
||||
"translation": "翻訳のみ",
|
||||
"both": "すべて",
|
||||
"source": "原文",
|
||||
"translation": "翻訳",
|
||||
"copySuccess": "字幕がクリップボードにコピーされました",
|
||||
"clear": "字幕ログをクリア"
|
||||
"clear": "ログをクリア"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,12 @@ export default {
|
||||
},
|
||||
status: {
|
||||
"engine": "字幕引擎",
|
||||
"engineStatus": "字幕引擎状态",
|
||||
"pid": "进程ID",
|
||||
"ppid": "父进程ID",
|
||||
"cpu": "CPU使用率",
|
||||
"mem": "内存使用量",
|
||||
"elapsed": "运行时间",
|
||||
"customized": "自定义",
|
||||
"status": "引擎状态",
|
||||
"started": "已启动",
|
||||
@@ -115,24 +121,25 @@ export default {
|
||||
},
|
||||
log: {
|
||||
"title": "字幕记录",
|
||||
"changeTime": "修改字幕时间",
|
||||
"changeTime": "修改时间",
|
||||
"baseTime": "首条字幕起始时间",
|
||||
"hour": "时",
|
||||
"min": "分",
|
||||
"sec": "秒",
|
||||
"ms": "毫秒",
|
||||
"export": "导出字幕记录",
|
||||
"copy": "复制到剪贴板",
|
||||
"export": "导出字幕",
|
||||
"copy": "复制内容",
|
||||
"exportOptions": "导出选项",
|
||||
"exportFormat": "导出格式",
|
||||
"exportContent": "导出内容",
|
||||
"copyOptions": "复制选项",
|
||||
"addIndex": "添加序号",
|
||||
"copyTime": "复制时间",
|
||||
"copyContent": "复制内容",
|
||||
"both": "原文与翻译",
|
||||
"source": "仅原文",
|
||||
"translation": "仅翻译",
|
||||
"both": "全部",
|
||||
"source": "原文",
|
||||
"translation": "翻译",
|
||||
"copySuccess": "字幕已复制到剪贴板",
|
||||
"clear": "清空字幕记录"
|
||||
"clear": "清空记录"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,3 +54,11 @@ export interface FullConfig {
|
||||
controls: Controls,
|
||||
captionLog: CaptionItem[]
|
||||
}
|
||||
|
||||
export interface EngineInfo {
|
||||
pid: number,
|
||||
ppid: number,
|
||||
cpu: number,
|
||||
mem: number,
|
||||
elapsed: number
|
||||
}
|
||||
Reference in New Issue
Block a user