mianaz/jargonslayer / docs / zh / 高级玩法
主页 English App GitHub
高级玩法

运行、定制、扩展

这一页面向运维者和开发者:从源码运行 JargonSlayer、搭建本地 sidecar、完整设置参考、主题和词典包的内部机制、webhook payload,以及应用自己的架构和测试套件。如果只是想用这个应用,使用指南已经够用。

npm workspace 本地 Whisper sidecar 17-token 主题 远程词典包 manifest Webhook IndexedDB

自己部署网页版

网页版是一个普通的 Next.js 项目,克隆、安装、运行:

git clone https://github.com/mianaz/jargonslayer.git
cd jargonslayer
npm install
npm run dev
# open http://localhost:3000

想要更接近生产环境的本地运行方式,用 build 和 start,而不是 dev server:

npm run build
npm start

提交改动前,跑一遍 CI 会跑的同一套检查:

npm run typecheck
npm test
npm run build

服务端的提供商 Key 放在 .env.local 里,永远不会发到浏览器:

ANTHROPIC_API_KEY=sk-ant-...

部署层级

默认构建是完整本地优先构建——所有功能都可用,只受访问者自己的配置门控。设置 NEXT_PUBLIC_DEPLOY_TIER=preview 会切换到在线体验层:依赖 sidecar 的功能(本地 Whisper、经 sidecar 的标签页音频、视频 URL 导入、订阅直连)会显示为禁用/灰色并附带说明,而不是直接失败;零 Key 的 AI 使用则由预览服务器自己配置好的模型路径支撑——这对隐私意味着什么,见使用指南的AI 模式一节。

PWA 安装

网页版直接用已有的 manifest 和图标安装成 PWA,不需要单独构建。桌面端 Chrome/Edge 会把它装成一个独立窗口的应用;iOS/iPadOS 上通过 Safari 添加到主屏幕。

本地 Whisper Sidecar

网页版的本地 Whisper、标签页音频,以及基于 sidecar 的录音/URL 导入,全部走同一个 Python 进程——sidecar/whisper_server.py。桌面版由首次启动向导自己安装、自己管理这个 sidecar——下面这些手动步骤在桌面版上都不需要,除非你要把它指向一个外部 sidecar(见下方 sidecarMode)。网页版则要手动搭:

cd sidecar
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python whisper_server.py --model small

它通过 ws://127.0.0.1:8765 提供实时转录,并用一个本地 HTTP job API 处理录音和视频 URL 导入,底层基于 faster-whisper、基于能量的 VAD、可选的本地音频保存,以及配置好后用于说话人分离的 pyannote。

模型选择

--model 可选 tinybasesmallmediumlarge-v3large-v3-turbo,以及 parakeet-tdt-0.6b-v3(MLX 加速、英文优先——是桌面版英文加速引擎在手动 sidecar 上的对应版本)。这条手动路径日常默认推荐 small。桌面版向导自己的模型清单更窄、且是 macOS 专属的精选清单:small / medium / large-v3 / large-v3-turbo,外加一个可用时才出现的 Parakeet 条目,预选 medium

说话人分离

配置一个 Hugging Face token(设置里的 hfToken,或桌面版首次启动引导时粘贴——见使用指南的桌面版),前提是已经在 Hugging Face 上接受了 pyannote 的 segmentation 和 speaker-diarization 模型使用条款。批量导入会对整段录音做说话人分离。实时说话人分离仍是 beta:sidecar 会在最近一段音频窗口上反复运行 pyannote,把说话人匹配到一个稳定的 registry,再把标签更新推回界面,不阻塞转录。

移动目录的坑

Python 虚拟环境里固化了绝对路径。移动或重命名仓库后,venv 会悄悄坏掉;重建它就好(rm -rf sidecar/.venv,再重复上面的安装步骤)。

sidecarMode(桌面版)

