文档

开始使用

novme 是什么?

听懂当下,带走一份完整记录。

novme 是一款面向 macOS 的会议字幕与复盘工具。它同时采集本机麦克风和指定会议应用的音频, 优先发布源语言字幕,再异步补充中英文翻译;会议结束后,它会保留完整逐字稿并生成摘要、决策、 行动项和风险。

  • 低延迟:源字幕先显示,翻译不会阻塞下一条源字幕。
  • 双路采集:区分“我”和“会议”两类音频来源,关键帧带有可追踪的序号与时间信息。
  • 完整复盘:实时路径可以降级或延后,但会议资料会持久化并在结束阶段补齐。
  • 两种推理方式:支持 Apple Silicon 本地 MLX,也支持通过 Bearer 认证连接 DGX Spark。

从声音到会议记录

novme 将“实时可读”和“会后完整”拆成两条策略不同的处理路径。

快速开始

首次使用本地 MLX

首次安装后,按顺序下载模型、启动本地 MLX,再填写连接地址。模型缺失或预热失败时,novme 会直接显示错误,不会静默切换到其他后端。

环境要求

系统macOS 13 或更新版本
本地推理Apple Silicon;运行组件已随 App 安装
客户端正式发布包不要求 Python、pip 或 Swift 工具链

首次安装:3 步完成本地配置

01

下载三个所选模型

打开 App 的“设置 → 模型”,依次下载语音识别、实时翻译和会议总结所选模型。等待三项都显示为已下载后再继续;下载中的模型不能用于启动。

02

启动本地 MLX

在“模型”页底部点击“启动并使用”。novme 会加载并预热所选模型;状态变为“本地推理已就绪”前不要开始会议。失败时按界面提供的日志路径检查实际错误。

03

填写本地连接地址

进入“设置 → 连接”,在后端地址中填写 http://127.0.0.1:18080,网络路由选择“直连”,API Key 留空,然后点击“保存并检查”。连接状态变为“可用”后即可开始会议。

授予系统权限

  1. 允许 novme 使用麦克风。
  2. 允许 novme 进行屏幕录制,以便 ScreenCaptureKit 读取会议应用音频。
  3. 授权后完全退出并重新打开 novme。

从源码运行(开发者)

Terminal
./script/build_and_run.sh --verify

正式发布包不需要执行此命令。仓库开发者使用验证模式检查应用签名、启动状态和权限连续性;普通重建不应重置系统权限。

novme 原生 macOS 会议设置界面
设置阶段只保留开始会议所需的来源、语言和后端状态。

开始使用

连接与认证

novme 没有用户名、密码、Cookie 或 OAuth 登录。连接身份是后端共享的 API Key,原生客户端会把它作为 Bearer 凭证发送给 HTTP 和 WebSocket。

本地后端

App 内置的本地 MLX 后端只监听 http://127.0.0.1:18080。首次安装时后端地址为空;下载三个所选模型并启动本地 MLX 后,请在“连接”页手动填写该地址,网络路由选择“直连”,API Key 留空,再点击“保存并检查”。严格健康检查通过后才允许开始会议。

远端 Spark

原生客户端不预置远端地址;请在设置中输入明确的后端原点。远端地址必须填写有效的 sk- API Key,Key 至少包含 20 个密钥字符;Spark 的 llama-server 和可选 MiMo 服务仍只监听远端回环地址。

在程序中保存连接

  1. 打开 macOS“设置”(Command-,),进入“连接”页。
  2. 填写后端原点地址和 API Key,地址只能包含协议、主机和端口,不能附带路径、查询参数或内嵌账号密码。
  3. 点击“保存并检查”。客户端先校验格式,再请求 GET /health;严格模式、模型身份和音频契约不匹配时会显示失败。
  • 后端地址保存在 macOS 应用偏好设置中。
  • API Key 只保存在 Keychain,不写入应用偏好设置;网络请求使用 Authorization: Bearer <API Key>
  • HTTP 与两个 WebSocket 路由共用同一个 Key。缺少或错误的 HTTP 凭证返回 401;WebSocket 会在握手阶段被拒绝。
  • 远端使用明文 HTTP 时,程序会在保存前显示风险警告,因为 Bearer Key、音频、字幕和会议数据都没有传输加密。当前直连只适合可信网络,不能视为 TLS 登录方案。

使用指南

