Skip to content

依赖按能力分层(四级语音阶梯)+ 跨平台 Python 修复 - #16

Merged
Lucas1479 merged 20 commits into
Code-Amadeus:mainfrom
Mieluoxxx:fix/cross-platform-python
Sep 2, 2026
Merged

依赖按能力分层(四级语音阶梯)+ 跨平台 Python 修复#16
Lucas1479 merged 20 commits into
Code-Amadeus:mainfrom
Mieluoxxx:fix/cross-platform-python

Conversation

@Mieluoxxx

@Mieluoxxx Mieluoxxx commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Closes #15

为什么按四级分层

依赖分层的目标:安装体积和系统依赖应该跟随用户实际需要的能力
而不是按开发机器上装了什么全量照搬。

达到这个目标的关键观察只有一个:torch 是整个依赖树里唯一的重量级分水岭(约 2GB,且引入 CUDA 相关复杂性),其余语音包(pyaudio、scipy、aec 等)加起来只有几百 MB。所以分层设计的核心问题就是:torch 应该在什么时机进入安装?

四级阶梯总表

梯级 能力 安装方式 torch
L1 core 文字聊天、工作、Provider、角色渲染 pip install -e .
L2 voice 说(远程 TTS、播放、口型)+ 听(麦克风、远程 ASR) pip install -e ".[voice]"
L3 vad 实时打断(角色说话时可以插话) pip install -e ".[voice,vad]"
L4 local-cu124 本地 GPT-SoVITS / Qwen3 ASR / 唤醒词 pip install -e ".[voice,vad,local-cu124]"

按用户画像逐层回答:

  1. 纯文字用户(CI、headless、只需要聊天和工作的开发机):连 pyaudio 都不需要,更不该见 torch → L1
  2. 远程语音用户(大多数桌面用户):推理全部发生在云端,本地只做麦克风采集、播放和口型——纯 numpy/pyaudio 就够,为"能对话"付出 2GB torch 不合理 → L2
  3. 要打断的用户:打断检测的 VAD(silero-vad)在 PyPI 上硬声明 torch>=1.12.0,装它必然带入 torch——这是 torch 无法再往后推的最早时机 → L3
  4. 本地推理用户(有 NVIDIA GPU):模型推理本身需要 torch 和完整模型栈 → L4

每层的划分规则:一个包放进哪层,取决于"哪些能力组合会一起被
需要"——pyaudio/scipy/aec 是任何语音路径的最小公共集;silero 只
服务于打断;模型栈只服务于本地推理。
按这个规则切,L2 用户可以
用几百 MB 获得完整远程对话体验,torch 只在用户真正需要它的能力时
才出现。

这个 PR 做了什么

把依赖清单从「全量一刀切」重构为上述四级,并修复全部阻止非 Windows
环境安装、启动的问题。

1. pyproject.toml 按四级重组

  • base(23 个包):L1 内核,移除 torch/torchaudio/onnxruntime/PyAudio
  • 新增 voice extra:L2 语音交互公共件
  • 新增 vad extra:silero-vad(torch 由它带入)
  • local-cu124:L4 本地模型栈,不再混入语音公共件

2. 无语音环境可以正常启动

以下模块原来在顶层 import torch / import pyaudio,全部改为用到时才导入:

  • tts/playback.py(torch 只用了 torch.is_tensor(),换成鸭子类型判断)
  • asr/barge_in_detector.py
  • asr/mic_input_service.py
  • asr/manager.py(设备选择改为惰性探测,远程 ASR 无 torch 时选 cpu)
  • server/app.py(onnxruntime 预加载加存在性检查)

新增测试 tests/test_core_install_tiers.py:把 9 个语音/推理包全部
屏蔽后,import server.app 必须成功。

3. 没有 vad 层时,语音输入自动降级为能量端点

capture_utterance 支持 vad_model=None:语音开始按 ASR_ENERGY_START_RMS(默认 0.02)判定,结束沿用既有能量路径(ASR_ENERGY_END_RMS/ASR_ENERGY_END_MS,迟滞避免抖动)。
代价是噪声环境准确率下降;装上 vad 层即恢复 silero 精准端点。