桌面版的 sidecarMode 设置可以是 managed(默认——应用自己安装、启动、重启内置 sidecar)或 external(指向你自己起的 sidecar,跟网页版一样)。网页版实质上永远等价于 external

sidecar 还没有 README。这一页和 sidecar 自己的测试文件(见测试)是目前 sidecar 操作的运行手册。

订阅直连 Agent Sidecar(实验性)

sidecar/agent_server.py 是实验性的、只在本地跑的功能。它驱动你自己已经登录的 claudecodex CLI,仅用于 detect/define——翻译和总结/报告在所有构建里始终走正常的应用 route。

  • 默认 loopback 地址:http://127.0.0.1:8767
  • 端点:GET /agent/healthPOST /agent/detectPOST /agent/define
  • detect/define 调用需要 loopback Origin,加上 sidecar 启动时打印的一次性连接码,手动粘贴进设置。
  • 功能开关:构建时设置 NEXT_PUBLIC_ENABLE_SUBSCRIPTION_DIRECT=1——不设置的话,整个 UI 区块和调用分支在构建产物里根本不存在。
  • sidecar 不可达、未登录,或额度用尽时,应用会回退到词典检测,而不是直接失败。
环境变量警告:如果 agent sidecar 自己的环境里存在 ANTHROPIC_API_KEY,Claude 调用可能会优先用这个 Key,而不是你的订阅登录。sidecar 会给出警告,但不会替你 unset——想让订阅登录生效,就自己从 sidecar 的 shell 环境里清掉它。

设置参考

一个设置对象控制转录、模型路由、检测、翻译、显示和各种集成。v0.7.3 起,LLM 提供商的 Key 按提供商分别存储、分别发送,不再共用一个 Key;v0.7.4 起,设置 → 密钥 是下表所有 Key 和 token 的统一 UI 入口。

已经没有单一的 apiKey 字段了。每个提供商预设都有自己的字段——apiKeyAnthropicapiKeyOpenaiapiKeyDeepseekapiKeyQwenapiKeyOpenrouterapiKeyPoeapiKeyOllamaapiKeyCustom(加上给自定义端点用的 llmCustomHost)——所以切换提供商永远不会把上一个提供商的 Key 带到新提供商那边。裸的 apiKey 字段现在只存在于分任务的 taskLlm 覆盖项里。

转录

字段作用说明
engine实时捕获引擎选择。importbrowser-whisper 会存在导入会话上,但不是可选的实时引擎。
mode音频来源:mic / tab / system-audio / import / urlv0.7.4 起是独立控件——会议进行中也能改,不只是开会前。
language传给 Web Speech 的 BCP-47 语言代码。例如 en-US
whisperUrl本地 Whisper 的 websocket URL。默认 ws://localhost:8765
whisperModelsidecar 模型名称。默认 small——完整可选列表见Whisper Sidecar
proxyUrl仅桌面版:手动代理覆盖。""(默认)跟随系统代理;否则可以是 http:///https:///socks5:///socks5h://,支持在 URL 里带用户信息做 basic auth——用于系统自动检测看不到的、只靠环境变量或只靠 PAC 的网络。
partialssidecar 是否推送中间(未定稿)文本。默认开启。
preferOnDeviceSpeech优先使用浏览器的设备端识别,而不是云端兜底。默认开启。
sidecarMode仅桌面版:managedexternalWhisper Sidecar
tabAudioCloudProvider标签页音频使用哪个 BYOK 云端引擎。sonioxdeepgram
sonioxKey / deepgramKey / elevenLabsKey三个第三方云端 STT 引擎各自的 BYOK Key。存在 设置 → 密钥 里。

AI 路由