一次会议的三个阶段

novme 把界面收敛为设置、实时字幕和会议复盘,结束处理期间会保留已有逐字稿。

01

设置

选择麦克风、会议应用、源语言和翻译方向。后端与本地权限未就绪时,“开始”不可用。

02

实时字幕

阅读源字幕和翻译,观察“我 / 会议”两路活动状态,并随时显式结束会议。

03

会议复盘

等待最终处理完成,查看摘要和逐字稿,导出 Markdown,或开始一场新会议。

novme 原生 macOS 实时字幕界面
实时阶段只保留字幕、两路音频状态和结束操作,减少会议中的视觉干扰。

核心能力

实时翻译字幕

每个音频帧先归档,再进入识别。源文本先到达客户端,翻译随后更新同一个字幕段。

源字幕优先

翻译任务具有独立的并发与排队边界。翻译繁忙或失败时,源字幕仍然保留并继续发布; 系统会发送 translation_delayedtranslation_error 事件,并在会议结束阶段重试。

音频帧协商

运行配置客户端帧后端处理
固定兼容模式1000 ms每个固定帧形成一个实时推理单元
当前 Spark 自适应 VAD80 ms常规边界为 800 ms 静音 / 15 秒硬上限;语音超过 4 秒后,出现 160 ms 低于来源阈值 75% 的停顿即可提前释放
历史 400 ms / 4 秒方案80 ms仅保留客户端兼容和反例验证;真实回放出现切句、请求/算力放大与无效翻译,不再作为生产部署配置

客户端必须以 GET /health 返回的 client_audio_chunk_ms 为准,不应硬编码帧长。

上传滑动窗口也随帧长缩放:1000 ms 模式允许 4 帧在途,80 ms 模式允许 50 帧在途, 始终保留 4000 ms 的合计来源音频预算。每帧仍使用精确的 (source, seq) 归档确认与重试语义。

novme 原生 macOS 置顶的实时字幕界面
实时阶段可以显式置顶窗口;置顶是可见的独立状态,不改变字幕内容。

背压与完整性

客户端上传和后端推理是两条独立的背压边界。客户端会保留已采集帧,直到收到服务端 archived 确认;如果上传长期追不上双路采集,客户端会显示积压错误并提前停止采集, 保护已经连续归档的会议记录,而不是静默丢弃新音频。后端每个音频来源的实时识别任务和翻译任务 也有明确上限,超出实时推理容量的内容会转为会后处理。

核心能力

会议复盘

结束会议不是立即清空现场,而是进入可见的收尾阶段,等待已接收音频和待处理任务完成。

复盘内容

  • 按时间排序的源语言逐字稿与翻译。
  • 最终说话人标签。
  • 会议摘要、决策、行动项和风险(有结果时显示)。
  • 由后端记录生成的 Markdown 导出文件。
novme 原生 macOS 正在生成会议记录界面
结束后进入可见的生成阶段,已有逐字稿继续保留,摘要和导出动作暂不出现。
novme 原生 macOS 会议复盘界面
成功复盘默认显示摘要,并允许切换到逐字稿或导出记录。

失败时保留什么

摘要或最终处理失败时,界面保留已经存在的逐字稿,并允许对同一个会议 ID 重试。 novme 不会静默创建替代会议,也不会自动返回设置页掩盖失败。

novme 原生 macOS 会议复盘失败界面
复盘失败时保留逐字稿,并把重试和新会议作为明确操作。

核心能力

音频采集

原生客户端分别管理麦克风与会议应用音频,任何来源的异常都必须可见且可追踪。

麦克风

使用 AVAudioEngine 采集本机输入,并在设置和实时阶段显示音量活动。

会议应用音频

macOS 13+ 使用 ScreenCaptureKit 读取用户明确选择的会议应用。 如果选中的应用退出,客户端会显示失败,不会自动换成另一个应用。

开发与部署

后端 API

FastAPI 后端同时提供会议生命周期 REST 接口和实时音频、字幕 WebSocket。

REST

GET/health严格运行身份、引擎、模型与音频帧契约
POST/meetings创建会议并设置源语言与目标语言
POST/meetings/{id}/finish等待接收屏障并完成复盘
GET/meetings/{id}/segments读取最终字幕段
GET/meetings/{id}/summary读取或生成会议摘要
GET/meetings/{id}/export.md导出后端拥有的 Markdown 记录

