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,220 @@
|
|
|
1
|
+
from typing import Any, Dict, Callable
|
|
2
|
+
import importlib.util
|
|
3
|
+
import json
|
|
4
|
+
import asyncio
|
|
5
|
+
import aiofiles
|
|
6
|
+
import logging
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AgentToolRegistry:
|
|
13
|
+
"""Agent 内部的工具注册表"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, tools_dir: Path) -> None:
|
|
16
|
+
self.tools_dir: Path = (
|
|
17
|
+
tools_dir if isinstance(tools_dir, Path) else Path(tools_dir)
|
|
18
|
+
)
|
|
19
|
+
self._tools_schema: list[dict[str, Any]] = []
|
|
20
|
+
self._tools_handlers: dict[str, Callable[..., Any]] = {}
|
|
21
|
+
self.load_tools()
|
|
22
|
+
|
|
23
|
+
def load_tools(self) -> None:
|
|
24
|
+
"""加载 agent 专属工具"""
|
|
25
|
+
if not self.tools_dir.exists():
|
|
26
|
+
logger.warning(f"Agent 工具目录不存在: {self.tools_dir}")
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
for item in self.tools_dir.iterdir():
|
|
30
|
+
if item.is_dir() and not item.name.startswith("_"):
|
|
31
|
+
self._load_tool_from_dir(item)
|
|
32
|
+
|
|
33
|
+
logger.info(
|
|
34
|
+
f"Agent 加载了 {len(self._tools_schema)} 个工具: {list(self._tools_handlers.keys())}"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def _load_tool_from_dir(self, tool_dir: Path) -> None:
|
|
38
|
+
"""从目录加载工具"""
|
|
39
|
+
config_path: Path = tool_dir / "config.json"
|
|
40
|
+
handler_path: Path = tool_dir / "handler.py"
|
|
41
|
+
|
|
42
|
+
if not config_path.exists() or not handler_path.exists():
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
47
|
+
config: dict[str, Any] = json.load(f)
|
|
48
|
+
|
|
49
|
+
if "function" not in config or "name" not in config.get("function", {}):
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
tool_name: str = config["function"]["name"]
|
|
53
|
+
|
|
54
|
+
spec = importlib.util.spec_from_file_location(
|
|
55
|
+
f"agent_tools.{tool_name}", handler_path
|
|
56
|
+
)
|
|
57
|
+
if spec is None or spec.loader is None:
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
module = importlib.util.module_from_spec(spec)
|
|
61
|
+
spec.loader.exec_module(module)
|
|
62
|
+
|
|
63
|
+
if not hasattr(module, "execute"):
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
self._tools_schema.append(config)
|
|
67
|
+
self._tools_handlers[tool_name] = module.execute
|
|
68
|
+
|
|
69
|
+
except Exception as e:
|
|
70
|
+
logger.error(f"从 {tool_dir} 加载工具失败: {e}")
|
|
71
|
+
|
|
72
|
+
def get_tools_schema(self) -> list[dict[str, Any]]:
|
|
73
|
+
"""获取工具 schema"""
|
|
74
|
+
return self._tools_schema
|
|
75
|
+
|
|
76
|
+
async def execute_tool(
|
|
77
|
+
self, tool_name: str, args: dict[str, Any], context: dict[str, Any]
|
|
78
|
+
) -> str:
|
|
79
|
+
"""执行工具"""
|
|
80
|
+
handler = self._tools_handlers.get(tool_name)
|
|
81
|
+
if not handler:
|
|
82
|
+
return f"未找到工具: {tool_name}"
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
if asyncio.iscoroutinefunction(handler):
|
|
86
|
+
result = await handler(args, context)
|
|
87
|
+
else:
|
|
88
|
+
result = handler(args, context)
|
|
89
|
+
return str(result)
|
|
90
|
+
except Exception as e:
|
|
91
|
+
logger.exception(f"执行工具 {tool_name} 时出错")
|
|
92
|
+
return f"执行工具 {tool_name} 时出错: {str(e)}"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
async def _load_prompt() -> str:
|
|
96
|
+
"""从 prompt.md 文件加载系统提示词"""
|
|
97
|
+
prompt_path: Path = Path(__file__).parent / "prompt.md"
|
|
98
|
+
if prompt_path.exists():
|
|
99
|
+
async with aiofiles.open(prompt_path, "r", encoding="utf-8") as f:
|
|
100
|
+
return await f.read()
|
|
101
|
+
return _get_default_prompt()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _get_default_prompt() -> str:
|
|
105
|
+
"""默认提示词"""
|
|
106
|
+
return "你是一个社交媒体助手..."
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
110
|
+
"""执行 social_agent"""
|
|
111
|
+
user_prompt: str = args.get("prompt", "")
|
|
112
|
+
|
|
113
|
+
if not user_prompt:
|
|
114
|
+
return "请提供您的搜索需求"
|
|
115
|
+
|
|
116
|
+
agent_tools_dir: Path = Path(__file__).parent / "tools"
|
|
117
|
+
tool_registry = AgentToolRegistry(agent_tools_dir)
|
|
118
|
+
|
|
119
|
+
tools: list[dict[str, Any]] = tool_registry.get_tools_schema()
|
|
120
|
+
|
|
121
|
+
ai_client = context.get("ai_client")
|
|
122
|
+
if not ai_client:
|
|
123
|
+
return "AI client 未在上下文中提供"
|
|
124
|
+
|
|
125
|
+
agent_config = ai_client.agent_config
|
|
126
|
+
|
|
127
|
+
system_prompt: str = await _load_prompt()
|
|
128
|
+
|
|
129
|
+
messages: list[dict[str, Any]] = [
|
|
130
|
+
{"role": "system", "content": system_prompt},
|
|
131
|
+
{"role": "user", "content": f"用户需求:{user_prompt}"},
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
max_iterations: int = 20
|
|
135
|
+
iteration: int = 0
|
|
136
|
+
|
|
137
|
+
while iteration < max_iterations:
|
|
138
|
+
iteration += 1
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
response = await ai_client._http_client.post(
|
|
142
|
+
agent_config.api_url,
|
|
143
|
+
headers={
|
|
144
|
+
"Authorization": f"Bearer {agent_config.api_key}",
|
|
145
|
+
"Content-Type": "application/json",
|
|
146
|
+
},
|
|
147
|
+
json=ai_client._build_request_body(
|
|
148
|
+
model_config=agent_config,
|
|
149
|
+
messages=messages,
|
|
150
|
+
max_tokens=agent_config.max_tokens,
|
|
151
|
+
tools=tools if tools else None,
|
|
152
|
+
tool_choice="auto",
|
|
153
|
+
),
|
|
154
|
+
)
|
|
155
|
+
response.raise_for_status()
|
|
156
|
+
result: dict[str, Any] = response.json()
|
|
157
|
+
|
|
158
|
+
choice: dict[str, Any] = result.get("choices", [{}])[0]
|
|
159
|
+
message: dict[str, Any] = choice.get("message", {})
|
|
160
|
+
content: str = message.get("content") or ""
|
|
161
|
+
tool_calls: list[dict[str, Any]] = message.get("tool_calls", [])
|
|
162
|
+
|
|
163
|
+
if content.strip() and tool_calls:
|
|
164
|
+
content = ""
|
|
165
|
+
|
|
166
|
+
if not tool_calls:
|
|
167
|
+
return content
|
|
168
|
+
|
|
169
|
+
messages.append(
|
|
170
|
+
{"role": "assistant", "content": content, "tool_calls": tool_calls}
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# 准备并发执行工具
|
|
174
|
+
tool_tasks = []
|
|
175
|
+
tool_call_ids = []
|
|
176
|
+
|
|
177
|
+
for tool_call in tool_calls:
|
|
178
|
+
call_id: str = tool_call.get("id", "")
|
|
179
|
+
function: dict[str, Any] = tool_call.get("function", {})
|
|
180
|
+
function_name: str = function.get("name", "")
|
|
181
|
+
function_args_str: str = function.get("arguments", "{}")
|
|
182
|
+
|
|
183
|
+
logger.info(f"Agent 正在准备工具: {function_name}")
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
function_args: dict[str, Any] = json.loads(function_args_str)
|
|
187
|
+
except json.JSONDecodeError:
|
|
188
|
+
function_args = {}
|
|
189
|
+
|
|
190
|
+
tool_call_ids.append(call_id)
|
|
191
|
+
tool_tasks.append(
|
|
192
|
+
tool_registry.execute_tool(function_name, function_args, context)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# 并发执行
|
|
196
|
+
if tool_tasks:
|
|
197
|
+
logger.info(f"Agent 正在并发执行 {len(tool_tasks)} 个工具")
|
|
198
|
+
results = await asyncio.gather(*tool_tasks, return_exceptions=True)
|
|
199
|
+
|
|
200
|
+
for i, tool_result in enumerate(results):
|
|
201
|
+
call_id = tool_call_ids[i]
|
|
202
|
+
content_str: str = ""
|
|
203
|
+
if isinstance(tool_result, Exception):
|
|
204
|
+
content_str = f"错误: {str(tool_result)}"
|
|
205
|
+
else:
|
|
206
|
+
content_str = str(tool_result)
|
|
207
|
+
|
|
208
|
+
messages.append(
|
|
209
|
+
{
|
|
210
|
+
"role": "tool",
|
|
211
|
+
"tool_call_id": call_id,
|
|
212
|
+
"content": content_str,
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
except Exception as e:
|
|
217
|
+
logger.exception(f"Agent 执行失败: {e}")
|
|
218
|
+
return f"处理失败: {e}"
|
|
219
|
+
|
|
220
|
+
return "达到最大迭代次数"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# 社交媒体助手
|
|
2
|
+
|
|
3
|
+
## 能力
|
|
4
|
+
- **Bilibili 服务**:搜索视频、番剧、UP主,查询用户详细信息
|
|
5
|
+
- **音乐服务**:全网搜索音乐,获取歌曲详情及歌词
|
|
6
|
+
- **视频推荐**:随机获取视频推荐内容
|
|
7
|
+
|
|
8
|
+
## 适用场景
|
|
9
|
+
- 用户想找 B 站视频或用户信息时
|
|
10
|
+
- 用户想听歌、找歌词或了解歌曲信息时
|
|
11
|
+
- 用户无聊想要随机视频推荐时
|
|
12
|
+
|
|
13
|
+
## 参数说明
|
|
14
|
+
- `keyword` (搜索): 搜索关键词
|
|
15
|
+
- `buid` (B站): B站用户 UID
|
|
16
|
+
- `music_name` (音乐): 歌曲名称
|
|
17
|
+
- `index` (通用): 结果序号选择
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
你是一个社交媒体助手,专门帮助用户搜索和获取社交媒体内容。
|
|
2
|
+
|
|
3
|
+
你的任务是根据用户需求,选择合适的工具来完成任务:
|
|
4
|
+
|
|
5
|
+
1. **搜索 B 站视频/番剧/用户** → bilibili_search
|
|
6
|
+
2. **获取 B 站用户详情** → bilibili_user_info
|
|
7
|
+
3. **搜索音乐** → music_global_search
|
|
8
|
+
4. **获取音乐详情** → music_info_get
|
|
9
|
+
5. **获取歌词** → music_lyrics
|
|
10
|
+
6. **获取随机视频推荐** → video_random_recommend
|
|
11
|
+
|
|
12
|
+
注意事项:
|
|
13
|
+
- 搜索结果可能较多,建议用户指定更精确的需求
|
|
14
|
+
- 音乐搜索支持按序号选择具体歌曲
|
|
15
|
+
- 保持回答简洁,突出关键信息
|
|
16
|
+
|
|
17
|
+
如果用户需求不明确,请先询问用户澄清问题。
|
|
18
|
+
|
|
19
|
+
如果问题涉及时间,立刻调用时间工具获取。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Social Agent Tools
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "bilibili_search",
|
|
5
|
+
"description": "搜索 Bilibili 视频、番剧、用户等。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"msg": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "搜索内容"
|
|
12
|
+
},
|
|
13
|
+
"n": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"description": "返回数据数量 (默认5)"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"required": ["msg"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import httpx
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
9
|
+
msg = args.get("msg")
|
|
10
|
+
n = args.get("n", 5)
|
|
11
|
+
|
|
12
|
+
url = "https://api.xingzhige.com/API/b_search/"
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
async with httpx.AsyncClient(timeout=15.0) as client:
|
|
16
|
+
response = await client.get(url, params={"msg": msg, "n": n})
|
|
17
|
+
response.raise_for_status()
|
|
18
|
+
data = response.json()
|
|
19
|
+
|
|
20
|
+
# API 返回一个以 0, 1, 2... 为键的字典来表示列表?
|
|
21
|
+
# 或者是一个字典列表?
|
|
22
|
+
# 根据 'n',它可能返回一个列表或字典索引。
|
|
23
|
+
# 让我们同时处理这两种情况。
|
|
24
|
+
|
|
25
|
+
results = []
|
|
26
|
+
if isinstance(data, list):
|
|
27
|
+
results = data
|
|
28
|
+
elif isinstance(data, dict):
|
|
29
|
+
# 检查是否为索引键 "0", "1" 等。
|
|
30
|
+
if "0" in data:
|
|
31
|
+
for i in range(len(data)):
|
|
32
|
+
key = str(i)
|
|
33
|
+
if key in data:
|
|
34
|
+
results.append(data[key])
|
|
35
|
+
elif "code" in data and data["code"] != 200:
|
|
36
|
+
return f"搜索失败: {data.get('msg', '未知错误')}"
|
|
37
|
+
else:
|
|
38
|
+
# 单个结果或非预期格式
|
|
39
|
+
results = [data]
|
|
40
|
+
|
|
41
|
+
output = f"🔍 B站搜索 '{msg}' 结果:\n"
|
|
42
|
+
for item in results:
|
|
43
|
+
title = item.get("title")
|
|
44
|
+
linktype = item.get("linktype")
|
|
45
|
+
name = item.get("name")
|
|
46
|
+
bvid = item.get("bvid")
|
|
47
|
+
|
|
48
|
+
item_str = ""
|
|
49
|
+
if linktype and title:
|
|
50
|
+
item_str += f"- [{linktype}] {title}\n"
|
|
51
|
+
elif title:
|
|
52
|
+
item_str += f"- {title}\n"
|
|
53
|
+
|
|
54
|
+
if name:
|
|
55
|
+
item_str += f" UP主: {name}\n"
|
|
56
|
+
|
|
57
|
+
if bvid:
|
|
58
|
+
url_link = f"https://www.bilibili.com/video/{bvid}"
|
|
59
|
+
item_str += f" 链接: {url_link}\n"
|
|
60
|
+
|
|
61
|
+
if item_str:
|
|
62
|
+
output += item_str + "\n"
|
|
63
|
+
|
|
64
|
+
return output
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.exception(f"B站搜索失败: {e}")
|
|
68
|
+
return f"B站搜索失败: {e}"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "bilibili_user_info",
|
|
5
|
+
"description": "查询 Bilibili 用户信息。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"mid": {
|
|
10
|
+
"type": "integer",
|
|
11
|
+
"description": "用户 UID (mid)"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": ["mid"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import httpx
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
9
|
+
mid = args.get("mid")
|
|
10
|
+
url = "https://api.xingzhige.com/API/b_personal/"
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
async with httpx.AsyncClient(timeout=15.0) as client:
|
|
14
|
+
response = await client.get(url, params={"mid": mid})
|
|
15
|
+
response.raise_for_status()
|
|
16
|
+
data = response.json()
|
|
17
|
+
|
|
18
|
+
if isinstance(data, dict):
|
|
19
|
+
if "code" in data and data["code"] != 0 and data["code"] != 200:
|
|
20
|
+
# 某些 API 返回 code 0 表示成功,其他返回 200。
|
|
21
|
+
# 但是检查是否有错误信息。
|
|
22
|
+
if "message" in data:
|
|
23
|
+
# 可能是一个错误
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
name = data.get("name")
|
|
27
|
+
level = data.get("level")
|
|
28
|
+
sex = data.get("sex")
|
|
29
|
+
desc = data.get("desc")
|
|
30
|
+
follower = data.get("follower")
|
|
31
|
+
following = data.get("following")
|
|
32
|
+
roomid = data.get("roomid")
|
|
33
|
+
face = data.get("face")
|
|
34
|
+
|
|
35
|
+
output_lines = []
|
|
36
|
+
|
|
37
|
+
header = "📺 B站用户"
|
|
38
|
+
if name:
|
|
39
|
+
header += f": {name}"
|
|
40
|
+
if data.get("mid"):
|
|
41
|
+
header += f" (UID: {data.get('mid')})"
|
|
42
|
+
output_lines.append(header)
|
|
43
|
+
|
|
44
|
+
if level is not None:
|
|
45
|
+
output_lines.append(f"🆙 等级: Lv{level}")
|
|
46
|
+
|
|
47
|
+
if sex:
|
|
48
|
+
output_lines.append(f"⚧ 性别: {sex}")
|
|
49
|
+
|
|
50
|
+
if desc:
|
|
51
|
+
output_lines.append(f"📝 简介: {desc}")
|
|
52
|
+
|
|
53
|
+
if follower is not None and following is not None:
|
|
54
|
+
output_lines.append(f"👥 粉丝: {follower} | 关注: {following}")
|
|
55
|
+
|
|
56
|
+
if roomid:
|
|
57
|
+
output_lines.append(f"🎥 直播间: {roomid}")
|
|
58
|
+
|
|
59
|
+
if face:
|
|
60
|
+
output_lines.append(f"🖼️ 头像: {face}")
|
|
61
|
+
|
|
62
|
+
return "\n".join(output_lines)
|
|
63
|
+
|
|
64
|
+
return str(data)
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.exception(f"B站用户查询失败: {e}")
|
|
68
|
+
return f"B站用户查询失败: {e}"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "music_global_search",
|
|
5
|
+
"description": "全网音乐搜索。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"msg": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "歌曲名称"
|
|
12
|
+
},
|
|
13
|
+
"n": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"description": "序号 (可选)"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"required": ["msg"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import httpx
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
8
|
+
msg = args.get("msg")
|
|
9
|
+
n = args.get("n", 1)
|
|
10
|
+
|
|
11
|
+
url = "https://api.jkyai.top/API/qsyyjs.php"
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
async with httpx.AsyncClient(timeout=15.0) as client:
|
|
15
|
+
response = await client.get(url, params={"msg": msg, "n": n, "type": "json"})
|
|
16
|
+
response.raise_for_status()
|
|
17
|
+
data = response.json()
|
|
18
|
+
|
|
19
|
+
if isinstance(data, dict):
|
|
20
|
+
output_lines = []
|
|
21
|
+
|
|
22
|
+
title = data.get("title")
|
|
23
|
+
if title:
|
|
24
|
+
output_lines.append(f"🎵 音乐搜索: {title}")
|
|
25
|
+
|
|
26
|
+
singer = data.get("singer")
|
|
27
|
+
if singer:
|
|
28
|
+
output_lines.append(f"👤 歌手: {singer}")
|
|
29
|
+
|
|
30
|
+
music_url = data.get("music")
|
|
31
|
+
if music_url:
|
|
32
|
+
output_lines.append(f"🔗 链接: {music_url}")
|
|
33
|
+
|
|
34
|
+
cover = data.get("cover")
|
|
35
|
+
if cover:
|
|
36
|
+
output_lines.append(f"🖼️ 封面: {cover}")
|
|
37
|
+
|
|
38
|
+
if output_lines:
|
|
39
|
+
return "\n".join(output_lines)
|
|
40
|
+
else:
|
|
41
|
+
return "未找到相关音乐信息。"
|
|
42
|
+
|
|
43
|
+
return str(data)
|
|
44
|
+
|
|
45
|
+
except Exception as e:
|
|
46
|
+
logger.exception(f"音乐搜索失败: {e}")
|
|
47
|
+
return f"音乐搜索失败: {e}"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "music_info_get",
|
|
5
|
+
"description": "获取音乐详细信息 (通过 ID)。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"id": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "歌曲 ID"
|
|
12
|
+
},
|
|
13
|
+
"type": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "音乐平台 (wy, qq, kw, mg, qi)",
|
|
16
|
+
"enum": ["wy", "qq", "kw", "mg", "qi"]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": ["id", "type"]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import httpx
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
9
|
+
song_id = args.get("id")
|
|
10
|
+
platform = args.get("type")
|
|
11
|
+
|
|
12
|
+
url = "https://api.jkyai.top/API/yyjhss.php"
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
async with httpx.AsyncClient(timeout=15.0) as client:
|
|
16
|
+
response = await client.get(url, params={"id": song_id, "type": platform})
|
|
17
|
+
response.raise_for_status()
|
|
18
|
+
data = response.json()
|
|
19
|
+
|
|
20
|
+
# 数据结构: code, msg, data{name, artist, url, ...}
|
|
21
|
+
if data.get("code") == 1:
|
|
22
|
+
info = data.get("data", {})
|
|
23
|
+
return (
|
|
24
|
+
f"🎵 歌曲信息: {info.get('name')}\n"
|
|
25
|
+
f"👤 歌手: {info.get('artist')}\n"
|
|
26
|
+
f"💿 专辑: {info.get('album')}\n"
|
|
27
|
+
f"🔗 链接: {info.get('url')}\n"
|
|
28
|
+
f"🖼️ 图片: {info.get('pic')}"
|
|
29
|
+
)
|
|
30
|
+
else:
|
|
31
|
+
return f"获取失败: {data.get('msg')}"
|
|
32
|
+
|
|
33
|
+
except Exception as e:
|
|
34
|
+
logger.exception(f"获取歌曲详情失败: {e}")
|
|
35
|
+
return f"获取歌曲详情失败: {e}"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "music_lyrics",
|
|
5
|
+
"description": "获取歌曲歌词。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"id": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "歌曲 ID"
|
|
12
|
+
},
|
|
13
|
+
"msg": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "音乐平台 (qq, wy, kw, qi)",
|
|
16
|
+
"enum": ["qq", "wy", "kw", "qi"]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": ["id", "msg"]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import httpx
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
|
|
9
|
+
song_id = args.get("id")
|
|
10
|
+
platform = args.get("msg")
|
|
11
|
+
|
|
12
|
+
url = "https://api.jkyai.top/API/jhlrcgc.php"
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
async with httpx.AsyncClient(timeout=15.0) as client:
|
|
16
|
+
response = await client.get(
|
|
17
|
+
url, params={"id": song_id, "msg": platform, "type": "text"}
|
|
18
|
+
)
|
|
19
|
+
# API 文档说明 type 是可选的,默认为 text。
|
|
20
|
+
# 如果是 text,它可能直接返回歌词。
|
|
21
|
+
|
|
22
|
+
return f"🎵 歌词内容:\n{response.text}"
|
|
23
|
+
|
|
24
|
+
except Exception as e:
|
|
25
|
+
logger.exception(f"获取歌词失败: {e}")
|
|
26
|
+
return f"获取歌词失败: {e}"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "video_random_recommend",
|
|
5
|
+
"description": "获取随机视频推荐(返回视频链接)。",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"target_id": {
|
|
10
|
+
"type": "integer",
|
|
11
|
+
"description": "目标 ID (用于日志记录)"
|
|
12
|
+
},
|
|
13
|
+
"message_type": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "消息类型 (group 或 private)"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"required": []
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|