字段作用说明
provider主 LLM 路由。anthropicopenai-compat
baseUrlopenai-compat 提供商的 base URL。例如 https://api.deepseek.com/v1
apiKeyAnthropic / apiKeyOpenai / apiKeyDeepseek / apiKeyQwen / apiKeyOpenrouter / apiKeyPoe / apiKeyOllama / apiKeyCustom每个提供商各自的 Key。自 v0.7.3 起彼此隔离——见上面的提示框。
llmCustomHostapiKeyCustom 绑定到「自定义」预设指向的那个 base URL。
taskLlm可选的分任务 provider/model 覆盖,支持 translatedetectsummary划词解释(define)始终跟随 detect 的配置;没配置的任务(或 enabled:false)完全继承主路由。
agentUrl订阅直连 agent sidecar 的 base URL。默认 http://127.0.0.1:8767——见Agent Sidecar

检测

字段作用说明
autoDetect实时检测总开关。
aiDetect只控制 LLM 那一层。不管这个开关状态如何,词典底座始终即时、离线。
minConfidence合并检测结果时用的置信度阈值。
enabledPacks哪些内置/已安装词典包处于启用状态。null 表示全部启用;core 始终启用。
detectIdiomMaxWords / detectIdiomMaxChars超过这个长度就会把习语/黑话片段当成「选中了整句」而丢弃。默认 12 词 / 90 字符。
packAutoUpdate已安装的远程词典包自动检查新版本。每天一次。

翻译

字段作用说明
bilingualTranscript实时逐片段翻译开关。目标语言由 explainLanguage 决定。
explainLanguage解释/翻译的目标语言。zh(默认)或 en
translateEngine使用哪个翻译引擎。"system"(本机翻译,默认)| "deepl" | "youdao" | "llm"
deeplKey自备的 DeepL Key。
youdaoAppKey / youdaoAppSecret自备的有道(Youdao)应用ID/应用密钥。仅原生 App 可用(桌面版/iOS)——有道的 API 不支持网页版所需的跨域请求。

显示

字段作用说明
uiMode设置的详细程度。simpleadvanced
themeId / customThemes当前主题 id 和用户自建的主题定义。主题
uiFont / monoFont界面字体和等宽字体选择。主题
overlayGlass毛玻璃浮层开关。默认关闭。
fontSize / transcriptScale / transcriptLeading全局字号、转录专属字号,以及转录行距控制。
bitCostumeBit 装扮的固定选项。"auto"(跟随主题,默认)、"none",或指定的装扮 id。

集成

字段作用说明
hfToken / realtimeDiarize说话人分离用的 token,和实时分离 beta 开关。Whisper Sidecar
ankiConnect{ enabled, deckName, port }——AnkiConnect 同步目标。端口默认 8765,可单独配置,因为它和 whisperUrl 的默认端口撞了。见自动化
usageTracking本地、设备端的用量账本(按天+提供商记录 STT 秒数、LLM 调用/token 数)。不上传遥测——这里的数据永远不会离开浏览器/桌面应用。
autoExport / webhookUrl / exportFrontmatter文件夹自动导出、webhook URL("" 表示关闭),以及 Markdown frontmatter。payload 格式和文件命名见自动化

模型路由

分任务模型

高级设置可以通过 taskLlm(见上面的设置参考)把检测、翻译、报告分别指向不同的提供商或模型。常见搭配是实时检测用又快又便宜的模型,会后报告用更强的模型;划词解释(define)始终跟随检测的配置。

提供商预设

设置 → AI 检测内置八个预设:

  • Anthropic 官方——api.anthropic.com,原生提供商。
  • OpenAI——api.openai.com/v1。
  • DeepSeek——api.deepseek.com。
  • 通义千问——dashscope.aliyuncs.com/compatible-mode/v1。
  • OpenRouter——openrouter.ai/api/v1,也能一键 OAuth 接入。
  • Poe 订阅——api.poe.com/v1,用 Poe 订阅驱动任意 OpenAI 兼容客户端。
  • Ollama 本地——localhost:11434/v1,完全本地推理。
  • 自定义——任意其他 OpenAI 兼容端点。

