🧠 唤醒词训练知识图谱

Jabobo Backend — FastAPI · GitNexus 索引分析

274 符号 · 605 关系 · 20 执行流

🏗️ 整体架构图

前端 → API → 业务层 → 外部系统 → 数据库 → 设备
%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#1e293b', 'primaryTextColor': '#f1f5f9', 'primaryBorderColor': '#475569', 'lineColor': '#38bdf8', 'secondaryColor': '#334155', 'tertiaryColor': '#0f172a'}}}%%
graph TB
    subgraph 前端层["前端 Dashboard"]
        UI[Web 管理界面]
    end

    subgraph API层["jabobo-backend REST API (FastAPI, port 8007)"]
        TrainAPI["POST /api/user/wake-word/train
trigger_wake_word_training()"] StatusAPI["GET /api/user/wake-word/train/status
get_wake_word_status()"] SyncAPI["POST /api/user/sync-config
sync_config()"] GetConfig["GET /api/user/config
get_user_config()"] end subgraph 核心业务层["核心业务流程"] direction TB NORMALIZE["_normalize_wake_word()
标准化唤醒词名"] DISPLAY["_wake_word_to_display()
生成显示名"] TRAIN["_run_wakeword_training()
异步训练任务"] UPDATE_STATUS["_update_wake_word_status()
更新数据库状态"] end subgraph 外部系统["外部系统"] CMD1["train_wakeword.py
--generate-samples
(TTS 生成 500 条样本)"] CMD2["train_wakeword.py
(特征提取+训练)"] CMD3["deploy_wakeword.py
(OTA 部署 .tflite)"] end subgraph 数据层["MySQL 数据库"] DB[("user_personas 表")] end subgraph 固件层["ESP32 设备"] DEVICE["捷宝宝硬件"] OTA_RECEIVER["OTA 接收+模型加载"] end UI -->|"POST /user/wake-word/train"| TrainAPI UI -->|"GET /user/wake-word/train/status"| StatusAPI UI -->|"POST /user/sync-config"| SyncAPI UI -->|"GET /user/config"| GetConfig TrainAPI -->|"asyncio.create_task"| TRAIN SyncAPI -->|"if wake_word_text changed"| TRAIN GetConfig -.->|"read model_status"| DB StatusAPI -->|"查询状态"| DB TRAIN --> NORMALIZE NORMALIZE --> DISPLAY TRAIN --> UPDATE_STATUS TRAIN -->|"检查已有模型"| CMD2 TRAIN -->|"生成样本"| CMD1 CMD1 --> CMD2 CMD2 --> CMD3 CMD3 -->|"OTA 推送"| OTA_RECEIVER OTA_RECEIVER --> DEVICE UPDATE_STATUS -->|"UPDATE model_status"| DB style 前端层 fill:#0f766e,stroke:#14b8a6,color:#fff style API层 fill:#1d4ed8,stroke:#3b82f6,color:#fff style 核心业务层 fill:#15803d,stroke:#22c55e,color:#fff style 外部系统 fill:#b45309,stroke:#f59e0b,color:#fff style 数据层 fill:#7c3aed,stroke:#a855f7,color:#fff style 固件层 fill:#b91c1c,stroke:#ef4444,color:#fff

🔗 函数调用关系图

GitNexus Cypher 查询结果 — 唤醒词训练相关符号调用链
%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#1e293b', 'primaryTextColor': '#f1f5f9', 'primaryBorderColor': '#475569', 'lineColor': '#38bdf8', 'secondaryColor': '#334155', 'tertiaryColor': '#0f172a'}}}%%
graph LR
    subgraph API入口["API 入口"]
        T["trigger_wake_word_training()
POST /user/wake-word/train"] S["sync_config()
POST /user/sync-config"] ST["get_wake_word_status()
GET /user/wake-word/train/status"] GC["get_user_config()
GET /user/config"] end subgraph 辅助函数["辅助函数"] NW["_normalize_wake_word()"] WD["_wake_word_to_display()"] UV["verify_user()
用户认证"] GVC["get_valid_cursor()
数据库游标"] end subgraph 核心训练["核心训练"] RT["_run_wakeword_training()"] US["_update_wake_word_status()"] end subgraph 数据库["MySQL"] CONN["db.connect()"] QUERY["SELECT / UPDATE
user_personas"] end subgraph 外部进程["外部进程"] CMD1["train_wakeword.py
--generate-samples"] CMD2["train_wakeword.py
训练"] CMD3["deploy_wakeword.py
OTA"] end T -->|"asyncio.create_task"| RT S -.->|"if wake_word_text"| NW NW --> RT ST --> UV --> CONN --> QUERY GC --> UV GC --> GVC --> CONN RT --> WD RT --> CMD1 --> CMD2 --> CMD3 RT --> US --> CONN -->|"UPDATE model_status"| QUERY style API入口 fill:#1e3a5f,stroke:#38bdf8,color:#fff style 辅助函数 fill:#1e3a5f,stroke:#38bdf8,color:#fff style 核心训练 fill:#1e3a5f,stroke:#22c55e,color:#fff style 数据库 fill:#4a1a7a,stroke:#a855f7,color:#fff style 外部进程 fill:#5c3d0a,stroke:#f59e0b,color:#fff

🕐 训练时序图

从用户点击"训练"到模型部署到设备的全过程
%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#1e293b', 'primaryTextColor': '#f1f5f9', 'primaryBorderColor': '#475569', 'lineColor': '#38bdf8', 'secondaryColor': '#334155', 'tertiaryColor': '#0f172a'}}}%%
sequenceDiagram
    participant U as 用户/前端
    participant API as jabobo-backend
    participant MEM as 进程缓存
_wake_word_tasks participant DB as MySQL participant CONDA as Conda wakeword
TTS + 训练脚本 participant DEV as ESP32 设备 U->>API: POST /user/wake-word/train
{device_id, wake_word: "Hey Jabra"} Note over API: 标准化: hey_jabra
显示名: Hey Jabra API->>MEM: {status: "running"} API-->>U: 200 任务已启动 API-->>API: asyncio.create_task() rect rgb(30, 58, 95) Note over API,CONDA: 阶段1: TTS 生成 500 条样本 alt 已有 .tflite API-->>API: 跳过训练,直接部署 else 首次训练 API->>CONDA: train_wakeword.py --generate-samples
--text "Hey Jabra" --max-samples 500
--voices lessac,amy,joe --length-scales 0.5~1.0 Note over CONDA: 多种音色 × 5 种语速
= 数千条 WAV 样本 CONDA-->>API: 样本生成完成 end end rect rgb(21, 128, 61) Note over API,CONDA: 阶段2: 模型训练 API->>CONDA: train_wakeword.py Note over CONDA: MFCC 特征提取 → CNN 训练 → TFLite 量化导出 CONDA-->>API: trained_models/hey_jabra/hey_jabra.tflite end rect rgb(180, 83, 9) Note over API,DEV: 阶段3: OTA 部署 API->>CONDA: deploy_wakeword.py CONDA-->>DEV: OTA 推送 .tflite 模型 DEV-->>CONDA: 部署确认 end rect rgb(124, 58, 237) Note over API,DB: 阶段4: 数据库持久化 API->>DB: UPDATE user_personas SET wake_word_model_status=1 API->>MEM: {status: "done", elapsed: 187s} end U->>API: GET /user/wake-word/train/status API->>MEM: 读取状态 API-->>U: {status: "done", elapsed_seconds: 187}

🔄 模型状态机

%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#1e293b', 'primaryTextColor': '#f1f5f9', 'primaryBorderColor': '#475569', 'lineColor': '#38bdf8', 'secondaryColor': '#334155', 'tertiaryColor': '#0f172a'}}}%%
stateDiagram-v2
    [*] --> 未训练 : 设备绑定
status = 0 未训练 --> 训练中 : POST /user/wake-word/train 训练中 --> 已部署 : 训练+部署成功
status = 1 训练中 --> 训练失败 : 异常退出
status = 2 已部署 --> 训练中 : 重新训练 训练失败 --> 训练中 : 重试

🗄️ 数据库 ER 图

user_login ↔ user_personas — 唤醒词相关字段高亮
%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#1e293b', 'primaryTextColor': '#f1f5f9', 'primaryBorderColor': '#475569', 'lineColor': '#38bdf8', 'secondaryColor': '#334155', 'tertiaryColor': '#0f172a'}}}%%
erDiagram
    user_login ||--o{ user_personas : has

    user_login {
        int id PK
        string username UK
    }

    user_personas {
        int id PK
        string username FK
        string jabobo_id UK
        json personas
        text memory
        string websocket_url
        string asr_provider
        string tts_provider
        string llm_provider
        boolean rag_enabled
        string wake_word_text "用户设定的唤醒词"
        int wake_word_model_status "0=未训练 1=已部署 2=失败"
        string current_version
        string expected_version
        json voiceprint_list
    }

⚙️ 配置参数表

参数说明
_TRAIN_WORK_DIR~/Jabobo/wakeword train/训练工作目录
_TRAIN_CONDA_ENVwakewordConda 训练环境
_TRAIN_LOG_DIR{WORK_DIR}/_training_logs/每轮训练日志
max-samples500每轮 TTS 生成样本数
length-scales0.5 0.6 0.75 0.9 1.05 种语速增强鲁棒性
EN_VOICESlessac, amy, joe, alan, norman, libritts_r英文 TTS 音色(6 种)
ZH_VOICESchaowen, huayan, xiao_ya中文 TTS 音色(3 种)
wake_word_text用户自定义存入 user_personas 表
model_status 0未训练设备绑定后默认状态
model_status 1已部署 ✓训练+部署成功
model_status 2失败 ✗训练异常退出

📋 函数清单

函数名文件行号职责
trigger_wake_word_trainingjabobo_config.pyAPI 入口,异步启动训练
get_wake_word_statusjabobo_config.pyAPI 查询训练状态
sync_configjabobo_config.py420同步配置时触发训练
get_user_configjabobo_config.py274读取设备配置含模型状态
_run_wakeword_trainingjabobo_config.py55🔥 核心异步训练任务
_normalize_wake_wordjabobo_config.py22标准化唤醒词为 code name
_wake_word_to_displayjabobo_config.py49生成前端显示文本
_update_wake_word_statusjabobo_config.py175写 model_status 到 DB
verify_usersecurity.pyAPI 认证校验
get_valid_cursorsecurity.py获取数据库游标

💡 关键代码片段

标准化唤醒词名
_normalize_wake_word(text)
"Hey Jabra" → "hey_jabra"
"hi,Jabra" → "hi_jabra"
智能音色选择
含中文 → ZH_VOICES
纯英文 → EN_VOICES
状态管理
_wake_word_tasks[
  f"{wake_word}@{device_id}"
] = {status, elapsed}
数据库更新
UPDATE user_personas
SET wake_word_model_status=N
WHERE jabobo_id = %s