xiaozhi-sdk 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- file/audio/greet.wav +0 -0
- file/audio/play_music.wav +0 -0
- file/audio/say_hello.wav +0 -0
- file/audio/take_photo.wav +0 -0
- file/image/leijun.jpg +0 -0
- file/opus/linux-arm64-libopus.so +0 -0
- file/opus/linux-x64-libopus.so +0 -0
- file/opus/macos-arm64-libopus.dylib +0 -0
- file/opus/macos-x64-libopus.dylib +0 -0
- file/opus/windows-opus.dll +0 -0
- xiaozhi_sdk/__init__.py +2 -154
- xiaozhi_sdk/__main__.py +7 -86
- xiaozhi_sdk/cli.py +231 -0
- xiaozhi_sdk/config.py +1 -3
- xiaozhi_sdk/core.py +269 -0
- xiaozhi_sdk/iot.py +61 -27
- xiaozhi_sdk/mcp.py +128 -32
- xiaozhi_sdk/opus.py +13 -11
- xiaozhi_sdk/utils/__init__.py +57 -0
- xiaozhi_sdk/utils/mcp_tool.py +185 -0
- xiaozhi_sdk-0.2.0.dist-info/METADATA +90 -0
- xiaozhi_sdk-0.2.0.dist-info/RECORD +25 -0
- xiaozhi_sdk-0.2.0.dist-info/licenses/LICENSE +21 -0
- xiaozhi_sdk/data.py +0 -58
- xiaozhi_sdk/utils.py +0 -23
- xiaozhi_sdk-0.1.0.dist-info/METADATA +0 -58
- xiaozhi_sdk-0.1.0.dist-info/RECORD +0 -12
- {xiaozhi_sdk-0.1.0.dist-info → xiaozhi_sdk-0.2.0.dist-info}/WHEEL +0 -0
- {xiaozhi_sdk-0.1.0.dist-info → xiaozhi_sdk-0.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import ctypes.util
|
|
2
|
+
import os
|
|
3
|
+
import platform
|
|
4
|
+
import wave
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_wav_info(file_path):
|
|
8
|
+
with wave.open(file_path, "rb") as wav_file:
|
|
9
|
+
return wav_file.getframerate(), wav_file.getnchannels()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def read_audio_file(file_path):
|
|
13
|
+
"""
|
|
14
|
+
读取音频文件并通过yield返回PCM流
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
file_path (str): 音频文件路径
|
|
18
|
+
|
|
19
|
+
Yields:
|
|
20
|
+
bytes: PCM音频数据块
|
|
21
|
+
"""
|
|
22
|
+
with wave.open(file_path, "rb") as wav_file:
|
|
23
|
+
while True:
|
|
24
|
+
pcm = wav_file.readframes(960) # 每次读取960帧(60ms的音频数据)
|
|
25
|
+
if not pcm:
|
|
26
|
+
break
|
|
27
|
+
yield pcm
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def setup_opus():
|
|
31
|
+
|
|
32
|
+
def fake_find_library(name):
|
|
33
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
34
|
+
if name == "opus":
|
|
35
|
+
system = platform.system().lower()
|
|
36
|
+
machine = platform.machine().lower()
|
|
37
|
+
|
|
38
|
+
# 检测架构
|
|
39
|
+
if machine in ["x86_64", "amd64", "x64"]:
|
|
40
|
+
arch = "x64"
|
|
41
|
+
elif machine in ["arm64", "aarch64"]:
|
|
42
|
+
arch = "arm64"
|
|
43
|
+
else:
|
|
44
|
+
# 默认使用x64作为回退
|
|
45
|
+
arch = "x64"
|
|
46
|
+
|
|
47
|
+
if system == "darwin": # macOS
|
|
48
|
+
return f"{current_dir}/../../file/opus/macos-{arch}-libopus.dylib"
|
|
49
|
+
elif system == "windows": # Windows
|
|
50
|
+
return f"{current_dir}/../../file/opus/windows-opus.dll"
|
|
51
|
+
elif system == "linux": # Linux
|
|
52
|
+
return f"{current_dir}/../../file/opus/linux-{arch}-libopus.so"
|
|
53
|
+
else:
|
|
54
|
+
# 默认情况,尝试系统查找
|
|
55
|
+
return ctypes.util.find_library(name)
|
|
56
|
+
|
|
57
|
+
ctypes.util.find_library = fake_find_library
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import random
|
|
3
|
+
|
|
4
|
+
import aiohttp
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def async_search_custom_music(data) -> tuple[dict, bool]:
|
|
9
|
+
search_url = f"https://music-api.gdstudio.xyz/api.php?types=search&name={data['music_name']}&count=100&pages=1"
|
|
10
|
+
|
|
11
|
+
# 为搜索请求设置 10 秒超时
|
|
12
|
+
timeout = aiohttp.ClientTimeout(total=10)
|
|
13
|
+
async with aiohttp.ClientSession(timeout=timeout) as session:
|
|
14
|
+
async with session.get(search_url) as response:
|
|
15
|
+
response_json = await response.json()
|
|
16
|
+
|
|
17
|
+
music_list = []
|
|
18
|
+
first_music_list = []
|
|
19
|
+
other_music_list1 = []
|
|
20
|
+
other_music_list2 = []
|
|
21
|
+
for line in response_json:
|
|
22
|
+
if data.get("author_name") and data["author_name"] in line["artist"][0]:
|
|
23
|
+
first_music_list.append(line)
|
|
24
|
+
elif data.get("author_name") and (data["author_name"] in line["artist"] or data["author_name"] in line["name"]):
|
|
25
|
+
other_music_list1.append(line)
|
|
26
|
+
else:
|
|
27
|
+
other_music_list2.append(line)
|
|
28
|
+
|
|
29
|
+
if len(first_music_list) <= 10:
|
|
30
|
+
music_list = first_music_list
|
|
31
|
+
random.shuffle(other_music_list2)
|
|
32
|
+
music_list = music_list + other_music_list1[: 20 - len(music_list)]
|
|
33
|
+
music_list = music_list + other_music_list2[: 20 - len(music_list)]
|
|
34
|
+
|
|
35
|
+
# print(data)
|
|
36
|
+
# print("找到音乐,数量:", len(first_music_list), len(music_list))
|
|
37
|
+
|
|
38
|
+
if not music_list:
|
|
39
|
+
return {}, False
|
|
40
|
+
return {"message": "已找到歌曲", "music_list": music_list}, False
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def _get_random_music_info(id_list: list) -> dict:
|
|
44
|
+
timeout = aiohttp.ClientTimeout(total=10)
|
|
45
|
+
async with aiohttp.ClientSession(timeout=timeout) as session:
|
|
46
|
+
random.shuffle(id_list)
|
|
47
|
+
|
|
48
|
+
for music_id in id_list:
|
|
49
|
+
url = f"https://music-api.gdstudio.xyz/api.php?types=url&id={music_id}&br=128"
|
|
50
|
+
async with session.get(url) as response:
|
|
51
|
+
res_json = await response.json()
|
|
52
|
+
if res_json.get("url"):
|
|
53
|
+
break
|
|
54
|
+
|
|
55
|
+
return res_json
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
async def async_mcp_play_music(data) -> tuple[list, bool]:
|
|
59
|
+
try:
|
|
60
|
+
from pydub import AudioSegment
|
|
61
|
+
except ImportError:
|
|
62
|
+
return [], True
|
|
63
|
+
|
|
64
|
+
id_list = data["id_list"]
|
|
65
|
+
res_json = await _get_random_music_info(id_list)
|
|
66
|
+
|
|
67
|
+
if not res_json:
|
|
68
|
+
return [], False
|
|
69
|
+
|
|
70
|
+
pcm_list = []
|
|
71
|
+
buffer = io.BytesIO()
|
|
72
|
+
# 为下载音乐文件设置 60 秒超时(音乐文件可能比较大)
|
|
73
|
+
download_timeout = aiohttp.ClientTimeout(total=60)
|
|
74
|
+
async with aiohttp.ClientSession(timeout=download_timeout) as session:
|
|
75
|
+
async with session.get(res_json["url"]) as resp:
|
|
76
|
+
async for chunk in resp.content.iter_chunked(1024):
|
|
77
|
+
buffer.write(chunk)
|
|
78
|
+
|
|
79
|
+
buffer.seek(0)
|
|
80
|
+
audio = AudioSegment.from_mp3(buffer)
|
|
81
|
+
audio = audio.set_frame_rate(16000).set_channels(1).set_sample_width(2) # 2 bytes = 16 bits
|
|
82
|
+
pcm_data = audio.raw_data
|
|
83
|
+
|
|
84
|
+
chunk_size = 960 * 2
|
|
85
|
+
for i in range(0, len(pcm_data), chunk_size):
|
|
86
|
+
chunk = pcm_data[i : i + chunk_size]
|
|
87
|
+
|
|
88
|
+
if chunk: # 确保不添加空块
|
|
89
|
+
chunk = np.frombuffer(chunk, dtype=np.int16)
|
|
90
|
+
pcm_list.extend(chunk)
|
|
91
|
+
|
|
92
|
+
return pcm_list, False
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
search_custom_music = {
|
|
96
|
+
"name": "search_custom_music",
|
|
97
|
+
"description": "Search music and get music IDs. Use this tool when the user asks to search or play music. This tool returns a list of music with their IDs, which are required for playing music. Args:\n `music_name`: The name of the music to search\n `author_name`: The name of the music author (optional)",
|
|
98
|
+
"inputSchema": {
|
|
99
|
+
"type": "object",
|
|
100
|
+
"properties": {"music_name": {"type": "string"}, "author_name": {"type": "string"}},
|
|
101
|
+
"required": ["music_name"],
|
|
102
|
+
},
|
|
103
|
+
"tool_func": async_search_custom_music,
|
|
104
|
+
"is_async": True,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
play_custom_music = {
|
|
108
|
+
"name": "play_custom_music",
|
|
109
|
+
"description": "Play music using music IDs. IMPORTANT: You must call `search_custom_music` first to get the music IDs before using this tool. Use this tool after getting music IDs from search results. Args:\n `id_list`: The id list of the music to play (obtained from search_custom_music results). The list must contain more than 2 music IDs, and the system will randomly select one to play.\n `music_name`: The name of the music (obtained from search_custom_music results)",
|
|
110
|
+
"inputSchema": {
|
|
111
|
+
"type": "object",
|
|
112
|
+
"properties": {
|
|
113
|
+
"music_name": {"type": "string"},
|
|
114
|
+
"id_list": {"type": "array", "items": {"type": "string"}, "minItems": 3},
|
|
115
|
+
},
|
|
116
|
+
"required": ["music_name", "id_list"],
|
|
117
|
+
},
|
|
118
|
+
"tool_func": async_mcp_play_music,
|
|
119
|
+
"is_async": True,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
stop_music = {
|
|
123
|
+
"name": "stop_music",
|
|
124
|
+
"description": "Stop playing music.",
|
|
125
|
+
"inputSchema": {"type": "object", "properties": {}},
|
|
126
|
+
"tool_func": None,
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
get_device_status = {
|
|
130
|
+
"name": "get_device_status",
|
|
131
|
+
"description": "Provides the real-time information of the device, including the current status of the audio speaker, screen, battery, network, etc.\nUse this tool for: \n1. Answering questions about current condition (e.g. what is the current volume of the audio speaker?)\n2. As the first step to control the device (e.g. turn up / down the volume of the audio speaker, etc.)",
|
|
132
|
+
"inputSchema": {"type": "object", "properties": {}},
|
|
133
|
+
"tool_func": None,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
set_volume = {
|
|
137
|
+
"name": "set_volume",
|
|
138
|
+
"description": "Set the volume of the audio speaker. If the current volume is unknown, you must call `get_device_status` tool first and then call this tool.",
|
|
139
|
+
"inputSchema": {
|
|
140
|
+
"type": "object",
|
|
141
|
+
"properties": {"volume": {"type": "integer", "minimum": 0, "maximum": 100}},
|
|
142
|
+
"required": ["volume"],
|
|
143
|
+
},
|
|
144
|
+
"tool_func": None,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
set_brightness = {
|
|
148
|
+
"name": "set_brightness",
|
|
149
|
+
"description": "Set the brightness of the screen.",
|
|
150
|
+
"inputSchema": {
|
|
151
|
+
"type": "object",
|
|
152
|
+
"properties": {"brightness": {"type": "integer", "minimum": 0, "maximum": 100}},
|
|
153
|
+
"required": ["brightness"],
|
|
154
|
+
},
|
|
155
|
+
"tool_func": None,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
set_theme = {
|
|
159
|
+
"name": "set_theme",
|
|
160
|
+
"description": "Set the theme of the screen. The theme can be `light` or `dark`.",
|
|
161
|
+
"inputSchema": {"type": "object", "properties": {"theme": {"type": "string"}}, "required": ["theme"]},
|
|
162
|
+
"tool_func": None,
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
take_photo = {
|
|
166
|
+
"name": "take_photo",
|
|
167
|
+
"description": "Use this tool when the user asks you to look at something, take a picture, or solve a problem based on what is captured.\nArgs:\n`question`: A clear question or task you want to ask about the captured photo (e.g., identify objects, read text, explain content, or solve a math/logic problem).\nReturn:\n A JSON object that provides the photo information, including answers, explanations, or problem-solving results if applicable.",
|
|
168
|
+
"inputSchema": {
|
|
169
|
+
"type": "object",
|
|
170
|
+
"properties": {"question": {"type": "string"}},
|
|
171
|
+
"required": ["question"],
|
|
172
|
+
},
|
|
173
|
+
"tool_func": None,
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
open_tab = {
|
|
177
|
+
"name": "open_tab",
|
|
178
|
+
"description": "Open a web page in the browser. 小智后台:https://xiaozhi.me",
|
|
179
|
+
"inputSchema": {
|
|
180
|
+
"type": "object",
|
|
181
|
+
"properties": {"url": {"type": "string"}},
|
|
182
|
+
"required": ["url"],
|
|
183
|
+
},
|
|
184
|
+
"tool_func": None,
|
|
185
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xiaozhi-sdk
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: 一个用于连接和控制小智智能设备的Python SDK,支持实时音频通信、MCP工具集成和设备管理功能。
|
|
5
|
+
Author-email: dairoot <623815825@qq.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/dairoot/xiaozhi-sdk
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: numpy
|
|
14
|
+
Requires-Dist: websockets>=15.0.1
|
|
15
|
+
Requires-Dist: aiohttp
|
|
16
|
+
Requires-Dist: av
|
|
17
|
+
Requires-Dist: opuslib
|
|
18
|
+
Requires-Dist: requests
|
|
19
|
+
Requires-Dist: sounddevice
|
|
20
|
+
Requires-Dist: python-socks
|
|
21
|
+
Requires-Dist: click
|
|
22
|
+
Requires-Dist: colorlog
|
|
23
|
+
Requires-Dist: soundfile>=0.13.1
|
|
24
|
+
Requires-Dist: pydub>=0.25.1
|
|
25
|
+
Requires-Dist: pillow>=11.3.0
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# 小智SDK (XiaoZhi SDK)
|
|
29
|
+
|
|
30
|
+
[](https://www.python.org/downloads/)
|
|
31
|
+
[](LICENSE)
|
|
32
|
+
[](https://pypi.org/project/xiaozhi-sdk/)
|
|
33
|
+
|
|
34
|
+
基于虾哥的 [小智esp32 websocket 通讯协议](https://github.com/78/xiaozhi-esp32/blob/main/docs/websocket.md) 实现的 Python SDK。
|
|
35
|
+
|
|
36
|
+
一个用于连接和控制小智设备的 Python SDK。支持以下功能:
|
|
37
|
+
- 实时音频通信
|
|
38
|
+
- MCP 工具集成
|
|
39
|
+
- 设备管理与控制
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 📦 安装
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install xiaozhi-sdk
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 🚀 快速开始
|
|
52
|
+
|
|
53
|
+
### 1. 终端使用
|
|
54
|
+
|
|
55
|
+
最简单的方式是通过终端直接连接设备:
|
|
56
|
+
|
|
57
|
+
#### 查看帮助信息
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python -m xiaozhi_sdk --help
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### 连接设备(需要提供 MAC 地址)
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
python -m xiaozhi_sdk 00:22:44:66:88:00
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 2. 编程使用 (高阶用法)
|
|
70
|
+
参考 [examples](examples/) 文件中的示例代码,可以快速开始使用 SDK。
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## ✅ 运行测试
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# 安装开发依赖
|
|
79
|
+
uv sync --group dev
|
|
80
|
+
|
|
81
|
+
# 运行测试
|
|
82
|
+
uv run pytest
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 🫡 致敬
|
|
89
|
+
|
|
90
|
+
- 🫡 虾哥的 [xiaozhi-esp32](https://github.com/78/xiaozhi-esp32) 项目
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
file/audio/greet.wav,sha256=F60kKKFVQZyYh67_-9AJHMviuquSWHHqwGQewUSOAFg,32720
|
|
2
|
+
file/audio/play_music.wav,sha256=uqUIKz-3bqViDsjEZ2n6g_7xsggbRY6JwdZTCGS8b2E,61772
|
|
3
|
+
file/audio/say_hello.wav,sha256=RGo2MDUF7npGmjFPT4III0ibf7dIZ1c47jijrF0Yjaw,34146
|
|
4
|
+
file/audio/take_photo.wav,sha256=_DNWg31Q8NIxN3eUS4wBC7mn4MZCWLCNPuKfKPv1ojQ,51412
|
|
5
|
+
file/image/leijun.jpg,sha256=plhBvnB4O21RjLwH-HjNq0jH4Msy5ppA_IDWe5ieNg4,70814
|
|
6
|
+
file/opus/linux-arm64-libopus.so,sha256=D2H5VDUomaYuLetejCvLwCgf-iAVP0isg1yGwfsuvEE,493032
|
|
7
|
+
file/opus/linux-x64-libopus.so,sha256=FmXJqkxLpDzNFOHYkmOzmsp1hP0eIS5b6x_XfOs-IQA,623008
|
|
8
|
+
file/opus/macos-arm64-libopus.dylib,sha256=H7wXwkrGwb-hesMMZGFxWb0Ri1Y4m5GWiKsd8CfOhE8,357584
|
|
9
|
+
file/opus/macos-x64-libopus.dylib,sha256=MqyL_OjwSACF4Xs_-KrGbcScy4IEprr5Rlkk3ddZye8,550856
|
|
10
|
+
file/opus/windows-opus.dll,sha256=kLfhioMvbJhOgNMAldpWk3DCZqC5Xd70LRbHnACvAnw,463360
|
|
11
|
+
xiaozhi_sdk/__init__.py,sha256=EnDhE3nCihG1u1vq2yjaZLzlHRKoNmEC-eJSlD7BXxo,77
|
|
12
|
+
xiaozhi_sdk/__main__.py,sha256=i0ZJdHUqAKg9vwZrK_w0TJkzdotTYTK8aUeSPcJc1ks,210
|
|
13
|
+
xiaozhi_sdk/cli.py,sha256=CEpjXW-vnT8DieaK1MV0AYCG4bmK2_vpIz-9zhWHVgE,7001
|
|
14
|
+
xiaozhi_sdk/config.py,sha256=h4mpMeBf2vT9qYAqCCbGVGmMemkgk98pcXP2Rh4TEFc,89
|
|
15
|
+
xiaozhi_sdk/core.py,sha256=kTcENYV7s91kpVyb5-E72l3GMweBpC8bKVZQ_SHR1GU,9807
|
|
16
|
+
xiaozhi_sdk/iot.py,sha256=VVAheynp1iV4GCaoPywQWpKtlyoACDLswH8yfV_JZgI,2699
|
|
17
|
+
xiaozhi_sdk/mcp.py,sha256=YLZOj1F2ILwqhfevETVK2_K7pVweJGMnuMcdRmu6PJg,6558
|
|
18
|
+
xiaozhi_sdk/opus.py,sha256=r3nnYg0ZKAJTreb_3nKgfHJh06MJiMvnNMPO1SWdoMM,2224
|
|
19
|
+
xiaozhi_sdk/utils/__init__.py,sha256=XKSHWoFmuSkpwaIr308HybRzfFIXoT1Fd-eUKo_im6Y,1705
|
|
20
|
+
xiaozhi_sdk/utils/mcp_tool.py,sha256=uxT8jUANGs1mDrTGVkIv1eO89k4qn8WAgXYzITBLObg,7251
|
|
21
|
+
xiaozhi_sdk-0.2.0.dist-info/licenses/LICENSE,sha256=Vwgps1iODKl43cAtME_0dawTjAzNW-O2BWiN5BHggww,1085
|
|
22
|
+
xiaozhi_sdk-0.2.0.dist-info/METADATA,sha256=PN5vqqocSqZEoQl30P_IO_QMfMY_cZo7YkboXP8SR3M,2121
|
|
23
|
+
xiaozhi_sdk-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
24
|
+
xiaozhi_sdk-0.2.0.dist-info/top_level.txt,sha256=nBpue4hU5Ykm5CtYPsAdxSa_yqbtZsIT_gF_EkBaJPM,12
|
|
25
|
+
xiaozhi_sdk-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 dairoot
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
xiaozhi_sdk/data.py
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
mcp_initialize_payload = {
|
|
2
|
-
"jsonrpc": "2.0",
|
|
3
|
-
"id": 1,
|
|
4
|
-
"result": {
|
|
5
|
-
"protocolVersion": "2024-11-05",
|
|
6
|
-
"capabilities": {"tools": {}},
|
|
7
|
-
"serverInfo": {"name": "", "version": "0.0.1"},
|
|
8
|
-
},
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
mcp_tool_conf = {
|
|
12
|
-
"get_device_status": {
|
|
13
|
-
"description": "Provides the real-time information of the device, including the current status of the audio speaker, screen, battery, network, etc.\nUse this tool for: \n1. Answering questions about current condition (e.g. what is the current volume of the audio speaker?)\n2. As the first step to control the device (e.g. turn up / down the volume of the audio speaker, etc.)",
|
|
14
|
-
"inputSchema": {"type": "object", "properties": {}},
|
|
15
|
-
},
|
|
16
|
-
"set_volume": {
|
|
17
|
-
"description": "Set the volume of the audio speaker. If the current volume is unknown, you must call `self.get_device_status` tool first and then call this tool.",
|
|
18
|
-
"inputSchema": {
|
|
19
|
-
"type": "object",
|
|
20
|
-
"properties": {"volume": {"type": "integer", "minimum": 0, "maximum": 100}},
|
|
21
|
-
"required": ["volume"],
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
"set_brightness": {
|
|
25
|
-
"description": "Set the brightness of the screen.",
|
|
26
|
-
"inputSchema": {
|
|
27
|
-
"type": "object",
|
|
28
|
-
"properties": {"brightness": {"type": "integer", "minimum": 0, "maximum": 100}},
|
|
29
|
-
"required": ["brightness"],
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
"set_theme": {
|
|
33
|
-
"description": "Set the theme of the screen. The theme can be `light` or `dark`.",
|
|
34
|
-
"inputSchema": {"type": "object", "properties": {"theme": {"type": "string"}}, "required": ["theme"]},
|
|
35
|
-
},
|
|
36
|
-
"take_photo": {
|
|
37
|
-
"description": "Take a photo and explain it. Use this tool after the user asks you to see something.\nArgs:\n `question`: The question that you want to ask about the photo.\nReturn:\n A JSON object that provides the photo information.",
|
|
38
|
-
"inputSchema": {
|
|
39
|
-
"type": "object",
|
|
40
|
-
"properties": {"question": {"type": "string"}},
|
|
41
|
-
"required": ["question"],
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
"open_tab": {
|
|
45
|
-
"description": "Open a web page in the browser. 小智后台:https://xiaozhi.me",
|
|
46
|
-
"inputSchema": {
|
|
47
|
-
"type": "object",
|
|
48
|
-
"properties": {"url": {"type": "string"}},
|
|
49
|
-
"required": ["url"],
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
mcp_tools_payload = {
|
|
55
|
-
"jsonrpc": "2.0",
|
|
56
|
-
"id": 2,
|
|
57
|
-
"result": {"tools": []},
|
|
58
|
-
}
|
xiaozhi_sdk/utils.py
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import wave
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def get_wav_info(file_path):
|
|
5
|
-
with wave.open(file_path, "rb") as wav_file:
|
|
6
|
-
return wav_file.getframerate(), wav_file.getnchannels()
|
|
7
|
-
|
|
8
|
-
def read_audio_file(file_path):
|
|
9
|
-
"""
|
|
10
|
-
读取音频文件并通过yield返回PCM流
|
|
11
|
-
|
|
12
|
-
Args:
|
|
13
|
-
file_path (str): 音频文件路径
|
|
14
|
-
|
|
15
|
-
Yields:
|
|
16
|
-
bytes: PCM音频数据块
|
|
17
|
-
"""
|
|
18
|
-
with wave.open(file_path, "rb") as wav_file:
|
|
19
|
-
while True:
|
|
20
|
-
pcm = wav_file.readframes(960) # 每次读取960帧(60ms的音频数据)
|
|
21
|
-
if not pcm:
|
|
22
|
-
break
|
|
23
|
-
yield pcm
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: xiaozhi-sdk
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: A short description of your package
|
|
5
|
-
Home-page: https://github.com/dairoot/xiaozhi-sdk
|
|
6
|
-
Author: dairoot
|
|
7
|
-
Author-email: 623815825@qq.com
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.8
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
Requires-Dist: numpy
|
|
14
|
-
Requires-Dist: requests>=2.32.1
|
|
15
|
-
Requires-Dist: sounddevice>=0.4.2
|
|
16
|
-
Dynamic: author
|
|
17
|
-
Dynamic: author-email
|
|
18
|
-
Dynamic: classifier
|
|
19
|
-
Dynamic: description
|
|
20
|
-
Dynamic: description-content-type
|
|
21
|
-
Dynamic: home-page
|
|
22
|
-
Dynamic: requires-dist
|
|
23
|
-
Dynamic: requires-python
|
|
24
|
-
Dynamic: summary
|
|
25
|
-
|
|
26
|
-
# 小智SDK (XiaoZhi SDK)
|
|
27
|
-
|
|
28
|
-
[](https://www.python.org/downloads/)
|
|
29
|
-
[](LICENSE)
|
|
30
|
-
[](https://pypi.org/project/xiaozhi-sdk/)
|
|
31
|
-
|
|
32
|
-
一个用于连接和控制小智智能设备的Python SDK,支持实时音频通信、MCP工具集成和设备管理功能。
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
## 📦 安装
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
pip install xiaozhi-sdk
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
## 🚀 快速开始
|
|
43
|
-
|
|
44
|
-
### 命令行使用
|
|
45
|
-
|
|
46
|
-
最简单的使用方式是通过命令行连接设备:
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
# 查看帮助信息
|
|
50
|
-
python -m xiaozhi_sdk -h
|
|
51
|
-
|
|
52
|
-
# 连接设备(需要提供MAC地址)
|
|
53
|
-
python -m xiaozhi_sdk 00:11:22:33:44:55
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 编程使用
|
|
57
|
-
...
|
|
58
|
-
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
xiaozhi_sdk/__init__.py,sha256=2QA0vIcmJJ3kJdN9U-UKXVJZacYfG0trVztuEskxnVc,5860
|
|
2
|
-
xiaozhi_sdk/__main__.py,sha256=lWMyMrVlTImZK9Kq5mosgwcaGjo3ynpTBstxXHxyz1g,2529
|
|
3
|
-
xiaozhi_sdk/config.py,sha256=q4e_xmYzUB4_E5h-YftsyAhfeBSapwYD-ogx9ps1fIQ,189
|
|
4
|
-
xiaozhi_sdk/data.py,sha256=Hc8dZXt5Cos3wusjsa8210neqgD9kEBC6_FevsB-RGU,2432
|
|
5
|
-
xiaozhi_sdk/iot.py,sha256=Iz3vVSQgWHBNzqe47zjM1zcoNXjluBcD0uHCmEP8l3w,1630
|
|
6
|
-
xiaozhi_sdk/mcp.py,sha256=jmgbGtzJkIRrEJxJxETSm9toJQS3c6D7_FZBWyD9sAk,2752
|
|
7
|
-
xiaozhi_sdk/opus.py,sha256=6FPwttk6_CameFmLMrr9SkG8kq8gcco6hEeasKTqJWo,2322
|
|
8
|
-
xiaozhi_sdk/utils.py,sha256=9hM_PBlprv8Kjq2EL6wQNzqP3Gk67NYnpkOnpaGJ1G0,594
|
|
9
|
-
xiaozhi_sdk-0.1.0.dist-info/METADATA,sha256=mIit7LLw_YQBca3G2zEXMRrjdQ1fNQM0gdBqGbRSbUg,1455
|
|
10
|
-
xiaozhi_sdk-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
-
xiaozhi_sdk-0.1.0.dist-info/top_level.txt,sha256=nBpue4hU5Ykm5CtYPsAdxSa_yqbtZsIT_gF_EkBaJPM,12
|
|
12
|
-
xiaozhi_sdk-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|