taixf/modules/docs/antaf-integration-plan.md

12 KiB
Raw Blame History

蚂蚁阿福接入小智 ESP32 — 实施方案

项目目标

将蚂蚁阿福 App 的 AI 能力接入小智 ESP32 硬件终端,用户通过 ESP32 设备语音对话, 后端对接蚂蚁阿福代替自建 LLM省去 GPU 资源(两张 RTX 3090 + Qwen3-32B


系统架构

方案A文字接入自定义 LLM Provider

ESP32 设备                    PlugAI 服务端                       手机
┌──────────┐    WebSocket    ┌──────────────────┐    HTTP/SSE    ┌─<E2948C><E29480><EFBFBD>────────────┐
│ 麦克风    │ ──────────────→│ ASR (FunASR)     │               │ 蚂蚁阿福 App  │
│ 唤<><E594A4><EFBFBD>词    │                │   语音→文字       │               │ + Frida 注入  │
│ AEC/NS   │                │                  │  GET /chat?q= │              │
│          │                │ AntafLLM Provider│──────────────→│ HTTP Bridge  │
│          │                │   (新增)          │←──────────────│ (port 18900) │
│          │                │                  │  SSE 流式回答  │              │
│ 喇叭     │←───────────────│ TTS (EdgeTTS)    │               │              │
│          │    WebSocket    │   文字→语音       │               │              │
└──────────┘                └──────────────────┘               └──────────────┘

数据流: ESP32 音频 → FunASR(语音转文字) → AntafLLM(文<><E69687><EFBFBD>发给阿福) → EdgeTTS(回答转语音) → ESP32 播放

方案B语音直通替代整个 ASR+LLM+TTS

ESP32 设备                    PlugAI 服务端                       手机
┌──────────┐    WebSocket    ┌─────<E29480><E29480><EFBFBD>────────────┐    TCP 二进制  ┌──<E29480><E29480><EFBFBD>───────────┐
│ 麦克风    │ ──────────────→│ 音频转发模块(新增) │               │ 蚂蚁<E89A82><E89A81>福 App  │
│          │                │   Opus解码        │  PCM注入mic   │ + Frida <20><>入  │
│          │                │   重采样 24k→48k  │──────────────→│ Voice Bridge │
│          │                │                  │  PCM speaker  │ (port 18901) │
│ 喇叭     │←───────────────│   重采样 24k→24k  │←──────────────│ libantaudio  │
│          │    WebSocket    │   Opus编码        │               │              │
└──────────┘                └──────────────────┘               └──────────────┘

数据流: ESP32 音频 → 解码+重采样 → 注入阿福麦克风 → 阿福完整处理(ASR+LLM+TTS) → 捕获音频 → 编码 → ESP32 播放


可行性评估

维度 方案A (文字接入) 方案B (语音直通)
可行性 中低
实现难度 低 (1个Python文件) 高 (改JS+写转发模块)
改动范围 新增 LLM Provider + 改配置 改 voice_bridge.js + 新增转发模块
延迟 中 (ASR+网络+TTS 各一轮) 低 (音频直通)
音质 EdgeTTS (微软高质量) 阿福原生 TTS
GPU 依赖 无 (省掉 Qwen3-32B)
手机依赖 需要 (App+Frida+adb) 需要 (App+Frida+adb)
核心风险 voice_bridge 当前不支持音频注入

结论: 先实施方案A验证通过后再做方案B。


方案A 详细实施

前置条件

组件 状态 说明
ESP32 设备 已就绪 固件已烧录WiFi+服务端已配置
小智服务端 已就绪 ws://14.18.247.51:8010 运行中
ASR (FunASR) 已就绪 CPU 模式
TTS (EdgeTTS) 已就绪 微软免费
蚂蚁阿福 HTTP Bridge 已就绪 http_bridge_stream.js (port 18900)
Frida + 手机 需部署 手机需连到服务端可达的网络

第1步创建 AntafLLM Provider

文件路径:backend/main/xiaozhi-server/core/providers/llm/antaf/antaf.py

import requests
from config.logger import setup_logging
from core.providers.llm.base import LLMProviderBase

TAG = __name__
logger = setup_logging()


class LLMProvider(LLMProviderBase):
    """
    蚂蚁阿福 LLM Provider
    通过 Frida HTTP Bridge (port 18900) 对接蚂蚁阿福 App 的文字对话 API。
    Bridge 运行在手机上,通过 adb forward 或网络暴露 SSE 流式接口。
    """

    def __init__(self, config):
        self.bridge_url = config.get("bridge_url", "http://127.0.0.1:18900")
        self.timeout = config.get("timeout", 60)
        logger.bind(tag=TAG).info(
            f"AntafLLM 初始化: bridge={self.bridge_url}, timeout={self.timeout}s"
        )

    def response(self, session_id, dialogue, **kwargs):
        """
        流式返回蚂蚁阿福的回答。
        1. 从 dialogue 取最后一条用户消息
        2. GET {bridge_url}/chat?q={query}
        3. 解析 SSE 流yield 每个 delta 文本
        """
        # 提取最后一条用户消息
        query = ""
        for msg in reversed(dialogue):
            if msg.get("role") == "user":
                query = msg.get("content", "")
                break

        if not query:
            logger.bind(tag=TAG).warning("对话中没有用户消息")
            yield "抱歉,我没有收到您的问题。"
            return

        logger.bind(tag=TAG).info(f"AntafLLM 请求: {query[:50]}...")

        try:
            url = f"{self.bridge_url}/chat"
            resp = requests.get(
                url,
                params={"q": query},
                stream=True,
                timeout=self.timeout
            )
            resp.encoding = "utf-8"

            for line in resp.iter_lines(decode_unicode=True):
                if not line:
                    continue
                if line.startswith("data: "):
                    data = line[6:]  # 去掉 "data: " 前缀
                    if data == "[DONE]":
                        break
                    if data and len(data.strip()) > 0:
                        yield data

        except requests.exceptions.ConnectionError:
            logger.bind(tag=TAG).error("无法连接蚂<E68EA5><E89A82>阿福 Bridge请检查手机和 Frida 状态")
            yield "抱歉,蚂蚁阿福服务暂时不可用。"
        except requests.exceptions.Timeout:
            logger.bind(tag=TAG).error(f"蚂蚁阿福 Bridge 超时 ({self.timeout}s)")
            yield "抱歉,回答超时了。"
        except Exception as e:
            logger.bind(tag=TAG).error(f"AntafLLM 异常: {e}")
            yield "抱歉,发生了错误。"

第2步修改服务端配置

编辑 backend/main/xiaozhi-server/data/.config.yaml

selected_module:
  LLM: antaf       # 改为<E694B9><E4B8BA><EFBFBD>蚁阿福

LLM:
  antaf:
    type: antaf
    bridge_url: http://<手机IP>:18900    # 手机的 HTTP Bridge 地址
    timeout: 60                          # SSE 流超时时间

也可以保留原来的 Qwen3 配置,方便切换:

LLM:
  antaf:
    type: antaf
    bridge_url: http://<手机IP>:18900
    timeout: 60
  Qwen3:
    type: openai
    model_name: Qwen3-32B
    url: http://127.0.0.1:30000/v1
    api_key: EMPTY

第3步网络打通

手机的 Frida Bridge 端口需要让 PlugAI 服<><E69C8D><EFBFBD>器能访问到。有两种方式

方式1手机直连局域网推荐

如果手机和 PlugAI 服务器在同一网络(或手机有公网可达 IP

# 手机上启动 bridge 后,服务端直接访问
# bridge_url: http://<手机内网IP>:18900
curl http://<手机IP>:18900/chat?q=hello

方式2adb forward + SSH 隧道

手机通过 USB 连接一台中间机器,再通过 SSH 隧道暴露<E69AB4><E99CB2><EFBFBD>

# 中间机器上
adb forward tcp:18900 tcp:18900

# PlugAI 上建 SSH 隧道
ssh -L 18900:127.0.0.1:18900 user@中间机器IP
# bridge_url: http://127.0.0.1:18900

第4步启动与测试

# 1. 手机端:启动 Frida + HTTP Bridge
frida -U -p <PID> -l http_bridge_stream.js

# 2. 先测 bridge 连通性
curl -N 'http://<手机IP>:18900/chat?q=你好'

# 3. PlugAI 服务端:重启小智服务
cd /home/ZeroStack/xiaozhi/xiaozhi-esp32-server/main/xiaozhi-server
source /home/ZeroStack/xiaozhi/venv/bin/activate
python app.py

# 4. ESP32 设备:唤醒测试
# 说 "你好小智" → 提问 → 应该听到蚂蚁阿福的回答EdgeTTS 合成的语音)

方案B 详细实施(后续)

核心改造voice_bridge.js 支持音频注入

当前 voice_bridge.js 的 MFAntAudio3AV2Filter::process hook 只读取 micIn 缓冲区。 需要改造为可以从外部写入 micIn 缓冲区,替换真实麦克风输入。

改造要点

// voice_bridge.js 新增功能
var injectBuffer = null;  // 外部注入的 PCM 数据

// 新增 inject 命令:接收外部 PCM 音频帧
// 客户端发送: [4字节长度][type=3][960字节PCM数据]
// type 3 = inject audio

Interceptor.attach(processAddr, {
    onEnter: function(args) {
        var micIn = args[1];       // 麦克风输入缓冲区 (960 bytes)
        var frameSize = args[4];   // 960

        if (injectBuffer !== null) {
            // 用注入数据覆盖真实麦克风输入
            micIn.writeByteArray(injectBuffer);
            injectBuffer = null;
        }
    }
});

采样率转换

来源 格式 需转换为
ESP32 → 服务端 Opus 24kHz mono PCM 48kHz mono (阿福 mic)
阿福 speaker 输出 PCM 24kHz stereo Opus 24kHz mono (ESP32)

服务端需要:

  • libopus 解码/编码
  • resampy 或 scipy 做采样率转换
  • 960字节帧对齐20ms @ 48kHz

新增音频转发模块

文件<EFBFBD><EFBFBD>backend/main/xiaozhi-server/core/providers/asr/antaf_voice/antaf_voice.py

这是一个特殊的 ASR Provider它不做语音识别而是

  1. 接收 ESP32 的 Opus 音频流
  2. 解码为 PCM重采样 24k→48k
  3. 通过 TCP 发送到 voice_bridge (port 18901) 的 inject 命令
  4. 接收 voice_bridge 的 speaker 输出
  5. 重采样 24k stereo → 24k monoOpus 编码
  6. 直接发回 ESP32跳过 LLM 和 TTS

方案B 风险点

  1. 帧时序同步: ESP32 音频帧和阿福 process() 调用频率可能不一致
  2. 延迟累积: 网络传输 + 两次重采样 + 注入延迟
  3. VAD 冲突: 阿福自带 VAD 可能与注入音频不匹配
  4. 回声消除失效: 注入 mic 数据后<EFBC8C><E998BF>的 AEC 参考信号spkRef对不上
  5. 对话控制: 何时 open_voice / close_voice 需要与 ESP32 唤醒状态同步

依赖清单

方案A新增依赖

  • requests — Python HTTP 库(服务端 venv 中应已有)

方案B新增<EFBFBD><EFBFBD>

  • opuslibpyogg — Opus 编解码
  • resampyscipy.signal — 采样率转换
  • numpy — 音频数据处理

文件清单

方案A

<EFBFBD><EFBFBD> 文件
新增 backend/main/xiaozhi-server/core/providers/llm/antaf/__init__.py
新增 backend/main/xiaozhi-server/core/providers/llm/antaf/antaf.py
修改 backend/main/xiaozhi-server/data/.config.yaml

方案B额外

操作 文件
修改 antaf/voice_bridge.js (新增 inject 命令)
新增 backend/main/xiaozhi-server/core/providers/asr/antaf_voice/antaf_voice.py
新增 backend/main/xiaozhi-server/core/utils/audio_resample.py

里程碑

阶段 目标 预期产出
M1 方案A 代码实现 AntafLLM Provider + 配置
M2 网络打通 PlugAI ↔ 手机 Bridge 连通
M3 端到端测试 ESP32 唤醒→阿福回答→语音播报
M4 方案B 原型 voice_bridge 音频注入验证
M5 方案B 集成 全语音直通链路