From 7030aaaae308c22b07a651e1db789db05d5a962e Mon Sep 17 00:00:00 2001 From: himeditator Date: Sat, 21 Jun 2025 20:35:49 +0800 Subject: [PATCH] =?UTF-8?q?feat=E5=8A=9F=E8=83=BD):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=AD=97=E5=B9=95=E5=BC=95=E6=93=8E=E5=B9=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AD=97=E5=B9=95=E8=AE=B0=E5=BD=95=E5=AF=BC=E5=87=BA=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 丰富了 README.md 文件,介绍了字幕引擎的原理和构建方法 - 更新了 .gitignore 文件,排除了 build 目录 - 移除了 python-prototype 和 python-subprocess 目录下的无用代码 - 添加了字幕记录导出功能,用户可以将字幕数据导出为 JSON 文件 - 调整了字幕控制面板,移除了未使用的 Whisper 引擎选项 --- .gitignore | 3 +- README.md | 15 ++++- python-prototype/webscoket.ipynb | 63 --------------------- python-subprocess/main.spec | 38 +++++++++++++ python-subprocess/wsconn.py | 61 -------------------- src/main/utils/engine.ts | 2 +- src/renderer/src/components/CaptionData.vue | 25 +++++++- src/renderer/src/stores/captionControl.ts | 12 +--- 8 files changed, 81 insertions(+), 138 deletions(-) delete mode 100644 python-prototype/webscoket.ipynb create mode 100644 python-subprocess/main.spec delete mode 100644 python-subprocess/wsconn.py diff --git a/.gitignore b/.gitignore index 3047754..4a5feda 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ out .eslintcache *.log* __pycache__ -subenv \ No newline at end of file +subenv +build \ No newline at end of file diff --git a/README.md b/README.md index f8c3206..2fee440 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,10 @@ ## ✨ 特性 -暂无 +- 丰富的字幕样式设置 +- 灵活的字幕引擎选择 +- 多语言识别与翻译 +- 字幕记录展示与导出 ## 🚀 项目运行 @@ -27,6 +30,14 @@ npm install ``` +### 构建字幕引擎 + +字幕引擎原理:所谓的字幕引擎实际上是一个子程序,它会实时获取系统音频输入(录音)或输出(播放声音)的流式数据,并调用音频转文字的模型生成对应音频的字幕。生成的字幕通过 IPC 输出为转换为字符串的 JSON 数据,并返回给主程序。主程序读取字幕数据,处理后显示在窗口上。 + +目前项目默认使用 [阿里云 Gummy 模型](https://help.aliyun.com/zh/model-studio/gummy-speech-recognition-translation/),需要有阿里云百炼平台的 API KEY 才能正常使用该模型。 + +gummy 字幕引擎是一个 python 子程序,可以选择配置好 python 环境后直接运行该程序,也可以使用 pyinstaller 构建一个可执行文件。 运行字幕引擎子程序的代码在 `src\main\utils\engine.ts` 文件中 + ### 运行项目 ```bash @@ -34,6 +45,8 @@ npm run dev ``` ### 构建项目 +注意目前软件没有适配 macOS 平台,请使用 Windows 或 Linux 系统进行构建。 + ```bash # For windows npm run build:win diff --git a/python-prototype/webscoket.ipynb b/python-prototype/webscoket.ipynb deleted file mode 100644 index 8189136..0000000 --- a/python-prototype/webscoket.ipynb +++ /dev/null @@ -1,63 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "4604aefd", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Received: {\"message\":\"Electron Initialized\"}\n", - "Client disconnected\n" - ] - } - ], - "source": [ - "import asyncio\n", - "import websockets\n", - "import nest_asyncio\n", - "import json\n", - "\n", - "# 应用补丁,允许在 Jupyter 中运行嵌套事件循环\n", - "nest_asyncio.apply()\n", - "\n", - "async def handle_client(websocket, path=\"/\"):\n", - " try:\n", - " async for message in websocket:\n", - " print(f\"Received: {message}\")\n", - " await websocket.send(json.dumps({\"message\": \"Hello from server!\"}))\n", - " except websockets.exceptions.ConnectionClosed:\n", - " print(\"Client disconnected\")\n", - "\n", - "start_server = websockets.serve(handle_client, \"localhost\", 8765)\n", - "\n", - "asyncio.get_event_loop().run_until_complete(start_server)\n", - "asyncio.get_event_loop().run_forever()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "mystd", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/python-subprocess/main.spec b/python-subprocess/main.spec new file mode 100644 index 0000000..2ba8dd9 --- /dev/null +++ b/python-subprocess/main.spec @@ -0,0 +1,38 @@ +# -*- mode: python ; coding: utf-8 -*- + + +a = Analysis( + ['main.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='main', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) diff --git a/python-subprocess/wsconn.py b/python-subprocess/wsconn.py deleted file mode 100644 index c96a669..0000000 --- a/python-subprocess/wsconn.py +++ /dev/null @@ -1,61 +0,0 @@ -import json -import websockets - -class WebSocketServer: - - def __init__(self): - self.server = None - self.websocket = None - - async def start(self, port=8765): - """启动 WebSocket 服务器""" - self.server = await websockets.serve(self.handle_client, "localhost", port) - print(f"INFO websocket server started on ws://localhost:{port}") - - async def stop(self): - """关闭 WebSocket 服务器""" - if self.server: - try: - if self.websocket: - await self.close() - self.server.close() - await self.server.wait_closed() - print("INFO server closed successfully") - except Exception as e: - print(f"ERROR failed to close server: {e}") - finally: - self.server = None - - async def handle_client(self, websocket, path="/"): - """处理客户端连接""" - try: - self.websocket = websocket - async for message in websocket: - print(f"INFO received: {message}") - except websockets.exceptions.ConnectionClosed: - print("INFO client disconnected") - self.websocket = None - - async def send(self, data): - """向连接的客户端发送数据""" - if self.websocket: - try: - await self.websocket.send(json.dumps(data)) - print(f"INFO sent: {data}") - return True - except websockets.exceptions.ConnectionClosed: - print("ERROR: Client disconnected while sending data") - self.websocket = None - return False - return False - - async def close(self): - """安全地断开WebSocket连接""" - if self.websocket: - try: - await self.websocket.close() - print("INFO connection closed successfully") - except Exception as e: - print(f"ERROR failed to close connection: {e}") - finally: - self.websocket = None \ No newline at end of file diff --git a/src/main/utils/engine.ts b/src/main/utils/engine.ts index 295a20d..2ac9aff 100644 --- a/src/main/utils/engine.ts +++ b/src/main/utils/engine.ts @@ -24,7 +24,7 @@ export class CaptionEngine { 'python-subprocess', 'main.py' )) this.command.push('-s', controls.sourceLang) - this.command.push('-t', controls.targetLang) + this.command.push('-t', controls.translation ? controls.targetLang : 'none') console.log(this.appPath) console.log(this.command) diff --git a/src/renderer/src/components/CaptionData.vue b/src/renderer/src/components/CaptionData.vue index 972cf4d..d40fcac 100644 --- a/src/renderer/src/components/CaptionData.vue +++ b/src/renderer/src/components/CaptionData.vue @@ -30,7 +30,16 @@
-
字幕记录
+
+ 字幕记录 + + 导出字幕记录 + +