xiaozhi-sdk 0.1.0__py3-none-any.whl → 0.1.1__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.

Potentially problematic release.


This version of xiaozhi-sdk might be problematic. Click here for more details.

@@ -1,4 +1,6 @@
1
- mcp_initialize_payload = {
1
+ from typing import Any, Dict
2
+
3
+ mcp_initialize_payload: Dict[str, Any] = {
2
4
  "jsonrpc": "2.0",
3
5
  "id": 1,
4
6
  "result": {
@@ -8,13 +10,32 @@ mcp_initialize_payload = {
8
10
  },
9
11
  }
10
12
 
11
- mcp_tool_conf = {
13
+ mcp_tool_conf: Dict[str, Dict[str, Any]] = {
14
+ "search_custom_music": {
15
+ "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)",
16
+ "inputSchema": {
17
+ "type": "object",
18
+ "properties": {"music_name": {"type": "string"}, "author_name": {"type": "string"}},
19
+ "required": ["music_name"],
20
+ },
21
+ },
22
+ "play_custom_music": {
23
+ "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)",
24
+ "inputSchema": {
25
+ "type": "object",
26
+ "properties": {
27
+ "music_name": {"type": "string"},
28
+ "id_list": {"type": "array", "items": {"type": "string"}, "minItems": 3},
29
+ },
30
+ "required": ["music_name", "id_list"],
31
+ },
32
+ },
12
33
  "get_device_status": {
13
34
  "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
35
  "inputSchema": {"type": "object", "properties": {}},
15
36
  },
16
37
  "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.",
38
+ "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.",
18
39
  "inputSchema": {
19
40
  "type": "object",
20
41
  "properties": {"volume": {"type": "integer", "minimum": 0, "maximum": 100}},
@@ -51,7 +72,7 @@ mcp_tool_conf = {
51
72
  },
52
73
  }
53
74
 
54
- mcp_tools_payload = {
75
+ mcp_tools_payload: Dict[str, Any] = {
55
76
  "jsonrpc": "2.0",
56
77
  "id": 2,
57
78
  "result": {"tools": []},
@@ -0,0 +1,92 @@
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
@@ -0,0 +1,89 @@
1
+ Metadata-Version: 2.4
2
+ Name: xiaozhi-sdk
3
+ Version: 0.1.1
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
+ Dynamic: license-file
26
+
27
+ # 小智SDK (XiaoZhi SDK)
28
+
29
+ [![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
30
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
31
+ [![PyPI](https://img.shields.io/badge/pypi-xiaozhi--sdk-blue.svg)](https://pypi.org/project/xiaozhi-sdk/)
32
+
33
+ 基于虾哥的 [小智esp32 websocket 通讯协议](https://github.com/78/xiaozhi-esp32/blob/main/docs/websocket.md) 实现的 Python SDK。
34
+
35
+ 一个用于连接和控制小智设备的 Python SDK。支持以下功能:
36
+ - 实时音频通信
37
+ - MCP 工具集成
38
+ - 设备管理与控制
39
+
40
+ ---
41
+
42
+ ## 📦 安装
43
+
44
+ ```bash
45
+ pip install xiaozhi-sdk
46
+ ```
47
+
48
+ ---
49
+
50
+ ## 🚀 快速开始
51
+
52
+ ### 1. 终端使用
53
+
54
+ 最简单的方式是通过终端直接连接设备:
55
+
56
+ #### 查看帮助信息
57
+
58
+ ```bash
59
+ python -m xiaozhi_sdk --help
60
+ ```
61
+
62
+ #### 连接设备(需要提供 MAC 地址)
63
+
64
+ ```bash
65
+ python -m xiaozhi_sdk 00:22:44:66:88:00
66
+ ```
67
+
68
+ ### 2. 编程使用 (高阶用法)
69
+ 参考 [examples](examples/) 文件中的示例代码,可以快速开始使用 SDK。
70
+
71
+
72
+ ---
73
+
74
+ ## ✅ 运行测试
75
+
76
+ ```bash
77
+ # 安装开发依赖
78
+ uv sync --group dev
79
+
80
+ # 运行测试
81
+ uv run pytest
82
+ ```
83
+
84
+
85
+ ---
86
+
87
+ ## 🫡 致敬
88
+
89
+ - 🫡 虾哥的 [xiaozhi-esp32](https://github.com/78/xiaozhi-esp32) 项目
@@ -0,0 +1,26 @@
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=-YmHE_cFBLemiK3AzbQAjKlaQON5TZsWKNig3atyyJQ,77
12
+ xiaozhi_sdk/__main__.py,sha256=i0ZJdHUqAKg9vwZrK_w0TJkzdotTYTK8aUeSPcJc1ks,210
13
+ xiaozhi_sdk/cli.py,sha256=86if9OjconMPdvtK_904ga8FDYWzVtH6E2FQI-tGrRA,5862
14
+ xiaozhi_sdk/config.py,sha256=h4mpMeBf2vT9qYAqCCbGVGmMemkgk98pcXP2Rh4TEFc,89
15
+ xiaozhi_sdk/core.py,sha256=564SefCBus6qNRApWqwI113aIN1p4eYpci1mLeMExIs,10007
16
+ xiaozhi_sdk/iot.py,sha256=VVAheynp1iV4GCaoPywQWpKtlyoACDLswH8yfV_JZgI,2699
17
+ xiaozhi_sdk/mcp.py,sha256=Pbr3JEDqEnWsPwLHKzRdrDYZMg6krYZoz74lXUSh9iI,5544
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_data.py,sha256=r_GLjFpvUKeV8IhlkT7Pfb4c9bDO9q4k3f4iPZBBcKI,3892
21
+ xiaozhi_sdk/utils/mcp_tool.py,sha256=imwehfUlENjelYmGbGYgb6C82-ijs53XCxrtCpqrJps,3152
22
+ xiaozhi_sdk-0.1.1.dist-info/licenses/LICENSE,sha256=Vwgps1iODKl43cAtME_0dawTjAzNW-O2BWiN5BHggww,1085
23
+ xiaozhi_sdk-0.1.1.dist-info/METADATA,sha256=j__sITpWYwcvM_7qYTb-gE4ZKrpMudbuiO35nuvBh6c,2091
24
+ xiaozhi_sdk-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
+ xiaozhi_sdk-0.1.1.dist-info/top_level.txt,sha256=nBpue4hU5Ykm5CtYPsAdxSa_yqbtZsIT_gF_EkBaJPM,12
26
+ xiaozhi_sdk-0.1.1.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/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
- [![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
29
- [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
30
- [![PyPI](https://img.shields.io/badge/pypi-xiaozhi--sdk-blue.svg)](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,,