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,131 @@
|
|
|
1
|
+
"""注入攻击回复生成器
|
|
2
|
+
|
|
3
|
+
用于根据 undefined 人设生成简短的嘲讽性回复
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
import httpx
|
|
8
|
+
from typing import Any
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from .config import SecurityModelConfig
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
# 加载系统提示词
|
|
16
|
+
PROMPT_PATH = Path("res/prompts/injection_response_agent.txt")
|
|
17
|
+
try:
|
|
18
|
+
INJECTION_RESPONSE_SYSTEM_PROMPT = PROMPT_PATH.read_text(encoding="utf-8")
|
|
19
|
+
except Exception as e:
|
|
20
|
+
logger.error(f"加载注入回复提示词失败: {e}")
|
|
21
|
+
INJECTION_RESPONSE_SYSTEM_PROMPT = "你是一个充满敌意的、说话带刺的 AI 助手。"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class InjectionResponseAgent:
|
|
25
|
+
"""注入攻击回复生成器"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, security_config: SecurityModelConfig) -> None:
|
|
28
|
+
"""初始化回复生成器
|
|
29
|
+
|
|
30
|
+
参数:
|
|
31
|
+
security_config: 安全模型配置
|
|
32
|
+
"""
|
|
33
|
+
self.security_config = security_config
|
|
34
|
+
self._http_client = httpx.AsyncClient(timeout=120.0)
|
|
35
|
+
|
|
36
|
+
async def generate_response(self, user_message: str) -> str:
|
|
37
|
+
"""生成嘲讽性回复
|
|
38
|
+
|
|
39
|
+
参数:
|
|
40
|
+
user_message: 用户的原始消息
|
|
41
|
+
|
|
42
|
+
返回:
|
|
43
|
+
生成的嘲讽性回复
|
|
44
|
+
"""
|
|
45
|
+
try:
|
|
46
|
+
# 构造请求
|
|
47
|
+
request_body = self._build_request_body(
|
|
48
|
+
messages=[
|
|
49
|
+
{"role": "system", "content": INJECTION_RESPONSE_SYSTEM_PROMPT},
|
|
50
|
+
{
|
|
51
|
+
"role": "user",
|
|
52
|
+
"content": f"<user_message>{user_message}</user_message>",
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
max_tokens=self.security_config.max_tokens,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
response = await self._http_client.post(
|
|
59
|
+
self.security_config.api_url,
|
|
60
|
+
headers={
|
|
61
|
+
"Authorization": f"Bearer {self.security_config.api_key}",
|
|
62
|
+
"Content-Type": "application/json",
|
|
63
|
+
},
|
|
64
|
+
json=request_body,
|
|
65
|
+
)
|
|
66
|
+
response.raise_for_status()
|
|
67
|
+
result = response.json()
|
|
68
|
+
content = self._extract_choices_content(result).strip()
|
|
69
|
+
|
|
70
|
+
# 去除所有换行符,确保 XML 格式正确
|
|
71
|
+
content = content.replace("\n", " ").replace("\r", " ")
|
|
72
|
+
# 去除多余空格
|
|
73
|
+
content = " ".join(content.split())
|
|
74
|
+
|
|
75
|
+
logger.debug(f"生成的嘲讽回复: {content}")
|
|
76
|
+
|
|
77
|
+
return content if content else "无聊。"
|
|
78
|
+
except Exception as e:
|
|
79
|
+
logger.exception(f"生成嘲讽回复失败: {e}")
|
|
80
|
+
# 失败时返回默认回复
|
|
81
|
+
return "有病?"
|
|
82
|
+
|
|
83
|
+
def _build_request_body(
|
|
84
|
+
self,
|
|
85
|
+
messages: list[dict[str, str]],
|
|
86
|
+
max_tokens: int,
|
|
87
|
+
) -> dict[str, Any]:
|
|
88
|
+
"""构建请求体"""
|
|
89
|
+
body: dict[str, Any] = {
|
|
90
|
+
"model": self.security_config.model_name,
|
|
91
|
+
"messages": messages,
|
|
92
|
+
"max_tokens": max_tokens,
|
|
93
|
+
"temperature": 0.7, # 稍微高一点的温度,让回复更有变化
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# 添加 thinking 参数(如果启用)
|
|
97
|
+
if self.security_config.thinking_enabled:
|
|
98
|
+
body["thinking"] = {
|
|
99
|
+
"type": "enabled",
|
|
100
|
+
"budget_tokens": self.security_config.thinking_budget_tokens,
|
|
101
|
+
}
|
|
102
|
+
else:
|
|
103
|
+
# 禁用 thinking
|
|
104
|
+
body["thinking"] = {"enabled": False, "budget_tokens": 0}
|
|
105
|
+
|
|
106
|
+
return body
|
|
107
|
+
|
|
108
|
+
def _extract_choices_content(self, result: dict[str, Any]) -> str:
|
|
109
|
+
"""从 API 响应中提取 choices 的内容"""
|
|
110
|
+
# 尝试从标准 OpenAI 格式提取
|
|
111
|
+
if "choices" in result and len(result["choices"]) > 0:
|
|
112
|
+
content = result["choices"][0]["message"]["content"]
|
|
113
|
+
if isinstance(content, str):
|
|
114
|
+
return content
|
|
115
|
+
return str(content)
|
|
116
|
+
|
|
117
|
+
# 尝试从 data.choices 提取
|
|
118
|
+
if "data" in result and isinstance(result["data"], dict):
|
|
119
|
+
data = result["data"]
|
|
120
|
+
if "choices" in data and len(data["choices"]) > 0:
|
|
121
|
+
content = data["choices"][0]["message"]["content"]
|
|
122
|
+
if isinstance(content, str):
|
|
123
|
+
return content
|
|
124
|
+
return str(content)
|
|
125
|
+
|
|
126
|
+
# 如果都失败,抛出错误
|
|
127
|
+
raise KeyError(f"无法从 API 响应中提取 choices 内容: {result}")
|
|
128
|
+
|
|
129
|
+
async def close(self) -> None:
|
|
130
|
+
"""关闭 HTTP 客户端"""
|
|
131
|
+
await self._http_client.aclose()
|
Undefined/main.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""程序入口"""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from logging.handlers import RotatingFileHandler
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from dotenv import load_dotenv
|
|
11
|
+
|
|
12
|
+
from .ai import AIClient
|
|
13
|
+
from .config import get_config
|
|
14
|
+
from .faq import FAQStorage
|
|
15
|
+
from .handlers import MessageHandler
|
|
16
|
+
from .memory import MemoryStorage
|
|
17
|
+
from .scheduled_task_storage import ScheduledTaskStorage
|
|
18
|
+
from .end_summary_storage import EndSummaryStorage
|
|
19
|
+
from .onebot import OneBotClient
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def setup_logging() -> None:
|
|
23
|
+
"""设置日志(控制台 + 文件轮转)"""
|
|
24
|
+
load_dotenv()
|
|
25
|
+
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
|
|
26
|
+
level = getattr(logging, log_level, logging.INFO)
|
|
27
|
+
|
|
28
|
+
# 日志格式
|
|
29
|
+
log_format = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
|
|
30
|
+
formatter = logging.Formatter(log_format)
|
|
31
|
+
|
|
32
|
+
# 根日志器
|
|
33
|
+
root_logger = logging.getLogger()
|
|
34
|
+
root_logger.setLevel(level)
|
|
35
|
+
|
|
36
|
+
# 控制台处理器
|
|
37
|
+
console_handler = logging.StreamHandler(sys.stdout)
|
|
38
|
+
console_handler.setFormatter(formatter)
|
|
39
|
+
root_logger.addHandler(console_handler)
|
|
40
|
+
|
|
41
|
+
# 日志文件配置
|
|
42
|
+
log_file_path = os.getenv("LOG_FILE_PATH", "logs/bot.log")
|
|
43
|
+
log_max_size = (
|
|
44
|
+
int(os.getenv("LOG_MAX_SIZE_MB", "10")) * 1024 * 1024
|
|
45
|
+
) # 兆字节 -> 字节
|
|
46
|
+
log_backup_count = int(os.getenv("LOG_BACKUP_COUNT", "5"))
|
|
47
|
+
|
|
48
|
+
# 确保日志目录存在
|
|
49
|
+
log_dir = Path(log_file_path).parent
|
|
50
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
51
|
+
|
|
52
|
+
file_handler = RotatingFileHandler(
|
|
53
|
+
log_file_path,
|
|
54
|
+
maxBytes=log_max_size,
|
|
55
|
+
backupCount=log_backup_count,
|
|
56
|
+
encoding="utf-8",
|
|
57
|
+
)
|
|
58
|
+
file_handler.setFormatter(formatter)
|
|
59
|
+
root_logger.addHandler(file_handler)
|
|
60
|
+
|
|
61
|
+
logging.info(
|
|
62
|
+
f"[启动] 日志系统初始化完成。级别: {log_level}, 文件: {log_file_path} "
|
|
63
|
+
f"(最大 {log_max_size // 1024 // 1024}MB, 保留 {log_backup_count} 份)"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def main() -> None:
|
|
68
|
+
"""主函数"""
|
|
69
|
+
setup_logging()
|
|
70
|
+
logger = logging.getLogger(__name__)
|
|
71
|
+
logger.info("[启动] 正在初始化 Undefined 机器人...")
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
config = get_config()
|
|
75
|
+
logger.info(f"[配置] 机器人 QQ: {config.bot_qq}")
|
|
76
|
+
logger.info(f"[配置] 超级管理员: {config.superadmin_qq}")
|
|
77
|
+
logger.info(f"[配置] 管理员 QQ 列表: {config.admin_qqs}")
|
|
78
|
+
except ValueError as e:
|
|
79
|
+
logger.error(f"[配置错误] 加载配置失败: {e}")
|
|
80
|
+
sys.exit(1)
|
|
81
|
+
|
|
82
|
+
# 初始化组件
|
|
83
|
+
logger.info("[初始化] 正在加载核心组件...")
|
|
84
|
+
try:
|
|
85
|
+
onebot = OneBotClient(config.onebot_ws_url, config.onebot_token)
|
|
86
|
+
memory_storage = MemoryStorage(max_memories=100)
|
|
87
|
+
task_storage = ScheduledTaskStorage()
|
|
88
|
+
end_summary_storage = EndSummaryStorage()
|
|
89
|
+
ai = AIClient(
|
|
90
|
+
config.chat_model,
|
|
91
|
+
config.vision_model,
|
|
92
|
+
config.agent_model,
|
|
93
|
+
memory_storage,
|
|
94
|
+
end_summary_storage,
|
|
95
|
+
)
|
|
96
|
+
faq_storage = FAQStorage()
|
|
97
|
+
|
|
98
|
+
handler = MessageHandler(config, onebot, ai, faq_storage, task_storage)
|
|
99
|
+
onebot.set_message_handler(handler.handle_message)
|
|
100
|
+
logger.info("[初始化] 核心组件加载完成")
|
|
101
|
+
except Exception as e:
|
|
102
|
+
logger.exception(f"[初始化错误] 组件初始化期间发生异常: {e}")
|
|
103
|
+
sys.exit(1)
|
|
104
|
+
|
|
105
|
+
logger.info("[启动] 机器人已准备就绪,开始连接 OneBot 服务...")
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
await onebot.run_with_reconnect()
|
|
109
|
+
except KeyboardInterrupt:
|
|
110
|
+
logger.info("[退出] 收到退出信号 (Ctrl+C)")
|
|
111
|
+
except Exception as e:
|
|
112
|
+
logger.exception(f"[异常] 运行期间发生未捕获的错误: {e}")
|
|
113
|
+
finally:
|
|
114
|
+
logger.info("[清理] 正在关闭机器人并释放资源...")
|
|
115
|
+
await onebot.disconnect()
|
|
116
|
+
await ai.close()
|
|
117
|
+
logger.info("[退出] 机器人已停止运行")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def run() -> None:
|
|
121
|
+
"""运行入口"""
|
|
122
|
+
asyncio.run(main())
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
run()
|
Undefined/memory.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""AI 记忆存储管理模块"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
from dataclasses import dataclass, asdict
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
# 记忆数据存储路径
|
|
12
|
+
MEMORY_FILE_PATH = Path("data/memory.json")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class Memory:
|
|
17
|
+
"""单条记忆数据"""
|
|
18
|
+
|
|
19
|
+
fact: str # 记忆内容
|
|
20
|
+
created_at: str # 创建时间
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MemoryStorage:
|
|
24
|
+
"""AI 记忆存储管理器"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, max_memories: int = 100) -> None:
|
|
27
|
+
"""初始化记忆存储
|
|
28
|
+
|
|
29
|
+
参数:
|
|
30
|
+
max_memories: 最大记忆数量
|
|
31
|
+
"""
|
|
32
|
+
self.max_memories = max_memories
|
|
33
|
+
self._memories: list[Memory] = []
|
|
34
|
+
self._load()
|
|
35
|
+
|
|
36
|
+
def _load(self) -> None:
|
|
37
|
+
"""从文件加载记忆"""
|
|
38
|
+
if not MEMORY_FILE_PATH.exists():
|
|
39
|
+
self._memories = []
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
with open(MEMORY_FILE_PATH, "r", encoding="utf-8") as f:
|
|
44
|
+
data = json.load(f)
|
|
45
|
+
self._memories = [Memory(**item) for item in data]
|
|
46
|
+
logger.info(f"已加载 {len(self._memories)} 条记忆")
|
|
47
|
+
except Exception as e:
|
|
48
|
+
logger.warning(f"加载记忆失败: {e}")
|
|
49
|
+
self._memories = []
|
|
50
|
+
|
|
51
|
+
def _save(self) -> None:
|
|
52
|
+
"""保存记忆到文件"""
|
|
53
|
+
try:
|
|
54
|
+
MEMORY_FILE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
55
|
+
with open(MEMORY_FILE_PATH, "w", encoding="utf-8") as f:
|
|
56
|
+
json.dump(
|
|
57
|
+
[asdict(m) for m in self._memories], f, ensure_ascii=False, indent=2
|
|
58
|
+
)
|
|
59
|
+
logger.debug(f"已保存 {len(self._memories)} 条记忆")
|
|
60
|
+
except Exception as e:
|
|
61
|
+
logger.error(f"保存记忆失败: {e}")
|
|
62
|
+
|
|
63
|
+
def add(self, fact: str) -> bool:
|
|
64
|
+
"""添加一条记忆
|
|
65
|
+
|
|
66
|
+
参数:
|
|
67
|
+
fact: 记忆内容
|
|
68
|
+
|
|
69
|
+
返回:
|
|
70
|
+
是否添加成功
|
|
71
|
+
"""
|
|
72
|
+
if not fact or not fact.strip():
|
|
73
|
+
logger.warning("尝试添加空记忆,已忽略")
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
# 检查是否已存在相同记忆
|
|
77
|
+
for existing in self._memories:
|
|
78
|
+
if existing.fact == fact.strip():
|
|
79
|
+
logger.debug(f"记忆已存在,忽略: {fact[:50]}...")
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
memory = Memory(
|
|
83
|
+
fact=fact.strip(), created_at=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# 添加到列表末尾
|
|
87
|
+
self._memories.append(memory)
|
|
88
|
+
|
|
89
|
+
# 如果超过上限,移除最旧的(最早的)
|
|
90
|
+
if len(self._memories) > self.max_memories:
|
|
91
|
+
removed = self._memories.pop(0)
|
|
92
|
+
logger.info(f"记忆数量超过上限,移除最旧记忆: {removed.fact[:50]}...")
|
|
93
|
+
|
|
94
|
+
self._save()
|
|
95
|
+
logger.info(
|
|
96
|
+
f"已添加记忆: {fact[:50]}... (当前 {len(self._memories)}/{self.max_memories})"
|
|
97
|
+
)
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
def get_all(self) -> list[Memory]:
|
|
101
|
+
"""获取所有记忆
|
|
102
|
+
|
|
103
|
+
返回:
|
|
104
|
+
记忆列表(按时间顺序,最早的在前)
|
|
105
|
+
"""
|
|
106
|
+
return self._memories.copy()
|
|
107
|
+
|
|
108
|
+
def clear(self) -> None:
|
|
109
|
+
"""清空所有记忆"""
|
|
110
|
+
self._memories = []
|
|
111
|
+
self._save()
|
|
112
|
+
logger.info("已清空所有记忆")
|
|
113
|
+
|
|
114
|
+
def count(self) -> int:
|
|
115
|
+
"""获取记忆数量
|
|
116
|
+
|
|
117
|
+
返回:
|
|
118
|
+
当前记忆数量
|
|
119
|
+
"""
|
|
120
|
+
return len(self._memories)
|