Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions docs/02-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,26 @@

### 描述

用户在**任意应用**中,按下听写快捷键说话,松开后语音被转成文字、经**轻量文本整理模型去噪**(去语气词、修标点、保留改口后的最终意图),再注入到当前光标位置。这是 Typex 的主干路径,其他功能都是这条流水线的变体。
用户在**任意应用**中,按下听写快捷键说话,按所选触发方式结束录音后,语音被转成文字、经**轻量文本整理模型去噪**(去语气词、修标点、保留改口后的最终意图),再注入到当前光标位置。这是 Typex 的主干路径,其他功能都是这条流水线的变体。

> 为什么必须有「整理」这一级:用户口语天然杂乱(语气词、重复、中途改口),原样上屏并不可用。「STT 原始转写 → 轻量模型整理」两级流水线是本品类的核心价值,规格详见 F-9。

### 流水线

```
按键按下 ──▶ 开始录音(HUD 出现,波形反馈)
按键松开 ──▶ 停止录音 ──▶ [所选 VAD 裁剪静音] ──▶ STT Provider 转写
松开按键(按住说话)/ 再次按下(按下切换)──▶ 停止录音
──▶ [所选 VAD 裁剪静音] ──▶ STT Provider 转写
──▶ 文本整理(F-9,默认开启,可一键切「原样模式」)
──▶ 文本注入(光标处)──▶ HUD 成功反馈后隐藏
```

### 规格

- **触发方式**(详见 F-5):
- **长按说话(push-to-talk)**:按住 ≥ 350 ms 进入长按模式,松开即结束。这是主推交互。
- **短按切换(toggle)**:按一下开始,再按一下结束。两种模式同一个键自动区分,无需配置。
- **按住说话(hold)**:按下立即开始,松开立即结束。
- **按下切换(toggle)**:第一次按下立即开始,第二次按下立即结束;两次 keyup 都不参与状态切换,适配只发送瞬时按键事件的翻页器与第三方键盘。
- 两种方式在设置中显式二选一,并在录音开始时快照;不再按按住时长自动推断意图。
- `Esc` 或点击 HUD 取消按钮 = 放弃当前尚未提交的流程,不产生任何输出;覆盖录音、录音收尾、转写、处理、注入提交前与失败态。全局 `Esc` 仅在成功认领当前会话取消权时吞掉该次物理按键的 down、自动重复与配对 up;空闲、设置关闭或注入已经提交时完整透传。设置中可关闭全局 `Esc` 取消,但不影响回答弹窗自身的关闭行为。
- **录音**:16-bit PCM,按设备原生采样率采集后重采样为 16 kHz 单声道(见 [06 代码架构 §7.4](06-code-architecture.md))。录音期间 HUD 显示实时波形(麦克风是否在工作必须一眼可见)。
- **松键反馈**:录音结束后先发布 `Transcribing` 状态,再在阻塞工作线程中关闭音频流、重采样、执行 VAD 与 WAV 编码;快捷键结束到 HUD 切换为「正在转写」目标 ≤ 100 ms,音频收尾期间仍可响应取消,且取消后不得启动 STT。
Expand Down Expand Up @@ -141,7 +143,7 @@

**规格**:

