ErisPulse 2.3.2__py3-none-any.whl → 2.3.3.dev0__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.
- ErisPulse/Core/Event/__init__.py +3 -1
- ErisPulse/Core/Event/base.py +5 -0
- ErisPulse/Core/Event/command.py +66 -17
- ErisPulse/Core/Event/wrapper.py +592 -0
- ErisPulse/__main__.py +0 -5
- {erispulse-2.3.2.dist-info → erispulse-2.3.3.dev0.dist-info}/METADATA +1 -3
- {erispulse-2.3.2.dist-info → erispulse-2.3.3.dev0.dist-info}/RECORD +10 -9
- {erispulse-2.3.2.dist-info → erispulse-2.3.3.dev0.dist-info}/WHEEL +0 -0
- {erispulse-2.3.2.dist-info → erispulse-2.3.3.dev0.dist-info}/entry_points.txt +0 -0
- {erispulse-2.3.2.dist-info → erispulse-2.3.3.dev0.dist-info}/licenses/LICENSE +0 -0
ErisPulse/Core/Event/__init__.py
CHANGED
|
@@ -15,6 +15,7 @@ from .message import message
|
|
|
15
15
|
from .notice import notice
|
|
16
16
|
from .request import request
|
|
17
17
|
from .meta import meta
|
|
18
|
+
from .wrapper import Event
|
|
18
19
|
from . import exceptions
|
|
19
20
|
from .. import config
|
|
20
21
|
|
|
@@ -61,5 +62,6 @@ __all__ = [
|
|
|
61
62
|
"notice",
|
|
62
63
|
"request",
|
|
63
64
|
"meta",
|
|
65
|
+
"Event",
|
|
64
66
|
"exceptions"
|
|
65
|
-
]
|
|
67
|
+
]
|
ErisPulse/Core/Event/base.py
CHANGED
|
@@ -12,6 +12,7 @@ ErisPulse 事件处理基础模块
|
|
|
12
12
|
from .. import adapter, logger
|
|
13
13
|
from typing import Callable, Any, Dict, List
|
|
14
14
|
import asyncio
|
|
15
|
+
from .wrapper import Event
|
|
15
16
|
|
|
16
17
|
class BaseEventHandler:
|
|
17
18
|
"""
|
|
@@ -94,6 +95,10 @@ class BaseEventHandler:
|
|
|
94
95
|
|
|
95
96
|
:param event: 事件数据
|
|
96
97
|
"""
|
|
98
|
+
# 如果还不是Event对象,则转换为Event对象
|
|
99
|
+
if not isinstance(event, Event):
|
|
100
|
+
event = Event(event)
|
|
101
|
+
|
|
97
102
|
# 执行处理器
|
|
98
103
|
for handler_info in self.handlers:
|
|
99
104
|
condition = handler_info.get("condition")
|
ErisPulse/Core/Event/command.py
CHANGED
|
@@ -240,35 +240,80 @@ class CommandHandler:
|
|
|
240
240
|
if event.get("type") != "message":
|
|
241
241
|
return
|
|
242
242
|
|
|
243
|
+
async def _process_text_for_command(event: Dict[str, Any], text: str) -> bool:
|
|
244
|
+
"""
|
|
245
|
+
处理文本内容,尝试匹配并执行命令
|
|
246
|
+
|
|
247
|
+
{!--< internal-use >!--}
|
|
248
|
+
内部使用的方法,用于处理文本内容并尝试执行命令
|
|
249
|
+
|
|
250
|
+
:param event: 消息事件数据
|
|
251
|
+
:param text: 要处理的文本内容
|
|
252
|
+
:return: 是否成功执行命令
|
|
253
|
+
"""
|
|
254
|
+
if not text:
|
|
255
|
+
return False
|
|
256
|
+
|
|
257
|
+
# 处理大小写敏感性
|
|
258
|
+
check_text = text if self.case_sensitive else text.lower()
|
|
259
|
+
prefix = self.prefix if self.case_sensitive else self.prefix.lower()
|
|
260
|
+
|
|
261
|
+
# 检查前缀
|
|
262
|
+
has_prefix = check_text.startswith(prefix)
|
|
263
|
+
has_space_prefix = self.allow_space_prefix and check_text.startswith(prefix + " ")
|
|
264
|
+
|
|
265
|
+
if not has_prefix and not has_space_prefix:
|
|
266
|
+
return False
|
|
267
|
+
|
|
268
|
+
# 尝试执行命令
|
|
269
|
+
return await self._try_execute_command(event, text, check_text)
|
|
270
|
+
|
|
271
|
+
# 从 message 列表和 alt_message 中提取文本内容
|
|
243
272
|
message_segments = event.get("message", [])
|
|
244
|
-
|
|
273
|
+
message_text = ""
|
|
245
274
|
for segment in message_segments:
|
|
246
275
|
if segment.get("type") == "text":
|
|
247
|
-
|
|
276
|
+
message_text = segment.get("data", {}).get("text", "")
|
|
248
277
|
break
|
|
249
278
|
|
|
250
|
-
|
|
251
|
-
return
|
|
279
|
+
alt_message = event.get("alt_message", "")
|
|
252
280
|
|
|
253
|
-
#
|
|
254
|
-
|
|
255
|
-
|
|
281
|
+
# 尝试使用 message 列表的内容
|
|
282
|
+
if message_text:
|
|
283
|
+
command_matched = await _process_text_for_command(event, message_text)
|
|
284
|
+
if command_matched:
|
|
285
|
+
return
|
|
256
286
|
|
|
257
|
-
#
|
|
258
|
-
if
|
|
259
|
-
|
|
260
|
-
if
|
|
261
|
-
pass
|
|
262
|
-
else:
|
|
263
|
-
# 检查是否是等待回复的消息
|
|
264
|
-
await self._check_pending_reply(event)
|
|
287
|
+
# 尝试使用 alt_message
|
|
288
|
+
if alt_message and alt_message != message_text:
|
|
289
|
+
command_matched = await _process_text_for_command(event, alt_message)
|
|
290
|
+
if command_matched:
|
|
265
291
|
return
|
|
266
292
|
|
|
293
|
+
# 如果都没有匹配,检查是否是等待回复的消息
|
|
294
|
+
await self._check_pending_reply(event)
|
|
295
|
+
return
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
async def _try_execute_command(self, event: Dict[str, Any], original_text: str, check_text: str) -> bool:
|
|
299
|
+
"""
|
|
300
|
+
尝试执行命令
|
|
301
|
+
|
|
302
|
+
{!--< internal-use >!--}
|
|
303
|
+
内部使用的方法,用于尝试解析和执行命令
|
|
304
|
+
|
|
305
|
+
:param event: 消息事件数据
|
|
306
|
+
:param original_text: 原始文本内容
|
|
307
|
+
:param check_text: 用于检查的文本内容(可能已转换为小写)
|
|
308
|
+
:return: 是否成功执行命令
|
|
309
|
+
"""
|
|
310
|
+
prefix = self.prefix if self.case_sensitive else self.prefix.lower()
|
|
311
|
+
|
|
267
312
|
# 解析命令和参数
|
|
268
313
|
command_text = check_text[len(prefix):].strip()
|
|
269
314
|
parts = command_text.split()
|
|
270
315
|
if not parts:
|
|
271
|
-
return
|
|
316
|
+
return False
|
|
272
317
|
|
|
273
318
|
cmd_name = parts[0]
|
|
274
319
|
args = parts[1:] if len(parts) > 1 else []
|
|
@@ -323,6 +368,10 @@ class CommandHandler:
|
|
|
323
368
|
except Exception as e:
|
|
324
369
|
logger.error(f"命令执行错误: {e}")
|
|
325
370
|
await self._send_command_error(event, str(e))
|
|
371
|
+
|
|
372
|
+
return True
|
|
373
|
+
|
|
374
|
+
return False
|
|
326
375
|
|
|
327
376
|
async def _check_pending_reply(self, event: Dict[str, Any]):
|
|
328
377
|
"""
|
|
@@ -486,4 +535,4 @@ class CommandHandler:
|
|
|
486
535
|
help_lines.append(f" {self.prefix}{cmd_name} - {help_text}")
|
|
487
536
|
return "\n".join(help_lines)
|
|
488
537
|
|
|
489
|
-
command = CommandHandler()
|
|
538
|
+
command = CommandHandler()
|
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ErisPulse 事件包装类
|
|
3
|
+
|
|
4
|
+
提供便捷的事件访问方法
|
|
5
|
+
|
|
6
|
+
{!--< tips >!--}
|
|
7
|
+
1. 继承自dict,完全兼容字典访问
|
|
8
|
+
2. 提供便捷方法简化事件处理
|
|
9
|
+
3. 支持点式访问 event.platform
|
|
10
|
+
{!--< /tips >!--}
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Any, Dict, List, Optional, Callable, Awaitable, Union
|
|
14
|
+
from .. import adapter, logger
|
|
15
|
+
import asyncio
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Event(dict):
|
|
19
|
+
"""
|
|
20
|
+
事件包装类
|
|
21
|
+
|
|
22
|
+
提供便捷的事件访问方法
|
|
23
|
+
|
|
24
|
+
{!--< tips >!--}
|
|
25
|
+
所有方法都是可选的,不影响原有字典访问方式
|
|
26
|
+
{!--< /tips >!--}
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, event_data: Dict[str, Any]):
|
|
30
|
+
"""
|
|
31
|
+
初始化事件包装器
|
|
32
|
+
|
|
33
|
+
:param event_data: 原始事件数据
|
|
34
|
+
"""
|
|
35
|
+
super().__init__(event_data)
|
|
36
|
+
self._event_data = event_data
|
|
37
|
+
|
|
38
|
+
# ==================== 核心必填字段方法 ====================
|
|
39
|
+
|
|
40
|
+
def get_id(self) -> str:
|
|
41
|
+
"""
|
|
42
|
+
获取事件ID
|
|
43
|
+
|
|
44
|
+
:return: 事件ID
|
|
45
|
+
"""
|
|
46
|
+
return self.get("id", "")
|
|
47
|
+
|
|
48
|
+
def get_time(self) -> int:
|
|
49
|
+
"""
|
|
50
|
+
获取事件时间戳
|
|
51
|
+
|
|
52
|
+
:return: Unix时间戳(秒级)
|
|
53
|
+
"""
|
|
54
|
+
return self.get("time", 0)
|
|
55
|
+
|
|
56
|
+
def get_type(self) -> str:
|
|
57
|
+
"""
|
|
58
|
+
获取事件类型
|
|
59
|
+
|
|
60
|
+
:return: 事件类型(message/notice/request/meta等)
|
|
61
|
+
"""
|
|
62
|
+
return self.get("type", "")
|
|
63
|
+
|
|
64
|
+
def get_detail_type(self) -> str:
|
|
65
|
+
"""
|
|
66
|
+
获取事件详细类型
|
|
67
|
+
|
|
68
|
+
:return: 事件详细类型(private/group/friend等)
|
|
69
|
+
"""
|
|
70
|
+
return self.get("detail_type", "")
|
|
71
|
+
|
|
72
|
+
def get_platform(self) -> str:
|
|
73
|
+
"""
|
|
74
|
+
获取平台名称
|
|
75
|
+
|
|
76
|
+
:return: 平台名称
|
|
77
|
+
"""
|
|
78
|
+
return self.get("platform", "")
|
|
79
|
+
|
|
80
|
+
# ==================== 机器人信息方法 ====================
|
|
81
|
+
|
|
82
|
+
def get_self_platform(self) -> str:
|
|
83
|
+
"""
|
|
84
|
+
获取机器人平台
|
|
85
|
+
|
|
86
|
+
:return: 机器人平台名称
|
|
87
|
+
"""
|
|
88
|
+
return self.get("self", {}).get("platform", "")
|
|
89
|
+
|
|
90
|
+
def get_self_user_id(self) -> str:
|
|
91
|
+
"""
|
|
92
|
+
获取机器人用户ID
|
|
93
|
+
|
|
94
|
+
:return: 机器人用户ID
|
|
95
|
+
"""
|
|
96
|
+
return self.get("self", {}).get("user_id", "")
|
|
97
|
+
|
|
98
|
+
def get_self_info(self) -> Dict[str, Any]:
|
|
99
|
+
"""
|
|
100
|
+
获取机器人完整信息
|
|
101
|
+
|
|
102
|
+
:return: 机器人信息字典
|
|
103
|
+
"""
|
|
104
|
+
return self.get("self", {})
|
|
105
|
+
|
|
106
|
+
# ==================== 消息事件专用方法 ====================
|
|
107
|
+
|
|
108
|
+
def get_message(self) -> List[Dict[str, Any]]:
|
|
109
|
+
"""
|
|
110
|
+
获取消息段数组
|
|
111
|
+
|
|
112
|
+
:return: 消息段数组
|
|
113
|
+
"""
|
|
114
|
+
return self.get("message", [])
|
|
115
|
+
|
|
116
|
+
def get_alt_message(self) -> str:
|
|
117
|
+
"""
|
|
118
|
+
获取消息备用文本
|
|
119
|
+
|
|
120
|
+
:return: 消息备用文本
|
|
121
|
+
"""
|
|
122
|
+
return self.get("alt_message", "")
|
|
123
|
+
|
|
124
|
+
def get_text(self) -> str:
|
|
125
|
+
"""
|
|
126
|
+
获取纯文本内容
|
|
127
|
+
|
|
128
|
+
:return: 纯文本内容
|
|
129
|
+
"""
|
|
130
|
+
return self.get_alt_message()
|
|
131
|
+
|
|
132
|
+
def get_message_text(self) -> str:
|
|
133
|
+
"""
|
|
134
|
+
获取纯文本内容(别名)
|
|
135
|
+
|
|
136
|
+
:return: 纯文本内容
|
|
137
|
+
"""
|
|
138
|
+
return self.get_alt_message()
|
|
139
|
+
|
|
140
|
+
def has_mention(self) -> bool:
|
|
141
|
+
"""
|
|
142
|
+
是否包含@消息
|
|
143
|
+
|
|
144
|
+
:return: 是否包含@消息
|
|
145
|
+
"""
|
|
146
|
+
message_segments = self.get_message()
|
|
147
|
+
self_id = self.get_self_user_id()
|
|
148
|
+
|
|
149
|
+
for segment in message_segments:
|
|
150
|
+
if segment.get("type") == "mention":
|
|
151
|
+
if segment.get("data", {}).get("user_id") == self_id:
|
|
152
|
+
return True
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
def get_mentions(self) -> List[str]:
|
|
156
|
+
"""
|
|
157
|
+
获取所有被@的用户ID列表
|
|
158
|
+
|
|
159
|
+
:return: 被@的用户ID列表
|
|
160
|
+
"""
|
|
161
|
+
message_segments = self.get_message()
|
|
162
|
+
mentions = []
|
|
163
|
+
|
|
164
|
+
for segment in message_segments:
|
|
165
|
+
if segment.get("type") == "mention":
|
|
166
|
+
user_id = segment.get("data", {}).get("user_id")
|
|
167
|
+
if user_id:
|
|
168
|
+
mentions.append(user_id)
|
|
169
|
+
|
|
170
|
+
return mentions
|
|
171
|
+
|
|
172
|
+
def get_user_id(self) -> str:
|
|
173
|
+
"""
|
|
174
|
+
获取发送者ID
|
|
175
|
+
|
|
176
|
+
:return: 发送者用户ID
|
|
177
|
+
"""
|
|
178
|
+
return self.get("user_id", "")
|
|
179
|
+
|
|
180
|
+
def get_user_nickname(self) -> str:
|
|
181
|
+
"""
|
|
182
|
+
获取发送者昵称
|
|
183
|
+
|
|
184
|
+
:return: 发送者昵称
|
|
185
|
+
"""
|
|
186
|
+
return self.get("user_nickname", "")
|
|
187
|
+
|
|
188
|
+
def get_group_id(self) -> str:
|
|
189
|
+
"""
|
|
190
|
+
获取群组ID
|
|
191
|
+
|
|
192
|
+
:return: 群组ID(群聊消息)
|
|
193
|
+
"""
|
|
194
|
+
return self.get("group_id", "")
|
|
195
|
+
|
|
196
|
+
def get_sender(self) -> Dict[str, Any]:
|
|
197
|
+
"""
|
|
198
|
+
获取发送者信息字典
|
|
199
|
+
|
|
200
|
+
:return: 发送者信息字典
|
|
201
|
+
"""
|
|
202
|
+
return {
|
|
203
|
+
"user_id": self.get_user_id(),
|
|
204
|
+
"nickname": self.get_user_nickname(),
|
|
205
|
+
"group_id": self.get_group_id() if self.is_group_message() else None
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
# ==================== 消息类型判断 ====================
|
|
209
|
+
|
|
210
|
+
def is_message(self) -> bool:
|
|
211
|
+
"""
|
|
212
|
+
是否为消息事件
|
|
213
|
+
|
|
214
|
+
:return: 是否为消息事件
|
|
215
|
+
"""
|
|
216
|
+
return self.get_type() == "message"
|
|
217
|
+
|
|
218
|
+
def is_private_message(self) -> bool:
|
|
219
|
+
"""
|
|
220
|
+
是否为私聊消息
|
|
221
|
+
|
|
222
|
+
:return: 是否为私聊消息
|
|
223
|
+
"""
|
|
224
|
+
return self.is_message() and self.get_detail_type() == "private"
|
|
225
|
+
|
|
226
|
+
def is_group_message(self) -> bool:
|
|
227
|
+
"""
|
|
228
|
+
是否为群聊消息
|
|
229
|
+
|
|
230
|
+
:return: 是否为群聊消息
|
|
231
|
+
"""
|
|
232
|
+
return self.is_message() and self.get_detail_type() == "group"
|
|
233
|
+
|
|
234
|
+
def is_at_message(self) -> bool:
|
|
235
|
+
"""
|
|
236
|
+
是否为@消息
|
|
237
|
+
|
|
238
|
+
:return: 是否为@消息
|
|
239
|
+
"""
|
|
240
|
+
return self.has_mention()
|
|
241
|
+
|
|
242
|
+
# ==================== 通知事件专用方法 ====================
|
|
243
|
+
|
|
244
|
+
def get_operator_id(self) -> str:
|
|
245
|
+
"""
|
|
246
|
+
获取操作者ID
|
|
247
|
+
|
|
248
|
+
:return: 操作者ID
|
|
249
|
+
"""
|
|
250
|
+
return self.get("operator_id", "")
|
|
251
|
+
|
|
252
|
+
def get_operator_nickname(self) -> str:
|
|
253
|
+
"""
|
|
254
|
+
获取操作者昵称
|
|
255
|
+
|
|
256
|
+
:return: 操作者昵称
|
|
257
|
+
"""
|
|
258
|
+
return self.get("operator_nickname", "")
|
|
259
|
+
|
|
260
|
+
# ==================== 通知类型判断 ====================
|
|
261
|
+
|
|
262
|
+
def is_notice(self) -> bool:
|
|
263
|
+
"""
|
|
264
|
+
是否为通知事件
|
|
265
|
+
|
|
266
|
+
:return: 是否为通知事件
|
|
267
|
+
"""
|
|
268
|
+
return self.get_type() == "notice"
|
|
269
|
+
|
|
270
|
+
def is_group_member_increase(self) -> bool:
|
|
271
|
+
"""
|
|
272
|
+
群成员增加
|
|
273
|
+
|
|
274
|
+
:return: 是否为群成员增加事件
|
|
275
|
+
"""
|
|
276
|
+
return self.is_notice() and self.get_detail_type() == "group_member_increase"
|
|
277
|
+
|
|
278
|
+
def is_group_member_decrease(self) -> bool:
|
|
279
|
+
"""
|
|
280
|
+
群成员减少
|
|
281
|
+
|
|
282
|
+
:return: 是否为群成员减少事件
|
|
283
|
+
"""
|
|
284
|
+
return self.is_notice() and self.get_detail_type() == "group_member_decrease"
|
|
285
|
+
|
|
286
|
+
def is_friend_add(self) -> bool:
|
|
287
|
+
"""
|
|
288
|
+
好友添加
|
|
289
|
+
|
|
290
|
+
:return: 是否为好友添加事件
|
|
291
|
+
"""
|
|
292
|
+
return self.is_notice() and self.get_detail_type() == "friend_add"
|
|
293
|
+
|
|
294
|
+
def is_friend_delete(self) -> bool:
|
|
295
|
+
"""
|
|
296
|
+
好友删除
|
|
297
|
+
|
|
298
|
+
:return: 是否为好友删除事件
|
|
299
|
+
"""
|
|
300
|
+
return self.is_notice() and self.get_detail_type() == "friend_delete"
|
|
301
|
+
|
|
302
|
+
# ==================== 请求事件专用方法 ====================
|
|
303
|
+
|
|
304
|
+
def get_comment(self) -> str:
|
|
305
|
+
"""
|
|
306
|
+
获取请求附言
|
|
307
|
+
|
|
308
|
+
:return: 请求附言
|
|
309
|
+
"""
|
|
310
|
+
return self.get("comment", "")
|
|
311
|
+
|
|
312
|
+
# ==================== 请求类型判断 ====================
|
|
313
|
+
|
|
314
|
+
def is_request(self) -> bool:
|
|
315
|
+
"""
|
|
316
|
+
是否为请求事件
|
|
317
|
+
|
|
318
|
+
:return: 是否为请求事件
|
|
319
|
+
"""
|
|
320
|
+
return self.get_type() == "request"
|
|
321
|
+
|
|
322
|
+
def is_friend_request(self) -> bool:
|
|
323
|
+
"""
|
|
324
|
+
是否为好友请求
|
|
325
|
+
|
|
326
|
+
:return: 是否为好友请求
|
|
327
|
+
"""
|
|
328
|
+
return self.is_request() and self.get_detail_type() == "friend"
|
|
329
|
+
|
|
330
|
+
def is_group_request(self) -> bool:
|
|
331
|
+
"""
|
|
332
|
+
是否为群组请求
|
|
333
|
+
|
|
334
|
+
:return: 是否为群组请求
|
|
335
|
+
"""
|
|
336
|
+
return self.is_request() and self.get_detail_type() == "group"
|
|
337
|
+
|
|
338
|
+
# ==================== 回复功能 ====================
|
|
339
|
+
|
|
340
|
+
def _get_adapter_and_target(self) -> tuple:
|
|
341
|
+
"""
|
|
342
|
+
获取适配器实例和目标信息
|
|
343
|
+
|
|
344
|
+
:return: (适配器实例, 详细类型, 目标ID)
|
|
345
|
+
"""
|
|
346
|
+
platform = self.get_platform()
|
|
347
|
+
if not platform:
|
|
348
|
+
raise ValueError("平台信息缺失")
|
|
349
|
+
|
|
350
|
+
adapter_instance = getattr(adapter, platform, None)
|
|
351
|
+
if not adapter_instance:
|
|
352
|
+
raise ValueError(f"找不到平台 {platform} 的适配器")
|
|
353
|
+
|
|
354
|
+
group_id = self.get_group_id()
|
|
355
|
+
user_id = self.get_user_id()
|
|
356
|
+
|
|
357
|
+
if group_id:
|
|
358
|
+
detail_type = "group"
|
|
359
|
+
target_id = group_id
|
|
360
|
+
else:
|
|
361
|
+
detail_type = "user"
|
|
362
|
+
target_id = user_id
|
|
363
|
+
|
|
364
|
+
return adapter_instance, detail_type, target_id
|
|
365
|
+
|
|
366
|
+
async def reply(self,
|
|
367
|
+
content: str,
|
|
368
|
+
method: str = "Text",
|
|
369
|
+
**kwargs) -> Any:
|
|
370
|
+
"""
|
|
371
|
+
通用回复方法
|
|
372
|
+
|
|
373
|
+
基于适配器的Text方法,但可以通过method参数指定其他发送方法
|
|
374
|
+
|
|
375
|
+
:param content: 发送内容(文本、URL等,取决于method参数)
|
|
376
|
+
:param method: 适配器发送方法,默认为"Text"
|
|
377
|
+
可选值: "Text", "Image", "Voice", "Video", "File" 等
|
|
378
|
+
:param kwargs: 额外参数,例如Mention方法的user_id
|
|
379
|
+
:return: 适配器发送方法的返回值
|
|
380
|
+
|
|
381
|
+
:example:
|
|
382
|
+
>>> await event.reply("你好") # 发送文本
|
|
383
|
+
>>> await event.reply("http://example.com/image.jpg", method="Image") # 发送图片
|
|
384
|
+
>>> await event.reply("回复内容", method="Mention", user_id="123456") # @用户并发送
|
|
385
|
+
>>> await event.reply("http://example.com/voice.mp3", method="Voice") # 发送语音
|
|
386
|
+
"""
|
|
387
|
+
adapter_instance, detail_type, target_id = self._get_adapter_and_target()
|
|
388
|
+
|
|
389
|
+
# 构建发送链
|
|
390
|
+
send_chain = adapter_instance.Send.To(detail_type, target_id)
|
|
391
|
+
|
|
392
|
+
# 处理特殊方法
|
|
393
|
+
if method == "Mention":
|
|
394
|
+
user_id = kwargs.get("user_id")
|
|
395
|
+
if user_id is None:
|
|
396
|
+
user_id = self.get_user_id()
|
|
397
|
+
send_chain = send_chain.Mention(user_id)
|
|
398
|
+
method = "Text"
|
|
399
|
+
|
|
400
|
+
# 调用指定方法
|
|
401
|
+
send_method = getattr(send_chain, method, None)
|
|
402
|
+
if not send_method or not callable(send_method):
|
|
403
|
+
raise ValueError(f"适配器不支持方法: {method}")
|
|
404
|
+
|
|
405
|
+
return await send_method(content)
|
|
406
|
+
|
|
407
|
+
async def forward_to_group(self, group_id: str):
|
|
408
|
+
"""
|
|
409
|
+
转发到群组
|
|
410
|
+
|
|
411
|
+
:param group_id: 目标群组ID
|
|
412
|
+
"""
|
|
413
|
+
adapter_instance = getattr(adapter, self.get_platform(), None)
|
|
414
|
+
if not adapter_instance:
|
|
415
|
+
raise ValueError(f"找不到平台 {self.get_platform()} 的适配器")
|
|
416
|
+
await adapter_instance.Forward.To("group", group_id).Event(self)
|
|
417
|
+
|
|
418
|
+
async def forward_to_user(self, user_id: str):
|
|
419
|
+
"""
|
|
420
|
+
转发给用户
|
|
421
|
+
|
|
422
|
+
:param user_id: 目标用户ID
|
|
423
|
+
"""
|
|
424
|
+
adapter_instance = getattr(adapter, self.get_platform(), None)
|
|
425
|
+
if not adapter_instance:
|
|
426
|
+
raise ValueError(f"找不到平台 {self.get_platform()} 的适配器")
|
|
427
|
+
await adapter_instance.Forward.To("user", user_id).Event(self)
|
|
428
|
+
|
|
429
|
+
# ==================== 等待回复功能 ====================
|
|
430
|
+
|
|
431
|
+
async def wait_reply(self,
|
|
432
|
+
prompt: str = None,
|
|
433
|
+
timeout: float = 60.0,
|
|
434
|
+
callback: Callable[[Dict[str, Any]], Awaitable[Any]] = None,
|
|
435
|
+
validator: Callable[[Dict[str, Any]], bool] = None) -> Optional['Event']:
|
|
436
|
+
"""
|
|
437
|
+
等待用户回复
|
|
438
|
+
|
|
439
|
+
:param prompt: 提示消息,如果提供会发送给用户
|
|
440
|
+
:param timeout: 等待超时时间(秒)
|
|
441
|
+
:param callback: 回调函数,当收到回复时执行
|
|
442
|
+
:param validator: 验证函数,用于验证回复是否有效
|
|
443
|
+
:return: 用户回复的事件数据,如果超时则返回None
|
|
444
|
+
"""
|
|
445
|
+
platform = self.get_platform()
|
|
446
|
+
user_id = self.get_user_id()
|
|
447
|
+
group_id = self.get_group_id()
|
|
448
|
+
target_id = group_id or user_id
|
|
449
|
+
detail_type = "group" if group_id else "private"
|
|
450
|
+
|
|
451
|
+
# 导入command处理器以复用等待逻辑
|
|
452
|
+
from .command import command as command_handler
|
|
453
|
+
|
|
454
|
+
# 发送提示消息(如果提供)
|
|
455
|
+
if prompt:
|
|
456
|
+
try:
|
|
457
|
+
adapter_instance = getattr(adapter, platform)
|
|
458
|
+
await adapter_instance.Send.To(detail_type, target_id).Text(prompt)
|
|
459
|
+
except Exception as e:
|
|
460
|
+
logger.warning(f"发送提示消息失败: {e}")
|
|
461
|
+
|
|
462
|
+
# 使用command处理器的wait_reply方法
|
|
463
|
+
result = await command_handler.wait_reply(
|
|
464
|
+
self,
|
|
465
|
+
prompt=None, # 已经发送过提示了
|
|
466
|
+
timeout=timeout,
|
|
467
|
+
callback=callback,
|
|
468
|
+
validator=validator
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
# 将结果转换为Event对象
|
|
472
|
+
if result:
|
|
473
|
+
return Event(result)
|
|
474
|
+
return None
|
|
475
|
+
|
|
476
|
+
# ==================== 原始数据和元信息 ====================
|
|
477
|
+
|
|
478
|
+
def get_raw(self) -> Dict[str, Any]:
|
|
479
|
+
"""
|
|
480
|
+
获取原始事件数据
|
|
481
|
+
|
|
482
|
+
:return: 原始事件数据
|
|
483
|
+
"""
|
|
484
|
+
platform = self.get_platform()
|
|
485
|
+
raw_key = f"{platform}_raw" if platform else "raw"
|
|
486
|
+
return self.get(raw_key, {})
|
|
487
|
+
|
|
488
|
+
def get_raw_type(self) -> str:
|
|
489
|
+
"""
|
|
490
|
+
获取原始事件类型
|
|
491
|
+
|
|
492
|
+
:return: 原始事件类型
|
|
493
|
+
"""
|
|
494
|
+
platform = self.get_platform()
|
|
495
|
+
raw_type_key = f"{platform}_raw_type" if platform else "raw_type"
|
|
496
|
+
return self.get(raw_type_key, "")
|
|
497
|
+
|
|
498
|
+
# ==================== 命令信息 ====================
|
|
499
|
+
|
|
500
|
+
def get_command_name(self) -> str:
|
|
501
|
+
"""
|
|
502
|
+
获取命令名称
|
|
503
|
+
|
|
504
|
+
:return: 命令名称
|
|
505
|
+
"""
|
|
506
|
+
return self.get("command", {}).get("name", "")
|
|
507
|
+
|
|
508
|
+
def get_command_args(self) -> List[str]:
|
|
509
|
+
"""
|
|
510
|
+
获取命令参数
|
|
511
|
+
|
|
512
|
+
:return: 命令参数列表
|
|
513
|
+
"""
|
|
514
|
+
return self.get("command", {}).get("args", [])
|
|
515
|
+
|
|
516
|
+
def get_command_raw(self) -> str:
|
|
517
|
+
"""
|
|
518
|
+
获取命令原始文本
|
|
519
|
+
|
|
520
|
+
:return: 命令原始文本
|
|
521
|
+
"""
|
|
522
|
+
return self.get("command", {}).get("raw", "")
|
|
523
|
+
|
|
524
|
+
def get_command_info(self) -> Dict[str, Any]:
|
|
525
|
+
"""
|
|
526
|
+
获取完整命令信息
|
|
527
|
+
|
|
528
|
+
:return: 命令信息字典
|
|
529
|
+
"""
|
|
530
|
+
return self.get("command", {})
|
|
531
|
+
|
|
532
|
+
def is_command(self) -> bool:
|
|
533
|
+
"""
|
|
534
|
+
是否为命令
|
|
535
|
+
|
|
536
|
+
:return: 是否为命令
|
|
537
|
+
"""
|
|
538
|
+
return "command" in self and bool(self.get("command"))
|
|
539
|
+
|
|
540
|
+
# ==================== 工具方法 ====================
|
|
541
|
+
|
|
542
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
543
|
+
"""
|
|
544
|
+
转换为字典
|
|
545
|
+
|
|
546
|
+
:return: 事件数据字典
|
|
547
|
+
"""
|
|
548
|
+
return dict(self)
|
|
549
|
+
|
|
550
|
+
def is_processed(self) -> bool:
|
|
551
|
+
"""
|
|
552
|
+
是否已被处理
|
|
553
|
+
|
|
554
|
+
:return: 是否已被处理
|
|
555
|
+
"""
|
|
556
|
+
return self.get("_processed", False)
|
|
557
|
+
|
|
558
|
+
def mark_processed(self):
|
|
559
|
+
"""
|
|
560
|
+
标记为已处理
|
|
561
|
+
"""
|
|
562
|
+
self["_processed"] = True
|
|
563
|
+
|
|
564
|
+
# ==================== 魔术方法 ====================
|
|
565
|
+
|
|
566
|
+
def __getattr__(self, name: str) -> Any:
|
|
567
|
+
"""
|
|
568
|
+
支持点式访问字典键
|
|
569
|
+
|
|
570
|
+
:param name: 属性名
|
|
571
|
+
:return: 属性值
|
|
572
|
+
"""
|
|
573
|
+
try:
|
|
574
|
+
return self[name]
|
|
575
|
+
except KeyError:
|
|
576
|
+
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
|
|
577
|
+
|
|
578
|
+
def __repr__(self) -> str:
|
|
579
|
+
"""
|
|
580
|
+
字符串表示
|
|
581
|
+
|
|
582
|
+
:return: 字符串表示
|
|
583
|
+
"""
|
|
584
|
+
event_type = self.get_type()
|
|
585
|
+
detail_type = self.get_detail_type()
|
|
586
|
+
platform = self.get_platform()
|
|
587
|
+
return f"Event(type={event_type}, detail_type={detail_type}, platform={platform})"
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
__all__ = [
|
|
591
|
+
"Event"
|
|
592
|
+
]
|
ErisPulse/__main__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ErisPulse
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.3.dev0
|
|
4
4
|
Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
|
|
5
5
|
Author-email: "艾莉丝·格雷拉特(WSu2059)" <wsu2059@qq.com>
|
|
6
6
|
License: MIT License
|
|
@@ -57,9 +57,7 @@ Requires-Dist: aiohttp
|
|
|
57
57
|
Requires-Dist: colorama
|
|
58
58
|
Requires-Dist: fastapi>=0.116.1
|
|
59
59
|
Requires-Dist: hypercorn>=0.14.0
|
|
60
|
-
Requires-Dist: keyboard
|
|
61
60
|
Requires-Dist: packaging>=25.0
|
|
62
|
-
Requires-Dist: pip
|
|
63
61
|
Requires-Dist: pydantic>=2.10.6
|
|
64
62
|
Requires-Dist: python-multipart>=0.0.20
|
|
65
63
|
Requires-Dist: rich
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
ErisPulse/__init__.py,sha256=u5b96KfFq57kB4I51t_YAU_aLVTftG4rLkAqFmmYwVA,50327
|
|
2
|
-
ErisPulse/__main__.py,sha256=
|
|
2
|
+
ErisPulse/__main__.py,sha256=AGA-Y6zBIRJYmfTU4hc1R_ykkpAUFalGXxftaBxRf6U,361
|
|
3
3
|
ErisPulse/Core/__init__.py,sha256=9RNwUq9Hbe3r6nA8QBvq2pvMJN4QiBfo71N0u_ywiwI,1398
|
|
4
4
|
ErisPulse/Core/_self_config.py,sha256=ReoVy2hYZxG7hPRHXUWRjLClC4nWZ2RG8VWdD-PAM7g,3549
|
|
5
5
|
ErisPulse/Core/adapter.py,sha256=9wpaE9B6LixlGTJ0p341wYe4AE3SVuczToMOWd7UkL4,19707
|
|
@@ -14,21 +14,22 @@ ErisPulse/Core/ux.py,sha256=jWC_v8e0Khe1LAg5ksKCVyEgmO2MJGIfmtOAPTorD90,29589
|
|
|
14
14
|
ErisPulse/Core/Bases/__init__.py,sha256=hHKsI2zQfBdahnEuHlMgzOX2_ygRDOVN8-VqTIrcxP4,230
|
|
15
15
|
ErisPulse/Core/Bases/adapter.py,sha256=aCupQdc8M5Ds7m5dZMCmtoyC-0Zqh5K_6F3uKle8WXE,6490
|
|
16
16
|
ErisPulse/Core/Bases/module.py,sha256=TtzZQ4x4u09S6yDibsIHa9srlGLFPXCHdn2WxZ3nmdo,1154
|
|
17
|
-
ErisPulse/Core/Event/__init__.py,sha256=
|
|
18
|
-
ErisPulse/Core/Event/base.py,sha256=
|
|
19
|
-
ErisPulse/Core/Event/command.py,sha256=
|
|
17
|
+
ErisPulse/Core/Event/__init__.py,sha256=JgvhhCM3RoeGE5egssyuHRdDfchF6Bt83XdSRmcToZc,1528
|
|
18
|
+
ErisPulse/Core/Event/base.py,sha256=bnTKdCTA0MRaFU8lheHm_ithiS2egZgU0oKSSajwCaM,4192
|
|
19
|
+
ErisPulse/Core/Event/command.py,sha256=mihGTv4kTkpncw6fE2n-GlTK66S3Y3kYx8mKzngbXto,19754
|
|
20
20
|
ErisPulse/Core/Event/exceptions.py,sha256=iGcuPaC7F4cZeujcvBdZb9bzQGnHBdb9CcPKoB760Bo,711
|
|
21
21
|
ErisPulse/Core/Event/message.py,sha256=wxg_GJsI1ZvPrV9611xELLxnlk2bcxMJH7EBEkoWwgE,4024
|
|
22
22
|
ErisPulse/Core/Event/meta.py,sha256=0cs0Cg5r58kll3P4lNtnVWAKLQiL6MoXPkbkk6_IEko,3660
|
|
23
23
|
ErisPulse/Core/Event/notice.py,sha256=tU28tc3Ig-FMB2EJUDO2Z9ewfJjzEPh2O2J4lU7GYDk,4557
|
|
24
24
|
ErisPulse/Core/Event/request.py,sha256=rYjFjRJccNRZ6bkY89ig8Q2YntnoytUfg-_PGntJxXg,2956
|
|
25
|
+
ErisPulse/Core/Event/wrapper.py,sha256=lKzsP67VFyPDLpqqGoDfDm8uWcnxOAYL-Z36yHeAOrU,16547
|
|
25
26
|
ErisPulse/utils/__init__.py,sha256=_4cDUbJyNebH-VXDUTnfdZKv8Y1MPYgsl-fOM0ZFNuw,299
|
|
26
27
|
ErisPulse/utils/cli.py,sha256=JMI3pOz_DrHj2sSscqhKzFUxGaRfa9Bs8jbvyqkZsy0,41234
|
|
27
28
|
ErisPulse/utils/console.py,sha256=IIo8kVTy0ikEp1H4V6BsokaQp_ISfBFuxlhQcRnk2vs,1145
|
|
28
29
|
ErisPulse/utils/package_manager.py,sha256=uv9Q24Qxa2bbotxLrSvhF-lX6vEmK-4KPCIwPe6ZyGc,32698
|
|
29
30
|
ErisPulse/utils/reload_handler.py,sha256=ToBE9EiXY8ZNNL8jntdsc2Dpy-Wgh73Jd3aBpedKAtg,3369
|
|
30
|
-
erispulse-2.3.
|
|
31
|
-
erispulse-2.3.
|
|
32
|
-
erispulse-2.3.
|
|
33
|
-
erispulse-2.3.
|
|
34
|
-
erispulse-2.3.
|
|
31
|
+
erispulse-2.3.3.dev0.dist-info/METADATA,sha256=esnXr889Sz96Hgonf_E9yWUx01aPGht7gfslVMQhViw,7435
|
|
32
|
+
erispulse-2.3.3.dev0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
33
|
+
erispulse-2.3.3.dev0.dist-info/entry_points.txt,sha256=NiOwT6-XQ7KIH1r6J8odjRO-uaKHfr_Vz_UIG96EWXg,187
|
|
34
|
+
erispulse-2.3.3.dev0.dist-info/licenses/LICENSE,sha256=tJjKWuY4OPWNgriiixWLvmFb8Pf8p_-4NMq_zZN3gWg,1858
|
|
35
|
+
erispulse-2.3.3.dev0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|