创建会议

HTTP
POST /meetings
Content-Type: application/json

{
  "source_lang": "en",
  "target_lang": "zh"
}

WebSocket

路径方向用途
/ws/audio双向客户端发送带来源、序号和时间信息的 PCM 音频帧;后端返回 archiveddeferrederror 状态
/ws/subtitles/{id}后端 → 客户端接收源字幕、翻译更新和类型化状态事件

真实实现

后端处理顺序与有效优先级

novme 没有一个统一的数字优先级队列。当前“优先级”由持久化顺序、每来源串行 ASR、 独立翻译信号量和结束屏障共同形成。

一帧音频的实际处理顺序

顺序实现行为失败或拥塞时
1解码 PCM,追加到会议音频归档;有序客户端还会写入 SQLite audio_chunks 与连续序号。未完成持久化就不发送 archived;错误直接返回给客户端。
2固定模式直接形成推理单元;VAD 模式按 /health 的完整 tuple,把 80 ms 帧按 RMS 组装成至少 1 秒、最多 4 秒或 15 秒的语音段。纯静音段标记完成但不创建字幕;格式、时间线或混合边界 tuple 错误直接失败。
3ASR 按 (meeting_id, source) 串行执行,同一来源保持输入顺序。每来源最多积压 4 个任务;达到上限后转入会后恢复,不无限排队。
4ASR 结果先写入数据库并立即发布源字幕。ASR 失败时保留已归档音频,发送错误并留给结束阶段重跑。
5翻译作为独立任务提交,完成后更新同一个 segment_id 并再次发布。队列满发送 translation_delayed;提供方失败发送 translation_error,源字幕不回滚。

当前队列与并发参数

控制项当前值作用范围
AudioUploadPolicy.inFlightAudioBudgetMs4000 ms原生客户端合计来源音频预算;1000 ms 为 4 帧,80 ms 为 50 帧。
pendingAudioStopThreshold / HardLimit48 s / 60 s原生客户端合计来源音频缓存;80 ms 模式对应 600 / 750 帧,双路采集的墙钟时长约为一半。
NOVME_REALTIME_MAX_PENDING_PER_SOURCE4每个会议、每个音频来源独立计算;同一来源 ASR 串行,麦克风与会议音频可以并行。
NOVME_TRANSLATION_MAX_CONCURRENCY10整个后端进程共享的翻译提供方并发信号量,与 Spark 的 10 个模型槽对齐。
NOVME_TRANSLATION_MAX_PENDING32整个进程中尚未完成的翻译任务总数,不按会议预留配额。
FINISH_BARRIER_TIMEOUT_SECONDS15一次结束请求等待接收、实时 ASR 与翻译收敛的总时限。

翻译和会后总结谁优先

对同一场会议,代码保证的有效顺序如下:

  1. 已确认音频接收:等待客户端上报的最后序号全部进入持久化序列。
  2. 实时工作收敛:等待已登记的音频接收、ASR 和翻译任务。
  3. 补齐翻译:扫描所有有源文本但无译文的字幕段并重新提交翻译。
  4. 翻译硬门禁:仍有缺失译文时,finish 返回 HTTP 502,不生成成功复盘。
  5. 会后处理:重跑延后 ASR、重建顺序音频、执行说话人处理,然后调用总结模型。
  6. 提交最终状态:先保存 summary,再把会议标记为 finalized

翻译请求细节

  • 只翻译当前字幕段,并带上同一音频来源之前最多 2 条字幕作为术语与指代上下文。
  • Spark 请求发送到 /v1/chat/completions,温度 0.1,最多生成 80 tokens,HTTP 超时 30 秒。
  • 提示词要求只返回一行译文,并使用 /no_think;代码会移除 <think> 内容和常见“Translation:”标签。
  • 兼容 /completion 的回退在 Spark 上关闭:NOVME_OPENAI_COMPLETION_FALLBACK=0
  • 翻译成功必须持久化到 SQLite;持久化失败与模型失败同样会进入错误和结束重试路径。

会后总结细节

  • 总结输入使用最终字幕列表,每行格式为 说话人: 译文或原文
  • 当前会把整场逐字稿一次性发送给模型,没有 token 预算计算、分块总结或 map/reduce。
  • 模型必须返回 JSON:summary 为字符串,decisionsaction_itemsrisks 为字符串数组。
  • 正式 finalize 路径严格验证 JSON 类型;解析或字段类型错误会让最终处理失败。
  • citations 不是模型生成的,后端固定附上前 5 个字幕段作为引用材料。
  • Spark 总结最多生成 1024 tokens,本地 MLX 也是同一默认上限。