- **呼出**:仅助手快捷键(按住 = push-to-talk;短按 = 切换式录音,再按结束——与听写键语义一致)。弹窗本身没有输入能力,不能主动打开空弹窗。
- **呼出**:仅助手快捷键,触发方式与听写键使用同一项全局设置(按住说话 / 按下切换)。弹窗本身没有输入能力,不能主动打开空弹窗。
- **弹窗内容**:顶部回显本次语音指令(有选区时附选区字数摘要),下方流式 Markdown 渲染回答,右上角 ✕ 关闭。无打字输入条、无麦克风键、无动作按钮(回答文本可直接选中复制)。
- **位置**:有选区 → 选区下方(放不下时上方);无选区 → 屏幕上 1/3 居中。
- **关闭**:✕ / `Esc` / 焦点切换到其他应用时自动关闭。回答仍在生成时,三种关闭方式都取消当前助手会话,迟到的流事件不得重新显示窗口或写入历史;回答已完成后关闭只隐藏窗口并保留成功历史。该行为不受全局「Esc 取消当前流程」设置影响。
Expand Down Expand Up @@ -198,7 +200,7 @@
- 三个全局快捷键:**听写**、**助手**、**翻译**(默认为全修饰键三角方案:右⌘/右Ctrl、右⌥/右Alt、两键同按;详见 [05 UX 规格 §7](05-ux-spec.md))。
- 三项配置中的每个按键数组分别表示一个可编辑的**完整 chord**,不是多个候选键:只有数组内全部物理键同时按住才触发。翻译 chord 可独立于听写与助手直接触发;默认值仍是听写键与助手键的有序组合。
- 三组 chord 必须非空。听写与助手不能相同或互为子集;翻译只不能与听写或助手完全相同,允许包含前两项的按键,也允许成为其中一项的严格子集。若当前 chord 是随后补全 chord 的严格子集,较长 chord 接管当前模式并保留音频;没有包含关系的其他已完成 chord 不改变本次手势最先启动的模式。设置界面必须阻止保存非法组合,后端也必须拒绝非法更新;读取到非法配置时仅把热键恢复为当前平台默认值,其他设置保持不变。
- 每个键支持「长按 push-to-talk / 短按 toggle」双模(同键自动区分,阈值 350 ms,可调)
- 设置提供全局触发方式二选一:`hold`(按下开始、松开结束)或 `toggle`(第一次按下开始、第二次按下结束)。两者都在完整 chord 的 keydown 立即开始;`toggle` 的停止也发生在第二次 keydown,不依赖持续按下、keyup 或时长阈值
- 支持**单个修饰键**作为触发键(如仅「右 ⌘」「右 Alt」)——这是品类标准体验,需要底层键盘监听而非普通热键 API(实现见 [06 代码架构 §7.3](06-code-architecture.md));**组合键让路规则**保证触发键的日常组合用法(⌘C 等)零干扰。
- Windows 在单修饰键 75 ms 语义确认窗口开始时立即启动仅驻内存的候选录音;确认 Typex 手势后以同一 token 提升为正式录音,不重开设备。普通键、AltGr、暂停、配置更新、hook 失败或退出会静默取消匹配候选,不显示 HUD、不播放提示音、不写历史或磁盘,也不向 Provider/电平事件发送任何候选数据。
- 自定义普通键按物理位置记录,与当前键盘布局及输入法输出字符无关;历史版本保存的后端别名在读取时迁移到稳定 `KeyId`,界面标签仍按 macOS/Windows/Linux 惯例显示。
Expand All @@ -208,7 +210,7 @@
## F-6 托盘与常驻行为

- Typex 无主窗口,启动后驻留系统托盘/菜单栏。托盘图标反映状态:空闲 / 录音中 / 处理中 / 错误(图标规格见 [04 设计系统 §3.4](04-design-system.md))。
- 托盘菜单:`复制上次结果`、`文本整理开关`、`翻译目标`、**`模型 ▸`(按 听写/文本整理/翻译/问答 分组列出兼容服务配置,点选即切,F-4 配置池的快速切换入口)**、`暂停 Typex`(临时禁用全局监听;进入暂停时静默取消当前录音,含短按 toggle,不中断已经进入转写/处理的会话)、`设置…`、`主页…`、`检查更新`、`退出`。
- 托盘菜单:`复制上次结果`、`文本整理开关`、`翻译目标`、**`模型 ▸`(按 听写/文本整理/翻译/问答 分组列出兼容服务配置,点选即切,F-4 配置池的快速切换入口)**、`暂停 Typex`(临时禁用全局监听;进入暂停时静默取消当前录音, toggle 会话,不中断已经进入转写/处理的会话)、`设置…`、`主页…`、`检查更新`、`退出`。
- 单实例:二次启动唤起设置窗口而非新进程。
- 开机自启:默认询问(onboarding 最后一步),可随时在设置中改;应用启动与设置变更只在系统注册状态和配置不一致时写入,已关闭且不存在注册项是正常状态,不得产生警告。Windows 注册项必须使用带引号的当前 EXE 完整路径;启用时自动修复仍指向旧 debug/安装目录的条目,关闭时删除残留条目,完全一致时不重复写注册表([ADR-26](08-decisions.md))。
- 自动更新:内置 updater(GitHub Releases 渠道),默认开启检查、手动确认安装([ADR-11](08-decisions.md))。首次生成设置时,开发版(SemVer prerelease,当前为 `-dev`)默认使用 nightly 通道,纯 `MAJOR.MINOR.PATCH` 正式版默认使用 stable 通道;用户手动选择通道后按保存值检查,不由构建类型覆盖。
Expand Down
59 changes: 53 additions & 6 deletions docs/03-model-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,44 @@ Content-Type: application/json
- F-10 词典经 `corpus.context` 传入(词条一行一个)。
- 流式识别(二进制 WS 帧协议,`wss://openspeech.bytedance.com/api/v3/sauc/bigmodel`)留待实时字幕需求出现时再实现。

