#pragma once #include #include #include #include namespace lc { class Qwen3Asr; // 官方流式解码的参数(见 docs/phase2-streaming.md) struct StreamOptions { double chunkSec = 2.0; // 累积多少秒音频跑一步 double windowSec = 16.0; // 仅 window 模式使用:滑窗上限,<=0 表示不滑窗 int unfixedTokenNum = 5; // 前缀回滚:丢掉最后 N 个 token int unfixedChunkNum = 2; // 前 N 个 chunk 不带前缀(冷启动) int maxTokensPerStep = 256; // true = 增量 KV 复用:只编码新音频,已解码音频留在 KV(推荐) // false = 每次重编码整个窗口(Phase 2 早期的做法,仅用于对比) bool incremental = true; // 单段最长时长(秒):超过就提交并重置上下文(0 = 不限)。 // 真实场景应由静音检测决定分段;这里是一个兜底上界, // 因为解码器对 KV 的注意力随总长增长,段太长单步会超预算。 double maxUtteranceSec = 30.0; }; // 把「累积音频 → 带前缀继续生成 → 前缀回滚」这套策略封装起来。 // 输出分两部分: // committed —— 已稳定文本(就是下一步要回喂的前缀) // full —— 含不稳定尾部(最后 unfixedTokenNum 个 token) class StreamingAsr { public: struct Step { int chunkIndex = 0; std::string language; std::string committed; // 稳定部分 std::string tail; // 不稳定尾部(committed 之后的部分) std::string full; // 含不稳定尾部 std::string rawFull; // 未 trim 的完整文本(含 language 头) double windowSeconds = 0.0; double encodeSeconds = 0.0; double inferSeconds = 0.0; int audioTokens = 0; bool ok = true; std::string error; }; StreamingAsr(Qwen3Asr & asr, StreamOptions opt = {}); // 喂入 16k 单声道音频;每凑够 chunkSec 就跑一步并回调 void feed(const float * pcm, size_t n, const std::function & onStep); // 处理不足一块的残留音频,并作为最后一步提交全部文本。 // 若没有待处理音频,也把当前已稳定文本提交为最终(静音分段时会用到)。 void flush(const std::function & onStep); // 结束当前这段(例如检测到静音):清空 KV 与状态,下一段重新开始 void reset(); // 重置全部状态(含历史文本) void resetAll(); // 全部已提交文本(含此前各段,已剥离 language 头) std::string committedText() const; const std::string & language() const { return language_; } int chunkCount() const { return chunkIndex_; } private: void runStep(const std::vector & audio, bool finalStep, const std::function & onStep); Qwen3Asr & asr_; StreamOptions opt_; std::vector buffer_; // window 模式:当前窗口音频 std::vector pending_; // 尚未凑够一块的音频 double totalSeconds_ = 0.0; std::string committedRaw_; // 当前段的原始已提交文本(含 language 头,用于回喂) std::string historyText_; // 此前各段已提交的正文(已剥离 language 头) std::string language_; int chunkIndex_ = 0; }; } // namespace lc