关键可观测字段

关键日志包含 meeting_idsourceseq、队列深度、模型 ID、 asr_msqueue_msprovider_ms、结束屏障任务数和总耗时。 这些字段用于判断瓶颈是在采集、传输、ASR、翻译排队、模型推理还是最终处理。

真实实现

当前模型与运行参数

下面区分“健康接口模型 ID”“llama-server 服务别名”和“实际模型文件”,三者不是同一概念。

模型选择不是自动切换

启动脚本通过显式的引擎配置选择本地或 Spark profile。严格模式不会因为模型不可用而偷偷换成另一个模型;MiMo 只作为单独的未验收 ASR POC。

Profile选择配置模型职责
Apple Silicon 本地NOVME_SPEECH_ENGINE=mlx-whisper
NOVME_TRANSLATION_ENGINE=mlx
NOVME_SUMMARY_ENGINE=mlx
Whisper Small MLX 做 ASR;共享 Qwen2.5 1.5B MLX 做翻译和总结。
DGX Spark 当前NOVME_SPEECH_ENGINE=qwen3-asr
NOVME_TRANSLATION_ENGINE=openai-compatible
NOVME_SUMMARY_ENGINE=openai-compatible
Qwen3-ASR 做 ASR;Qwen2.5 1.5B 独立负责实时翻译;DeepSeek Chat Q5 独立负责会后复核。
MiMo POCNOVME_SPEECH_ENGINE=mimo-asr只替换 Spark ASR,必须单独部署 loopback sidecar;未完成 GB10 负载、质量和回滚验收,不是默认选项。

当前 Spark 实际部署

以下值在 2026-07-21 通过远端非密钥配置、发布元数据和 /health 严格核对, 当前认证发布为 20260721T162100Z-adaptive-vad;实时翻译与会后复核使用两个独立的 loopback 模型服务,说话人复盘使用独立的 CPU CampPlus 模型,三者不会互相静默回退。

能力引擎 / 模型当前参数与边界
实时 ASRQwen3 ASR
Qwen/Qwen3-ASR-1.7B
固定 revision 7278e1e…dd6e5;BF16;Transformers 离线推理;CUDA 0;单模型锁串行;最多 256 tokens;模型不提供置信概率。
说话人标签CampPlus
iic/speech_campplus_sv_zh-cn_16k-common@v2.0.2
实时阶段仍按来源显示;会议结束后读取完整系统 WAV,在 CPU 上按音色聚类并持久化 对话人1/2/...,模型权重 SHA 和 0.31 阈值由严格健康检查锁定。
实时翻译OpenAI-compatible
qwen2.5-1.5b-realtime-local
80 tokens;前序同来源上下文 2 条;后端并发 10。真实持久字幕顺序测试 P50/P95 为 220/322 ms;英文译中文结果若没有中文会直接报错。
会后复核OpenAI-compatible
deepseek-llm-7b-chat-q5-local
独立端口和两路槽位;分层 map/reduce;1024 tokens 最终输出;135 段真实会议已完成复核与总结。

Qwen3-ASR 使用 qwen-asr==0.0.6transformers==4.57.6 和现有 torch==2.11.0。 模型不返回置信概率,因此字幕记录中的 confidence=0.0 是明确的“不可用”哨兵, /health 同时返回 confidence_available=false,不会伪造固定高置信度。

Spark 实际 GGUF 与 llama.cpp

实时翻译文件/opt/novme/shared/models/qwen2.5-1.5b-instruct-q4_k_m.gguf
实时翻译 SHA-2566a1a2eb6d15622bf3c96857206351ba97e1af16c30d7a74ee38970e434e9407e
实时翻译服务qwen2.5-1.5b-realtime-local @ 127.0.0.1:18081
实时翻译容量40960 / 10 slots / 4096 each
会后复核文件/opt/novme/shared/models/deepseek-llm-7b-chat-q5_k_m.gguf
会后复核 SHA-2565ab7fade2ec4efe8793a1b557694a8e23a573ccccbadd2ef75d706a04a66f6c6
会后复核服务deepseek-llm-7b-chat-q5-local @ 127.0.0.1:18083
会后复核容量8192 / 2 slots / 4096 each