### 2.3 内置实现三:`local`(本地推理,[ADR-20](08-decisions.md)/[ADR-22](08-decisions.md))
### 2.3 内置实现三:`mimo`(Xiaomi MiMo ASR)

MiMo ASR 不实现 OpenAI Audio Transcriptions 协议;它使用 Chat Completions 路径承载 JSON + Base64 WAV:

```text
POST {base_url}/chat/completions
Authorization: Bearer {api_key}
Content-Type: application/json

{
"model": "mimo-v2.5-asr",
"messages": [{
"role": "user",
"content": [{
"type": "input_audio",
"input_audio": {
"data": "data:audio/wav;base64,<完整 WAV 字节的 Base64>"
}
}]
}],
"stream": false,
"asr_options": { "language": "auto" }
}
```

响应文本位于 `choices[0].message.content`。`SttOptions.language` 未设置、空字符串或为 `auto` 时发送 `auto`,其他值原样发送;MiMo adapter 不发送 `prompt` 或 `temperature`。默认 Base URL 为 `https://api.xiaomimimo.com/v1`,默认模型为 `mimo-v2.5-asr`。

用户配置示例:

```text
Provider: Xiaomi MiMo
Base URL: https://api.xiaomimimo.com/v1
Model: mimo-v2.5-asr
API Key: 用户自己的 MiMo API Key
Language: auto 或 zh
```

### 2.4 内置实现四:`local`(本地推理,[ADR-20](08-decisions.md)/[ADR-22](08-decisions.md))

不走 HTTP,进程内推理,实现同一个 `SttProvider` trait。按硬件档位提供两条引擎路线:

Expand All @@ -105,7 +142,7 @@ Content-Type: application/json
- `capabilities()` 报告:不限音频时长(本地无 25 MB 上限);错误分类只剩 `InvalidRequest`/模型未下载。
- 模型文件由**模型下载管理器**负责(见 §8):不随安装包分发,按需下载。

### 2.4 扩展位
### 2.5 扩展位