除 Anthropic 外的每个预设都对应同一个 openai-compat provider 类型,只是 base URL 不同。每个预设的 Key 都独立存储、独立发送——这是 v0.7.3 的修复,让切换提供商永远不会把上一个提供商的 Key 发到新提供商那边。

BYOK Key 处理路径

路径Key 存在哪里说明
浏览器存储本地浏览器存储设置 → 密钥 里填入;下面每条路径都从这里开始。
自托管网页版,中转经你自己服务器的 API route 内存中转服务端从不落盘。
在线体验,BYOK浏览器直连提供商完全不经过项目服务器;服务端会直接拒绝任何带 Key 的转发请求。
环境变量 Key.env.local 服务端变量,例如 ANTHROPIC_API_KEYKey 完全不进入浏览器。
桌面版,OAuthmacOS 钥匙串,经 RFC 8252 loopback OAuth系统默认浏览器打开做 OpenRouter 登录,不是应用内弹窗,和首次引导是同一套流程。

proxyUrl(仅桌面版)是系统级自动检测看不到路由时,手动触达 BYOK 端点的应急出口——比如只靠环境变量配置的代理,或者应用没法执行脚本的纯 PAC 网络。

主题

每套主题——不管内置还是自定义——都是一张扁平的 token 到 hex 的映射表,加一个 scheme 标记。每个值必须是严格的 hex,#RGB#RRGGBB——rgb()hsl()、颜色名和 CSS 变量全部会被直接拒绝——值会作为 CSS 自定义属性注入,而不是拼字符串。每套主题都会做 WCAG AA 对比度检查。schemedarklight)是一个独立的结构字段,不是第 18 个 token——它决定原生表单控件/滚动条外观和界面内图标的切换。

17 个 token

inkpanelpanel2panel3edgeedge2fgmutmut2lab-redlab-orangelab-yellowlab-greenlab-purplelab-cyanactwarn-soft

编辑器行为

  • 主题网格里的 新建格子可以从零建一套主题,也可以复制任意一套(内置或自定义)。
  • 编辑每个 token 时会实时预览,取消编辑会恢复到已保存的那套。
  • 对比度提示会随时标出掉到 AA/控件对比度门槛以下的 token——只警告,从不阻止保存。
  • 可以导出成 JSON 文件,也能通过粘贴或选择文件导入;导入的主题会重新校验,id 也会重新分配,所以导入文件永远盖不掉、也覆盖不了内置主题。
  • 删除主题需要二次确认;删掉当前正在使用的那套会回退到终端默认主题。

自定义主题示例

{
  "id": "custom-1737421200000",
  "label": "深海蓝调",
  "scheme": "dark",
  "tokens": {
    "ink": "#050b14",
    "panel": "#0d1620",
    "panel2": "#14202c",
    "panel3": "#1b2c3a",
    "edge": "#25384a",
    "edge2": "#37516a",
    "fg": "#e8f1fb",
    "mut": "#93a9bd",
    "mut2": "#5c7186",
    "lab-red": "#ff6b6b",
    "lab-orange": "#ffa552",
    "lab-yellow": "#f4d35e",
    "lab-green": "#4ade80",
    "lab-purple": "#b895ff",
    "lab-cyan": "#41d1e0",
    "act": "#2fd0e8",
    "warn-soft": "#ffcf7a"
  }
}
字体被特意排除在外。字体不在主题 schema 里,也不在导出的主题文件里——共享出去的主题 JSON 永远改不了你加载的是哪套字体。字体是两个独立设置,界面字体(UI font)和等宽字体(monospace),各自提供零下载的系统预设(界面:默认 / 衬线 / 圆体;等宽:内置的 JetBrains Mono 默认 / 你的系统等宽),或者你自己输入一个系统字体名。uiFont/monoFont 接受 "default"、某个预设 id,或 "custom:<family>";自定义名字使用前会做净化处理。

词典包制作

远程词典包是 JSON manifest,会被校验、归一化后载入内存 registry,再和内置词典包一起显示在设置里。发布到 GitHub raw URL 或 jsDelivr URL,粘贴该 URL 即可安装;也可以直接分享文件,走文件导入。

