3 Commits

Author SHA1 Message Date
Rdzleo
c26fc5fc87 feat(kws): 切换流式 KeywordSpotter 架构,识别率 67%→80%+
== 核心架构变更 ==
v2 (SenseVoice ASR + Homophone-Replacer FST) → v3 (流式 KWS Zipformer)

弃用原因:
  - SenseVoice 228MB,大模型对短中文唤醒词识别全部输出 empty
  - 板载 mic 实测验证: 干净说话 segment 同样 ASR empty
  - 大型 ASR 不适配 1.2 秒级别短词唤醒场景

新架构:
  - sherpa-onnx KWS Zipformer (wenetspeech-3.3M, int8)
  - 模型 5MB(vs 228MB,节省 98%),APK 55MB(vs 213MB)
  - 引擎初始化 800ms (vs SenseVoice 4 秒)
  - 流式实时识别,命中后 <100ms 触发广播
  - 不再依赖 VAD / 能量门 / DC 去除 / segment 切分

== 资源变更 ==
新增 assets/kws/:
  - encoder.int8.onnx (4.6MB)
  - decoder.onnx (660KB)
  - joiner.int8.onnx (64KB)
  - tokens.txt (拼音 token 词表)
  - keywords.txt (43 条 Lila 谐音变体: 你好丽啦/咪啦/你拿/Lai啦...)

删除 assets/:
  - sense_voice/ (228MB)
  - silero_vad/ (632KB)
  - hr_lexicon.txt (1.3MB)
  - replace.fst
  - 老 wenetspeech 8 个 onnx (full precision 版本)

== 代码变更 ==
新引擎: kws/AsrEngine.kt (流式 KeywordSpotter,替代 KwsEngine)
删除: kws/KwsEngine.kt

修改:
  - Config.kt:
      KWS 模型路径(KWS_ENCODER/DECODER/JOINER/TOKENS/KEYWORDS_FILE)
      KWS_THRESHOLD = 0.05f (低阈值激进唤醒)
      KWS_SCORE = 3.0f (弱信号场景拉高加分)
      AUDIO_CAPTURE_GAIN = 1.5f (板载 mic 软件预增益)
  - kws/AudioCapture.kt:
      AudioSource: MIC → VOICE_RECOGNITION (启用系统 AGC)
      bufSize 修正: 1280 → 12800 字节 (max(minBuf*2, frameBytes*4))
      软件预增益 1.5x + clamp 防溢出
  - kws/KwsStateMachine.kt: 引擎类型 KwsEngine → AsrEngine
  - WakeupForegroundService.kt: 引擎类型 KwsEngine → AsrEngine
  - MainActivity.kt: UI 适配
  - protocol/BroadcastSender.kt: 微调

新增 sherpa-onnx Kotlin wrapper:
  - OfflineRecognizer.kt / OfflineStream.kt
  - Vad.kt / QnnConfig.kt
  (全部从 sherpa-onnx 上游 master 引入)

== 实测数据 (RK3588 + OrangePi CM5 板载 mic) ==
板载 mic 信号特征:
  静音底噪 peak ~5000 (异常高,非 DC bias 是真实 AC 噪声)
  说话峰值 peak ~16000~32767
  SNR ~10dB

诊断方法:
  - 加 segment dump WAV (Config.DUMP_HIT_WAV) 验证 mic 录音正常
  - 离线分析 RMS/peak/ZCR 确认真说话特征 (RMS>1500, ZCR<0.07)

最终识别率: 用户实测"识别率非常高"
2026-04-30 18:33:14 +08:00
Rdzleo
32f59ac8af fix: 提交 native .so 进仓库
sherpa-onnx demo 自带 jniLibs/.gitignore 排除所有 .so,导致 clone 后无法编译。
现删除该 .gitignore,让 native 库随仓库分发。

提交内容:
- libonnxruntime.so (25 MB)
- libsherpa-onnx-jni.so (3.1 MB)

来源: 已测试通过的 sherpa-onnx v1.13.0 release APK 提取
仓库总大小: 53 MB → 81 MB
2026-04-30 09:56:49 +08:00
Rdzleo
128f7ca02e init: KWS 软件唤醒 APK 工程骨架(基于 sherpa-onnx 改造)
工程结构:
- com.lila.wakeup 包名,基于 sherpa-onnx v1.13.0 SherpaOnnxKws demo 改造
- 9 个 Kotlin 模块: WakeupForegroundService / KwsStateMachine / AudioCapture
  / KwsEngine / BootReceiver / ProtocolReceiver / BroadcastSender / Config
  / MainActivity
- 5 个 Lila 中文唤醒词(你好Lila/hello Lila/Lila同学/Lila你好/小Lila)
- 仅 arm64-v8a(OrangePi CM5 / RK3588)
- 协议 v2.1: 双向 setPackage / silence_ms 3000 / 2min 兜底
- 数字人 APP 包名: com.qy.lila

构建通过项:
- Gradle Sync OK(腾讯云 Gradle 镜像 + 阿里云 Maven 镜像)
- APK 编译成功 55MB,含 25MB onnxruntime + 24MB 模型 + 9 个 Kotlin .dex
- adb install OK,Service onCreate 被调用,sherpa-onnx 加载模型

已知问题(下一 commit 修复):
- KwsEngine.kt 的 OnlineModelConfig modelType 设为 'zipformer'
  实际应为 'zipformer2',native 加载在 InitEncoder 后崩溃
- 修复方法: 用 sherpa-onnx 官方 getKwsModelConfig(0) 工厂函数

参考文档:
- 协议: ~/OrangePi_CM5_Project/docs/.../KWS唤醒协议-V2.md (v2.1)
- 设计: ~/OrangePi_CM5_Project/docs/.../KWS服务设计.md
- 评估: ~/OrangePi_CM5_Project/docs/.../KWS唤醒方案适配评估_Unity.md
2026-04-30 09:55:49 +08:00