4. venv Python 路径跨平台

新增 config/environment.py::venv_python(),自动区分 Windows(Scripts/python.exe)和 macOS/Linux(bin/python3)。asr 里 4 处写死的 Windows 路径全部改为调用它。

5. API key 容错

config/settings.py 新增 _secret():读取 API key 时自动去掉首尾引号和空格。之前 .env 里 key 末尾多一个引号会导致 401,报错很难定位。

6. 锁文件与工具链同步

  • windows-py312-cpu.txt:76 个包,纯 L1,不再含 torch
  • windows-py312-ci.txt:106 个包,L1 + dev,不再含 torch
  • requirements-cu124.txt:补上遗漏的 voice extra
  • 锁生成器从 pip-tools 迁移到 uv(--python-platform windows),
    macOS/Linux 也能重新生成 Windows 锁;锁头不再泄漏本机路径
  • verify_python_environment.pytools/run_tests.py 按 L1 语义校验,
    梯级测试在依赖缺席时自动跳过(pytest 退出码 5 + skipped 视为健康)

验证

  • 相关测试 96+ 全部通过;新增契约测试 4 个
  • macOS(M4 Max)实测:L1 无音频环境可安装可启动;L2 远程 TTS(MiMo)播放 + 口型同步正常
  • Windows CI(Python + Electron 两个 job)通过

对 Windows 用户的影响

无。requirements-cu124.txt 全量安装路径不变,锁文件只是内容更新。

Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Aug 30, 2026
- BASE_IMPORTS 移除 onnxruntime/pyaudio/torch/torchaudio(它们属于
  voice / local-cu124 梯级,不再是内核必检项)
- ci profile:仅校验 T1 内核 + 项目导入(model-less 语义)
- cpu profile:T1 + voice 公共件
- cu124 profile:完整栈 + torch 2.5.1+cu124 版本与设备检查保留
- 修复 PR Code-Amadeus#16 CI:新 ci 锁正确地不含 onnxruntime,
  旧验证器却仍要求导入导致 Verify environment 步骤失败
@Mieluoxxx Mieluoxxx changed the title 依赖按能力分层 + 跨平台 Python 修复 依赖按能力分层(四级语音阶梯)+ 跨平台 Python 修复 Aug 30, 2026

@Lucas1479 Lucas1479 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

整体方向我赞同:把依赖按 core / voice / vad / local-cu124 分层、移除 L1 启动链上的 PyAudio/Torch 顶层导入、统一跨平台 venv Python 路径,都是正确的结构性修复。Windows 的 Python/Electron CI 已通过;我也用现有 cu124 环境跑了相关测试(39 passed)和完整测试(1679 passed、1 skipped),没有发现既有运行逻辑回归。

不过当前版本的安装合同还有几个确定性问题,建议修复后再合并:

1. requirements-cu124.txt 漏装 vad

最终提交已把 silero-vadvoice / local-cu124 移到独立的 vad extra,但 requirements-cu124.txt 仍然是:

.[voice,local-cu124]

这会导致全新 CUDA 基线安装缺少 silero_vad、失去实时打断,并在 verify_python_environment.py --profile cu124 中导入失败。因此“Windows 用户无影响”目前不成立。这里应至少改成:

.[voice,vad,local-cu124]

并增加一个测试,冻结官方 cu124 profile 必须包含 voice + vad + local-model 三组直接能力。

2. cpu verifier 与 CPU lock 自相矛盾

新的 windows-py312-cpu.txt 是纯 L1 core,不包含 PyAudio、SciPy 或 silero-vad;但 verify_python_environment.pyprofile in {"cpu", "cu124"} 强制导入 VOICE_IMPORTS,而 VOICE_IMPORTS 里还包含 silero_vad

因此 README 当前推荐的全新 CPU/model-less 安装完成后,执行:

verify_python_environment.py --profile cpu

会必然失败。

建议把验证合同显式拆开,例如:

  • ci/core:仅 L1;
  • voice:L1 + L2;
  • vad:L1 + L2 + L3;
  • cu124:L1 + L2 + L3 + L4。

