# Jarvis — 实时语音 AI 助手

基于 **LiveKit WebRTC + Gemini Multimodal Live + Hermes Agent** 的三层架构实时语音助手。

```
手机/浏览器 ──WebRTC──► LiveKit Server ──► Python Agent ──► Gemini Live (语音)
                   (SFU 转发)         (Arch C)     └──► Hermes Proxy (深度推理)
```

## 项目文件

| 文件 | 用途 |
|:---|:---|
| `agent.py` | **Architecture C** — Gemini 原生语音 + Hermes function calling |
| `webapp.html` | Push-to-Talk Web 前端，按住说话松开结束 |
| `start_webapp.py` | 一键：生成 JWT Token → 打开浏览器 → HTTP 服务 |
| `livekit-client.umd.min.js` | LiveKit JS SDK v2.9.5（本地化，绕过 CDN 墙） |
| `.env` | 环境变量（GOOGLE_API_KEY, Hermes Proxy URL 等） |
| `pyproject.toml` | uv 项目配置，依赖：`livekit-agents[google]`, `httpx`, `python-dotenv` |

## 架构决策记录 (ADR)

### 为什么最终选 Architecture C？

经过三轮迭代：

1. **Architecture B（混合管道）**：Whisper STT + Hermes LLM + Edge TTS
   - 问题：串行延迟 2-5s，Whisper 误识别中文，Silero VAD 噪声环境下不可靠，OpenAI Key 欠费

2. **Architecture A（Gemini 直连）**：Gemini 原生全双工
   - 问题：延迟极低但完全绕过 Hermes，没有 SOUL.md 人格和技能系统

3. **Architecture C（当前）**：Gemini 语音 + Hermes function calling
   - 日常对话：Gemini Live 原生处理，<500ms 延迟，原生打断
   - 深度推理：Gemini 自动判断并调用 `query_hermes()` → Hermes Proxy → SOUL.md + 三实体分流
   - 单进程部署，无额外 STT/TTS 服务

### API 陷阱

| 陷阱 | 症状 | 根因 |
|:---|:---|:---|
| `OPENAI_API_BASE` 全局污染 | STT/TTS 404 | Hermes 无法处理 `/v1/audio/*` 端点 |
| `Voice.Aoede` AttributeError | Agent 启动崩溃 | 1.6.x 中 Voice 是 `Literal` 类型，需用字符串 `"Aoede"` |
| `google.beta.realtime.MultimodalAgent` | 不存在 | 1.6.x 已移除，直接用 `Agent(llm=RealtimeModel(...))` |
| jsDelivr CDN 被墙 | 浏览器 `LiveKit is not defined` | 下载 JS SDK 到本地引用 |
| `close_on_disconnect=True` | 刷新页面后 Agent 退出 | 设置 `RoomInputOptions(close_on_disconnect=False)` |
| `python-multipart` 缺失 | Whisper Server 500 | Starlette form 解析需要此依赖 |
| JWT 密钥 6 字节 | 安全警告 | `secret` 不足 32 字节，生产用 `openssl rand -hex 32` |

### Push-to-Talk vs VAD

- **Console 模式**：Gemini 自带 VAD，在安静环境下表现良好
- **WebApp**：实现为 push-to-talk（按住说话松开结束），完全避免环境噪声问题
- 打断功能经过多次迭代但均不完美——Gemini 的打断依赖音频信号而非客户端指令

## 部署

### 本地测试

```bash
# 1. LiveKit Server
livekit-server --dev --bind 0.0.0.0 &

# 2. Jarvis Agent (systemd)
systemctl --user enable --now jarvis-agent

# 3. Web 前端
uv run python start_webapp.py
```

### 迁移到 Arch VM

```bash
# 复制整个项目目录
scp -r ~/Project/livekit-llm-agent user@arch-vm:~/Project/

# 在 Arch VM 上
cd ~/Project/livekit-llm-agent
uv sync
uv run -m livekit.agents download-files

# 安装 LiveKit
paru -S livekit livekit-cli

# 配置 systemd
cp deploy/jarvis-agent.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now jarvis-agent
```

## 下一步

1. **frp 穿透**：Tokyo VPS 运行 frps，Arch VM 运行 frpc，TCP 隧道暴露 LiveKit (7880) 和 WebApp (8080)
2. **TLS 加密**：frp `vhostHTTPSPort` + certbot 证书，`transport.useEncryption` 加密隧道
3. **TG Bot 集成**：Bot 处理 `/voice` 命令 → Python SDK 签发 JWT → 回复 WebApp 按钮 → H5 打开即用
4. **生产密钥**：`openssl rand -hex 32` 替换 devkey/secret
5. **多房间隔离**：每个 TG 用户分配独立 room，Agent 自动加入

## 依赖版本

- Python ≥ 3.14
- livekit-agents 1.6.0
- livekit-plugins-google 1.6.0
- livekit-server 1.13.1
- livekit-client (JS) 2.9.5
