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。
158 lines
6.4 KiB
CMake
158 lines
6.4 KiB
CMake
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()
|