Metadata-Version: 2.5
Name: aichat_sdk
Version: 0.1.1
Summary: Voice chat SDK with streaming LLMs, MCP tools, and ByteDance, Edge, and MiMo TTS.
Project-URL: Homepage, https://gitee.com/fa0/aichat_sdk
Project-URL: Repository, https://gitee.com/fa0/aichat_sdk
Author: dairoot
Keywords: chat,openai,sdk,tts
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: av>=12.0
Requires-Dist: edge-tts>=7.0
Requires-Dist: fastmcp>=3.4.7
Requires-Dist: jinja2>=3.1.0
Requires-Dist: lunardate==0.2.2
Requires-Dist: numpy>=1.24
Requires-Dist: openai>=1.40.0
Requires-Dist: pydantic>=2.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: python-socks>=3.0.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: sounddevice>=0.5.6
Requires-Dist: websockets>=12.0
Provides-Extra: dev
Requires-Dist: types-pyyaml>=6.0.12; extra == 'dev'
Description-Content-Type: text/markdown

# aichat_sdk

一个语音对话 SDK。用户对着麦克风说话，SDK 负责听懂（语音识别）、想清楚（大模型 + 工具）、说出来（语音合成），宿主程序只需要把声音收进来、把声音放出去。

## 它能做什么

- **像人一样聊天**：回复是口语、短句，不念标题、不念符号，适合直接朗读；用户随时插话就能打断
- **会查东西**：天气、笑话、联网搜索（微博、搜狗，不用配 key），还能按需接入外部 MCP 工具
- **会用技能**：读取本机 `~/.agents/skills` 下的技能说明，按里面的指引一步步执行命令，比如查飞书群聊、发消息、看日程
- **会放音乐**：本地曲库点歌，边放边推歌词
- **知道时间和地点**：公历、农历、临近节日、用户所在城市，都会告诉模型
- **自己结束对话**：聊完了或者空闲太久，会说句再见然后关会话

## 它是怎么工作的

整条链路是一根事件驱动的流水线：

1. **听**：麦克风的声音通过 WebSocket 送到独立的 ASR 服务（单独的 `asr_server` 仓库，识别、断句、声纹都在那边），识别结果回到 SDK
2. **想**：识别出的文字交给大模型。模型可以直接回答，也可以先调工具、读技能、执行命令，拿到结果再回答；整个过程流式进行，第一个字出来就开始往下传
3. **说**：模型每吐出一点文字就喂给语音合成，合成出的音频编成 Opus 包排进队列
4. **播**：宿主从队列里按顺序取消息——识别结果、工具调用、每句话的开始和结束、音频包、歌词、结束信号——自己解码播放

有一条必须遵守的约定：**收到音频就把麦克风静音，收到「音频播完」再恢复拾音**，否则机器会听见自己说话。

## 大模型这一层

- 支持任何 OpenAI 兼容的接口，实际用过 DeepSeek 和通义千问
- 系统提示词是模板生成的，把角色人设、当前日期、用户位置、可用技能清单一起注入；提示词专门为语音场景写，要求模型说人话、说短话
- **思考模式按需开关**：用户刚说完话的第一次调用不开思考，保证回得快；一旦调过工具，后面的调用就打开思考，让推理过程走单独的通道、不会被念出来（`AgentInfo.tool_thinking` 可关掉，网页控制台上也有对应勾选框）。这么做是因为某些模型关掉思考后会把「让我先看看」这类内心独白直接写进回复，提示词管不住
- 推理内容会保存在对话记录里，web 页面上折叠显示，方便排查模型为什么这么答

## 语音合成

- **字节跳动**（默认）：服务端双向流式，逐字喂进去就出声，延迟最低；`tts_engine="bytedancev1"`（默认，简写 `v1`）或 `"bytedancev2"`（简写 `v2`）
- **微软 Edge**：免 key，按标点切成小段并发请求，段短所以首包也快
- **小米 MiMo**：`tts_engine="mimo"`，使用 `mimo-v2.5-tts` 预置音色，按标点分段请求、逐段流式输出 24kHz PCM，支持插话打断

各引擎输出格式一致，切换只需要改一个参数。

从 `0.1.0` 升级到 `0.1.1` 时，原 `bytedance`、`v2`、`bytedancev2` 配置改用 `bytedancev1`（简写 `v1`）；原 `v3`、`bytedancev3` 改用 `bytedancev2`（简写 `v2`）。直接导入 TTS 模块时也需同步调整路径，旧 `tts/bytedance/` 实现已删除。默认引擎仍使用原来的实现。

可通过 `from aichat_sdk import get_tts_engines` 查询 SDK 支持的引擎，返回每个引擎的 `name`、`label`、`aliases` 和 `default`。查询目录无需配置密钥，也不会加载各引擎依赖或发起连接；web 配置台的下拉选项和配置校验均使用该目录。

### 使用 MiMo TTS

按 [MiMo 官方文档](https://mimo.mi.com/docs/zh-CN/quick-start/usage-guide/audio/speech-synthesis-v2.5) 获取 API Key，在环境变量或 `.env` 中配置：

```dotenv
MIMO_API_KEY=你的小米MiMo密钥
MIMO_TTS_VOICE=mimo_default
# 可选：语气、语速等自然语言指令，不会被朗读
MIMO_TTS_INSTRUCTIONS=用自然、温柔的语气说话
# 可选，默认地址如下
MIMO_BASE_URL=https://api.xiaomimimo.com/v1
```

使用 `.env` 时，在导入 SDK 前加载配置（web 配置台已自动加载）：

```python
from dotenv import load_dotenv

load_dotenv()
from aichat_sdk import ChatBot

chat_bot = ChatBot(tts_engine="mimo")
```

其余初始化、拾音和队列播放流程与现有示例相同；web 配置台也可直接选择 `mimo`。`MIMO_API_KEY` 独立于聊天模型的 `OPENAI_API_KEY`。音色默认 `mimo_default`，可改为 `冰糖`、`茉莉`、`苏打`、`白桦` 等预置音色。

MiMo 每次请求接收一段完整文本；SDK 在逗号、句号等停顿处发起请求，段内边收音频边推送，结束时补发未带标点的尾句。当前接入预置音色合成，音色设计和音色克隆模型尚未接入。

## 怎么试

- 配好 `.env`：大模型的地址、模型名和 key；用字节 TTS 的话再加它的 App ID 和 Key；ASR 服务地址不改就用默认的本机端口
- 先把 `asr_server` 跑起来
- 有麦克风和扬声器就运行 `tests/test_run_v2.py` 直接对话；没有麦克风就运行 `tests/test_run.py`，它在代码里塞了两句话进去
- 想边聊边改配置，运行 `examples/web/main.py`，浏览器打开本机 8080 端口：可以换模型、换音色、改人设、开关工具、配外部 MCP，保存后立即生效；页面上还能实时看到每一轮对话、工具调用和模型的思考内容，每轮聊完会自动存一份完整记录

## 给开发者

要改代码，先看 `AGENTS.md`：队列和事件的实现细节、MCP 工具怎么注册注销、TTS 会话的生命周期限制、各种踩过的坑都记在那里。