Manifest 格式

{
  "id": "biotech-terms",
  "name": "Biotech Terms",
  "version": "1.2.0",
  "terms": [{
    "term": "IND",
    "type": "acronym",
    "gloss_en": "Investigational New Drug application",
    "gloss_zh": "美国 FDA 新药临床试验申请"
  }],
  "expressions": [{
    "expression": "go/no-go",
    "category": "phrase",
    "meaning": "a decision point to proceed or stop a program",
    "chinese_explanation": "继续或终止(项目决策点)",
    "plain_english": "decide whether to continue or stop",
    "tone": "neutral, common in R&D governance"
  }]
}

manifest 根层必须有 idnameversiontermsexpressions 都是可选数组。缩写就是 terms"type": "acronym" 的条目——没有单独的缩写结构。

校验行为

  • 坏条目会被单独丢弃并打印 warning;只有 manifest 本身不可用时整个包才会安装失败。
  • 条目级 pack 字段会被忽略,并强制改成 manifest 自己的 id——单个条目没法冒充另一个包的 id。
  • 只要 version 改变,就足以触发一次更新;已安装的包每天自动检查一次新版本(packAutoUpdate)。

官方目录

设置里有一个一键浏览安装的官方目录——医学、生物医药、AI/ML、法律、金融、工程计算机六个专业包,共 4,300+ 词条,发布在 jargonslayer-dicts——此外还支持从文件或 GitHub URL 导入任意第三方包。

优先级

个人词典 > 已安装词典包 > 内置词典。个人词典条目会盖过任何词典命中。已安装包的释义优先于内置词典(而不是内置词典默默获胜)是 v0.7.2 上线的。

导入大型缩写源前先过滤。全局缩写库只是候选数据,不是一个可以直接用的包——先按领域和质量过滤,把结果发布成一个可选词典包,验证过后再考虑把条目提升进内置词典。

自动化与集成

自动导出文件夹

设置里可以把每场会议保存时同步写入一个文件夹,格式是 Markdown 加 JSON,命名为 YYYY-MM-DD-HHmm-jargonslayer.md 和同名的 .json。这个功能用的是 File System Access API,所以偏 Chromium(Chrome/Edge)——是为 Obsidian vault 和 agent 工作流设计的,不是一个通用的跨浏览器功能。

Webhook

配置好 webhook URL 后,每次会议保存都会 POST 一个 meeting.saved payload:

{
  "schemaVersion": 1,
  "event": "meeting.saved",
  "exportedAt": 1735689600000,
  "session": { /* full MeetingSession */ }
}

同一个 URL 也会收到后台任务生命周期事件——task.startedtask.donetask.error——payload 结构和上面完全一致,只是把完整的 session 换成了一个 task 对象(id、kind、label、stage、progress、status、error、sessionId、timestamps);这些事件对应的正是桌面版后台任务的任务 registry(模型下载、说话人分离扩展安装、导入任务)。每次调用超时 8 秒,不重试——接收端慢或者挂了,只会错过那一次事件,不会阻塞或者重新排队。

接收端应该尽快返回 200,把真正的处理逻辑放到异步里做:

app.post("/jargonslayer-webhook", (req, res) => {
  res.sendStatus(200);                   // ack immediately, before the 8s timeout
  queue.add("process-event", req.body);  // do the real work off-request
});

AnkiConnect

开启 ankiConnect 后,每次保存会议都会向本地 AnkiConnect 实例发起一次 addNotes 调用,用的是和手动导出 Anki TSV 一样的卡片映射规则,并做了去重,重复保存同一场会议不会产生重复卡片。它的默认端口 8765 和 Whisper sidecar 自己的 websocket 默认端口撞了,所以是可以独立配置而不是写死的——两者同机运行时检查一下 ankiConnect.port

Obsidian

