Files
live-caption/CMakeLists.txt
T
blumia bd921b1ac5 feat(asr): add pluggable ONNX streaming backend and model registry
Add a second backend (sherpa-onnx) alongside llama.cpp, so native
streaming models can be selected by ID from a JSON registry. All such
models share one adapter: only the model files and a few options differ.
Models now live under the app data directory and are fetched by
scripts/fetch-models.sh. Adding a model is a data change, not code.

Measured on the same audio: the streaming backend is ~35x cheaper in CPU
than Qwen3-ASR (0.10-0.12 vs 4.27 core-seconds per audio second), shows
the first caption at 0.48-1.44s, and matches its accuracy for zh/en.

新增 sherpa-onnx 流式后端,与 llama.cpp 并存;模型按注册表 id 从应用
数据目录加载。同族模型共用一个适配器,新增模型只改 data/models.json。
实测流式后端 CPU 约为 Qwen3-ASR 的 1/35,首个字幕 0.48~1.44s,中英
准确率持平。注意预编译库是旧 C++ ABI,必须走其 C API。
2026-10-12 16:06:51 +08:00

158 lines
6.4 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
cmake_minimum_required(VERSION 3.24)
project(live-caption LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_AUTOMOC ON)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
endif()
option(LC_BUILD_TESTS "构建单元测试" ON)
# ---------------------------------------------------------------------------
# llama.cpp / libmtmd 的搜索路径
#
# Debian/Deepin 把 llama 的 CMake config 放在非标准目录 cmake-private/,
# 而 pkg-config 的 llama.pc 又漏了 -lmtmd。所以这里把两个路径都塞进搜索前缀,
# 并单独用 find_library 找 mtmd。
# ---------------------------------------------------------------------------
foreach(_p
/usr/lib/x86_64-linux-gnu/llama
/usr/lib/x86_64-linux-gnu/llama/cmake-private
/usr/lib/x86_64-linux-gnu/llama/pkgconfig)
if(EXISTS "${_p}")
list(APPEND CMAKE_PREFIX_PATH "${_p}")
set(ENV{PKG_CONFIG_PATH} "${_p}:$ENV{PKG_CONFIG_PATH}")
endif()
endforeach()
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
find_package(PkgConfig REQUIRED)
find_package(Threads REQUIRED)
pkg_check_modules(SAMPLERATE REQUIRED IMPORTED_TARGET samplerate)
pkg_check_modules(PULSE REQUIRED IMPORTED_TARGET libpulse)
# --- llama:优先系统 pkg-config,其次 CMake config,最后 FetchContent 兜底 ---
pkg_check_modules(LLAMA QUIET IMPORTED_TARGET llama)
if(LLAMA_FOUND)
set(LC_LLAMA_TARGET PkgConfig::LLAMA)
message(STATUS "llama: 使用系统 pkg-config (${LLAMA_VERSION})")
else()
message(STATUS "llama: 系统未找到,改用 FetchContent 拉取固定版本")
include(FetchContent)
set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE ALWAYS) # 先 find_package,失败再拉源码
FetchContent_Declare(llama
GIT_REPOSITORY https://github.com/ggml-org/llama.cpp.git
GIT_TAG b9951
FIND_PACKAGE_ARGS NAMES llama CONFIG)
set(LLAMA_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(LLAMA_BUILD_SERVER OFF CACHE BOOL "" FORCE)
set(LLAMA_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(llama)
set(LC_LLAMA_TARGET llama)
endif()
# --- mtmd:llama.pc 里没有,单独找 ---
find_library(LC_MTMD_LIB NAMES mtmd HINTS /usr/lib/x86_64-linux-gnu/llama)
if(NOT LC_MTMD_LIB)
message(FATAL_ERROR "找不到 libmtmd(应随 libllama0 一起安装)")
endif()
message(STATUS "mtmd: ${LC_MTMD_LIB}")
# ---------------------------------------------------------------------------
# sherpa-onnx(X-ASR / zipformer / Nemotron 等流式 ONNX 模型)
#
# 注意:官方预编译库是用旧 C++ ABI 编译的,所以只能用它的 C API。
# 安装:把官方的 sherpa-onnx-vX.Y.Z-linux-x64-shared.tar.bz2 解到某个目录,
# 用 -DSHERPA_ONNX_ROOT=<dir> 指定(默认见下)。
# ---------------------------------------------------------------------------
set(SHERPA_ONNX_ROOT "$ENV{HOME}/.local/opt/sherpa-onnx" CACHE PATH "sherpa-onnx 安装目录")
set(LC_HAS_SHERPA OFF)
if(EXISTS "${SHERPA_ONNX_ROOT}/include/sherpa-onnx/c-api/c-api.h")
find_library(LC_SHERPA_C_API NAMES sherpa-onnx-c-api
HINTS "${SHERPA_ONNX_ROOT}/lib" REQUIRED)
find_library(LC_SHERPA_ORT NAMES onnxruntime
HINTS "${SHERPA_ONNX_ROOT}/lib" REQUIRED)
set(LC_HAS_SHERPA ON)
message(STATUS "sherpa-onnx: ${SHERPA_ONNX_ROOT}")
else()
message(WARNING "未找到 sherpa-onnx(${SHERPA_ONNX_ROOT}),流式 ONNX 后端将不可用")
endif()
# ---------------------------------------------------------------------------
# core:全部业务逻辑,刻意不依赖 Qt(方便测试与复用)
# ---------------------------------------------------------------------------
add_library(livecaption_core STATIC
src/core/transcript.cpp
src/core/audio.cpp
src/core/qwen3asr.cpp
src/core/streamingasr.cpp
src/core/livepipeline.cpp
)
if(LC_HAS_SHERPA)
target_sources(livecaption_core PRIVATE src/core/sherpaasr.cpp)
target_compile_definitions(livecaption_core PUBLIC LC_HAVE_SHERPA=1)
target_include_directories(livecaption_core PRIVATE "${SHERPA_ONNX_ROOT}/include")
target_link_libraries(livecaption_core PUBLIC ${LC_SHERPA_C_API} ${LC_SHERPA_ORT})
endif()
target_include_directories(livecaption_core PUBLIC src/core)
target_link_libraries(livecaption_core PUBLIC
Threads::Threads
PkgConfig::SAMPLERATE
PkgConfig::PULSE
${LC_LLAMA_TARGET}
${LC_MTMD_LIB}
)
# ---------------------------------------------------------------------------
# models:模型注册表与存储(Qt;注册表编译进二进制)
# ---------------------------------------------------------------------------
add_library(livecaption_models STATIC
src/models/modelstore.cpp
)
target_include_directories(livecaption_models PUBLIC src/models)
target_link_libraries(livecaption_models PUBLIC Qt6::Core)
qt_add_resources(livecaption_models "registry"
PREFIX "/"
BASE "${CMAKE_CURRENT_SOURCE_DIR}"
FILES data/models.json)
# ---------------------------------------------------------------------------
# ui:悬浮窗与 Qt 适配层
# ---------------------------------------------------------------------------
add_library(livecaption_ui STATIC
src/ui/captionwindow.cpp
src/ui/livetranscriber.cpp
)
target_include_directories(livecaption_ui PUBLIC src/ui)
target_link_libraries(livecaption_ui PUBLIC livecaption_core Qt6::Widgets)
# ---------------------------------------------------------------------------
# 可执行程序
# ---------------------------------------------------------------------------
# GUI:悬浮字幕窗
add_executable(live-caption apps/gui/main.cpp)
target_include_directories(live-caption PRIVATE apps/common)
target_link_libraries(live-caption PRIVATE livecaption_ui livecaption_models)
# CLI:文件 / 流式文件 / 命令行实时;不链接 Qt Widgets
add_executable(live-caption-cli apps/cli/main.cpp)
target_include_directories(live-caption-cli PRIVATE apps/common)
target_link_libraries(live-caption-cli PRIVATE livecaption_core livecaption_models)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
foreach(_t livecaption_core livecaption_ui livecaption_models live-caption live-caption-cli)
target_compile_options(${_t} PRIVATE -Wall -Wextra -Wno-unused-parameter)
endforeach()
endif()
# ---------------------------------------------------------------------------
if(LC_BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()