xiaozhi-sdk 0.0.7__py3-none-any.whl → 0.0.9__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.
- xiaozhi_sdk/__init__.py +1 -1
- xiaozhi_sdk/cli.py +14 -10
- xiaozhi_sdk/mcp.py +4 -3
- xiaozhi_sdk/utils/mcp_data.py +5 -2
- xiaozhi_sdk/utils/mcp_tool.py +6 -2
- {xiaozhi_sdk-0.0.7.dist-info → xiaozhi_sdk-0.0.9.dist-info}/METADATA +1 -1
- {xiaozhi_sdk-0.0.7.dist-info → xiaozhi_sdk-0.0.9.dist-info}/RECORD +10 -10
- {xiaozhi_sdk-0.0.7.dist-info → xiaozhi_sdk-0.0.9.dist-info}/WHEEL +0 -0
- {xiaozhi_sdk-0.0.7.dist-info → xiaozhi_sdk-0.0.9.dist-info}/licenses/LICENSE +0 -0
- {xiaozhi_sdk-0.0.7.dist-info → xiaozhi_sdk-0.0.9.dist-info}/top_level.txt +0 -0
xiaozhi_sdk/__init__.py
CHANGED
xiaozhi_sdk/cli.py
CHANGED
|
@@ -46,12 +46,14 @@ async def handle_message(message):
|
|
|
46
46
|
is_end = True
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
async def play_assistant_audio(audio_queue: deque[bytes]):
|
|
49
|
+
async def play_assistant_audio(audio_queue: deque[bytes], enable_audio):
|
|
50
50
|
"""播放音频流"""
|
|
51
51
|
global is_playing_audio
|
|
52
52
|
|
|
53
|
-
stream =
|
|
54
|
-
|
|
53
|
+
stream = None
|
|
54
|
+
if enable_audio:
|
|
55
|
+
stream = sd.OutputStream(samplerate=INPUT_SERVER_AUDIO_SAMPLE_RATE, channels=1, dtype=np.int16)
|
|
56
|
+
stream.start()
|
|
55
57
|
last_audio_time = None
|
|
56
58
|
|
|
57
59
|
while True:
|
|
@@ -66,7 +68,8 @@ async def play_assistant_audio(audio_queue: deque[bytes]):
|
|
|
66
68
|
|
|
67
69
|
is_playing_audio = True
|
|
68
70
|
pcm_data = audio_queue.popleft()
|
|
69
|
-
stream
|
|
71
|
+
if stream:
|
|
72
|
+
stream.write(pcm_data)
|
|
70
73
|
last_audio_time = time.time()
|
|
71
74
|
|
|
72
75
|
|
|
@@ -83,7 +86,7 @@ class XiaoZhiClient:
|
|
|
83
86
|
self.ota_url = ota_url
|
|
84
87
|
self.mac_address = ""
|
|
85
88
|
|
|
86
|
-
async def start(self, mac_address: str, serial_number: str
|
|
89
|
+
async def start(self, mac_address: str, serial_number: str, license_key: str, enable_audio):
|
|
87
90
|
"""启动客户端连接"""
|
|
88
91
|
self.mac_address = mac_address
|
|
89
92
|
self.xiaozhi = XiaoZhiWebsocket(handle_message, url=self.url, ota_url=self.ota_url, send_wake=True)
|
|
@@ -92,7 +95,7 @@ class XiaoZhiClient:
|
|
|
92
95
|
self.mac_address, aec=False, serial_number=serial_number, license_key=license_key
|
|
93
96
|
)
|
|
94
97
|
|
|
95
|
-
asyncio.create_task(play_assistant_audio(self.xiaozhi.output_audio_queue))
|
|
98
|
+
asyncio.create_task(play_assistant_audio(self.xiaozhi.output_audio_queue, enable_audio))
|
|
96
99
|
|
|
97
100
|
def audio_callback(self, indata, frames, time, status):
|
|
98
101
|
"""音频输入回调函数"""
|
|
@@ -115,11 +118,11 @@ class XiaoZhiClient:
|
|
|
115
118
|
await self.xiaozhi.send_audio(pcm_data)
|
|
116
119
|
|
|
117
120
|
|
|
118
|
-
async def run_client(mac_address: str, url: str, ota_url: str, serial_number: str, license_key: str):
|
|
121
|
+
async def run_client(mac_address: str, url: str, ota_url: str, serial_number: str, license_key: str, enable_audio: bool):
|
|
119
122
|
"""运行客户端的异步函数"""
|
|
120
123
|
logger.debug("Recording... Press Ctrl+C to stop.")
|
|
121
124
|
client = XiaoZhiClient(url, ota_url)
|
|
122
|
-
await client.start(mac_address, serial_number, license_key)
|
|
125
|
+
await client.start(mac_address, serial_number, license_key, enable_audio)
|
|
123
126
|
|
|
124
127
|
with sd.InputStream(callback=client.audio_callback, channels=1, samplerate=16000, blocksize=960):
|
|
125
128
|
await client.process_audio_input()
|
|
@@ -131,9 +134,10 @@ async def run_client(mac_address: str, url: str, ota_url: str, serial_number: st
|
|
|
131
134
|
@click.option("--ota_url", help="OTA地址")
|
|
132
135
|
@click.option("--serial_number", default="", help="设备的序列号")
|
|
133
136
|
@click.option("--license_key", default="", help="设备的授权密钥")
|
|
134
|
-
|
|
137
|
+
@click.option("--enable_audio", default=True, help="是否开启音频播放")
|
|
138
|
+
def main(mac_address: str, url: str, ota_url: str, serial_number: str, license_key: str, enable_audio: bool):
|
|
135
139
|
"""小智SDK客户端
|
|
136
140
|
|
|
137
141
|
MAC_ADDRESS: 设备的MAC地址 (格式: XX:XX:XX:XX:XX:XX)
|
|
138
142
|
"""
|
|
139
|
-
asyncio.run(run_client(mac_address, url, ota_url, serial_number, license_key))
|
|
143
|
+
asyncio.run(run_client(mac_address, url, ota_url, serial_number, license_key, enable_audio))
|
xiaozhi_sdk/mcp.py
CHANGED
|
@@ -43,7 +43,7 @@ class McpTool(object):
|
|
|
43
43
|
try:
|
|
44
44
|
response = requests.post(self.explain_url, files=files, data=payload, headers=headers, timeout=5)
|
|
45
45
|
res_json = response.json()
|
|
46
|
-
except Exception
|
|
46
|
+
except Exception:
|
|
47
47
|
return "网络异常", True
|
|
48
48
|
if res_json.get("error"):
|
|
49
49
|
return res_json, True
|
|
@@ -72,10 +72,11 @@ class McpTool(object):
|
|
|
72
72
|
else:
|
|
73
73
|
tool_res, is_error = {"message": "正在为你播放: {}".format(arguments["music_name"])}, False
|
|
74
74
|
data = {
|
|
75
|
-
"type": "music",
|
|
75
|
+
"type": "music",
|
|
76
|
+
"state": "start",
|
|
76
77
|
"url": music_info["url"],
|
|
77
78
|
"text": arguments["music_name"],
|
|
78
|
-
"source": "sdk.mcp_music_tool"
|
|
79
|
+
"source": "sdk.mcp_music_tool",
|
|
79
80
|
}
|
|
80
81
|
await self.message_handler_callback(data)
|
|
81
82
|
|
xiaozhi_sdk/utils/mcp_data.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any, Dict
|
|
1
|
+
from typing import Any, Dict
|
|
2
2
|
|
|
3
3
|
mcp_initialize_payload: Dict[str, Any] = {
|
|
4
4
|
"jsonrpc": "2.0",
|
|
@@ -23,7 +23,10 @@ mcp_tool_conf: Dict[str, Dict[str, Any]] = {
|
|
|
23
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
24
|
"inputSchema": {
|
|
25
25
|
"type": "object",
|
|
26
|
-
"properties": {
|
|
26
|
+
"properties": {
|
|
27
|
+
"music_name": {"type": "string"},
|
|
28
|
+
"id_list": {"type": "array", "items": {"type": "string"}, "minItems": 3},
|
|
29
|
+
},
|
|
27
30
|
"required": ["music_name", "id_list"],
|
|
28
31
|
},
|
|
29
32
|
},
|
xiaozhi_sdk/utils/mcp_tool.py
CHANGED
|
@@ -3,7 +3,6 @@ import random
|
|
|
3
3
|
|
|
4
4
|
import aiohttp
|
|
5
5
|
import numpy as np
|
|
6
|
-
from pydub import AudioSegment
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
async def async_search_custom_music(data) -> tuple[dict, bool]:
|
|
@@ -57,6 +56,11 @@ async def _get_random_music_info(id_list: list) -> dict:
|
|
|
57
56
|
|
|
58
57
|
|
|
59
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
|
+
|
|
60
64
|
id_list = data["id_list"]
|
|
61
65
|
res_json = await _get_random_music_info(id_list)
|
|
62
66
|
|
|
@@ -79,7 +83,7 @@ async def async_mcp_play_music(data) -> tuple[list, bool]:
|
|
|
79
83
|
|
|
80
84
|
chunk_size = 960 * 2
|
|
81
85
|
for i in range(0, len(pcm_data), chunk_size):
|
|
82
|
-
chunk = pcm_data[i: i + chunk_size]
|
|
86
|
+
chunk = pcm_data[i : i + chunk_size]
|
|
83
87
|
|
|
84
88
|
if chunk: # 确保不添加空块
|
|
85
89
|
chunk = np.frombuffer(chunk, dtype=np.int16)
|
|
@@ -8,19 +8,19 @@ file/opus/linux-x64-libopus.so,sha256=FmXJqkxLpDzNFOHYkmOzmsp1hP0eIS5b6x_XfOs-IQ
|
|
|
8
8
|
file/opus/macos-arm64-libopus.dylib,sha256=H7wXwkrGwb-hesMMZGFxWb0Ri1Y4m5GWiKsd8CfOhE8,357584
|
|
9
9
|
file/opus/macos-x64-libopus.dylib,sha256=MqyL_OjwSACF4Xs_-KrGbcScy4IEprr5Rlkk3ddZye8,550856
|
|
10
10
|
file/opus/windows-opus.dll,sha256=kLfhioMvbJhOgNMAldpWk3DCZqC5Xd70LRbHnACvAnw,463360
|
|
11
|
-
xiaozhi_sdk/__init__.py,sha256
|
|
11
|
+
xiaozhi_sdk/__init__.py,sha256=-gx5Vs8YIZLaWKtMWumKSkCiYu2Nu8Z7rFjFnYbkDhQ,77
|
|
12
12
|
xiaozhi_sdk/__main__.py,sha256=i0ZJdHUqAKg9vwZrK_w0TJkzdotTYTK8aUeSPcJc1ks,210
|
|
13
|
-
xiaozhi_sdk/cli.py,sha256=
|
|
13
|
+
xiaozhi_sdk/cli.py,sha256=LFZE4f4A44EIPXLsowxQ4z_EskTh62MLusPwwFVtXr8,4490
|
|
14
14
|
xiaozhi_sdk/config.py,sha256=h4mpMeBf2vT9qYAqCCbGVGmMemkgk98pcXP2Rh4TEFc,89
|
|
15
15
|
xiaozhi_sdk/core.py,sha256=564SefCBus6qNRApWqwI113aIN1p4eYpci1mLeMExIs,10007
|
|
16
16
|
xiaozhi_sdk/iot.py,sha256=IO3SfiuQxucYl_917BCNCwIAv1dajCJI-IFTWwHnSDE,2580
|
|
17
|
-
xiaozhi_sdk/mcp.py,sha256=
|
|
17
|
+
xiaozhi_sdk/mcp.py,sha256=Pbr3JEDqEnWsPwLHKzRdrDYZMg6krYZoz74lXUSh9iI,5544
|
|
18
18
|
xiaozhi_sdk/opus.py,sha256=r3nnYg0ZKAJTreb_3nKgfHJh06MJiMvnNMPO1SWdoMM,2224
|
|
19
19
|
xiaozhi_sdk/utils/__init__.py,sha256=XKSHWoFmuSkpwaIr308HybRzfFIXoT1Fd-eUKo_im6Y,1705
|
|
20
|
-
xiaozhi_sdk/utils/mcp_data.py,sha256=
|
|
21
|
-
xiaozhi_sdk/utils/mcp_tool.py,sha256=
|
|
22
|
-
xiaozhi_sdk-0.0.
|
|
23
|
-
xiaozhi_sdk-0.0.
|
|
24
|
-
xiaozhi_sdk-0.0.
|
|
25
|
-
xiaozhi_sdk-0.0.
|
|
26
|
-
xiaozhi_sdk-0.0.
|
|
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.0.9.dist-info/licenses/LICENSE,sha256=Vwgps1iODKl43cAtME_0dawTjAzNW-O2BWiN5BHggww,1085
|
|
23
|
+
xiaozhi_sdk-0.0.9.dist-info/METADATA,sha256=kqk96A4tgE9-b4rn-eyFKLLoXYqky1v3tlnVscck14k,2091
|
|
24
|
+
xiaozhi_sdk-0.0.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
25
|
+
xiaozhi_sdk-0.0.9.dist-info/top_level.txt,sha256=nBpue4hU5Ykm5CtYPsAdxSa_yqbtZsIT_gF_EkBaJPM,12
|
|
26
|
+
xiaozhi_sdk-0.0.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|