- `deepgram` / `elevenlabs`:各约百行的薄 adapter(改鉴权头、上传方式)。
- 流式:各家协议互不兼容(OpenAI Realtime 事件 JSON / 火山二进制帧 / Deepgram 裸推);唯一准标准是 OpenAI Realtime(阿里 Qwen3-ASR 已模仿)。故流式做成可选 capability;当前默认路径使用「快 Provider + 一次性转写」。
Expand Down Expand Up @@ -358,7 +395,7 @@ F-3 不引入新的 Provider 类型:
```
功能槽位 服务池能力 实现走向
────────────────────────────────────────────────────────────
语音转文字 ──▶ stt profile ──▶ SttProvider(openai_compat | volcengine | local)
语音转文字 ──▶ stt profile ──▶ SttProvider(openai_compat | mimo | volcengine | local)
文本整理 ──▶ llm profile ──▶ LlmProvider + 整理 system/XML(推荐轻量快模型;可用 local)
翻译模型 ──▶ llm profile ──▶ LlmProvider + 翻译 system/XML(可用 local)
问答模型 ──▶ llm profile ──▶ LlmProvider + 处理/问答 system/XML(推荐强模型;可手动选择 local)
Expand All @@ -374,7 +411,7 @@ F-3 不引入新的 Provider 类型:

```jsonc
{
"schema_version": 10,
"schema_version": 11,
"dictionary": {
"terms": ["Typex", "OpenAI", "Qwen3-ASR"]
},
Expand Down Expand Up @@ -402,7 +439,7 @@ F-3 不引入新的 Provider 类型:
"dictation": ["ControlRight"], // 一个完整 chord,稳定物理 KeyId
"assistant": ["AltRight"],
"translation": ["ControlRight", "AltRight"], // 独立完整 chord;此处为默认三角键位
"hold_threshold_ms": 350
"trigger_mode": "hold" // hold | toggle;显式选择,不按时长推断
},
"slots": {
"stt": { "active_profile": "groq-fast" },
Expand Down Expand Up @@ -431,6 +468,14 @@ F-3 不引入新的 Provider 类型:
},
"options": { "resource_id": "volc.bigasr.auc_turbo", "enable_punc": true, "enable_itn": true }
},
{
"id": "mimo-asr", "capability": "stt", "kind": "mimo",
"label": "Xiaomi MiMo",
"base_url": "https://api.xiaomimimo.com/v1",
"model": "mimo-v2.5-asr", "timeout_ms": 60000,
"credentials": { "api_key": "用户自己的 MiMo API Key" },
"options": { "language": "auto" }
},
{
"id": "deepseek", "capability": "llm", "kind": "chat_completions",
"label": "DeepSeek V3",
Expand Down Expand Up @@ -467,9 +512,10 @@ F-3 不引入新的 Provider 类型:
- schema v8 将 `hotkeys.translation` 从派生值改为独立完整 chord。v7 及更旧配置升级时仍按旧规则把听写与助手 chord 有序去重合并为翻译 chord,保持当前行为;v8 起三组 chord 分别归一化和持久化,修改任一项不再重算另外两项。
- schema v9 以四个 `*_system_prompt` 字段替换旧的 `polish_prompt` / `translate_prompt` / `process_prompt` / `ask_prompt` 模板字段。应用尚未发布,不兼容旧自定义模板:v8 及更旧配置升级时删除旧字段并把新字段置空,直接使用当前内置 system prompt。固定 XML user message 不进入配置 schema。
- schema v10 将 profile 调用超时默认值从 30 秒提高到 60 秒;迁移时把旧版 UI 自动写入的 `timeout_ms=30000` 更新为 `60000`,其他显式值保持不变。
- schema v11 以 `hotkeys.trigger_mode`(`hold` / `toggle`)替换 `hold_threshold_ms`。旧配置迁移为 `hold` 以保持原先主推的按住说话行为;触发方式在会话开始时快照,后端不再按按住时长推断语义。
- profile 的 `timeout_ms` 是该模型服务的唯一全局调用时限,默认 `60000`。STT 覆盖从转写调用开始到完整文本返回,LLM 覆盖连接、请求发送、首 token 等待与完整流式响应接收;本地与远端实现使用相同语义。同一 profile 被多个功能或连接测试复用时统一生效,功能层不得另设总时限或 idle timeout。
- LLM `options.reasoning_effort` 控制思考等级,允许 `none` / `minimal` / `low` / `medium` / `high` / `xhigh`;设置 UI 默认保存 `none`,缺省仅表示旧配置或手写配置“不指定”。Responses 发送 `reasoning.effort`,普通 OpenAI 兼容 Chat Completions 发送顶层 `reasoning_effort`。Qwen 兼容端点与本地模型只支持开关语义,使用兼容字段 `options.enable_thinking` / `/think` / `/no_think`,其中 `none` 视为关闭,其他等级视为开启。
- **预设模板**(前端内置数据,非后端逻辑):OpenAI / Groq / SiliconFlow / 火山·豆包 / DeepSeek / OpenRouter / Ollama —— 选中即预填 `kind/base_url/model` 与凭据字段表单,用户只贴密钥。
- **预设模板**(前端内置数据,非后端逻辑):OpenAI / Groq / SiliconFlow / Xiaomi MiMo / 火山·豆包 / DeepSeek / OpenRouter / Ollama —— 选中即预填 `kind/base_url/model` 与凭据字段表单,用户只贴密钥。
- 「测试连接」:STT 槽发内置 2 秒样音(assets 内置,中文「你好,Typex」),LLM 槽发 `ping` 单词请求;展示延迟与分类后的错误。

## 7. 各厂商兼容性速查(配置预设的依据)
Expand All @@ -479,6 +525,7 @@ F-3 不引入新的 Provider 类型:
| OpenAI | openai_compat | chat_completions / responses | 基准 |
| Groq | openai_compat | chat_completions | STT 极快(whisper-turbo),语音输入首选预设 |
| SiliconFlow | openai_compat(子集) | chat_completions | SenseVoice 中文;参数支持面窄 |
| Xiaomi MiMo | **mimo adapter**(`/chat/completions` JSON + Base64 WAV) | chat_completions | MiMo ASR 不是 OpenAI Audio Transcriptions 兼容接口 |
| 火山引擎 · 豆包 | **volcengine adapter** | chat_completions(方舟端点) | STT 双凭据;LLM 是 OpenAI 兼容的 |
| DeepSeek | — | chat_completions | 整理/翻译高性价比 |
| OpenRouter | — | chat_completions / responses | 聚合网关 |
Expand Down
Loading
Loading