Markdown 导出可以带上给 Obsidian/Dataview 用的 YAML frontmatter(exportFrontmatter)——配合文件夹自动导出,就能搭出一个每次开完会自动更新的 vault。

备份与恢复

完整备份会把会议、词典和设置一起导出。导出对话框里的 不包含 API Key 选项默认勾选,下载前会从内嵌的设置里剥离所有 API Key、Hugging Face token、订阅直连 agent token、webhook URL,以及分任务 API Key;取消勾选就会把它们留在文件里。恢复备份时会先预览内容再写入,不管备份导出时是怎么处理的,都会重新对这些字段做一遍脱敏,并清空订阅直连的连接状态,避免恢复后静默重连到旧的本地 agent sidecar。

架构

仓库是一个 npm workspace:apps/web(Next.js 15、TypeScript、Tailwind、zustand、IndexedDB、服务端 LLM route proxy)加上 packages/core(纯 TS 共享核心——词典、类型定义)、apps/desktop(Tauri 外壳)、apps/extension(Chrome MV3 侧边栏)。apps/web 里的 zustand store 是转录片段、中间结果、卡片、术语、纪要、设置和会议历史的共享总线。

apps/web(浏览器客户端)
  transcription engines
    demo | Web Speech | local Whisper | tab audio | appaudio(桌面版)
  zustand store
    segments | cards | terms | summaries | settings | sessions
  detection
    dictionary instant floor
    LLM scheduler and dedupe
  UI
    transcript | cards | history | summary | review

Server routes
  /api/detect
  /api/define
  /api/translate
  /api/summarize

Sidecars(Python)
  whisper_server.py
  agent_server.py

apps/desktop(Tauri v2,macOS)
  Rust 核心:用固定版本的 uv 装独立 Python、
    管理 sidecar 进程、CoreAudio process-tap 管线
  jargonslayer-audiocap:签名的 Swift 辅助进程(CoreAudio process tap)

apps/extension(Chrome MV3)
  侧边栏:Web Speech 实时捕获 + 内置词典 + 设备端 Translator API
  自己的 IndexedDB 数据库 + chrome.storage.local,跟 apps/web 的存储互不相通

packages/core
  共享类型 + 内置词典,网页版和插件都消费它
  • apps/web/src/lib/types.ts(转出自 @jargonslayer/core)维护跨模块契约。
  • apps/web/src/lib/store.ts 是应用总线;STT 和检测通过 store 通信,而不是直接互相依赖。
  • apps/web/src/lib/detect/dictionary.ts 是同步即时词典层。
  • apps/web/src/lib/detect/scheduler.ts 负责 LLM 批处理和词典模式 fallback。
  • apps/web/src/lib/detect/dedupe.ts 合并重复命中,并用 LLM 结果原地升级词典卡片。
  • apps/web/src/app/api/summarize/route.ts 编排总结、分块翻译和漏检补扫。
  • apps/desktop/src-tauri/src/audiocap.rs 监管 Swift 捕获辅助进程,把它的输出重采样后接入既有转录管线。

数据与存储

所有应用数据都在 IndexedDB 里,通过 idb-keyval 访问——不是 localStorage。历史遗留的 meetlingo:* key 会在启动时复制迁移到新命名空间,并保留原数据,方便回退。

位置存储 key说明
设置jargonslayer:settings本地配置。
会议jargonslayer:sessions:index + jargonslayer:session:<id>一个索引数组,加上每个 key 一条完整的 MeetingSession 记录。
个人词典jargonslayer:glossary个人条目和掌握状态。
自动保存文件夹jargonslayer:export-dir浏览器文件 handle;偏 Chromium。
远程词典包jargonslayer:remote-packs已安装包的来源 URL 和校验过的 manifest。

Schema version 1 覆盖会议 JSON、Markdown frontmatter、webhook payload、全量备份和远程词典包。