至少也要保证现有 cpu 名称与它实际安装的纯 core lock 完全一致,并为各 profile 的 required imports / extras 建立契约测试。

3. “依赖缺席”与“依赖已安装但损坏”需要区分

server/app.py 当前会捕获 ONNX Runtime 实际导入阶段的所有 ImportError。如果包存在但 DLL 或其依赖损坏,也会被当作“L1 没安装可选包”静默略过。

ASRManager._init_vad() 同样捕获所有异常并切到能量端点。L2 确实未安装 VAD 时可以显式降级;但 L3/L4 已安装 VAD、加载却失败时,应暴露损坏/不可用状态,而不应伪装成正常的能力缺席。

建议只对明确的包缺席执行降级;包存在后的加载错误应失败或进入可观察的 degraded/health 状态。提示文字中的 install -e '.[vad'] 引号也需要修正。

4. 四层合同需要落入仓库文档和可复现验证

目前 L1–L4 的完整说明主要存在于 PR 描述中;README 没有对应的 voice / vad 安装与验证命令,requirements/locks/README.md 仍写“三层”,也没有可复现的 L2/L3 clean-install 验证。

建议在本 PR 内补齐:

  • 四层安装命令和每层能力/降级边界;
  • requirements-cu124.txt 与锁文件说明;
  • 至少静态 profile 契约测试,以及 L1/L2 的 clean resolver/import smoke;
  • 不把 macOS 描述为正式支持平台,直到安装、CI 和真实设备旅程都形成持续证据。

另外,API key 自动去引号与 Issue #15 的依赖/跨平台启动问题没有共同根因,建议拆成独立 PR;这不是上述 profile 修复的核心阻塞项。

总体结论:方案无需推倒重来,修正 profile 闭环和错误降级边界后可以进入主线。修订后我愿意继续复审。

Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Aug 31, 2026
回应 PR Code-Amadeus#16 评审(CHANGES_REQUESTED):

1. requirements-cu124.txt 补上遗漏的 vad extra
   (silero-vad 移入独立 extra 后 CUDA 基线丢失实时打断)
2. verify_python_environment 的 profile 语义与锁对齐:
   cpu 恢复为纯 L1 校验;新增 voice profile(L1+voice);
   cu124 校验 voice+vad+local 全量;silero_vad 归 VAD_IMPORTS
3. 区分「依赖缺席」与「依赖损坏」:
   - server/app.py:onnxruntime 预载仅跳过以自身命名的
     ModuleNotFoundError(支持缺席);依赖损坏重新抛出
   - ASRManager._init_vad:silero 缺席 → 能量端点降级(L2 语义);
     已安装但加载失败 → 记录 _vad_degraded 并 ERROR 标记 DEGRADED,
     不再伪装成能力缺席
4. 四层合同落入仓库:README 四级阶梯表、locks README 更新、
   新增 tests/test_profile_contract.py(extras 组成冻结、
   profile 导入映射校验、cu124 组成校验、uv resolver smoke:
   torch 仅从 vad 层进入解析)

按评审建议,API key 引号容错已从本 PR 拆出(另行提交)。
@Mieluoxxx

Mieluoxxx commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

感谢细致的评审,四点全部认同并已修复(bbf11cc):

  1. cu124 组成requirements-cu124.txt 已改为 .[voice,vad,local-cu124]
  2. cpu profile 自相矛盾:cpu 恢复为纯 L1 校验;新增 voice profile(L1+voice);silero_vad 移入独立的 VAD_IMPORTS
  3. 缺席 vs 损坏
    • server/app.py:预载只跳过以自身命名的 ModuleNotFoundError
      (支持缺席);依赖损坏会重新抛出,不再吞掉。
    • _init_vad:silero 缺失 → 能量端点降级(L2 语义,INFO 级日志);
      已安装但加载失败 → _vad_degraded 记录 + ERROR 级 DEGRADED 标记。
    • 提示文案引号已修正('.[vad]')。
  4. 四层合同落库:README 四级阶梯表、locks README 更新;
    新增 tests/test_profile_contract.py——extras 组成冻结、profile
    导入映射校验、cu124 组成校验、以及 uv resolver smoke(L2 解析无 torch,vad 层起 torch 进入)。L1/L2 的导入冒烟
    即原有的 test_core_install_tiers(探针已改为带 name= 的 ModuleNotFoundError,与真实缺席语义一致)。