两个 GGUF 文件都与发布元数据中的 SHA-256 一致,部署门禁分别验证路径、哈希、别名、端口与容量。 各自的启动脚本要求总上下文能被槽数整除,并保证每槽至少 4096。历史 DeepSeek R1 Q5 评估因空译文而结束,不是活动配置,也不是失败时的自动回退。

Spark 并发实测

下表是 2026-07-13 的 Qwen 历史容量基线。当前实时 Qwen 对 20 条真实持久字幕顺序测试 P50/P95 为 220/322 ms,十路执行为 775/1056 ms;并发运行 135 段 DeepSeek 会后复核时,实时 Qwen P95 为 982 ms。

并发P50P95最大
138 ms39 ms104 ms
456 ms197 ms197 ms
1087 ms393 ms394 ms

Qwen3-ASR 在 GB10 上的固定 revision 权重峰值分配约 4.376 GiB,缓存加载约 26.8 s。 真实后端回放的四个 1 秒 ASR 请求耗时为 90–215 ms,对应翻译均成功; 当前 Spark 将实时 Qwen 翻译与 DeepSeek 会后复核隔离。短字幕翻译和 135 段会议复核已通过窄范围实机门禁,但持续混合负载、广泛质量以及 4 秒 VAD 候选仍未完成验收。

Apple Silicon 本地 MLX

能力模型运行方式
ASRmlx-community/whisper-small-mlx16 kHz PCM;温度 0;不继承上一段文本;启动时执行 1 秒静音预热。
翻译mlx-community/Qwen2.5-1.5B-Instruct-4bit80 tokens;温度 0;带中英 few-shot 示例。
总结mlx-community/Qwen2.5-1.5B-Instruct-4bit1024 tokens;严格 JSON;与翻译共享同一个已加载运行时。

MLX 翻译和总结按精确模型 ID 共享模型、tokenizer 和一把生成锁,因此同一进程内不会并发操作该运行时。 当前自适应配置使用 80 ms 传输帧,并由后端按来源 RMS 组装语音段:常规 800 ms 静音释放、15 秒硬上限;超过 4 秒后遇到 160 ms 低能量停顿可提前释放。666.56 秒生产模型回放得到 107 段,仅 2 段触发硬上限,ASR 与翻译均无失败。

模型就绪与失败策略

  • 严格模式下,ASR、翻译、说话人和总结引擎任一不可用都会阻止后端启动;模型不会在运行中自动互换。
  • MLX 模型和 Spark Qwen3-ASR 都必须在启动阶段完成加载与一次真实预热推理;失败会阻止严格模式启动。
  • Spark 的 OpenAI-compatible 引擎在启动时探测回环 /health;当前就绪状态是构造时快照,不是持续容量监控。
  • /health 暴露精确引擎名称、配置模型 ID、部署修订和音频/VAD 契约;Spark 部署验证另外核对 GGUF 指纹。

开发与部署

运行模式

严格模式

默认模式。必需引擎不可用、模型身份不匹配或健康契约缺失时,后端和原生客户端都会拒绝继续。

Terminal
export NOVME_ENGINE_MODE=strict
scripts/run-backend.sh

开发模式

仅用于 UI、存储和传输开发。替代引擎会在健康状态中明确标记为降级,不会伪装成正式提供方。

Terminal
NOVME_ENGINE_MODE=development scripts/run-backend.sh

健康契约 v2

/health 必须返回部署修订、配置档、引擎模式、精确模型 ID、协商帧长、RMS 指标、来源专属阈值和完整 VAD 边界。 原生客户端和回放工具会拒绝缺失或不匹配的契约;单纯的 HTTP 200 不是可接受的部署验证。

开发与部署

DGX Spark 部署

当前发布使用受 Bearer 认证保护的直连 HTTP 配置。FastAPI 对外映射到 Spark 的 8080,推理服务仍只绑定远端回环地址。

部署顺序

Terminal
scripts/spark-deploy.sh --execute --maintenance-window
scripts/spark-verify.sh --execute

必须先完成发布验证,再打开客户端。原生客户端不会自动启动 SSH 隧道,也不会预填远端 origin;隧道脚本仍保留为运维访问路径。

Spark 直连