应用里真正用到 localStorage 的只有两处:一个是主题 FOUC(无样式内容闪烁)镜像 js-display,在 IndexedDB 解析完成前就同步读取,让首次渲染就用上正确的主题/字号;另一个是更新检查的 ETag 缓存 js-update-etag-cache,让重复的 GitHub release 检查更省资源。

这张表说的是网页版/桌面版。Chrome 插件(Lite)有自己完全独立的本地存储——一个专用的 IndexedDB 数据库存会话历史,chrome.storage.local 存收藏的查词记录——从不和网页版的存储同步或共享。

行为规格

这些是排查配置问题、或者想扩展这个工具时最值得了解的行为。

检测规格

  • 启用检测时,每个最终转录片段都会被词典同步扫描。
  • LLM 层只批处理新增文本,之前的 context tail 仅用于消歧。
  • LLM 结果可以原地升级词典卡片,但不会撤回词典命中。
  • 重复表达按归一化 key 合并,更新 count 和 last-seen 元数据。
  • 个人词典优先于内置词典,且不会被 AI 覆盖。
  • 全大写缩写使用更严格匹配,降低误报;普通混合大小写术语匹配更宽松。

翻译规格

  • 实时双语转录按 segment id 分小批翻译最终片段。
  • 会议中打开双语转录时,会补翻最近几个尚未翻译的最终片段。
  • 手动修改某个片段文本时,旧翻译会失效;会议仍在进行时,会重新入队。
  • 无 Key 暂停是可自愈的:填入 Key 后,新翻译工作可以恢复,不必重启会议。
  • 连续 429 会暂停,并最终跳过最老的卡住批次,避免新片段一直被阻塞。
  • 会后报告翻译是另一条路径:按 segment index 分块翻译,并尽量修复缺失的 index。

导入规格

导入路径处理方式限制 / 说明
文稿粘贴 / .txt / .srt / .vtt解析、构建合成会话、检测、可选翻译、保存。有时间戳的 cue 会归一到导入时间;纯文本会使用合成时间间隔。
浏览器音频导入浏览器 AudioContext 解码,重采样到 16 kHz mono,交给浏览器 Whisper worker。45 分钟时长上限;200 MB 压缩音频上限。
浏览器视频导入用 ffmpeg.wasm 提取音轨,再复用浏览器音频路径。视频提取有单独的大小限制;首次运行可能下载浏览器侧模型资源。
Sidecar 录音导入本地 job API 处理转录和可选说话人分离。需要本地 sidecar;进度显示是 UI 本地状态,刷新会丢失显示但任务会继续。
视频 URL 导入本地 sidecar 使用 yt-dlp,再走同一转录 job 管线。仅本地版;用户自行负责版权和平台条款。

失败与恢复规格

  • 无 API Key:检测回退到词典;实时翻译暂停;生成报告会提示需要 Key。
  • 限流:检测对 429 带抖动重试一次;翻译会暂停,并避免老批次永久阻塞新片段。
  • Sidecar 不可达:本地 Whisper、sidecar 导入、URL 导入、说话人分离、订阅直连都不可用;浏览器本地导入仍可处理支持的文件。
  • 会议已切换:异步结果携带 meetingGen;旧会议的过期结果会被丢弃。
  • 后台标签页:浏览器会节流 timer,所以检测也会在片段到达和可见性变化时触发 flush。
  • 停止后的晚到结果:检测和翻译可能在停止后到达;store 会安排补保存,避免历史记录缺尾部结果。

词典与学习规格

  • 今天个人词典是持久学习主场;会议记录保持为不可变归档。
  • 条目可以手动创建、由划词 AI 定义创建,也可以从本场卡片收藏。
  • 每个条目保存 headword、variants、解释、例句、原始上下文、用户笔记、来源、时间戳和复习状态。
  • 表达条目可保存分类、英文含义、plain-English 改写和语气。术语条目可保存术语类型和英文 gloss。
  • 复习状态包括 mastered、review count、last reviewed time——v0.3.0 起已经是真正的 learn-set 和到期复习循环(SM-2 简化排期)。