另外按建议:API key 引号容错已拆出为独立 PR #20,本分支已回退该改动。

Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Aug 31, 2026
- BASE_IMPORTS 移除 onnxruntime/pyaudio/torch/torchaudio(它们属于
  voice / local-cu124 梯级,不再是内核必检项)
- ci profile:仅校验 T1 内核 + 项目导入(model-less 语义)
- cpu profile:T1 + voice 公共件
- cu124 profile:完整栈 + torch 2.5.1+cu124 版本与设备检查保留
- 修复 PR Code-Amadeus#16 CI:新 ci 锁正确地不含 onnxruntime,
  旧验证器却仍要求导入导致 Verify environment 步骤失败
Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Aug 31, 2026
回应 PR Code-Amadeus#16 评审(CHANGES_REQUESTED):

1. requirements-cu124.txt 补上遗漏的 vad extra
   (silero-vad 移入独立 extra 后 CUDA 基线丢失实时打断)
2. verify_python_environment 的 profile 语义与锁对齐:
   cpu 恢复为纯 L1 校验;新增 voice profile(L1+voice);
   cu124 校验 voice+vad+local 全量;silero_vad 归 VAD_IMPORTS
3. 区分「依赖缺席」与「依赖损坏」:
   - server/app.py:onnxruntime 预载仅跳过以自身命名的
     ModuleNotFoundError(支持缺席);依赖损坏重新抛出
   - ASRManager._init_vad:silero 缺席 → 能量端点降级(L2 语义);
     已安装但加载失败 → 记录 _vad_degraded 并 ERROR 标记 DEGRADED,
     不再伪装成能力缺席
4. 四层合同落入仓库:README 四级阶梯表、locks README 更新、
   新增 tests/test_profile_contract.py(extras 组成冻结、
   profile 导入映射校验、cu124 组成校验、uv resolver smoke:
   torch 仅从 vad 层进入解析)

按评审建议,API key 引号容错已从本 PR 拆出(另行提交)。
@Mieluoxxx
Mieluoxxx force-pushed the fix/cross-platform-python branch from bbf11cc to 60164e1 Compare August 31, 2026 04:44
@Mieluoxxx
Mieluoxxx requested a review from Lucas1479 September 1, 2026 01:10

@Lucas1479 Lucas1479 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢继续跟进。上轮提出的 cu124 补 vad、CPU profile/lock 对齐、依赖缺席与损坏区分,以及四层文档,这些方向已经基本修正,不需要推倒重来。复核当前 head 60164e1 后,还剩以下问题:

  1. #20 改动仍未拆出:回复称 secret patch 已回退,但当前分支仍包含 _secret()tests/test_secret_parsing.py,与 #20 的 stable patch-id 相同。请从本 PR 删除,待 #20 修好后再 rebase。
  2. Windows 编码失败tests/test_profile_contract.py:65 读取 pyproject.toml 未指定 UTF-8。中文 Windows/CP936 下可复现 UnicodeDecodeError: gbk;请显式指定 encoding="utf-8"
  3. resolver smoke 被 CI 跳过:关键用例依赖 uv,但 workflow 没有安装它;绿色 CI 实际是 4 passed, 1 skipped,因此 L2 无 torch、L3 引入 torch/silero-vad 的合同没有进入门禁。请在 CI 安装固定版本的 uv,并确保该用例实际运行。
  4. 缺少独立 L3 验证:验证器只有 cpu / ci / voice / cu124;既然公开声明独立 vad 层,应提供 L1+L2+L3 的 profile。
  5. degraded 状态不可观察:VAD 已安装但加载失败时只设置私有 _vad_degraded 和日志;公开 health/status 仍可能显示 ASR ready。请将原因纳入公开、可测试的状态。

