smartpi 1.1.4__py3-none-any.whl → 1.1.5__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.
Files changed (125) hide show
  1. smartpi/__init__.py +8 -0
  2. smartpi/__init__.pyc +0 -0
  3. smartpi/_gui.py +66 -0
  4. smartpi/_gui.pyc +0 -0
  5. smartpi/ai_asr.py +1037 -0
  6. smartpi/ai_asr.pyc +0 -0
  7. smartpi/ai_llm.py +934 -0
  8. smartpi/ai_llm.pyc +0 -0
  9. smartpi/ai_tts.py +938 -0
  10. smartpi/ai_tts.pyc +0 -0
  11. smartpi/ai_vad.py +83 -0
  12. smartpi/ai_vad.pyc +0 -0
  13. smartpi/audio.py +125 -0
  14. smartpi/audio.pyc +0 -0
  15. smartpi/base_driver.py +618 -0
  16. smartpi/base_driver.pyc +0 -0
  17. smartpi/camera.py +84 -0
  18. smartpi/camera.pyc +0 -0
  19. smartpi/color_sensor.py +18 -0
  20. smartpi/color_sensor.pyc +0 -0
  21. smartpi/cw2015.py +179 -0
  22. smartpi/cw2015.pyc +0 -0
  23. smartpi/flash.py +130 -0
  24. smartpi/flash.pyc +0 -0
  25. smartpi/humidity.py +20 -0
  26. smartpi/humidity.pyc +0 -0
  27. smartpi/led.py +19 -0
  28. smartpi/led.pyc +0 -0
  29. smartpi/light_sensor.py +72 -0
  30. smartpi/light_sensor.pyc +0 -0
  31. smartpi/local_model.py +432 -0
  32. smartpi/local_model.pyc +0 -0
  33. smartpi/mcp_client.py +100 -0
  34. smartpi/mcp_client.pyc +0 -0
  35. smartpi/mcp_fastmcp.py +322 -0
  36. smartpi/mcp_fastmcp.pyc +0 -0
  37. smartpi/mcp_intent_recognizer.py +408 -0
  38. smartpi/mcp_intent_recognizer.pyc +0 -0
  39. smartpi/models/__init__.py +0 -0
  40. smartpi/models/__init__.pyc +0 -0
  41. smartpi/models/snakers4_silero-vad/__init__.py +0 -0
  42. smartpi/models/snakers4_silero-vad/__init__.pyc +0 -0
  43. smartpi/models/snakers4_silero-vad/hubconf.py +56 -0
  44. smartpi/models/snakers4_silero-vad/hubconf.pyc +0 -0
  45. smartpi/motor.py +177 -0
  46. smartpi/motor.pyc +0 -0
  47. smartpi/move.py +218 -0
  48. smartpi/move.pyc +0 -0
  49. smartpi/onnx_hand_workflow.py +201 -0
  50. smartpi/onnx_hand_workflow.pyc +0 -0
  51. smartpi/onnx_image_workflow.py +176 -0
  52. smartpi/onnx_image_workflow.pyc +0 -0
  53. smartpi/onnx_pose_workflow.py +482 -0
  54. smartpi/onnx_pose_workflow.pyc +0 -0
  55. smartpi/onnx_text_workflow.py +173 -0
  56. smartpi/onnx_text_workflow.pyc +0 -0
  57. smartpi/onnx_voice_workflow.py +437 -0
  58. smartpi/onnx_voice_workflow.pyc +0 -0
  59. smartpi/posemodel/__init__.py +0 -0
  60. smartpi/posemodel/__init__.pyc +0 -0
  61. smartpi/posenet_utils.py +222 -0
  62. smartpi/posenet_utils.pyc +0 -0
  63. smartpi/rknn_hand_workflow.py +245 -0
  64. smartpi/rknn_hand_workflow.pyc +0 -0
  65. smartpi/rknn_image_workflow.py +405 -0
  66. smartpi/rknn_image_workflow.pyc +0 -0
  67. smartpi/rknn_pose_workflow.py +592 -0
  68. smartpi/rknn_pose_workflow.pyc +0 -0
  69. smartpi/rknn_text_workflow.py +240 -0
  70. smartpi/rknn_text_workflow.pyc +0 -0
  71. smartpi/rknn_voice_workflow.py +394 -0
  72. smartpi/rknn_voice_workflow.pyc +0 -0
  73. smartpi/servo.py +178 -0
  74. smartpi/servo.pyc +0 -0
  75. smartpi/temperature.py +18 -0
  76. smartpi/temperature.pyc +0 -0
  77. smartpi/tencentcloud-speech-sdk-python/__init__.py +1 -0
  78. smartpi/tencentcloud-speech-sdk-python/__init__.pyc +0 -0
  79. smartpi/tencentcloud-speech-sdk-python/asr/__init__.py +0 -0
  80. smartpi/tencentcloud-speech-sdk-python/asr/__init__.pyc +0 -0
  81. smartpi/tencentcloud-speech-sdk-python/asr/flash_recognizer.py +178 -0
  82. smartpi/tencentcloud-speech-sdk-python/asr/flash_recognizer.pyc +0 -0
  83. smartpi/tencentcloud-speech-sdk-python/asr/speech_recognizer.py +311 -0
  84. smartpi/tencentcloud-speech-sdk-python/asr/speech_recognizer.pyc +0 -0
  85. smartpi/tencentcloud-speech-sdk-python/common/__init__.py +1 -0
  86. smartpi/tencentcloud-speech-sdk-python/common/__init__.pyc +0 -0
  87. smartpi/tencentcloud-speech-sdk-python/common/credential.py +6 -0
  88. smartpi/tencentcloud-speech-sdk-python/common/credential.pyc +0 -0
  89. smartpi/tencentcloud-speech-sdk-python/common/log.py +16 -0
  90. smartpi/tencentcloud-speech-sdk-python/common/log.pyc +0 -0
  91. smartpi/tencentcloud-speech-sdk-python/common/utils.py +7 -0
  92. smartpi/tencentcloud-speech-sdk-python/common/utils.pyc +0 -0
  93. smartpi/tencentcloud-speech-sdk-python/soe/__init__.py +0 -0
  94. smartpi/tencentcloud-speech-sdk-python/soe/__init__.pyc +0 -0
  95. smartpi/tencentcloud-speech-sdk-python/soe/speaking_assessment.py +276 -0
  96. smartpi/tencentcloud-speech-sdk-python/soe/speaking_assessment.pyc +0 -0
  97. smartpi/tencentcloud-speech-sdk-python/tts/__init__.py +0 -0
  98. smartpi/tencentcloud-speech-sdk-python/tts/__init__.pyc +0 -0
  99. smartpi/tencentcloud-speech-sdk-python/tts/flowing_speech_synthesizer.py +294 -0
  100. smartpi/tencentcloud-speech-sdk-python/tts/flowing_speech_synthesizer.pyc +0 -0
  101. smartpi/tencentcloud-speech-sdk-python/tts/speech_synthesizer.py +144 -0
  102. smartpi/tencentcloud-speech-sdk-python/tts/speech_synthesizer.pyc +0 -0
  103. smartpi/tencentcloud-speech-sdk-python/tts/speech_synthesizer_ws.py +234 -0
  104. smartpi/tencentcloud-speech-sdk-python/tts/speech_synthesizer_ws.pyc +0 -0
  105. smartpi/tencentcloud-speech-sdk-python/vc/__init__.py +0 -0
  106. smartpi/tencentcloud-speech-sdk-python/vc/__init__.pyc +0 -0
  107. smartpi/tencentcloud-speech-sdk-python/vc/speech_convertor_ws.py +237 -0
  108. smartpi/tencentcloud-speech-sdk-python/vc/speech_convertor_ws.pyc +0 -0
  109. smartpi/text_gte_model/__init__.py +0 -0
  110. smartpi/text_gte_model/__init__.pyc +0 -0
  111. smartpi/text_gte_model/config/__init__.py +0 -0
  112. smartpi/text_gte_model/config/__init__.pyc +0 -0
  113. smartpi/text_gte_model/gte/__init__.py +0 -0
  114. smartpi/text_gte_model/gte/__init__.pyc +0 -0
  115. smartpi/touch_sensor.py +16 -0
  116. smartpi/touch_sensor.pyc +0 -0
  117. smartpi/trace.py +120 -0
  118. smartpi/trace.pyc +0 -0
  119. smartpi/ultrasonic.py +20 -0
  120. smartpi/ultrasonic.pyc +0 -0
  121. {smartpi-1.1.4.dist-info → smartpi-1.1.5.dist-info}/METADATA +3 -2
  122. smartpi-1.1.5.dist-info/RECORD +137 -0
  123. smartpi-1.1.4.dist-info/RECORD +0 -77
  124. {smartpi-1.1.4.dist-info → smartpi-1.1.5.dist-info}/WHEEL +0 -0
  125. {smartpi-1.1.4.dist-info → smartpi-1.1.5.dist-info}/top_level.txt +0 -0
