Undefined-bot 2.1.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.
- Undefined/__init__.py +3 -0
- Undefined/__main__.py +6 -0
- Undefined/ai.py +1215 -0
- Undefined/config.py +371 -0
- Undefined/end_summary_storage.py +48 -0
- Undefined/faq.py +244 -0
- Undefined/handlers.py +1247 -0
- Undefined/injection_response_agent.py +131 -0
- Undefined/main.py +126 -0
- Undefined/memory.py +120 -0
- Undefined/onebot.py +512 -0
- Undefined/rate_limit.py +130 -0
- Undefined/render.py +123 -0
- Undefined/scheduled_task_storage.py +88 -0
- Undefined/services/__init__.py +1 -0
- Undefined/services/queue_manager.py +206 -0
- Undefined/skills/README.md +53 -0
- Undefined/skills/__init__.py +10 -0
- Undefined/skills/agents/README.md +144 -0
- Undefined/skills/agents/__init__.py +116 -0
- Undefined/skills/agents/entertainment_agent/config.json +17 -0
- Undefined/skills/agents/entertainment_agent/handler.py +220 -0
- Undefined/skills/agents/entertainment_agent/intro.md +25 -0
- Undefined/skills/agents/entertainment_agent/prompt.md +20 -0
- Undefined/skills/agents/entertainment_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/entertainment_agent/tools/ai_draw_one/config.json +34 -0
- Undefined/skills/agents/entertainment_agent/tools/ai_draw_one/handler.py +62 -0
- Undefined/skills/agents/entertainment_agent/tools/ai_study_helper/config.json +22 -0
- Undefined/skills/agents/entertainment_agent/tools/ai_study_helper/handler.py +35 -0
- Undefined/skills/agents/entertainment_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/entertainment_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/entertainment_agent/tools/horoscope/config.json +24 -0
- Undefined/skills/agents/entertainment_agent/tools/horoscope/handler.py +141 -0
- Undefined/skills/agents/entertainment_agent/tools/minecraft_skin/config.json +43 -0
- Undefined/skills/agents/entertainment_agent/tools/minecraft_skin/handler.py +55 -0
- Undefined/skills/agents/entertainment_agent/tools/novel_search/config.json +25 -0
- Undefined/skills/agents/entertainment_agent/tools/novel_search/handler.py +31 -0
- Undefined/skills/agents/entertainment_agent/tools/renjian/config.json +12 -0
- Undefined/skills/agents/entertainment_agent/tools/renjian/handler.py +30 -0
- Undefined/skills/agents/entertainment_agent/tools/wenchang_dijun/config.json +12 -0
- Undefined/skills/agents/entertainment_agent/tools/wenchang_dijun/handler.py +44 -0
- Undefined/skills/agents/file_analysis_agent/__init__.py +1 -0
- Undefined/skills/agents/file_analysis_agent/config.json +21 -0
- Undefined/skills/agents/file_analysis_agent/handler.py +248 -0
- Undefined/skills/agents/file_analysis_agent/intro.md +22 -0
- Undefined/skills/agents/file_analysis_agent/prompt.md +36 -0
- Undefined/skills/agents/file_analysis_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/file_analysis_agent/tools/analyze_code/config.json +17 -0
- Undefined/skills/agents/file_analysis_agent/tools/analyze_code/handler.py +427 -0
- Undefined/skills/agents/file_analysis_agent/tools/analyze_multimodal/config.json +25 -0
- Undefined/skills/agents/file_analysis_agent/tools/analyze_multimodal/handler.py +178 -0
- Undefined/skills/agents/file_analysis_agent/tools/cleanup_temp/config.json +16 -0
- Undefined/skills/agents/file_analysis_agent/tools/cleanup_temp/handler.py +35 -0
- Undefined/skills/agents/file_analysis_agent/tools/detect_file_type/config.json +17 -0
- Undefined/skills/agents/file_analysis_agent/tools/detect_file_type/handler.py +221 -0
- Undefined/skills/agents/file_analysis_agent/tools/download_file/config.json +21 -0
- Undefined/skills/agents/file_analysis_agent/tools/download_file/handler.py +124 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_archive/config.json +25 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_archive/handler.py +190 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_docx/config.json +17 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_docx/handler.py +78 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_pdf/config.json +21 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_pdf/handler.py +67 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_pptx/config.json +17 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_pptx/handler.py +73 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_xlsx/config.json +17 -0
- Undefined/skills/agents/file_analysis_agent/tools/extract_xlsx/handler.py +101 -0
- Undefined/skills/agents/file_analysis_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/file_analysis_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/file_analysis_agent/tools/read_text_file/config.json +21 -0
- Undefined/skills/agents/file_analysis_agent/tools/read_text_file/handler.py +90 -0
- Undefined/skills/agents/info_agent/config.json +17 -0
- Undefined/skills/agents/info_agent/handler.py +220 -0
- Undefined/skills/agents/info_agent/intro.md +22 -0
- Undefined/skills/agents/info_agent/prompt.md +27 -0
- Undefined/skills/agents/info_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/info_agent/tools/baiduhot/config.json +18 -0
- Undefined/skills/agents/info_agent/tools/baiduhot/handler.py +49 -0
- Undefined/skills/agents/info_agent/tools/base64/config.json +22 -0
- Undefined/skills/agents/info_agent/tools/base64/handler.py +44 -0
- Undefined/skills/agents/info_agent/tools/douyinhot/config.json +18 -0
- Undefined/skills/agents/info_agent/tools/douyinhot/handler.py +53 -0
- Undefined/skills/agents/info_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/info_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/info_agent/tools/gold_price/config.json +12 -0
- Undefined/skills/agents/info_agent/tools/gold_price/handler.py +58 -0
- Undefined/skills/agents/info_agent/tools/hash/config.json +22 -0
- Undefined/skills/agents/info_agent/tools/hash/handler.py +43 -0
- Undefined/skills/agents/info_agent/tools/history/config.json +12 -0
- Undefined/skills/agents/info_agent/tools/history/handler.py +37 -0
- Undefined/skills/agents/info_agent/tools/net_check/config.json +17 -0
- Undefined/skills/agents/info_agent/tools/net_check/handler.py +117 -0
- Undefined/skills/agents/info_agent/tools/news_tencent/config.json +17 -0
- Undefined/skills/agents/info_agent/tools/news_tencent/handler.py +38 -0
- Undefined/skills/agents/info_agent/tools/qq_level_query/config.json +29 -0
- Undefined/skills/agents/info_agent/tools/qq_level_query/handler.py +48 -0
- Undefined/skills/agents/info_agent/tools/speed/config.json +17 -0
- Undefined/skills/agents/info_agent/tools/speed/handler.py +37 -0
- Undefined/skills/agents/info_agent/tools/tcping/config.json +21 -0
- Undefined/skills/agents/info_agent/tools/tcping/handler.py +53 -0
- Undefined/skills/agents/info_agent/tools/weather_query/config.json +22 -0
- Undefined/skills/agents/info_agent/tools/weather_query/handler.py +207 -0
- Undefined/skills/agents/info_agent/tools/weibohot/config.json +18 -0
- Undefined/skills/agents/info_agent/tools/weibohot/handler.py +49 -0
- Undefined/skills/agents/info_agent/tools/whois/config.json +17 -0
- Undefined/skills/agents/info_agent/tools/whois/handler.py +63 -0
- Undefined/skills/agents/naga_code_analysis_agent/config.json +17 -0
- Undefined/skills/agents/naga_code_analysis_agent/handler.py +222 -0
- Undefined/skills/agents/naga_code_analysis_agent/intro.md +17 -0
- Undefined/skills/agents/naga_code_analysis_agent/prompt.md +19 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/glob/config.json +17 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/glob/handler.py +37 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/list_directory/config.json +17 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/list_directory/handler.py +31 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/read_file/config.json +17 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/read_file/handler.py +66 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/read_naga_intro/config.json +12 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/read_naga_intro/handler.py +327 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/search_file_content/config.json +25 -0
- Undefined/skills/agents/naga_code_analysis_agent/tools/search_file_content/handler.py +46 -0
- Undefined/skills/agents/scheduler_agent/__init__.py +1 -0
- Undefined/skills/agents/scheduler_agent/config.json +17 -0
- Undefined/skills/agents/scheduler_agent/handler.py +218 -0
- Undefined/skills/agents/scheduler_agent/intro.md +17 -0
- Undefined/skills/agents/scheduler_agent/prompt.md +67 -0
- Undefined/skills/agents/scheduler_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/scheduler_agent/tools/create_schedule_task/config.json +37 -0
- Undefined/skills/agents/scheduler_agent/tools/create_schedule_task/handler.py +68 -0
- Undefined/skills/agents/scheduler_agent/tools/delete_schedule_task/config.json +19 -0
- Undefined/skills/agents/scheduler_agent/tools/delete_schedule_task/handler.py +26 -0
- Undefined/skills/agents/scheduler_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/scheduler_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/scheduler_agent/tools/list_schedule_tasks/config.json +11 -0
- Undefined/skills/agents/scheduler_agent/tools/list_schedule_tasks/handler.py +47 -0
- Undefined/skills/agents/scheduler_agent/tools/update_schedule_task/config.json +39 -0
- Undefined/skills/agents/scheduler_agent/tools/update_schedule_task/handler.py +46 -0
- Undefined/skills/agents/social_agent/config.json +17 -0
- Undefined/skills/agents/social_agent/handler.py +220 -0
- Undefined/skills/agents/social_agent/intro.md +17 -0
- Undefined/skills/agents/social_agent/prompt.md +19 -0
- Undefined/skills/agents/social_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/social_agent/tools/bilibili_search/config.json +21 -0
- Undefined/skills/agents/social_agent/tools/bilibili_search/handler.py +68 -0
- Undefined/skills/agents/social_agent/tools/bilibili_user_info/config.json +17 -0
- Undefined/skills/agents/social_agent/tools/bilibili_user_info/handler.py +68 -0
- Undefined/skills/agents/social_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/social_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/social_agent/tools/music_global_search/config.json +21 -0
- Undefined/skills/agents/social_agent/tools/music_global_search/handler.py +47 -0
- Undefined/skills/agents/social_agent/tools/music_info_get/config.json +22 -0
- Undefined/skills/agents/social_agent/tools/music_info_get/handler.py +35 -0
- Undefined/skills/agents/social_agent/tools/music_lyrics/config.json +22 -0
- Undefined/skills/agents/social_agent/tools/music_lyrics/handler.py +26 -0
- Undefined/skills/agents/social_agent/tools/video_random_recommend/config.json +21 -0
- Undefined/skills/agents/social_agent/tools/video_random_recommend/handler.py +21 -0
- Undefined/skills/agents/web_agent/config.json +17 -0
- Undefined/skills/agents/web_agent/handler.py +221 -0
- Undefined/skills/agents/web_agent/intro.md +14 -0
- Undefined/skills/agents/web_agent/prompt.md +16 -0
- Undefined/skills/agents/web_agent/tools/__init__.py +1 -0
- Undefined/skills/agents/web_agent/tools/crawl_webpage/config.json +21 -0
- Undefined/skills/agents/web_agent/tools/crawl_webpage/handler.py +102 -0
- Undefined/skills/agents/web_agent/tools/get_current_time/config.json +12 -0
- Undefined/skills/agents/web_agent/tools/get_current_time/handler.py +5 -0
- Undefined/skills/agents/web_agent/tools/web_search/config.json +21 -0
- Undefined/skills/agents/web_agent/tools/web_search/handler.py +29 -0
- Undefined/skills/tools/README.md +85 -0
- Undefined/skills/tools/__init__.py +120 -0
- Undefined/skills/tools/debug/config.json +17 -0
- Undefined/skills/tools/debug/handler.py +35 -0
- Undefined/skills/tools/end/config.json +17 -0
- Undefined/skills/tools/end/handler.py +24 -0
- Undefined/skills/tools/get_current_time/config.json +12 -0
- Undefined/skills/tools/get_current_time/handler.py +5 -0
- Undefined/skills/tools/get_forward_msg/config.json +17 -0
- Undefined/skills/tools/get_forward_msg/handler.py +131 -0
- Undefined/skills/tools/get_group_member_info/config.json +38 -0
- Undefined/skills/tools/get_group_member_info/handler.py +142 -0
- Undefined/skills/tools/get_messages_by_time/config.json +30 -0
- Undefined/skills/tools/get_messages_by_time/handler.py +128 -0
- Undefined/skills/tools/get_picture/config.json +45 -0
- Undefined/skills/tools/get_picture/handler.py +191 -0
- Undefined/skills/tools/get_recent_messages/config.json +30 -0
- Undefined/skills/tools/get_recent_messages/handler.py +88 -0
- Undefined/skills/tools/qq_like/config.json +22 -0
- Undefined/skills/tools/qq_like/handler.py +58 -0
- Undefined/skills/tools/render_html/config.json +26 -0
- Undefined/skills/tools/render_html/handler.py +39 -0
- Undefined/skills/tools/render_latex/config.json +26 -0
- Undefined/skills/tools/render_latex/handler.py +78 -0
- Undefined/skills/tools/render_markdown/config.json +26 -0
- Undefined/skills/tools/render_markdown/handler.py +63 -0
- Undefined/skills/tools/save_memory/config.json +17 -0
- Undefined/skills/tools/save_memory/handler.py +17 -0
- Undefined/skills/tools/send_message/config.json +21 -0
- Undefined/skills/tools/send_message/handler.py +60 -0
- Undefined/skills/tools/send_private_message/config.json +21 -0
- Undefined/skills/tools/send_private_message/handler.py +35 -0
- Undefined/utils/__init__.py +0 -0
- Undefined/utils/common.py +186 -0
- Undefined/utils/history.py +284 -0
- Undefined/utils/scheduler.py +286 -0
- Undefined/utils/sender.py +140 -0
- undefined_bot-2.1.0.dist-info/METADATA +259 -0
- undefined_bot-2.1.0.dist-info/RECORD +211 -0
- undefined_bot-2.1.0.dist-info/WHEEL +4 -0
- undefined_bot-2.1.0.dist-info/entry_points.txt +2 -0
- undefined_bot-2.1.0.dist-info/licenses/LICENSE +7 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _resolve_chat_id(chat_id: str, msg_type: str, history_manager: Any) -> str:
|
|
6
|
+
"""将群名/用户名转换为对应的 ID
|
|
7
|
+
|
|
8
|
+
参数:
|
|
9
|
+
chat_id: 群名、用户名或群号/用户ID
|
|
10
|
+
msg_type: "group" 或 "private"
|
|
11
|
+
history_manager: 历史记录管理器实例
|
|
12
|
+
|
|
13
|
+
返回:
|
|
14
|
+
解析后的群号或用户ID
|
|
15
|
+
"""
|
|
16
|
+
if chat_id.isdigit():
|
|
17
|
+
return chat_id
|
|
18
|
+
|
|
19
|
+
if not history_manager:
|
|
20
|
+
return chat_id
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
# 使用生成器表达式简化查找逻辑
|
|
24
|
+
if msg_type == "group":
|
|
25
|
+
histories = history_manager._message_history.items()
|
|
26
|
+
elif msg_type == "private":
|
|
27
|
+
histories = history_manager._private_message_history.items()
|
|
28
|
+
else:
|
|
29
|
+
return chat_id
|
|
30
|
+
|
|
31
|
+
# 查找第一个匹配的 ID
|
|
32
|
+
for id_val, messages in histories:
|
|
33
|
+
if messages and messages[0].get("chat_name") == chat_id:
|
|
34
|
+
return str(id_val)
|
|
35
|
+
|
|
36
|
+
except Exception:
|
|
37
|
+
# 忽略任何查找过程中的错误,回退到返回原始 chat_id
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
return chat_id
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _filter_messages(
|
|
44
|
+
messages: list[Dict[str, Any]], start_dt: datetime, end_dt: datetime
|
|
45
|
+
) -> list[Dict[str, Any]]:
|
|
46
|
+
"""根据时间范围过滤消息
|
|
47
|
+
|
|
48
|
+
参数:
|
|
49
|
+
messages: 原始消息列表
|
|
50
|
+
start_dt: 开始时间
|
|
51
|
+
end_dt: 结束时间
|
|
52
|
+
|
|
53
|
+
返回:
|
|
54
|
+
过滤后的消息列表
|
|
55
|
+
"""
|
|
56
|
+
filtered = []
|
|
57
|
+
for msg in messages:
|
|
58
|
+
timestamp = msg.get("timestamp", "")
|
|
59
|
+
if not timestamp:
|
|
60
|
+
continue
|
|
61
|
+
try:
|
|
62
|
+
msg_dt = datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")
|
|
63
|
+
if start_dt <= msg_dt <= end_dt:
|
|
64
|
+
filtered.append(msg)
|
|
65
|
+
except ValueError:
|
|
66
|
+
continue
|
|
67
|
+
return filtered
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
71
|
+
chat_id = args.get("chat_id")
|
|
72
|
+
msg_type = args.get("type")
|
|
73
|
+
start_time = args.get("start_time", "")
|
|
74
|
+
end_time = args.get("end_time", "")
|
|
75
|
+
|
|
76
|
+
if not chat_id or not msg_type:
|
|
77
|
+
return "chat_id 和 type 参数不能为空"
|
|
78
|
+
if not start_time or not end_time:
|
|
79
|
+
return "start_time 和 end_time 参数不能为空"
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
start_dt = datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S")
|
|
83
|
+
end_dt = datetime.strptime(end_time, "%Y-%m-%d %H:%M:%S")
|
|
84
|
+
except ValueError:
|
|
85
|
+
return "时间格式错误,请使用格式:YYYY-MM-DD HH:MM:SS"
|
|
86
|
+
|
|
87
|
+
if start_dt > end_dt:
|
|
88
|
+
return "开始时间不能晚于结束时间"
|
|
89
|
+
|
|
90
|
+
get_recent_messages_callback = context.get("get_recent_messages_callback")
|
|
91
|
+
history_manager = context.get("history_manager")
|
|
92
|
+
|
|
93
|
+
resolved_chat_id = _resolve_chat_id(chat_id, msg_type, history_manager)
|
|
94
|
+
|
|
95
|
+
if get_recent_messages_callback:
|
|
96
|
+
messages = await get_recent_messages_callback(
|
|
97
|
+
resolved_chat_id, msg_type, 0, 10000
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# 使用提取的函数进行过滤
|
|
101
|
+
filtered_messages = _filter_messages(messages, start_dt, end_dt)
|
|
102
|
+
|
|
103
|
+
formatted = []
|
|
104
|
+
for msg in filtered_messages:
|
|
105
|
+
msg_type_val = msg.get("type", "group")
|
|
106
|
+
sender_name = msg.get("display_name", "未知用户")
|
|
107
|
+
sender_id = msg.get("user_id", "")
|
|
108
|
+
chat_name = msg.get("chat_name", "未知群聊")
|
|
109
|
+
timestamp_str = msg.get("timestamp", "")
|
|
110
|
+
text = msg.get("message", "")
|
|
111
|
+
|
|
112
|
+
if msg_type_val == "group":
|
|
113
|
+
# 确保群名以"群"结尾
|
|
114
|
+
location = chat_name if chat_name.endswith("群") else f"{chat_name}群"
|
|
115
|
+
else:
|
|
116
|
+
location = "私聊"
|
|
117
|
+
|
|
118
|
+
# 格式:XML 标准化
|
|
119
|
+
formatted.append(f"""<message sender="{sender_name}" sender_id="{sender_id}" location="{location}" time="{timestamp_str}">
|
|
120
|
+
<content>{text}</content>
|
|
121
|
+
</message>""")
|
|
122
|
+
|
|
123
|
+
if formatted:
|
|
124
|
+
return f"找到 {len(formatted)} 条消息:\n" + "\n---\n".join(formatted)
|
|
125
|
+
else:
|
|
126
|
+
return f"在 {start_time} 到 {end_time} 之间没有找到消息"
|
|
127
|
+
else:
|
|
128
|
+
return "获取消息回调未设置"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "get_picture",
|
|
5
|
+
"description": "获取指定数量的指定类型的图片并发送到群聊或指定私聊。支持白丝、黑丝、头像、JK、二次元、小姐姐、壁纸、原神、历史上的今天、4K图片、美腿十一种类型。二次元类型支持选择手机端或PC端。4K图片支持选择二次元或风景。默认获取二次元图片,默认使用PC端。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"message_type": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "消息类型",
|
|
12
|
+
"enum": ["group", "private"]
|
|
13
|
+
},
|
|
14
|
+
"target_id": {
|
|
15
|
+
"type": "integer",
|
|
16
|
+
"description": "目标 ID(群聊为群号,私聊为用户 QQ 号)"
|
|
17
|
+
},
|
|
18
|
+
"picture_type": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "图片类型",
|
|
21
|
+
"enum": ["baisi", "heisi", "head", "jk", "acg", "meinvpic", "wallpaper", "ys", "historypic", "random4kPic"],
|
|
22
|
+
"default": "acg"
|
|
23
|
+
},
|
|
24
|
+
"count": {
|
|
25
|
+
"type": "integer",
|
|
26
|
+
"description": "获取图片的数量",
|
|
27
|
+
"default": 1
|
|
28
|
+
},
|
|
29
|
+
"device": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "设备类型(仅 acg 类型支持)",
|
|
32
|
+
"enum": ["pc", "wap"],
|
|
33
|
+
"default": "pc"
|
|
34
|
+
},
|
|
35
|
+
"fourk_type": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "4K图片类型(仅 random4kPic 类型支持)",
|
|
38
|
+
"enum": ["acg", "wallpaper"],
|
|
39
|
+
"default": "acg"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"required": ["message_type", "target_id"]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import logging
|
|
3
|
+
import httpx
|
|
4
|
+
import asyncio
|
|
5
|
+
import uuid
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
# API 地址映射
|
|
11
|
+
API_URLS = {
|
|
12
|
+
"baisi": "https://v2.xxapi.cn/api/baisi",
|
|
13
|
+
"heisi": "https://v2.xxapi.cn/api/heisi",
|
|
14
|
+
"head": "https://v2.xxapi.cn/api/head",
|
|
15
|
+
"jk": "https://v2.xxapi.cn/api/jk",
|
|
16
|
+
"acg": "https://v2.xxapi.cn/api/randomAcgPic",
|
|
17
|
+
"meinvpic": "https://v2.xxapi.cn/api/meinvpic",
|
|
18
|
+
"wallpaper": "https://v2.xxapi.cn/api/wallpaper",
|
|
19
|
+
"ys": "https://v2.xxapi.cn/api/ys",
|
|
20
|
+
"historypic": "https://v2.xxapi.cn/api/historypic",
|
|
21
|
+
"random4kPic": "https://v2.xxapi.cn/api/random4kPic",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# 图片类型名称映射
|
|
25
|
+
TYPE_NAMES = {
|
|
26
|
+
"baisi": "白丝",
|
|
27
|
+
"heisi": "黑丝",
|
|
28
|
+
"head": "头像",
|
|
29
|
+
"jk": "JK",
|
|
30
|
+
"acg": "二次元",
|
|
31
|
+
"meinvpic": "小姐姐",
|
|
32
|
+
"wallpaper": "壁纸",
|
|
33
|
+
"ys": "原神",
|
|
34
|
+
"historypic": "历史上的今天",
|
|
35
|
+
"random4kPic": "4K图片",
|
|
36
|
+
"meitui": "美腿",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
40
|
+
message_type = args.get("message_type")
|
|
41
|
+
target_id = args.get("target_id")
|
|
42
|
+
picture_type = args.get("picture_type", "acg")
|
|
43
|
+
count = args.get("count", 1)
|
|
44
|
+
device = args.get("device", "pc")
|
|
45
|
+
fourk_type = args.get("fourk_type", "acg")
|
|
46
|
+
|
|
47
|
+
# 参数验证
|
|
48
|
+
if not message_type:
|
|
49
|
+
return "❌ 消息类型不能为空"
|
|
50
|
+
if message_type not in ["group", "private"]:
|
|
51
|
+
return "❌ 消息类型必须是 group(群聊)或 private(私聊)"
|
|
52
|
+
if not target_id:
|
|
53
|
+
return "❌ 目标 ID 不能为空"
|
|
54
|
+
if not isinstance(target_id, int):
|
|
55
|
+
return "❌ 目标 ID 必须是整数"
|
|
56
|
+
if picture_type not in API_URLS:
|
|
57
|
+
return f"❌ 不支持的图片类型: {picture_type}\n支持的类型: {', '.join(TYPE_NAMES.values())}"
|
|
58
|
+
if not isinstance(count, int):
|
|
59
|
+
return "❌ 图片数量必须是整数"
|
|
60
|
+
if count < 1 or count > 10:
|
|
61
|
+
return "❌ 图片数量必须在 1-10 之间"
|
|
62
|
+
if picture_type == "acg" and device not in ["pc", "wap"]:
|
|
63
|
+
return "❌ 设备类型必须是 pc(电脑端)或 wap(手机端)"
|
|
64
|
+
if picture_type == "random4kPic" and fourk_type not in ["acg", "wallpaper"]:
|
|
65
|
+
return "❌ 4K图片类型必须是 acg(二次元)或 wallpaper(风景)"
|
|
66
|
+
|
|
67
|
+
# 获取发送图片回调
|
|
68
|
+
send_image_callback = context.get("send_image_callback")
|
|
69
|
+
if not send_image_callback:
|
|
70
|
+
return "发送图片回调未设置"
|
|
71
|
+
|
|
72
|
+
# 构造请求参数
|
|
73
|
+
params: Dict[str, Any] = {"return": "json"}
|
|
74
|
+
if picture_type == "acg":
|
|
75
|
+
params["type"] = device
|
|
76
|
+
elif picture_type == "random4kPic":
|
|
77
|
+
params["type"] = fourk_type
|
|
78
|
+
|
|
79
|
+
# 获取图片
|
|
80
|
+
success_count = 0
|
|
81
|
+
fail_count = 0
|
|
82
|
+
local_image_paths: list[str] = []
|
|
83
|
+
|
|
84
|
+
# 创建图片保存目录
|
|
85
|
+
img_dir = Path.cwd() / "img"
|
|
86
|
+
img_dir.mkdir(exist_ok=True)
|
|
87
|
+
|
|
88
|
+
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
89
|
+
for i in range(count):
|
|
90
|
+
try:
|
|
91
|
+
logger.info(f"正在获取第 {i+1}/{count} 张 {TYPE_NAMES[picture_type]} 图片...")
|
|
92
|
+
response = await client.get(API_URLS[picture_type], params=params)
|
|
93
|
+
response.raise_for_status()
|
|
94
|
+
|
|
95
|
+
# 美腿类型直接返回 JPEG 图片,不需要解析 JSON
|
|
96
|
+
if picture_type == "meitui":
|
|
97
|
+
# 验证响应内容类型
|
|
98
|
+
content_type = response.headers.get("content-type", "")
|
|
99
|
+
if "image" not in content_type.lower():
|
|
100
|
+
logger.error(f"响应不是图片格式: {content_type}")
|
|
101
|
+
fail_count += 1
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
# 保存图片
|
|
105
|
+
filename = f"{picture_type}_{uuid.uuid4().hex[:16]}.jpg"
|
|
106
|
+
filepath = img_dir / filename
|
|
107
|
+
filepath.write_bytes(response.content)
|
|
108
|
+
|
|
109
|
+
logger.info(f"图片已保存到: {filepath}")
|
|
110
|
+
local_image_paths.append(str(filepath))
|
|
111
|
+
success_count += 1
|
|
112
|
+
else:
|
|
113
|
+
data = response.json()
|
|
114
|
+
|
|
115
|
+
# 检查响应
|
|
116
|
+
if data.get("code") != 200:
|
|
117
|
+
logger.error(f"获取图片失败: {data.get('msg')}")
|
|
118
|
+
fail_count += 1
|
|
119
|
+
continue
|
|
120
|
+
|
|
121
|
+
# 获取图片 URL
|
|
122
|
+
image_url = data.get("data")
|
|
123
|
+
if not image_url:
|
|
124
|
+
logger.error("响应中未找到图片 URL")
|
|
125
|
+
fail_count += 1
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
logger.info(f"图片 URL: {image_url}")
|
|
129
|
+
|
|
130
|
+
# 下载图片到本地
|
|
131
|
+
logger.info("正在下载图片到本地...")
|
|
132
|
+
image_response = await client.get(image_url, timeout=15.0)
|
|
133
|
+
image_response.raise_for_status()
|
|
134
|
+
|
|
135
|
+
# 保存图片
|
|
136
|
+
filename = f"{picture_type}_{uuid.uuid4().hex[:16]}.jpg"
|
|
137
|
+
filepath = img_dir / filename
|
|
138
|
+
filepath.write_bytes(image_response.content)
|
|
139
|
+
|
|
140
|
+
logger.info(f"图片已保存到: {filepath}")
|
|
141
|
+
local_image_paths.append(str(filepath))
|
|
142
|
+
success_count += 1
|
|
143
|
+
|
|
144
|
+
except httpx.TimeoutException:
|
|
145
|
+
logger.error(f"获取图片超时: {picture_type} 第 {i+1} 张")
|
|
146
|
+
fail_count += 1
|
|
147
|
+
except httpx.HTTPStatusError as e:
|
|
148
|
+
logger.error(f"HTTP 错误: {e}")
|
|
149
|
+
fail_count += 1
|
|
150
|
+
except Exception as e:
|
|
151
|
+
logger.exception(f"获取图片失败: {e}")
|
|
152
|
+
fail_count += 1
|
|
153
|
+
|
|
154
|
+
# 如果没有获取到任何图片
|
|
155
|
+
if success_count == 0:
|
|
156
|
+
return f"获取 {TYPE_NAMES[picture_type]} 图片失败,请稍后重试"
|
|
157
|
+
|
|
158
|
+
# 发送图片
|
|
159
|
+
for idx, image_path in enumerate(local_image_paths, 1):
|
|
160
|
+
try:
|
|
161
|
+
logger.info(f"正在发送第 {idx}/{success_count} 张图片到 {message_type} {target_id}")
|
|
162
|
+
logger.info(f"图片路径: {image_path}")
|
|
163
|
+
await send_image_callback(target_id, message_type, image_path)
|
|
164
|
+
logger.info(f"图片 {idx} 发送成功")
|
|
165
|
+
|
|
166
|
+
# 删除本地图片文件
|
|
167
|
+
try:
|
|
168
|
+
Path(image_path).unlink()
|
|
169
|
+
logger.info(f"已删除本地图片: {image_path}")
|
|
170
|
+
except Exception as e:
|
|
171
|
+
logger.warning(f"删除图片文件失败: {e}")
|
|
172
|
+
|
|
173
|
+
# 避免发送过快
|
|
174
|
+
await asyncio.sleep(0.5)
|
|
175
|
+
except Exception as e:
|
|
176
|
+
logger.exception(f"发送图片失败: {e}")
|
|
177
|
+
fail_count += 1
|
|
178
|
+
|
|
179
|
+
# 返回结果
|
|
180
|
+
device_text = f"({device}端)" if picture_type == "acg" else ""
|
|
181
|
+
fourk_text = f"({fourk_type})" if picture_type == "random4kPic" else ""
|
|
182
|
+
|
|
183
|
+
# 中文数字映射
|
|
184
|
+
cn_nums = {1: "一", 2: "二", 3: "三", 4: "四", 5: "五", 6: "六", 7: "七", 8: "八", 9: "九", 10: "十"}
|
|
185
|
+
success_cn = cn_nums.get(success_count, str(success_count))
|
|
186
|
+
fail_cn = cn_nums.get(fail_count, str(fail_count))
|
|
187
|
+
|
|
188
|
+
if fail_count == 0:
|
|
189
|
+
return f"✅ 已成功发送 {success_cn} 张 {TYPE_NAMES[picture_type]} 图片{device_text}{fourk_text}到 {message_type} {target_id}"
|
|
190
|
+
else:
|
|
191
|
+
return f"⚠️ 已发送 {success_cn} 张 {TYPE_NAMES[picture_type]} 图片{device_text}{fourk_text},失败 {fail_cn} 张"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "get_recent_messages",
|
|
5
|
+
"description": "获取指定聊天的历史消息。用于查看对话历史,了解上下文。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"chat_id": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "聊天ID(群号或QQ号)"
|
|
12
|
+
},
|
|
13
|
+
"type": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "聊天类型(group 或 private)",
|
|
16
|
+
"enum": ["group", "private"]
|
|
17
|
+
},
|
|
18
|
+
"start": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"description": "起始位置(从最新消息往前数),默认为 0(最新消息)"
|
|
21
|
+
},
|
|
22
|
+
"end": {
|
|
23
|
+
"type": "integer",
|
|
24
|
+
"description": "结束位置(从最新消息往前数),默认为 10"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"required": ["chat_id", "type"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _resolve_chat_id(chat_id: str, msg_type: str, history_manager: Any) -> str:
|
|
5
|
+
"""将群名/用户名转换为对应的 ID
|
|
6
|
+
|
|
7
|
+
参数:
|
|
8
|
+
chat_id: 群名、用户名或群号/用户ID
|
|
9
|
+
msg_type: "group" 或 "private"
|
|
10
|
+
history_manager: 历史记录管理器实例
|
|
11
|
+
|
|
12
|
+
返回:
|
|
13
|
+
解析后的群号或用户ID
|
|
14
|
+
"""
|
|
15
|
+
if chat_id.isdigit():
|
|
16
|
+
return chat_id
|
|
17
|
+
|
|
18
|
+
if not history_manager:
|
|
19
|
+
return chat_id
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
if msg_type == "group":
|
|
23
|
+
for group_id, messages in history_manager._message_history.items():
|
|
24
|
+
if messages and messages[0].get("chat_name") == chat_id:
|
|
25
|
+
return str(group_id)
|
|
26
|
+
elif msg_type == "private":
|
|
27
|
+
for user_id, messages in history_manager._private_message_history.items():
|
|
28
|
+
if messages and messages[0].get("chat_name") == chat_id:
|
|
29
|
+
return str(user_id)
|
|
30
|
+
except Exception:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
return chat_id
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
37
|
+
chat_id = args.get("chat_id")
|
|
38
|
+
msg_type = args.get("type")
|
|
39
|
+
start = args.get("start", 0)
|
|
40
|
+
end = args.get("end", 10)
|
|
41
|
+
|
|
42
|
+
if not chat_id or not msg_type:
|
|
43
|
+
return "chat_id 和 type 参数不能为空"
|
|
44
|
+
|
|
45
|
+
if start is None or not isinstance(start, int) or start < 0:
|
|
46
|
+
start = 0
|
|
47
|
+
if end is None or not isinstance(end, int) or end < 0:
|
|
48
|
+
end = 10
|
|
49
|
+
|
|
50
|
+
get_recent_messages_callback = context.get("get_recent_messages_callback")
|
|
51
|
+
history_manager = context.get("history_manager")
|
|
52
|
+
|
|
53
|
+
resolved_chat_id = _resolve_chat_id(chat_id, msg_type, history_manager)
|
|
54
|
+
|
|
55
|
+
messages = []
|
|
56
|
+
if history_manager:
|
|
57
|
+
messages = history_manager.get_recent(resolved_chat_id, msg_type, start, end)
|
|
58
|
+
elif get_recent_messages_callback:
|
|
59
|
+
messages = await get_recent_messages_callback(
|
|
60
|
+
resolved_chat_id, msg_type, start, end
|
|
61
|
+
)
|
|
62
|
+
else:
|
|
63
|
+
return "获取消息回调未设置"
|
|
64
|
+
|
|
65
|
+
if messages is not None:
|
|
66
|
+
formatted = []
|
|
67
|
+
for msg in messages:
|
|
68
|
+
msg_type_val = msg.get("type", "group")
|
|
69
|
+
sender_name = msg.get("display_name", "未知用户")
|
|
70
|
+
sender_id = msg.get("user_id", "")
|
|
71
|
+
chat_name = msg.get("chat_name", "未知群聊")
|
|
72
|
+
timestamp = msg.get("timestamp", "")
|
|
73
|
+
text = msg.get("message", "")
|
|
74
|
+
|
|
75
|
+
if msg_type_val == "group":
|
|
76
|
+
# 确保群名以"群"结尾
|
|
77
|
+
location = chat_name if chat_name.endswith("群") else f"{chat_name}群"
|
|
78
|
+
else:
|
|
79
|
+
location = "私聊"
|
|
80
|
+
|
|
81
|
+
# 格式:XML 标准化
|
|
82
|
+
formatted.append(f"""<message sender="{sender_name}" sender_id="{sender_id}" location="{location}" time="{timestamp}">
|
|
83
|
+
<content>{text}</content>
|
|
84
|
+
</message>""")
|
|
85
|
+
|
|
86
|
+
return "\n---\n".join(formatted) if formatted else "没有找到最近的消息"
|
|
87
|
+
else:
|
|
88
|
+
return "获取消息失败"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "qq_like",
|
|
5
|
+
"description": "给指定QQ号的资料卡点赞。当有人说类似这种:赞我,给我点赞之类的可以积极进行调用。完成后记得发信息说明并让ta给你点赞!(比如:赞了~记得回赞~)",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"target_user_id": {
|
|
10
|
+
"type": "integer",
|
|
11
|
+
"description": "要点赞的目标QQ号"
|
|
12
|
+
},
|
|
13
|
+
"times": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"description": "点赞次数(默认10次)",
|
|
16
|
+
"default": 10
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": ["target_user_id"]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
logger = logging.getLogger(__name__)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
8
|
+
"""给指定QQ号点赞
|
|
9
|
+
|
|
10
|
+
参数:
|
|
11
|
+
args: 工具参数,包含 target_user_id 和可选的 times
|
|
12
|
+
context: 工具上下文,包含 send_like_callback 等回调函数
|
|
13
|
+
|
|
14
|
+
返回:
|
|
15
|
+
操作结果描述
|
|
16
|
+
"""
|
|
17
|
+
target_user_id = args.get("target_user_id")
|
|
18
|
+
times = args.get("times", 1)
|
|
19
|
+
|
|
20
|
+
if target_user_id is None:
|
|
21
|
+
return "请提供要点赞的目标QQ号(target_user_id参数)"
|
|
22
|
+
|
|
23
|
+
# 验证参数类型
|
|
24
|
+
try:
|
|
25
|
+
target_user_id = int(target_user_id)
|
|
26
|
+
times = int(times)
|
|
27
|
+
except (ValueError, TypeError):
|
|
28
|
+
return "参数类型错误:target_user_id和times必须是整数"
|
|
29
|
+
|
|
30
|
+
if times < 1:
|
|
31
|
+
return "点赞次数必须大于0"
|
|
32
|
+
if times > 10: # 限制最大点赞次数,避免滥用
|
|
33
|
+
return "单次点赞次数不能超过10次"
|
|
34
|
+
|
|
35
|
+
send_like_callback = context.get("send_like_callback")
|
|
36
|
+
if not send_like_callback:
|
|
37
|
+
return "点赞功能不可用(回调函数未设置)"
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
# 调用点赞回调
|
|
41
|
+
await send_like_callback(target_user_id, times)
|
|
42
|
+
|
|
43
|
+
if times == 1:
|
|
44
|
+
return f"✅ 已给 QQ{target_user_id} 点赞。"
|
|
45
|
+
else:
|
|
46
|
+
return f"✅ 已给 QQ{target_user_id} 点赞 {times} 次。"
|
|
47
|
+
|
|
48
|
+
except Exception as e:
|
|
49
|
+
logger.exception(f"点赞失败: {e}")
|
|
50
|
+
error_msg = str(e)
|
|
51
|
+
|
|
52
|
+
# 根据错误消息提供更友好的提示
|
|
53
|
+
if "SVIP 上限" in error_msg:
|
|
54
|
+
return "点赞失败:今日给同一好友的点赞数已达SVIP上限"
|
|
55
|
+
elif "点赞失败" in error_msg:
|
|
56
|
+
return f"点赞失败:{error_msg}"
|
|
57
|
+
else:
|
|
58
|
+
return f"点赞失败:{error_msg}"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "render_html",
|
|
5
|
+
"description": "将 HTML 内容渲染为图片并发送到指定目标(群聊或私聊)。支持完整的 HTML 文档,包括内联 CSS 和样式。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"html_content": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "要渲染的 HTML 内容。必须是完整的 HTML 文档(包含 <!DOCTYPE html>、<html>、<head>、<body> 标签)。"
|
|
12
|
+
},
|
|
13
|
+
"target_id": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"description": "目标 ID(群号或用户 QQ 号)"
|
|
16
|
+
},
|
|
17
|
+
"message_type": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "消息类型",
|
|
20
|
+
"enum": ["group", "private"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"required": ["html_content", "target_id", "message_type"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import logging
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import uuid
|
|
5
|
+
from Undefined.render import render_html_to_image
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
10
|
+
html_content = args.get("html_content", "")
|
|
11
|
+
target_id = args.get("target_id")
|
|
12
|
+
message_type = args.get("message_type")
|
|
13
|
+
|
|
14
|
+
if not html_content:
|
|
15
|
+
return "HTML 内容不能为空"
|
|
16
|
+
if not target_id:
|
|
17
|
+
return "目标 ID 不能为空"
|
|
18
|
+
if not message_type:
|
|
19
|
+
return "消息类型不能为空"
|
|
20
|
+
if message_type not in ["group", "private"]:
|
|
21
|
+
return "消息类型必须是 group 或 private"
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
filename = f"render_{uuid.uuid4().hex[:16]}.png"
|
|
25
|
+
filepath = Path.cwd() / "img" / filename
|
|
26
|
+
filepath.parent.mkdir(exist_ok=True)
|
|
27
|
+
|
|
28
|
+
await render_html_to_image(html_content, str(filepath))
|
|
29
|
+
|
|
30
|
+
send_image_callback = context.get("send_image_callback")
|
|
31
|
+
if send_image_callback:
|
|
32
|
+
await send_image_callback(target_id, message_type, str(filepath))
|
|
33
|
+
return f"HTML 图片已渲染并发送到 {message_type} {target_id}"
|
|
34
|
+
else:
|
|
35
|
+
return "发送图片回调未设置"
|
|
36
|
+
|
|
37
|
+
except Exception as e:
|
|
38
|
+
logger.exception(f"HTML 渲染并发送图片失败: {e}")
|
|
39
|
+
return f"HTML 渲染失败: {e}"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "render_latex",
|
|
5
|
+
"description": "将 LaTeX 文本渲染为图片并发送到指定目标(群聊或私聊)。支持完整的 LaTeX 语法(包含 \\begin 和 \\end)。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"content": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "要渲染的 LaTeX 内容。必须是完整格式(包含 \\begin 和 \\end)。"
|
|
12
|
+
},
|
|
13
|
+
"target_id": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"description": "目标 ID(群号或用户 QQ 号)"
|
|
16
|
+
},
|
|
17
|
+
"message_type": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "消息类型",
|
|
20
|
+
"enum": ["group", "private"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"required": ["content", "target_id", "message_type"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|