refactor: split core/ui/apps targets and add unit tests
Move all business logic into liblivecaption_core (no Qt dependency) and the widgets into liblivecaption_ui, leaving two executables: the caption window and the CLI, which no longer links Qt Widgets. Abstract the ASR backend behind IAsr so the streaming policy and the live pipeline can be tested with a scripted fake backend instead of a real model. 把全部业务逻辑下沉到不依赖 Qt 的 liblivecaption_core,界面独立成 liblivecaption_ui,拆出悬浮窗与命令行两个可执行程序(CLI 不再链接 Qt Widgets);并用 IAsr 抽象推理后端,使流式策略与实时管线可脱离真模型 用假实现做单元测试。测试还抓到一个真 bug:段恰好结束在 chunk 边界时 只提交了稳定部分,最后几个词被丢掉,已修。
This commit is contained in:
1 parent
4ed4e23282
commit
736ec14d5b
32 files changed
+1502
-655
No files matched your search
@@ -0,0 +1,79 @@
|
||||
#include "transcript.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
namespace lc {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string trim(const std::string & s)
|
||||
{
|
||||
const auto notSpace = [](unsigned char c) { return !std::isspace(c); };
|
||||
auto begin = std::find_if(s.begin(), s.end(), notSpace);
|
||||
auto end = std::find_if(s.rbegin(), s.rend(), notSpace).base();
|
||||
if (begin >= end) return {};
|
||||
return std::string(begin, end);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ParsedTranscript parseAsrOutput(const std::string & raw)
|
||||
{
|
||||
ParsedTranscript out;
|
||||
|
||||
static const std::string kMarker = "<asr_text>";
|
||||
const std::string trimmed = trim(raw);
|
||||
|
||||
const auto markerPos = trimmed.rfind(kMarker);
|
||||
std::string head;
|
||||
if (markerPos != std::string::npos) {
|
||||
head = trimmed.substr(0, markerPos);
|
||||
out.text = trimmed.substr(markerPos + kMarker.size());
|
||||
} else {
|
||||
head = trimmed;
|
||||
out.text = trimmed;
|
||||
}
|
||||
|
||||
// 头部里找 "language <Name>"
|
||||
// 允许前面有空白,语言名只取连续的字母
|
||||
const std::string key = "language";
|
||||
auto pos = head.find(key);
|
||||
if (pos != std::string::npos) {
|
||||
pos += key.size();
|
||||
while (pos < head.size() && std::isspace(static_cast<unsigned char>(head[pos]))) ++pos;
|
||||
size_t end = pos;
|
||||
while (end < head.size() && std::isalpha(static_cast<unsigned char>(head[end]))) ++end;
|
||||
out.language = head.substr(pos, end - pos);
|
||||
}
|
||||
|
||||
out.text = trim(out.text);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string languageDisplayName(const std::string & lang)
|
||||
{
|
||||
if (lang.empty()) return {};
|
||||
|
||||
static const struct { const char * key; const char * display; } kMap[] = {
|
||||
{ "English", "英语" },
|
||||
{ "Chinese", "中文" },
|
||||
{ "Japanese", "日语" },
|
||||
{ "Korean", "韩语" },
|
||||
{ "French", "法语" },
|
||||
{ "German", "德语" },
|
||||
{ "Spanish", "西班牙语" },
|
||||
{ "Russian", "俄语" },
|
||||
{ "Italian", "意大利语" },
|
||||
{ "Portuguese", "葡萄牙语" },
|
||||
{ "Arabic", "阿拉伯语" },
|
||||
{ "Cantonese", "粤语" },
|
||||
};
|
||||
|
||||
for (const auto & e : kMap) {
|
||||
if (lang == e.key) return e.display;
|
||||
}
|
||||
return lang;
|
||||
}
|
||||
|
||||
} // namespace lc
|
||||
Reference in new issue
Block a user