smartpi/mcp_fastmcp.py ADDED
@@ -0,0 +1,322 @@
1
+ # -*- coding: utf-8 -*-
2
+ """简易版fastmcp模块实现,提供基础的Client类"""
3
+ import asyncio
4
+ import aiohttp
5
+ import json
6
+ from typing import List, Dict, Any
7
+ import logging
8
+
9
+ # 配置日志
10
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class Client:
15
+ """简易版MCP客户端实现"""
16
+
17
+ def __init__(self, url: str = None):
18
+ self.server_url = url if url else None
19
+ self.session = None
20
+ self.exit_stack = None
21
+ logger.info("FastMCP Client 已初始化")
22
+
23
+ async def connect(self, url: str = None) -> bool:
24
+ """连接到MCP服务器"""
25
+ try:
26
+ # 如果提供了URL,更新服务器地址
27
+ if url:
28
+ self.server_url = url
29
+ elif not self.server_url:
30
+ # 如果没有提供URL且没有默认URL,则使用一个默认值
31
+ self.server_url = "http://127.0.0.1:8000/mcp"
32
+
33
+ self.session = aiohttp.ClientSession()
34
+ logger.info(f"成功连接到MCP服务器: {self.server_url}")
35
+ return True
36
+ except Exception as e:
37
+ logger.error(f"连接MCP服务器失败: {str(e)}")
38
+ return False
39
+
40
+ async def get_tools(self) -> List[Dict[str, Any]]:
41
+ """获取可用工具列表"""
42
+ try:
43
+ # 这里返回一个模拟的工具列表,包含intent_recognizer工具
44
+ tools = [
45
+ {
46
+ "name": "recognize_intent",
47
+ "description": "识别用户输入中的意图",
48
+ "parameters": {
49
+ "type": "object",
50
+ "properties": {
51
+ "user_input": {
52
+ "type": "string",
53
+ "description": "用户输入的文本内容"
54
+ }
55
+ },
56
+ "required": ["user_input"]
57
+ }
58
+ }
59
+ ]
60
+
61
+ # 转换为特定格式
62
+ formatted_tools = []
63
+ for tool in tools:
64
+ formatted_tools.append({
65
+ "type": "function",
66
+ "function": {
67
+ "name": tool["name"],
68
+ "description": tool["description"],
69
+ "parameters": tool["parameters"]
70
+ }
71
+ })
72
+
73
+ return formatted_tools
74
+ except Exception as e:
75
+ logger.error(f"获取工具列表失败: {str(e)}")
76
+ return []
77
+
78
+ async def call_tool(self, tool_calls: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
79
+ """调用MCP工具"""
80
+ try:
81
+ # 模拟工具调用响应
82
+ responses = []
83
+
84
+ # 处理每个工具调用
85
+ for tool_call in tool_calls:
86
+ # 提取函数名和参数(支持不同格式)
87
+ if isinstance(tool_call, dict):
88
+ function_name = tool_call.get("function", {}).get("name")
89
+ arguments = tool_call.get("function", {}).get("arguments")
90
+ else:
91
+ # 如果是对象格式
92
+ function_name = getattr(tool_call, "function", None)
93
+ if function_name:
94
+ function_name = getattr(function_name, "name", None)
95
+ arguments = getattr(tool_call, "function", None)
96
+ if arguments:
97
+ arguments = getattr(arguments, "arguments", None)
98
+
99
+ if function_name == "recognize_intent" and arguments:
100
+ try:
101
+ # 解析参数
102
+ if isinstance(arguments, str):
103
+ args_dict = json.loads(arguments)
104
+ else:
105
+ args_dict = arguments
106
+
107
+ user_input = args_dict.get("user_input", "")
108
+ print(f"[MCP] 识别意图: '{user_input}'")
109
+
110
+ # 简单的意图识别逻辑(基于关键词)
111
+ intent_result = await self._simple_intent_recognizer(user_input)
112
+ print(f"[MCP] 识别结果: {intent_result}")
113
+
114
+ # 添加工具调用结果
115
+ responses.append({
116
+ "role": "tool",
117
+ "content": json.dumps(intent_result, ensure_ascii=False)
118
+ })
119
+ except Exception as e:
120
+ print(f"[MCP] 处理意图识别时出错: {str(e)}")
121
+ responses.append({
122
+ "role": "tool",
123
+ "content": "[]"
124
+ })
125
+
126
+ # 如果没有工具响应,返回空结果
127
+ if not responses:
128
+ responses.append({
129
+ "role": "tool",
130
+ "content": "[]"
131
+ })
132
+
133
+ return responses
134
+ except Exception as e:
135
+ logger.error(f"调用工具失败: {str(e)}")
136
+ # 返回错误响应
137
+ return [
138
+ {"role": "system", "content": "Error processing tool call"},
139
+ {"role": "tool", "content": "[]"}
140
+ ]
141
+
142
+ async def _simple_intent_recognizer(self, user_input: str) -> List[Dict[str, Any]]:
143
+ """改进的基于关键词的意图识别实现 - 灵活支持各种带参数的意图"""
144
+ import re
145
+ # 导入全局意图映射
146
+ try:
147
+ from . import ai_llm
148
+ global_intents = ai_llm.gLOBAL_INTENTS
149
+ logger.info(f"获取到的全局意图映射: {global_intents}")
150
+ except ImportError:
151
+ logger.error("无法导入ai_llm模块,使用空意图映射")
152
+ global_intents = {}
153
+ except AttributeError:
154
+ logger.error("ai_llm模块中未找到gLOBAL_INTENTS,使用空意图映射")
155
+ global_intents = {}
156
+
157
+ intents = []
158
+ user_input_lower = user_input.lower()
159
+
160
+ # 将输入文本按逻辑分隔符分割成多个子句,保持意图顺序
161
+ # 分隔符包括:然后、并且、接着、再、先...然后
162
+ split_patterns = [r'[然后并且接着再]', r'先.*?然后']
163
+ clauses = [user_input_lower]
164
+
165
+ for pattern in split_patterns:
166
+ new_clauses = []
167
+ for clause in clauses:
168
+ # 使用正则表达式分割,保留分隔符以便后续处理
169
+ parts = re.split(f'({pattern})', clause)
170
+ temp_clauses = []
171
+ for i, part in enumerate(parts):
172
+ if part:
173
+ temp_clauses.append(part)
174
+ new_clauses.extend(temp_clauses)
175
+ clauses = new_clauses
176
+
177
+ # 清理子句,移除空白和分隔符
178
+ cleaned_clauses = []
179
+ for clause in clauses:
180
+ # 移除分隔符
181
+ clause = re.sub(r'[然后并且接着再先]', '', clause)
182
+ # 移除空白字符
183
+ clause = clause.strip()
184
+ if clause: # 只保留非空的子句
185
+ cleaned_clauses.append(clause)
186
+
187
+ # 如果没有分割出子句,使用原始输入
188
+ if not cleaned_clauses:
189
+ cleaned_clauses.append(user_input_lower)
190
+
191
+ # 对每个子句独立进行意图识别,保持顺序
192
+ for clause in cleaned_clauses:
193
+ # 遍历所有全局意图,检查每个意图的关键词是否在子句中出现
194
+ for intent_code, intent_info in global_intents.items():
195
+ keywords = intent_info.get("keywords", [])
196
+ matched = False
197
+
198
+ for keyword in keywords:
199
+ keyword_lower = keyword.lower()
200
+ # 1. 精确匹配
201
+ if keyword_lower == clause:
202
+ matched = True
203
+ break
204
+
205
+ # 2. 包含匹配(关键词是子句的一部分)
206
+ if keyword_lower in clause:
207
+ matched = True
208
+ break
209
+
210
+ # 3. 语义相似匹配(关键词的核心词汇出现在子句中)
211
+ # 提取关键词中的核心词汇(去掉修饰词)
212
+ keyword_core = re.sub(r'[调节到了]', '', keyword_lower)
213
+ if keyword_core and keyword_core in clause:
214
+ matched = True
215
+ break
216
+
217
+ if matched:
218
+ # 提取参数 - 只从当前子句中提取与该意图相关的参数
219
+ args = []
220
+
221
+ # 尝试从子句中提取数字作为参数(支持整数、小数和百分比)
222
+ # 匹配模式:数字(可能带小数点)后跟可选的单位
223
+ number_patterns = [
224
+ r'\d+(?:\.\d+)?', # 匹配整数和小数
225
+ r'\d+(?:\.\d+)?%' # 匹配百分比
226
+ ]
227
+
228
+ for pattern in number_patterns:
229
+ numbers = re.findall(pattern, clause)
230
+ if numbers:
231
+ # 提取第一个数字作为主要参数
232
+ args.append(numbers[0].replace('%', '')) # 移除百分号
233
+ break
234
+
235
+ intents.append({
236
+ "intent": str(intent_code), # 将数字代码转换为字符串,与传统意图识别保持一致
237
+ "arg": args # 返回提取的参数
238
+ })
239
+
240
+ # 去重 - 避免同一子句中同一意图被多次识别(但允许不同子句中识别相同意图)
241
+ unique_intents = []
242
+ seen_in_clauses = [] # 记录已经在哪些子句中识别了哪些意图
243
+ for i, clause in enumerate(cleaned_clauses):
244
+ clause_intents = []
245
+ clause_seen = set()
246
+
247
+ for intent in intents:
248
+ # 检查这个意图是否来自当前子句
249
+ # 由于我们没有直接记录意图来自哪个子句,这里使用一个近似的方法
250
+ # 检查意图的关键词是否在当前子句中出现
251
+ intent_code = int(intent["intent"])
252
+ intent_info = global_intents.get(intent_code, {})
253
+ keywords = intent_info.get("keywords", [])
254
+
255
+ for keyword in keywords:
256
+ keyword_lower = keyword.lower()
257
+ if keyword_lower in clause or re.sub(r'[调节到了]', '', keyword_lower) in clause:
258
+ # 这个意图可能来自当前子句
259
+ if intent["intent"] not in clause_seen:
260
+ clause_seen.add(intent["intent"])
261
+ clause_intents.append(intent)
262
+ break
263
+
264
+ seen_in_clauses.extend(clause_intents)
265
+
266
+ # 最终的意图列表是按子句顺序排列的去重后的意图
267
+ return seen_in_clauses
268
+
269
+ async def close(self):
270
+ """关闭MCP客户端连接和会话"""
271
+ try:
272
+ if self.session:
273
+ await self.session.close()
274
+ self.session = None
275
+ self.connected = False
276
+ logger.info("MCP客户端连接已关闭")
277
+ except Exception as e:
278
+ logger.error(f"关闭MCP客户端连接时出错: {str(e)}")
279
+ # 确保即使出错也设置为未连接状态
280
+ self.connected = False
281
+ self.session = None
282
+
283
+ async def __aenter__(self):
284
+ return self
285
+
286
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
287
+ await self.close()
288
+
289
+
290
+ # 为了兼容原有的exit_stack使用方式
291
+ class AsyncExitStack:
292
+ """简易的异步退出栈实现"""
293
+
294
+ def __init__(self):
295
+ self._exit_callbacks = []
296
+
297
+ async def aclose(self):
298
+ """关闭并执行所有退出回调"""
299
+ for callback in reversed(self._exit_callbacks):
300
+ try:
301
+ if asyncio.iscoroutinefunction(callback):
302
+ await callback()
303
+ else:
304
+ callback()
305
+ except Exception as e:
306
+ logger.error(f"执行退出回调时出错: {str(e)}")
307
+
308
+ def push(self, callback):
309
+ """添加退出回调"""
310
+ self._exit_callbacks.append(callback)
311
+ return callback
312
+
313
+
314
+ # 为Client类添加exit_stack属性
315
+ async def create_client(url: str = None):
316
+ """创建并初始化MCP客户端"""
317
+ client = Client(url)
318
+ client.exit_stack = AsyncExitStack()
319
+ client.exit_stack.push(client.close)
320
+ # 总是调用connect以确保会话被创建
321
+ await client.connect()
322
+ return client
smartpi/mcp_fastmcp.pyc CHANGED
Binary file