feat(ui): add floating caption window with live transcription

Add a frameless always-on-top caption window wired to the live capture
pipeline. Silence-based segmentation gates the audio so the model never
sees silence, and the panel background is painted in paintEvent with a
configurable opacity instead of a style sheet.

新增悬浮字幕窗(无边框、置顶、可折叠/展开),接入实时采集与流式转写。
分段由静音检测驱动,静音期间不送音频,避免模型对静音产生幻觉。底板
改为在 paintEvent 中绘制,不透明度可调。
This commit is contained in:
blumia committed 2026-10-12 13:32:16 +08:00
1 parent 21d68e2294
commit 4ed4e23282
14 files changed
+803 -259

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
#pragma once
#include <QObject>
#include <QString>
#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include "audio.h"
#include "streamingasr.h"
namespace lc {
class Qwen3Asr;
// 实时字幕:采集默认输出 → 流式转写 → 用信号把文本推给 UI。
// 分段由静音检测驱动:句子之间的自然停顿就收束一段、清空上下文,
// 这样解码器的上下文不会无限增长(见 docs/phase2-streaming.md)。
class LiveTranscriber : public QObject {
Q_OBJECT
public:
explicit LiveTranscriber(Qwen3Asr & asr, QObject * parent = nullptr);
~LiveTranscriber() override;
bool start(const StreamOptions & opts, QString * error = nullptr);
void stop();
QString deviceName() const;
Q_SIGNALS:
// committed = 已稳定文本;tail = 不稳定尾部(UI 用暗色显示)
void caption(const QString & committed, const QString & tail, const QString & language);
void failed(const QString & message);
private:
void workerLoop();
Qwen3Asr & asr_;
MonitorCapture capture_;
StreamOptions opts_;
std::thread worker_;
std::mutex mutex_;
std::condition_variable cv_;
std::vector<float> pending_;
bool quit_ = false;
};
} // namespace lc