异步委派设计

产品体验应该像一个稳定的前台进程,背后有多个专业后台 worker。前台负责监听、文本编辑、用户焦点和已保存会议状态;昂贵任务交给异步委派者,结果准备好后再自然合并回来。

这是概念设计,不是字面 schema:这一节描述的是实时检测/翻译目前已经在遵循的覆盖率模型,属于概念层面。真正上线、用户看得见的「后台任务 / background task center」,跟踪的是更粗粒度的整任务(导入、模型下载、说话人分离扩展安装),用的是它自己的内存 registry——并不是下面这套按片段的账本,也没有 translate | detect | search | diarize 这几种 kind。

前台

追加最终转录片段,保持用户焦点稳定,允许编辑和复盘,渲染当前最好的状态,不等待 AI 或搜索。

委派者

翻译、LLM 检测、实时搜索、说话人分离、会后报告各自排队运行,有优先级和重试策略。

任务账本

按片段记录覆盖情况:词典已完成、LLM 检测待处理/完成/失败、翻译待处理/完成/跳过、搜索待处理/完成/过期。

{
  "id": "job_x",
  "kind": "translate | detect | search | diarize",
  "meetingGen": 12,
  "segmentIds": ["seg_1", "seg_2"],
  "textHash": "...",
  "priority": 2,
  "status": "queued | running | done | failed | stale",
  "attempts": 0
}

结果只有在 meeting generation 仍匹配、目标片段仍存在、源文本 hash 仍是当前版本时才应用。结果应该以 patch 方式合并到相关字段,不能替换前台转录,也不能抢走用户焦点。

为什么重要:翻译和检测可能失败、暂停或延迟完成。任务账本能让这些状态可见,避免文本静默丢失:它要么已处理,要么待处理,要么过期,要么带原因跳过,要么可重试。

未来的实时搜索天然适合这个模型:卡片可以用当前表达加最近上下文发起一次后台搜索,同时立刻显示本地解释,等搜索委派者返回后再附加参考来源或消歧说明。搜索应该由歧义、用户请求,或显式的词典包/卡片操作触发,而不是默认给每张卡都搜一遍;结果应该作为引用或上下文说明附加到卡片上,而不是替换掉本地解释;搜索任务的优先级应该低于实时转录、词典扫描和可见卡片检测;隐私设置也应该清楚区分本地词典、模型提供商 AI 和联网搜索这三类调用。

测试

Web App

npm run typecheck
npm test
npm run build

Sidecar

sidecar/.venv/bin/python sidecar/test_agent_json.py
sidecar/.venv/bin/python sidecar/test_agent_postfilter.py
sidecar/.venv/bin/python sidecar/test_agent_server.py
sidecar/.venv/bin/python sidecar/test_download.py
sidecar/.venv/bin/python sidecar/test_ingest_url.py
sidecar/.venv/bin/python sidecar/test_lazy_load.py
sidecar/.venv/bin/python sidecar/test_model_registry.py
sidecar/.venv/bin/python sidecar/test_parakeet_backend.py
sidecar/.venv/bin/python sidecar/test_realtime_diar.py
sidecar/.venv/bin/python sidecar/test_whisper_protocol.py

sidecar 测试是 plain-assert 脚本,依赖 sidecar/requirements.txt。本地 Whisper 和 agent sidecar 是独立进程,改哪个测哪个。

桌面版(Rust + Swift)

cd apps/desktop/src-tauri && cargo test
cd apps/desktop/src-tauri/audiocap-helper && swift test

Rust 核心(进程监管、重采样、CoreAudio framing 协议)和签名的 Swift 捕获辅助进程各有自己的测试套件;CI 环境没有真实 CoreAudio session,所以音频捕获相关的测试都是围绕 fake/seam 设计的,不依赖真实 tap。

插件

npm test -w apps/extension