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 @@