diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image1.png b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image1.png new file mode 100644 index 0000000..9b55957 Binary files /dev/null and b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image1.png differ diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image10.png b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image10.png new file mode 100644 index 0000000..9db5dc2 Binary files /dev/null and b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image10.png differ diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image2.png b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image2.png new file mode 100644 index 0000000..5e4a61c Binary files /dev/null and b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image2.png differ diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image3.png b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image3.png new file mode 100644 index 0000000..ffd595d Binary files /dev/null and b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image3.png differ diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image4.png b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image4.png new file mode 100644 index 0000000..b55e482 Binary files /dev/null and b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image4.png differ diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image5.png b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image5.png new file mode 100644 index 0000000..a474f78 Binary files /dev/null and b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image5.png differ diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image6.png b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image6.png new file mode 100644 index 0000000..803700e Binary files /dev/null and b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image6.png differ diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image7.png b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image7.png new file mode 100644 index 0000000..6e5a56e Binary files /dev/null and b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image7.png differ diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image8.png b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image8.png new file mode 100644 index 0000000..80f0859 Binary files /dev/null and b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image8.png differ diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image9.png b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image9.png new file mode 100644 index 0000000..cebf119 Binary files /dev/null and b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/images/image9.png differ diff --git a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/index.md b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/index.md index 2a01c22..9007f0a 100644 --- a/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/index.md +++ b/docs/zh-cn/stage-3/cross-platform/3.10-electron-voice-to-text/index.md @@ -20,6 +20,8 @@ Electron 是一个开源框架,它让你可以用 **HTML + CSS + JavaScript** **一句话理解**:Electron = 一个"隐形的 Chrome 浏览器" + Node.js 的系统能力。 +![placeholder: 一张示意图,展示 Electron 的架构:Chromium(负责 UI 渲染)+ Node.js(负责系统访问)= 桌面应用](images/image1.png) + ## 1.2 Electron 的核心架构 @@ -47,6 +49,7 @@ Electron 应用由两种进程组成,理解它们是开发的关键: 它们之间通过 **IPC(进程间通信)** 来传递消息,就像打电话一样:渲染进程说"我要录音",主进程收到后去调用系统麦克风。 +![placeholder: 一张 Electron 进程架构图,展示 Main Process、Renderer Process、Preload Script 之间的关系和 IPC 通信](images/image2.png) ## 1.3 我们要做什么? @@ -69,6 +72,7 @@ Electron 应用由两种进程组成,理解它们是开发的关键: | 模型体积 | 无需下载 | tiny 模型 75MB,large 模型 3GB | | 适合场景 | 快速上手、轻量使用 | 注重隐私、离线使用、长期高频使用 | +![placeholder: 一张应用效果预览图,展示语音转文字应用的 UI:顶部有录音按钮和波形动画,下方是识别出的文字,右上角有模式切换开关](images/image3.png) ## 1.4 重要提醒:Web Speech API 在 Electron 中不可用 @@ -96,12 +100,10 @@ Google 已经关闭了对非 Chrome/Edge 浏览器壳的语音 API 支持。Elec 打开你的 AI 编程助手,在对话框中输入以下 Prompt: ``` -请帮我使用 Electron Forge 创建一个新的 Electron 项目,使用 Vite 模板。 -项目名叫 voice-to-text。 -请执行:npx create-electron-app voice-to-text --template=vite -创建完成后进入项目目录并安装依赖。 +帮我用 Electron Forge 创建一个新的 Electron 项目,项目名称叫 voice-to-text,使用 Vite 模板。命令参考:npx create-electron-app voice-to-text --template=vite创建完后进入项目目录,安装依赖并帮我把基础环境搭好。 ``` + Electron Forge 是 Electron 官方推荐的脚手架工具,它帮你处理了项目初始化、打包、分发等繁琐的事情。 创建完成后,项目结构大致如下: @@ -125,11 +127,12 @@ voice-to-text/ 让 AI 帮你启动开发服务器: ``` -请帮我启动 Electron 开发服务器,执行 npm start +帮我把 voice-to-text 项目的 Electron 开发服务器启动,用 npm start 启动 ``` 几秒钟后,一个桌面窗口会弹出来——这就是你的 Electron 应用!虽然现在只有一个默认的欢迎页面,但它已经是一个真正的桌面程序了。 +![placeholder: Electron 应用首次启动的截图,展示默认的欢迎页面窗口](images/image4.png) ## 2.3 理解进程间通信(IPC) @@ -141,12 +144,12 @@ voice-to-text/ ``` 渲染进程(UI) 主进程(系统) │ │ - │── "我要开始录音" ──────────→ │ + │── "我要开始录音" ──────────→ │ │ │── 调用麦克风 │ │── 处理音频 - │ ←──── "这是识别结果" ────────│ + │ ←──── "这是识别结果" ────────│ │ │ - │── 显示文字到界面 │ + │── 显示文字到界面 │ ``` 在代码中,这个通信通过 `preload.js` 来桥接: @@ -174,6 +177,7 @@ ipcMain.handle('transcribe-audio', async (event, audioData) => { }) ``` +![placeholder: 一张 IPC 通信流程图,展示 Renderer → Preload → Main 的消息传递过程](images/image5.png) # 第 3 章:实现录音功能 @@ -183,21 +187,19 @@ ipcMain.handle('transcribe-audio', async (event, audioData) => { 浏览器(也就是 Electron 的渲染进程)提供了 `navigator.mediaDevices.getUserMedia` API 来访问麦克风。让 AI 帮你实现录音功能: ``` -请帮我修改 src/index.html 和 src/renderer.js,实现以下功能: - +麻烦帮我修改一下项目里的 src/index.html 和 src/renderer.js 这两个文件,帮我实现完整的语音录制 + 语音识别功能,具体要求我整理好了: 界面设计: -1. 一个大的圆形 "开始录音" 按钮,点击后变成红色的 "停止录音" -2. 录音时显示一个简单的脉冲动画,表示正在录音 -3. 下方有一个文字显示区域,用于展示识别结果 -4. 底部有 "复制文字" 和 "清空" 两个按钮 -5. 右上角有一个设置图标,点击可以切换识别模式(云端/本地) - -录音逻辑(在 renderer.js 中): -1. 点击按钮后,使用 navigator.mediaDevices.getUserMedia 获取麦克风权限 -2. 使用 MediaRecorder 录制音频,格式为 webm -3. 停止录音后,将音频 Blob 转为 ArrayBuffer -4. 通过 window.electronAPI.sendAudio 发送给主进程 -5. 等待主进程返回识别结果并显示 +1. 做一个大尺寸的圆形按钮,默认显示“开始录音”;点击后按钮变成红色,文字切换成“停止录音” +2. 录音过程中,按钮要带一个简单的脉冲动画,让用户能直观看到正在录音 +3. 按钮下方放一块文字展示区,用来显示语音识别出来的文本内容 +4. 页面底部配置 “复制文字” 和 “清空” 两个功能按钮,分别实现识别结果复制、结果区域清空的功能 +5. 页面右上角增加设置图标,点击可切换识别模式(云端识别 / 本地识别) +录音逻辑要求(需要在 renderer.js 中实现) +1. 点击录音按钮后,调用 navigator.mediaDevices.getUserMedia 获取麦克风权限 +2. 用 MediaRecorder 实现音频录制,录制格式固定为 webm +3. 停止录音后,把录制好的音频 Blob 对象转成 ArrayBuffer 格式 +4. 调用 window.electronAPI.sendAudio 方法,把音频数据发送给主进程 +5. 还需要监听主进程返回的识别结果,并将结果展示在文字显示区域中 ``` 核心录音代码: @@ -236,7 +238,7 @@ async function startRecording() { mediaRecorder.start() } ``` - +![placeholder: 应用录音界面的截图,展示录音按钮(录音中状态,红色脉冲动画)和下方的文字显示区域](images/image6.png) ## 3.2 处理麦克风权限 @@ -245,9 +247,9 @@ Electron 默认会拦截权限请求。我们需要在主进程中明确允许 ``` 请帮我在 main.js 中添加麦克风权限处理: -1. 使用 session.defaultSession.setPermissionRequestHandler 处理权限请求 -2. 当请求类型为 'media' 时,自动允许 -3. 对于 macOS,确保在 package.json 或 entitlements 中声明了麦克风使用说明 +1. 用 session.defaultSession.setPermissionRequestHandler 来处理权限请求 +2. 当请求类型是 media 麦克风权限时,直接自动允许 +3. 如果是 macOS 系统,记得在 package.json 或者 entitlements 里加上麦克风使用说明,保证权限能正常生效 ``` ```javascript @@ -285,12 +287,12 @@ session.defaultSession.setPermissionRequestHandler( ``` 请帮我在 main.js 中实现 OpenAI Whisper API 的调用: -1. 安装 node-fetch(如果需要)或使用 Node.js 内置的 fetch -2. 创建 transcribeWithWhisper 函数,接收音频 ArrayBuffer -3. 将 ArrayBuffer 转为 Blob/File,构建 FormData +1. 安装 node-fetch(如果项目需要),或者直接用 Node.js 自带的 fetch +2. 写一个 transcribeWithWhisper 函数,参数传入音频的 ArrayBuffer +3. 把传入的 ArrayBuffer 转换成 Blob 或 File,然后组装成 FormData 格式 4. 调用 https://api.openai.com/v1/audio/transcriptions -5. 模型使用 whisper-1,语言设为 zh(中文) -6. 返回识别出的文字 +5. 模型指定用 whisper-1,语言设置为中文 zh +6. 接口调用完成后,返回识别出来的文本内容 7. API Key 从环境变量或配置文件读取 ``` @@ -318,7 +320,7 @@ async function transcribeWithWhisper(audioBuffer, apiKey) { return data.text } ``` - +![placeholder: 应用运行截图,展示用户说了一段中文后,Whisper API 返回的识别结果](images/image7.png) ## 4.3 添加设置界面 @@ -327,15 +329,12 @@ async function transcribeWithWhisper(audioBuffer, apiKey) { ``` 请帮我在 index.html 中添加一个设置面板: -1. 右上角有一个齿轮图标,点击展开设置面板 -2. 设置面板包含: - - 识别模式切换(云端 API / 本地模型) - - API Key 输入框(仅云端模式显示) - - 语言选择下拉框(中文/英文/自动检测) -3. 设置保存到 localStorage -4. 面板可以点击外部区域关闭 +1. 页面右上角加一个齿轮样式的设置图标,点击后弹出设置面板 +2. 面板里要包含这几项:识别模式切换(云端 API / 本地模型)、API Key 输入框(只有云端模式下才显示)、语言选择下拉菜单(中文、英文、自动检测可选) +3. 所有设置内容自动保存到 localStorage +4. 点击面板外面的区域就能关闭面板 ``` - +![placeholder: 设置面板展开的截图,展示模式切换开关和 API Key 输入框](images/image8.png) # 第 5 章:方案 B——本地识别(whisper.cpp) @@ -351,7 +350,7 @@ async function transcribeWithWhisper(audioBuffer, apiKey) { npm install nodejs-whisper 安装完成后,请帮我下载 whisper 的 tiny 模型(用于测试,体积小速度快)。 -nodejs-whisper 会自动处理模型下载。 +nodejs-whisper 本身会自动完成模型下载,不用额外处理。 ``` > **模型选择指南**: @@ -366,13 +365,8 @@ nodejs-whisper 会自动处理模型下载。 让 AI 帮你实现本地识别功能: ``` -请帮我在 main.js 中添加 whisper.cpp 本地识别功能: -1. 引入 nodejs-whisper -2. 创建 transcribeWithLocal 函数 -3. 接收音频 ArrayBuffer,先保存为临时 WAV 文件(16kHz 单声道) -4. 调用 nodejs-whisper 进行识别 -5. 返回识别文字 -6. 识别完成后删除临时文件 +请帮我在main.js里添加 whisper.cpp 本地语音识别功能: +先引入 nodejs-whisper 包,然后写一个 transcribeWithLocal 函数。函数接收音频 ArrayBuffer,先把它保存成临时的 WAV 文件(要求 16kHz、单声道),再调用 nodejs-whisper 做识别,识别完成后返回文字结果,最后把临时文件删掉就行 ``` 核心代码: @@ -405,7 +399,7 @@ async function transcribeWithLocal(audioBuffer) { } } ``` - +![placeholder: 本地模型识别的运行截图,展示离线状态下依然能正常识别中文语音](images/image9.png) ## 5.3 Apple Silicon 用户的福音 @@ -423,7 +417,7 @@ async function transcribeWithLocal(audioBuffer) { Electron Forge 已经内置在我们的项目中,打包非常简单: ``` -请帮我执行 Electron Forge 的打包命令: +麻烦帮我运行一下 Electron Forge 的打包命令,执行以下指令就行: npx electron-forge make ``` @@ -434,7 +428,7 @@ npx electron-forge make * **Linux**:生成 `.deb`(Debian/Ubuntu)和 `.rpm`(Fedora)包 打包产物在 `out/make/` 目录下。 - +![placeholder: out/make 目录的文件列表截图,展示生成的 .dmg 或 .exe 安装包](images/image10.png) ## 6.2 应用体积优化