补齐以上闭环并重新运行 profile、CI 与 health/status 测试后,请再次请求 review。

Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Sep 1, 2026
1. 拆出 API key 容错改动(revert 60164e1,见 f6d0e06,移交 Code-Amadeus#20)
2. test_profile_contract 读取 pyproject 显式 encoding="utf-8"(CP936 兼容)
3. CI 安装 uv==0.12.8,resolver smoke 不再被静默跳过;补输出目录 mkdir
4. verify_python_environment 提取 PROFILE_TIER_IMPORTS 阶梯映射,
   新增 vad profile(L1+L2+L3);--profile choices 由映射生成防漂移;
   阶梯契约测试冻结严格前缀链
5. asr/manager 新增公开 vad_status()(ready/fallback/degraded 三态),
   runtime_status 投影 snapshot["vad"]/["vad_degraded"],
   readiness 在 vad=="degraded" 时判 False(L2 fallback 保持 ready)

文档同步:README 梯级验证命令、locks README 验证阶梯说明。
Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Sep 1, 2026
- BASE_IMPORTS 移除 onnxruntime/pyaudio/torch/torchaudio(它们属于
  voice / local-cu124 梯级,不再是内核必检项)
- ci profile:仅校验 T1 内核 + 项目导入(model-less 语义)
- cpu profile:T1 + voice 公共件
- cu124 profile:完整栈 + torch 2.5.1+cu124 版本与设备检查保留
- 修复 PR Code-Amadeus#16 CI:新 ci 锁正确地不含 onnxruntime,
  旧验证器却仍要求导入导致 Verify environment 步骤失败
Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Sep 1, 2026
回应 PR Code-Amadeus#16 评审(CHANGES_REQUESTED):

1. requirements-cu124.txt 补上遗漏的 vad extra
   (silero-vad 移入独立 extra 后 CUDA 基线丢失实时打断)
2. verify_python_environment 的 profile 语义与锁对齐:
   cpu 恢复为纯 L1 校验;新增 voice profile(L1+voice);
   cu124 校验 voice+vad+local 全量;silero_vad 归 VAD_IMPORTS
3. 区分「依赖缺席」与「依赖损坏」:
   - server/app.py:onnxruntime 预载仅跳过以自身命名的
     ModuleNotFoundError(支持缺席);依赖损坏重新抛出
   - ASRManager._init_vad:silero 缺席 → 能量端点降级(L2 语义);
     已安装但加载失败 → 记录 _vad_degraded 并 ERROR 标记 DEGRADED,
     不再伪装成能力缺席
4. 四层合同落入仓库:README 四级阶梯表、locks README 更新、
   新增 tests/test_profile_contract.py(extras 组成冻结、
   profile 导入映射校验、cu124 组成校验、uv resolver smoke:
   torch 仅从 vad 层进入解析)

按评审建议,API key 引号容错已从本 PR 拆出(另行提交)。
Mieluoxxx added a commit to Mieluoxxx/Amadeus that referenced this pull request Sep 1, 2026
1. 拆出 API key 容错改动(revert 60164e1,见 f6d0e06,移交 Code-Amadeus#20)
2. test_profile_contract 读取 pyproject 显式 encoding="utf-8"(CP936 兼容)
3. CI 安装 uv==0.12.8,resolver smoke 不再被静默跳过;补输出目录 mkdir
4. verify_python_environment 提取 PROFILE_TIER_IMPORTS 阶梯映射,
   新增 vad profile(L1+L2+L3);--profile choices 由映射生成防漂移;
   阶梯契约测试冻结严格前缀链
5. asr/manager 新增公开 vad_status()(ready/fallback/degraded 三态),
   runtime_status 投影 snapshot["vad"]/["vad_degraded"],
   readiness 在 vad=="degraded" 时判 False(L2 fallback 保持 ready)

文档同步:README 梯级验证命令、locks README 验证阶梯说明。
@Mieluoxxx
Mieluoxxx force-pushed the fix/cross-platform-python branch from 0699ef5 to ba9f833 Compare September 1, 2026 12:03
- pyproject:base 瘦身为 T1 对话内核(移除 torch/torchaudio/onnxruntime/PyAudio);
  新增 voice extra(播放/采集/AEC/barge-in 跨平台公共件);
  local-cu124 纯化为 T2b 本地推理栈
- tts/playback.py:torch/pyaudio 惰性化(_is_tensor_like 鸭子类型 +
  initialize 内导入),模块在无音频环境可安全导入
- server/app.py:onnxruntime 预载加 find_spec 守卫,本地栈缺席时跳过
- config/settings.py:新增 _secret(),API key 读取自动去首尾空白与引号
- config/environment.py:新增 venv_python() 统一 venv 解释器路径
  (Windows Scripts/python.exe vs Unix bin/python3),
  修复 asr/registry.py 与 qwen3_asr.py 的 Windows 路径写死
- tests/test_core_install_tiers.py:T1 契约测试——屏蔽 9 个语音/推理包后
  import server.app 必须成功;secret 清洗测试
- requirements-cu124.txt 修复遗漏的 voice extra(依赖分层后的回归:
  缺失会导致 CUDA 安装丢失播放/采集/AEC 公共件)
- windows cpu/ci 锁重新生成:cpu 76 包纯 T1 内核,ci 106 包无 torch
  (此前均含 torch/torchaudio/onnxruntime/pyaudio 全量)
- dev extra 移除 torchmetrics(无 live caller;真实使用方 GPT_SoVITS
  由 local-cu124 承载)
- 锁生成器迁移到 uv pip compile --python-platform windows,
  任意平台可再生成(原 pip-tools 方案必须在 Windows 上跑);
  移除 lock extra
- BASE_IMPORTS 移除 onnxruntime/pyaudio/torch/torchaudio(它们属于
  voice / local-cu124 梯级,不再是内核必检项)
- ci profile:仅校验 T1 内核 + 项目导入(model-less 语义)
- cpu profile:T1 + voice 公共件
- cu124 profile:完整栈 + torch 2.5.1+cu124 版本与设备检查保留
- 修复 PR Code-Amadeus#16 CI:新 ci 锁正确地不含 onnxruntime,
  旧验证器却仍要求导入导致 Verify environment 步骤失败
model-less CI 环境(T1 内核)没有 pyaudio/torch,这两个测试文件
在收集阶段因项目模块的顶层导入而报错。改为 pytest.importorskip:
缺哪个梯级的依赖就跳过哪个测试,本地全量环境行为不变。
uv pip compile 会把完整命令行写入锁头注释;改用相对路径输出,
避免 private-unix-home-path 源码策略违规
run_tests.py 的声明清单不变量新增导入探针:测试模块因缺少
voice/local-model 梯级依赖而无法导入时(importorskip 场景),
其声明视为合法缺席;导入成功却未收集到仍判定为命名漂移违规
pytest 9.1 起 importorskip 默认只捕获 ModuleNotFoundError,
而 CI 锁(pytest 8.4.2)会抛 Skipped;探针对两种形态都放行
- test_speculative_turn / test_system_settings 的个别用例运行时才触发
  torch/pyaudio 导入,改为用例内 importorskip
- run_tests.py:整模块被梯级跳过(collected=0, skipped>0)视为健康,
  不再误报为失败套件
- asr/barge_in_detector.py:模块级 import torch 移入 _run(VAD 循环
  仅在 voice 环境启动后运行),修复 model-less CI 的 Electron smoke
  超时(bootstrap → barge_in → torch 崩溃)
- server/app.py:onnxruntime 预载守卫改为 try/except ImportError,
  对真实缺席与探测环境都健壮
- T1 契约测试探针改用 find_spec 抛 ModuleNotFoundError 语义
- asr/mic_input_service.py:模块级 pyaudio/torch 移入使用点
  (_run 采集线程 / record 的 VAD 喂入),bootstrap 经 barge-in
  可达本模块,model-less 环境不再崩溃
- asr/barge_in_detector.py:mic_input_service 导入移入 _run
四层能力阶梯定稿:
  L1 core          对话内核(base)
  L2 voice         语音交互:远程 TTS 播放/口型/字幕 + 麦克风 + 远程 ASR(无 torch)
  L3 vad           实时打断:silero VAD barge-in(torch 由此进入)
  L4 local-cu124   本地语音智能:本地 TTS/ASR/唤醒词

- pyproject:silero-vad 移出 voice extra → 独立 vad extra;
  L2 安装从 ~2.5GB 缩到几百 MB
- asr/manager.py:模块级 torch 移除,设备选择经 _torch_runtime()
  惰性探测(远程后端在无 torch 环境选 cpu 加载);
  _init_vad 失败不再 raise,降级为能量端点并提示安装 vad extra
- asr/mic_input_service.py:capture_utterance 支持 vad_model=None 的
  能量端点回退(speech start 按 ASR_ENERGY_START_RMS 判定,
  结束/投机端点复用既有能量路径)
- config/settings.py:新增 ASR_ENERGY_START_RMS(默认 0.02,
  与结束阈值 0.008 形成迟滞)
回应 PR Code-Amadeus#16 评审(CHANGES_REQUESTED):

1. requirements-cu124.txt 补上遗漏的 vad extra
   (silero-vad 移入独立 extra 后 CUDA 基线丢失实时打断)
2. verify_python_environment 的 profile 语义与锁对齐:
   cpu 恢复为纯 L1 校验;新增 voice profile(L1+voice);
   cu124 校验 voice+vad+local 全量;silero_vad 归 VAD_IMPORTS
3. 区分「依赖缺席」与「依赖损坏」:
   - server/app.py:onnxruntime 预载仅跳过以自身命名的
     ModuleNotFoundError(支持缺席);依赖损坏重新抛出
   - ASRManager._init_vad:silero 缺席 → 能量端点降级(L2 语义);
     已安装但加载失败 → 记录 _vad_degraded 并 ERROR 标记 DEGRADED,
     不再伪装成能力缺席
4. 四层合同落入仓库:README 四级阶梯表、locks README 更新、
   新增 tests/test_profile_contract.py(extras 组成冻结、
   profile 导入映射校验、cu124 组成校验、uv resolver smoke:
   torch 仅从 vad 层进入解析)

按评审建议,API key 引号容错已从本 PR 拆出(另行提交)。
.env 中 key 末尾多一个引号会导致 401 鉴权失败且难以定位。
新增 _secret() 读取器:DEEPSEEK/OPENAI/GEMINI/TTS/MIMO/ASR 六个
key 统一去除首尾空白与成对引号。
1. 拆出 API key 容错改动(revert 60164e1,见 f6d0e06,移交 Code-Amadeus#20)
2. test_profile_contract 读取 pyproject 显式 encoding="utf-8"(CP936 兼容)
3. CI 安装 uv==0.12.8,resolver smoke 不再被静默跳过;补输出目录 mkdir
4. verify_python_environment 提取 PROFILE_TIER_IMPORTS 阶梯映射,
   新增 vad profile(L1+L2+L3);--profile choices 由映射生成防漂移;
   阶梯契约测试冻结严格前缀链
5. asr/manager 新增公开 vad_status()(ready/fallback/degraded 三态),
   runtime_status 投影 snapshot["vad"]/["vad_degraded"],
   readiness 在 vad=="degraded" 时判 False(L2 fallback 保持 ready)

文档同步:README 梯级验证命令、locks README 验证阶梯说明。
rebase 到 upstream/main 后合入的 test_t2s_static_kv_mask 与
test_local_tts_semantic_guard 在模块顶层 import torch(及经
GPT_SoVITS/local_tts_infer 间接依赖 torchmetrics/librosa),
与无 torch 的 ci 锁在 merge preview 中相撞,收集阶段即崩溃。

按既有梯级跳过模式补 importorskip 双守卫:
- torch 缺席(L1–L3)→ 跳过
- torch 存在但 local-cu124 extra 缺席(torchmetrics/librosa)→ 跳过

验证:无 torch 模拟双 SKIPPED;有 torch 无 L4 extra 收集 2 skipped
无 error;ruff 通过。
- asr/mic_input_service.py:self._pa 的 pyaudio 类型注解改经
  TYPE_CHECKING 导入(跟随 server/handlers 先例),修复惰性化后
  模块级 pyaudio 缺失导致的 F821(rebase 后由全库 ruff 暴露)
- python-windows.yml:Install/Check source/Build Electron 三处
  shell 由 pwsh 改 bash——Actions 的 bash 以 -e 运行,任一命令
  失败即 fail 步骤;此前 pwsh 多命令步骤只取最后一条退出码,
  ruff 的 F821 曾被 generate_views 的 exit 0 吞掉(与 resolver
  smoke 假绿灯同性质)
@Mieluoxxx
Mieluoxxx force-pushed the fix/cross-platform-python branch from ba9f833 to b9600e0 Compare September 2, 2026 01:44
asr/microphone.py 顶层 import pyaudio 经 mic_input_service 的模块级
from asr.microphone import ... 泄漏到所有 import 者(Code-Amadeus#36 handoff 测试、
asr/manager、asr/wake_service),model-less CI 收集直接崩溃。

- mic_input_service.py:microphone 四符号改函数内惰性导入;
  MicDeviceDescriptor 进 TYPE_CHECKING;configured_device_index() 读配置
  在无 voice tier 时降级 None(缺席→默认设备)。
- manager.py:模块级 configured_device_index() 调用改首次实例化惰性
  解析(类属性语义与 set_microphone_index 覆写行为不变),同样的
  None 降级。
- test_mic_input_handoff_endpointing.py:fixture 对 torch 补 shim
  (torch 在该路径仅 from_numpy 胶水,scripted VAD 忽略输入),
  测试在无 voice/vad tier 环境照常运行。
- test_core_install_tiers.py:T1 探针扩展 import asr.mic_input_service
  与 asr.manager,冻结 asr 模块的 T1 可导入合同。
@Mieluoxxx
Mieluoxxx requested a review from Lucas1479 September 2, 2026 03:30

@Lucas1479 Lucas1479 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复核当前 head 1a5d256:前两轮要求的 cu124/vad 组成、profile 阶梯、UTF-8、固定 uv resolver、公开 VAD degraded 状态以及 #20 拆分均已落实;build、cpu-model-less CI 与本地相关测试通过。四级依赖方案的主要合同已经闭合。

有两点非阻塞建议:

  1. L2 合同不承诺 barge-in;在 L2 环境中额外开启默认关闭的 AEC_REALTIME_ENABLED/AEC_REALTIME_BARGE_IN 时,当前实现会停止检测线程、记录异常并发出 barge_in_error,已经 fail closed 且可观察。后续若有真实用户遇到这一配置组合,可以优先把错误提示改成明确说明需要安装 vad extra;现阶段不需要为此新增能力状态或另一层防御。

  2. tests/test_speculative_turn.py::test_manager_on_result_callback() 实际不依赖 torch。建议删除 pytest.importorskip("torch"),让 model-less CI 继续覆盖远程 ASR 的投机回调;这是测试覆盖改进,不影响当前运行合同和合并判断。

结论:上述建议均不阻塞合并,当前 head 可以批准。

@Lucas1479 Lucas1479 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复核当前 head 1a5d256,前两轮阻塞项已经闭合。现有两点仅为非阻塞建议:后续可改善 L2 误开 barge-in 时的缺少 vad extra 提示,并移除不必要的 torch 测试跳过以保留 model-less CI 覆盖。它们不影响当前运行合同与合并判断。

批准合并。

@Lucas1479
Lucas1479 merged commit f5a5850 into Code-Amadeus:main Sep 2, 2026
2 checks passed
Lucas1479 pushed a commit that referenced this pull request Sep 3, 2026
## 问题

`.env` 中 API key 末尾多一个引号(例如复制粘贴时带上的)会让鉴权串
变成畸形值,表现为 401 Unauthorized,报错完全不会指向引号这个原因,
排查成本很高。

## 修复

`config/settings.py` 新增 `_secret()` 读取器,六个 key
(DEEPSEEK / OPENAI / GEMINI / TTS / MIMO / ASR)统一去除首尾空白与
成对引号后使用。

## 测试

`tests/test_secret_parsing.py`:带引号+空白的 key 经 settings 读取后
等于干净值。

## 说明

该改动原在 #16 中,按评审意见拆出为独立 PR(与依赖分层无共同根因)。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

非 Windows 平台安装与启动的 4 个问题

2 participants