批准的直连 profile 是 direct-http-8080:运维者明确配置的 origin 转发到 Spark 的 FastAPI 0.0.0.0:8080。它要求 Bearer 认证,但 HTTP 不加密 Key、音频、字幕或会议数据,只适合可信网络。实时翻译 18081、会后复核 18083 和可选 MiMo 18082 仍必须保持回环绑定。

Terminal
python3 -c 'import secrets; print("sk-novme-" + secrets.token_urlsafe(32))'

# 将生成的 Key 写入 Spark 的受限 secrets 文件后执行
scripts/spark-deploy.sh --execute --maintenance-window
scripts/spark-verify.sh --execute

专用 Key 写入 Spark 的 /etc/novme/novme.secrets,认证发布验证了缺失/错误 Key 的 HTTP 拒绝和 WebSocket 握手拒绝;同一 Key 由客户端用户在 macOS“设置”的“连接”页保存到 Keychain。HTTPS/WSS 是后续替代明文直连的安全目标,当前没有用它假装已经完成。

当前 Spark 配置

  • 当前发布:20260721T162100Z-adaptive-vaddirect-http-8080、严格模式、强制 Bearer 认证并使用 UMask=0077
  • 实时 ASR:固定 revision 的 BF16 Qwen/Qwen3-ASR-1.7B,Transformers 离线推理,单模型锁串行。
  • 实时翻译:qwen2.5-1.5b-instruct-q4_k_m.gguf,别名 qwen2.5-1.5b-realtime-local,回环端口 18081,十路槽位。
  • 会后复核:非 reasoning 的 deepseek-llm-7b-chat-q5_k_m.gguf,别名 deepseek-llm-7b-chat-q5-local,回环端口 18083,两路槽位。
  • 实时音频:VAD 协商 80 ms 帧,按来源 RMS 阈值分类,常规 800 ms 静音释放并保留 15 秒硬上限;超过 4 秒后,160 ms 低于来源阈值 75% 的停顿会触发软边界。
  • 历史方案:固定 400 ms 静音 / 4 秒硬切已被真实回放拒绝,仅保留兼容测试;当前生产已切到自适应边界。
  • 服务:单用户、单进程、可信运维边界;FastAPI 使用 Spark 0.0.0.0:8080 直连映射,llama-server 和 MiMo 保持回环。

其他

故障排查

客户端提示后端不可用

先访问当前配置对应的 /health:App 内置本地运行时是 http://127.0.0.1:18080/health,仓库开发脚本通常使用 127.0.0.1:8000,远端则使用运维者明确配置的 origin 并带上 Bearer Key。不要只验证端口是否打开,还要核对健康契约中的模型、部署身份和 VAD 参数。

麦克风或会议音频没有活动

检查 macOS 麦克风和屏幕录制权限,确认本地签名证书没有变化,并完全退出后重新打开应用。持续零系统音频会在 5 秒后显示警告。

源字幕正常,但翻译延迟

这通常表示翻译队列饱和或提供方失败。源字幕不会被丢弃;查看类型化事件与后端日志,结束会议后系统会尝试补齐翻译。

提示“音频连接积压达到上限”

这表示双路采集速度持续高于服务端归档确认速度。先检查 Spark 隧道往返延迟和后端归档日志, 再查看客户端的 audio upload protocol configuredaudio archive latency highaudio backlog stopping session 日志。不要只调大缓存阈值来延后失败。

会议结束后复盘失败

保留当前会议 ID 和逐字稿,在复盘界面对同一会议重试。检查结束屏障、待处理翻译和摘要提供方日志,不要新建会议掩盖原始失败。

其他

当前边界

以下能力仍是明确边界,不应从现有实现推断为已完成。

  • 原生 macOS 客户端尚未完成分发签名、公证和正式发布自动化。
  • Spark 的全新主机搭建、真实维护窗口回滚和断电恢复尚未完成实机验收。
  • 后端当前是可信、单用户、单进程运行边界;远端 Bearer 认证已实现,但明文 HTTP、WebSocket Origin、按用户授权、数据保留/删除、备份恢复和全局容量控制仍未完成。
  • 新的 80 ms 上传窗口已通过双路高延迟模拟,但真实 Spark 连接下至少 5 分钟的双路采集验收仍未完成。
  • 实时说话人标签不是最终精确分离结果;会后复盘负责更完整的整理。