# ai_worker **Repository Path**: wyonging/ai_worker ## Basic Information - **Project Name**: ai_worker - **Description**: 1、ASR->LLM->TTS 2、视觉系统 3、OCR->TTS - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-09-30 - **Last Updated**: 2026-07-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ai_worker 本地多模态 AI 工作站——语音对话(ASR → LLM → TTS)与视觉理解(OCR 文字识别、YOLO 目标检测)全程本地运行,无需联网。所有模块由 Qt5 控制面板(`control_panel`)统一编排启动。 ## 系统架构 ### 总体编排 `control_panel` 是唯一入口,通过 `QProcess` 拉起并管理三组相互独立的子进程: ``` ┌──────────────────────────────────────────────┐ │ control_panel (Qt5 GUI) │ │ 控制面板:拉起/停止/回收所有子进程 │ └───────┬──────────┬──────────────┬────────────┘ │ │ │ ┌─────────────┘ │ └──────────────┐ ▼ 语音流水线 ▼ OCR ▼ 视频检测 LLM →(5s)→ ASR + TTS ppocr video_inference (POSIX MQ + 共享内存) (PaddleOCR PP-OCRv5) (YOLOs-CPP ONNX) ``` ### 语音流水线(ASR / LLM / TTS) ``` ┌────────────────────────────┐ │ POSIX 共享内存 │ │ /pipeline_state │ │ │ │ asr_state ← ASR 写入 │ │ asr_turn_id ← ASR 递增 │ │ tts_interrupt ← LLM 写入 │ └────────┬──────────┬──────────┘ │ │ ┌────────────────────┘ └──────────────────┐ ▲ ▼ ┌──────────┐ │ POSIX MQ ┌──────────┐ POSIX MQ ┌──────────┐ │ ASR │ ───────────▶ │ LLM │ ───────────▶ │ TTS │ │ 语音识别 │ /queue_asr2llm│ 大语言模型│ /queue_llm2tts│ 语音合成 │ │ │ │ │ │ │ │ Sherpa │ │ llama. │ │ Sherpa │ │ ONNX │ │ cpp │ │ ONNX │ └──────────┘ └──────────┘ └──────────┘ ▲ │ │ ALSA 采集 │ ALSA 播放 └─────── 麦克风 ◀─────────────────── 扬声器 ◀────────┘ ``` **启动顺序:** LLM(创建消息队列)→ sleep 5s → ASR(创建共享内存)+ TTS **数据流:** 麦克风音频 → ASR 流式识别 → endpoint 检测到句子结束 → 发送文本到 LLM → LLM 逐 token 生成 → 按标点切分发送到 TTS → TTS 合成语音 → 扬声器播放 **打断机制:** 三进程通过 POSIX 共享内存实时共享状态。ASR 检测到用户开口说话时写入 `asr_state=SPEAKING` 并递增 `asr_turn_id`;LLM 在 token 生成循环中检测到 turn_id 变化后立即停止生成,同时设置 `tts_interrupt=1`;TTS 在播放过程中检测到中断标志后立即停止音频输出。详见下方"常见问题"中的打断流程说明。 ## 目录结构 ``` ai_worker/ ├── control_panel/ # Qt5 控制面板(统一入口,QProcess 编排所有子进程) ├── asr_process/ # 语音识别(C++17,Sherpa-ONNX 流式 Zipformer) ├── llm_process/ # 大语言模型推理(C++17,llama.cpp,CMake 构建) ├── tts_process/ # 语音合成(C,Sherpa-ONNX VITS / MatchaTTS) ├── pp-ocr-cpp-infer/ # OCR 文字识别(C++17,PaddlePaddle Inference,PP-OCRv5) │ ├── app/ # 入口(cli.cc / main.cpp → ppocr 可执行文件) │ ├── src/ # 核心库 → ppocr_core.a(检测/识别/分类/矫正/流水线) │ ├── models/ # 推理模型(未提交,需自行下载) │ └── third_party/ # 依赖库(未提交:paddle_inference、opencv4、abseil-cpp 等) ├── YOLOs-CPP/ # 目标检测(C++17,ONNX Runtime,YOLOv11/YOLOv26 系列) │ ├── src/ # 推理示例(图像/视频/批量/摄像头,含检测/分割/姿态/分类/OBB/YOLOE) │ ├── include/yolos/ # 头文件(core + tasks) │ ├── models/ # 模型权重(未提交,需自行下载 .onnx) │ └── build.sh # 一键编译脚本 ├── face_process/ # 人脸识别(C/C++,InspireFace SDK) │ ├── c_src/ # C 语言版本(CPU/GPU,control_panel 集成) │ ├── cpp_src/ # C++ 语言版本 │ ├── InspireFace/ # InspireFace SDK 头文件和库 │ ├── test_res/ # 测试资源和模型包(Pikachu/Megatron) │ ├── models/ # 特征库数据库 │ │ ├── face_db.sqlite # SQLite 特征库 │ │ └ name_mapping.txt # ID-姓名映射 │ └ README.md # 使用文档 ├── common_lib/ │ ├── mqueue/ # POSIX 消息队列封装库(mq_ipc.h / mq_ipc.c) │ │ └── mq_names.h # 共享队列名和常量定义 │ ├── shm/ # POSIX 共享内存封装库(shm_ipc.h / shm_ipc.c) │ │ # 包含管道状态结构 SHN_RUN_SYS_PARAMS_T │ └── socket/ # Unix Socket IPC(备用) ├── lib/ # 预编译依赖库(Sherpa-ONNX、llama.cpp、ONNX Runtime 等) ├── bin/ # 编译输出目录(make install 后生成) ├── Makefile # 统一构建入口 └── run.sh # 命令行一键启动脚本(不依赖 GUI) ``` ## 依赖 - **GCC 11+**(支持 C++17) - **CMake 3.14+** - **Qt5 Widgets**(`control_panel` 控制面板) - **ALSA**(libasound2-dev) - **CUDA**(可选,LLM GPU 加速) - **预编译库** 已包含在 `lib/` 中:Sherpa-ONNX、llama.cpp、ONNX Runtime 等 视觉模块各自的额外依赖(独立编译,详见各自目录下的 README): | 模块 | 核心依赖 | 获取方式 | |------|---------|---------| | `pp-ocr-cpp-infer` | PaddlePaddle C++ Inference、OpenCV4、abseil-cpp | 解压到 `pp-ocr-cpp-infer/third_party/`(未提交) | | `YOLOs-CPP` | ONNX Runtime | 指定 `-DONNXRUNTIME_DIR=...` | | `face_process` | InspireFace SDK、OpenCV4 | SDK 已包含在 `face_process/InspireFace/` | ## 编译 ```bash make # 编译所有组件(含 control_panel) make install # 将可执行文件复制到 bin/ make clean # 清理编译产物 ``` 构建顺序:`common_lib/mqueue/mq_ipc.o` → `asr_process` / `tts_process`(Make)→ `llm_process`(CMake)→ `control_panel`(CMake/Qt5) 视觉模块为独立子工程,需在其各自目录下单独编译(见下文"视觉模块")。 ## 模型下载 将模型放置到对应目录后,修改 `run.sh` 和源码中的路径: | 组件 | 模型 | 默认路径 | |------|------|---------| | LLM | Qwen3-4B-Instruct (GGUF) | `/home/wy/misc/llama.cpp/models/` | | ASR | Sherpa-ONNX Streaming Zipformer (中文) | `/home/wy/misc/models/sherpa-onnx-streaming-zipformer-multi-zh-hans-2023-12-12/` | | TTS (vits) | VITS 中文模型 (fanchen-C) | `/home/wy/misc/models/vits-zh-hf-fanchen-C/` | | TTS (matcha) | MatchaTTS + Vocos vocoder | `/home/wy/misc/models/matcha-icefall-zh-baker/` | | OCR | PP-OCRv5 server 检测/识别(Paddle Inference) | `pp-ocr-cpp-infer/models/PP-OCRv5_server_*_infer/` | | YOLO | YOLOv26s 检测(ONNX) | `YOLOs-CPP/models/yolo26s.onnx` | ## 运行 ### 方式一:控制面板(推荐) ```bash make && make install ./bin/control_panel ``` Qt5 GUI 启动后可通过按钮控制所有模块: - **语音对话** — "▶ 启动"按钮启动 LLM → ASR → TTS 语音流水线,支持暂停/停止/打断 - **OCR 文字识别** — "OCR 识别"按钮选取图片后调用 `ppocr` 进行文字识别,结果在面板中展示并支持滚轮缩放 - **视频检测** — "▶ 视频检测"按钮启动 `video_inference` 进行实时 YOLO 目标检测 - **人脸识别** — 五个功能按钮: - 🔍 **人脸检测** — 检测图片中的人脸,显示全部属性(位置、姿态、性别、年龄、表情、质量、活体、身份) - 📝 **人脸注册** — 选择图片并输入姓名,注册人脸到特征库(自动检测重复) - 👤 **人脸识别** — 在特征库中搜索匹配的人脸,显示姓名和置信度 - 📹 **视频跟踪** — 实时视频人脸跟踪(弹出窗口) - 🎥 **实时识别** — 实时视频人脸识别,在画面上显示识别结果 ### 方式二:命令行(仅语音流水线) ```bash # 确认音频设备 arecord -l # 查看录音设备 aplay -l # 查看播放设备 # 启动(修改 run.sh 中的设备名和模型路径后) ./run.sh ``` `run.sh` 执行流程: 1. 启动 LLM 进程(加载模型,创建两个消息队列) 2. 等待 5 秒(模型加载 + 队列就绪) 3. 启动 ASR 和 TTS 进程 4. Ctrl+C 停止所有进程并清理 ### 单独运行各组件 ```bash # LLM(必须最先启动,创建消息队列) ./bin/llm_process -m /path/to/model.gguf # ASR ./bin/asr_process \ --tokens=/path/to/tokens.txt \ --encoder=/path/to/encoder.onnx \ --decoder=/path/to/decoder.onnx \ --joiner=/path/to/joiner.onnx \ plughw:2,0 # TTS(支持两种引擎) ./bin/tts_process --engine vits plughw:1,0 22050 ./bin/tts_process --engine matcha plughw:1,0 22050 ``` ## 视觉模块 OCR(`pp-ocr-cpp-infer`)、目标检测(`YOLOs-CPP`)和人脸识别(`face_process`)是独立子工程,与语音流水线通过 IPC 解耦,通常由 `control_panel` 以子进程方式拉起,也可在各自目录下单独编译运行。 ### OCR 文字识别(pp-ocr-cpp-infer) 基于 PaddlePaddle C++ Inference 的 PP-OCRv5 文本检测与识别,编译产出 `build/app/ppocr`。 ```bash cd pp-ocr-cpp-infer # 1. 准备 third_party/paddle_inference、opencv4,models/PP-OCRv5_server_*_infer # 2. 一键编译 ./tools/build.sh # 3. 运行(设置 LD_LIBRARY_PATH 见 pp-ocr-cpp-infer/README.md) ./build/app/ppocr ocr \ --input ./general_ocr_002.png \ --save_path ./output/ \ --text_detection_model_dir models/PP-OCRv5_server_det_infer \ --text_recognition_model_dir models/PP-OCRv5_server_rec_infer \ --use_doc_orientation_classify False \ --use_doc_unwarping False \ --device cpu --vis_font_dir ./fonts/simhei.ttf ``` ### 目标检测(YOLOs-CPP) 基于 ONNX Runtime 的 YOLO 系列推理,支持检测、分类、分割、姿态、OBB、YOLOE 等任务。`control_panel` 调用的入口是 `build/video_inference`。 ```bash cd YOLOs-CPP # 指定 ONNX Runtime 路径后编译(详见 YOLOs-CPP/build.sh / README.md) mkdir build && cd build cmake .. -DONNXRUNTIME_DIR=../../../onnxruntime-src -DCMAKE_BUILD_TYPE=Release make -j$(nproc) # 运行 ./image_inference ../models/yolo26s.onnx ../data/dog.jpg ./video_inference ../models/yolo26s.onnx ``` ### 人脸识别(face_process) 基于 InspireFace SDK 的人脸检测、跟踪、识别模块,提供 C 和 C++ 两种版本。`control_panel` 集成使用 C 版本(`c_src/face_inference_c`)。 ```bash cd face_process/c_src mkdir build && cd build cmake .. && make -j$(nproc) # 设置库路径 export LD_LIBRARY_PATH=$PWD/../InspireFace/lib:$LD_LIBRARY_PATH # 人脸检测(带属性和身份识别) ./face_inference_c detect --input ../../test_res/data/emotion/anger.png --draw # 人脸注册(自动检测重复) ./face_inference_c register --input face.jpg --name "张三" # 人脸搜索 ./face_inference_c search --input query.jpg # 视频跟踪 ./face_inference_c track --source 0 --show # 实时识别(跟踪+识别) ./face_inference_c track_recognition --source 0 --show ``` **功能特性:** - 人脸检测:返回位置、姿态、性别、年龄、表情、质量、口罩、活体等属性 - 人脸注册:自动检测重复,支持 `--force` 强制注册 - 人脸搜索:在 SQLite 特征库中搜索匹配人脸 - 视频跟踪:实时多人脸跟踪 - 实时识别:视频跟踪同时进行人脸识别,显示身份信息 ## IPC 通信 ### 消息队列(数据流) 三个进程通过 POSIX 消息队列传输文本数据,封装在 `common_lib/mqueue/` 中: | 队列 | 方向 | 创建者 | 消息大小 | 队列容量 | |------|------|--------|---------|---------| | `/queue_asr2llm` | ASR → LLM | LLM | 4096 字节 | 50 条 | | `/queue_llm2tts` | LLM → TTS | LLM | 4096 字节 | 50 条 | 队列资源管理: - LLM 进程负责创建(`mq_ipc_create_*`)和销毁(`mq_ipc_destroy` with unlink) - ASR / TTS 只打开使用(`mq_ipc_open_*`),退出时 close 不 unlink ### 共享内存(控制信号) 三进程通过 POSIX 共享内存实时共享状态,封装在 `common_lib/shm/` 中: | 共享内存 | Owner | 用途 | |---------|-------|------| | `/pipeline_state` | ASR | 管道打断状态 | **`SHN_RUN_SYS_PARAMS_T` 结构体字段:** | 字段 | 类型 | 写入者 | 说明 | |------|------|--------|------| | `asr_state` | `volatile int` | ASR | `0`=idle, `1`=用户正在说话, `2`=一句话结束已发送 | | `asr_turn_id` | `volatile uint64_t` | ASR | 单调递增,每次检测到新语音 +1 | | `tts_interrupt` | `volatile int` | LLM | `0`=正常, `1`=打断 TTS 播放 | **工作原理:** 各进程通过 `shm_ipc_create()` 获取共享内存后,直接读写 `runtime_addr` 指向的结构体(volatile 访问),不走信号量的 write/read 函数。ASR 是共享内存 owner,退出时负责 unlink。 ## 常见问题 **Q: LLM 编译报 CUDA 链接错误?** A: 安装 CUDA Toolkit 或在 `llm_process/CMakeLists.txt` 中移除 `ggml-cuda` 链接项,改用 CPU 推理。 **Q: TTS 启动报 "Failed to open queue"?** A: 确保 LLM 进程已启动并完成模型加载(队列由 LLM 创建)。`run.sh` 中的 `sleep 5` 即为此目的。 **Q: ASR 检测不到声音?** A: 检查麦克风设备名(`arecord -l`),修改 `run.sh` 中的设备参数(如 `plughw:2,0`)。 **Q: 如何打断正在进行的 LLM 回答和 TTS 播放?** A: 系统已内置打断机制,直接开口说话即可打断。完整流程如下: ``` 打断时序: T=0 ASR: 检测到新语音 → asr_state=SPEAKING, asr_turn_id++ T≈0 LLM: token生成循环中检测到 turn_id 变化 → 停止生成, tts_interrupt=1, 排空TTS队列 T≈0 TTS: 播放中检测到 tts_interrupt=1 → snd_pcm_drop 停止播放, 丢弃后续消息 T≈2s ASR: 用户说完 → asr_state=ENDPOINT, 发送新文本到消息队列 T≈2s LLM: 收到新文本 → 正常生成回答 → 发送到 TTS T≈2s TTS: 收到新文本 → 正常播放 ``` 1. **ASR(触发源)**:检测到用户开始说话时,无需等待 endpoint,立即将 `asr_state` 设为 `ASR_SPEAKING` 并递增 `asr_turn_id` 2. **LLM(响应打断)**:在每个 token 生成后检查共享内存中的 `asr_turn_id`,如果发现变化说明用户说了新话,立即停止当前生成、设置 `tts_interrupt=1` 通知 TTS、并排空 TTS 队列中的旧消息 3. **TTS(执行打断)**:在音频播放的每个 ALSA period 前检查 `tts_interrupt` 标志,如果为 1 则调用 `snd_pcm_drop()` 立即停止音频输出 **Q: 共享内存残留导致启动失败?** A: 异常退出后 `/dev/shm/pipeline_state` 可能残留。`run.sh` 会在启动前和退出时自动清理。手动清理:`rm -f /dev/shm/pipeline_state`。