mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
Home assistant (#97)
* add home assistant * update home assistant remark * update config * update:优化文档 --------- Co-authored-by: ck3 <kyriechen03@qq.com> Co-authored-by: Kyrie Chen <794103684@qq.com> Co-authored-by: hrz <1710360675@qq.com>
This commit is contained in:
co-authored by
ck3
Kyrie Chen
hrz
parent
de793625e4
commit
afa469c08c
@@ -80,15 +80,16 @@ server:
|
|||||||
|
|
||||||
### LLM
|
### LLM
|
||||||
|
|
||||||
| 类型 | 平台名称 | 使用方式 | 收费模式 | 备注 |
|
| 类型 | 平台名称 | 使用方式 | 收费模式 | 备注 |
|
||||||
|:---:|:------------------:|:-----------:|:--------:|:-----------------------------------------------------------------:|
|
|:---:|:------------------:|:---------------------:|:--------:|:-----------------------------------------------------------------:|
|
||||||
| LLM | 阿里百炼 (AliLLM) | openai 接口调用 | 消耗 token | [点击申请密钥](https://bailian.console.aliyun.com/?apiKey=1#/api-key) |
|
| LLM | 阿里百炼 (AliLLM) | openai 接口调用 | 消耗 token | [点击申请密钥](https://bailian.console.aliyun.com/?apiKey=1#/api-key) |
|
||||||
| LLM | 深度求索 (DeepSeekLLM) | openai 接口调用 | 消耗 token | [点击申请密钥](https://platform.deepseek.com/) |
|
| LLM | 深度求索 (DeepSeekLLM) | openai 接口调用 | 消耗 token | [点击申请密钥](https://platform.deepseek.com/) |
|
||||||
| LLM | 智谱(ChatGLMLLM) | openai 接口调用 | 免费 | 虽然免费,仍需[点击申请密钥](https://bigmodel.cn/usercenter/proj-mgmt/apikeys) |
|
| LLM | 智谱(ChatGLMLLM) | openai 接口调用 | 免费 | 虽然免费,仍需[点击申请密钥](https://bigmodel.cn/usercenter/proj-mgmt/apikeys) |
|
||||||
| LLM | OllamaLLM | ollama 接口调用 | 免费/自定义 | 需预先下载模型(`ollama pull`),服务地址:`http://localhost:11434` |
|
| LLM | OllamaLLM | ollama 接口调用 | 免费/自定义 | 需预先下载模型(`ollama pull`),服务地址:`http://localhost:11434` |
|
||||||
| LLM | DifyLLM | dify 接口调用 | 消耗 token | 本地化部署,注意配置提示词需在 Dify 控制台设置 |
|
| LLM | DifyLLM | dify 接口调用 | 消耗 token | 本地化部署,注意配置提示词需在 Dify 控制台设置 |
|
||||||
| LLM | GeminiLLM | gemini 接口调用 | 免费 | [点击申请密钥](https://aistudio.google.com/apikey) |
|
| LLM | GeminiLLM | gemini 接口调用 | 免费 | [点击申请密钥](https://aistudio.google.com/apikey) |
|
||||||
| LLM | CozeLLM | coze 接口调用 | 消耗 token | 需提供 bot_id、user_id 及个人令牌 |
|
| LLM | CozeLLM | coze 接口调用 | 消耗 token | 需提供 bot_id、user_id 及个人令牌 |
|
||||||
|
| LLM | Home Assistant | homeassistant语音助手接口调用 | 免费 | 需提供home assistant令牌 |
|
||||||
|
|
||||||
实际上,任何支持 openai 接口调用的 LLM 均可接入使用。
|
实际上,任何支持 openai 接口调用的 LLM 均可接入使用。
|
||||||
|
|
||||||
@@ -127,11 +128,8 @@ server:
|
|||||||
|
|
||||||
### 一、[部署文档](./docs/Deployment.md)
|
### 一、[部署文档](./docs/Deployment.md)
|
||||||
|
|
||||||
1.
|
1.**[本地源码运行](./docs/Deployment.md#%E6%96%B9%E5%BC%8F%E4%B8%89%E6%9C%AC%E5%9C%B0%E6%BA%90%E7%A0%81%E8%BF%90%E8%A1%8C)**
|
||||||
*
|
|
||||||
|
|
||||||
*[本地源码运行](./docs/Deployment.md#%E6%96%B9%E5%BC%8F%E4%B8%89%E6%9C%AC%E5%9C%B0%E6%BA%90%E7%A0%81%E8%BF%90%E8%A1%8C)
|
|
||||||
**
|
|
||||||
适合熟悉 Conda 环境或希望从零搭建运行环境的用户。
|
适合熟悉 Conda 环境或希望从零搭建运行环境的用户。
|
||||||
对于对响应速度要求较高的场景,推荐使用本地源码运行方式以降低额外开销。
|
对于对响应速度要求较高的场景,推荐使用本地源码运行方式以降低额外开销。
|
||||||
|
|
||||||
@@ -152,7 +150,7 @@ server:
|
|||||||
|
|
||||||
### 2、我想通过小智控制电灯、空调、远程开关机等操作 💡
|
### 2、我想通过小智控制电灯、空调、远程开关机等操作 💡
|
||||||
|
|
||||||
建议:在配置文件中将 `LLM` 设置为 `DifyLLM`,并通过 `Dify` 编排智能体来实现相关控制。
|
建议:在配置文件中将 `LLM` 设置为 `HomeAssistant`,通过 调用`HomeAssistant`接口实现相关控制。
|
||||||
|
|
||||||
### 3、我说话很慢,停顿时小智老是抢话 🗣️
|
### 3、我说话很慢,停顿时小智老是抢话 🗣️
|
||||||
|
|
||||||
@@ -166,7 +164,21 @@ VAD:
|
|||||||
min_silence_duration_ms: 700 # 如果说话停顿较长,可将此值调大
|
min_silence_duration_ms: 700 # 如果说话停顿较长,可将此值调大
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4、如何提高小智对话响应速度? ⚡
|
### 4、为什么我说的话,小智识别出来很多韩文、日文、英文?🇰🇷
|
||||||
|
|
||||||
|
建议:检查一下`models/SenseVoiceSmall`是否已经有`model.pt`文件,如果没有就要下载,查看这里[下载语音识别模型文件](docs/Deployment.md#模型文件)
|
||||||
|
|
||||||
|
### 5、为什么会出现“TTS 任务出错 文件不存在”?📁
|
||||||
|
|
||||||
|
建议:检查一下是否正确使用`conda` 安装了`libopus`和`ffmpeg`库。
|
||||||
|
|
||||||
|
如果没有安装,就安装
|
||||||
|
```
|
||||||
|
conda install conda-forge::libopus
|
||||||
|
conda install conda-forge::ffmpeg
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6、如何提高小智对话响应速度? ⚡
|
||||||
|
|
||||||
本项目默认配置为低成本方案,建议初学者先使用默认免费模型,解决“跑得动”的问题,再优化“跑得快”。
|
本项目默认配置为低成本方案,建议初学者先使用默认免费模型,解决“跑得动”的问题,再优化“跑得快”。
|
||||||
如需提升响应速度,可尝试更换各组件。以下为各组件的响应速度测试数据(仅供参考,不构成承诺):
|
如需提升响应速度,可尝试更换各组件。以下为各组件的响应速度测试数据(仅供参考,不构成承诺):
|
||||||
@@ -224,7 +236,7 @@ TTS 性能排行:
|
|||||||
- LLM:`AliLLM`
|
- LLM:`AliLLM`
|
||||||
- TTS:`DoubaoTTS`
|
- TTS:`DoubaoTTS`
|
||||||
|
|
||||||
### 5、更多问题,可联系我们反馈 💬
|
### 7、更多问题,可联系我们反馈 💬
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,12 @@ LLM:
|
|||||||
user_id: 你的user_id
|
user_id: 你的user_id
|
||||||
base_url: "https://api.coze.cn/open_api/v2/chat" # 服务地址
|
base_url: "https://api.coze.cn/open_api/v2/chat" # 服务地址
|
||||||
personal_access_token: 你的coze个人令牌
|
personal_access_token: 你的coze个人令牌
|
||||||
|
HomeAssistant:
|
||||||
|
# 定义LLM API类型
|
||||||
|
type: homeassistant
|
||||||
|
base_url: http://homeassistant.local:8123
|
||||||
|
agent_id: conversation.chatgpt
|
||||||
|
api_key: 你的home assistant api访问令牌
|
||||||
TTS:
|
TTS:
|
||||||
# 当前支持的type为edge、doubao,可自行适配
|
# 当前支持的type为edge、doubao,可自行适配
|
||||||
EdgeTTS:
|
EdgeTTS:
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import requests
|
||||||
|
from requests.exceptions import RequestException
|
||||||
|
from config.logger import setup_logging
|
||||||
|
from core.providers.llm.base import LLMProviderBase
|
||||||
|
|
||||||
|
TAG = __name__
|
||||||
|
logger = setup_logging()
|
||||||
|
|
||||||
|
|
||||||
|
class LLMProvider(LLMProviderBase):
|
||||||
|
def __init__(self, config):
|
||||||
|
self.agent_id = config.get("agent_id") # 对应 agent_id
|
||||||
|
self.api_key = config.get("api_key")
|
||||||
|
self.base_url = config.get("base_url", config.get("url")) # 默认使用 base_url
|
||||||
|
self.api_url = f"{self.base_url}/api/conversation/process" # 拼接完整的 API URL
|
||||||
|
|
||||||
|
def response(self, session_id, dialogue):
|
||||||
|
print(dialogue)
|
||||||
|
try:
|
||||||
|
# home assistant语音助手自带意图,无需使用xiaozhi ai自带的,只需要把用户说的话传递给home assistant即可
|
||||||
|
|
||||||
|
# 提取最后一个 role 为 'user' 的 content
|
||||||
|
input_text = None
|
||||||
|
if isinstance(dialogue, list): # 确保 dialogue 是一个列表
|
||||||
|
# 逆序遍历,找到最后一个 role 为 'user' 的消息
|
||||||
|
for message in reversed(dialogue):
|
||||||
|
if message.get("role") == "user": # 找到 role 为 'user' 的消息
|
||||||
|
input_text = message.get("content", "")
|
||||||
|
break # 找到后立即退出循环
|
||||||
|
|
||||||
|
# 构造请求数据
|
||||||
|
payload = {
|
||||||
|
"text": input_text,
|
||||||
|
"agent_id": self.agent_id,
|
||||||
|
"conversation_id": session_id # 使用 session_id 作为 conversation_id
|
||||||
|
}
|
||||||
|
# 设置请求头
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {self.api_key}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 发起 POST 请求
|
||||||
|
response = requests.post(self.api_url, json=payload, headers=headers)
|
||||||
|
|
||||||
|
# 检查请求是否成功
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
# 解析返回数据
|
||||||
|
data = response.json()
|
||||||
|
speech = data.get("response", {}).get("speech", {}).get("plain", {}).get("speech", "")
|
||||||
|
|
||||||
|
# 返回生成的内容
|
||||||
|
if speech:
|
||||||
|
yield speech
|
||||||
|
else:
|
||||||
|
logger.bind(tag=TAG).warning("API 返回数据中没有 speech 内容")
|
||||||
|
|
||||||
|
except RequestException as e:
|
||||||
|
logger.bind(tag=TAG).error(f"HTTP 请求错误: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.bind(tag=TAG).error(f"生成响应时出错: {e}")
|
||||||
@@ -9,8 +9,11 @@ from pydantic import BaseModel, Field, conint, model_validator
|
|||||||
from typing_extensions import Annotated
|
from typing_extensions import Annotated
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
# from base import TTSProviderBase
|
|
||||||
from core.providers.tts.base import TTSProviderBase
|
from core.providers.tts.base import TTSProviderBase
|
||||||
|
from config.logger import setup_logging
|
||||||
|
|
||||||
|
TAG = __name__
|
||||||
|
logger = setup_logging()
|
||||||
|
|
||||||
|
|
||||||
class ServeReferenceAudio(BaseModel):
|
class ServeReferenceAudio(BaseModel):
|
||||||
@@ -86,6 +89,9 @@ class TTSProvider(TTSProviderBase):
|
|||||||
self.channels = config.get("channels",1)
|
self.channels = config.get("channels",1)
|
||||||
self.rate = config.get("rate",44100)
|
self.rate = config.get("rate",44100)
|
||||||
self.api_key = config.get("api_key","YOUR_API_KEY")
|
self.api_key = config.get("api_key","YOUR_API_KEY")
|
||||||
|
if not self.api_key or "你" in self.api_key:
|
||||||
|
logger.bind(tag=TAG).error("你还没配置FishSpeech TTS的密钥,请在配置文件中配置密钥,否则无法正常工作")
|
||||||
|
return
|
||||||
self.normalize = config.get("normalize",True)
|
self.normalize = config.get("normalize",True)
|
||||||
self.max_new_tokens = config.get("max_new_tokens",1024)
|
self.max_new_tokens = config.get("max_new_tokens",1024)
|
||||||
self.chunk_length = config.get("chunk_length",200)
|
self.chunk_length = config.get("chunk_length",200)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
import json
|
|
||||||
import base64
|
|
||||||
import requests
|
import requests
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from core.providers.tts.base import TTSProviderBase
|
from core.providers.tts.base import TTSProviderBase
|
||||||
|
|||||||
+2
-1
@@ -15,4 +15,5 @@ aiohttp==3.9.3
|
|||||||
aiohttp_cors==0.7.0
|
aiohttp_cors==0.7.0
|
||||||
ormsgpack==1.7.0
|
ormsgpack==1.7.0
|
||||||
ruamel.yaml==0.18.10
|
ruamel.yaml==0.18.10
|
||||||
loguru==0.7.3
|
loguru==0.7.3
|
||||||
|
requests>=2.0.0
|
||||||
Reference in New Issue
Block a user