更新说明
123
This commit is contained in:
95
README.md
95
README.md
@@ -22,6 +22,15 @@
|
|||||||
|
|
||||||
关于麦麦的开发和部署相关的讨论群(不建议发布无关消息)这里不会有麦麦发言!
|
关于麦麦的开发和部署相关的讨论群(不建议发布无关消息)这里不会有麦麦发言!
|
||||||
|
|
||||||
|
## 开发计划TODO:LIST
|
||||||
|
|
||||||
|
- 兼容gif的解析和保存
|
||||||
|
- 小程序转发链接解析
|
||||||
|
- 对思考链长度限制
|
||||||
|
- 修复已知bug
|
||||||
|
- 完善文档
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="docs/qq.png" width="300" />
|
<img src="docs/qq.png" width="300" />
|
||||||
</div>
|
</div>
|
||||||
@@ -62,6 +71,92 @@ NAPCAT_UID=$(id -u) NAPCAT_GID=$(id -g) docker compose restart
|
|||||||
- 把env.example改成.env,并填上你的apikey(硅基流动或deepseekapi)
|
- 把env.example改成.env,并填上你的apikey(硅基流动或deepseekapi)
|
||||||
- 把bot_config_toml改名为bot_config.toml,并填写相关内容,不然无法正常运行
|
- 把bot_config_toml改名为bot_config.toml,并填写相关内容,不然无法正常运行
|
||||||
|
|
||||||
|
#### .env 文件配置说明
|
||||||
|
```ini
|
||||||
|
# 环境配置
|
||||||
|
ENVIRONMENT=dev # 开发环境设置
|
||||||
|
HOST=127.0.0.1 # 主机地址
|
||||||
|
PORT=8080 # 端口号
|
||||||
|
|
||||||
|
# 命令前缀设置
|
||||||
|
COMMAND_START=["/"] # 命令起始符
|
||||||
|
|
||||||
|
# 插件配置
|
||||||
|
PLUGINS=["src2.plugins.chat"] # 启用的插件列表
|
||||||
|
|
||||||
|
# MongoDB配置
|
||||||
|
MONGODB_HOST=127.0.0.1 # MongoDB主机地址
|
||||||
|
MONGODB_PORT=27017 # MongoDB端口
|
||||||
|
DATABASE_NAME=MegBot # 数据库名称
|
||||||
|
MONGODB_USERNAME="" # MongoDB用户名(可选)
|
||||||
|
MONGODB_PASSWORD="" # MongoDB密码(可选)
|
||||||
|
MONGODB_AUTH_SOURCE="" # MongoDB认证源(可选)
|
||||||
|
|
||||||
|
# API密钥配置
|
||||||
|
CHAT_ANY_WHERE_KEY= # ChatAnyWhere API密钥
|
||||||
|
SILICONFLOW_KEY= # 硅基流动 API密钥(必填)
|
||||||
|
DEEP_SEEK_KEY= # DeepSeek API密钥(必填)
|
||||||
|
|
||||||
|
# API地址配置
|
||||||
|
CHAT_ANY_WHERE_BASE_URL=https://api.chatanywhere.tech/v1
|
||||||
|
SILICONFLOW_BASE_URL=https://api.siliconflow.cn/v1/
|
||||||
|
DEEP_SEEK_BASE_URL=https://api.deepseek.com/v1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### bot_config.toml 文件配置说明
|
||||||
|
```toml
|
||||||
|
# 数据库设置
|
||||||
|
[database]
|
||||||
|
host = "127.0.0.1" # MongoDB主机地址
|
||||||
|
port = 27017 # MongoDB端口
|
||||||
|
name = "MegBot" # 数据库名称
|
||||||
|
|
||||||
|
# 机器人基本设置
|
||||||
|
[bot]
|
||||||
|
qq = # 你的机器人QQ号(必填)
|
||||||
|
nickname = "麦麦" # 机器人昵称
|
||||||
|
|
||||||
|
# 消息处理设置
|
||||||
|
[message]
|
||||||
|
min_text_length = 2 # 最小响应文本长度
|
||||||
|
max_context_size = 15 # 上下文最大保存数量
|
||||||
|
emoji_chance = 0.2 # 表情包使用概率
|
||||||
|
|
||||||
|
# 表情包功能设置
|
||||||
|
[emoji]
|
||||||
|
check_interval = 120 # 表情检查间隔(秒)
|
||||||
|
register_interval = 10 # 表情注册间隔(秒)
|
||||||
|
|
||||||
|
# CQ码设置
|
||||||
|
[cq_code]
|
||||||
|
enable_pic_translate = false # 是否启用图片转换(无效)
|
||||||
|
|
||||||
|
# 响应设置
|
||||||
|
[response]
|
||||||
|
api_using = "siliconflow" # 回复使用的API(siliconflow/deepseek)
|
||||||
|
model_r1_probability = 0.8 # R1模型使用概率
|
||||||
|
model_v3_probability = 0.1 # V3模型使用概率
|
||||||
|
model_r1_distill_probability = 0.1 # R1蒸馏模型使用概率(对deepseek api 无效)
|
||||||
|
|
||||||
|
# 其他设置
|
||||||
|
[others]
|
||||||
|
enable_advance_output = false # 是否启用详细日志输出
|
||||||
|
|
||||||
|
# 群组设置
|
||||||
|
[groups]
|
||||||
|
talk_allowed = [ # 允许回复的群号列表
|
||||||
|
# 在这里添加群号,逗号隔开
|
||||||
|
]
|
||||||
|
|
||||||
|
talk_frequency_down = [ # 降低回复频率的群号列表
|
||||||
|
# 在这里添加群号,逗号隔开
|
||||||
|
]
|
||||||
|
|
||||||
|
ban_user_id = [ # 禁止回复的用户QQ号列表
|
||||||
|
# 在这里添加QQ号,逗号隔开
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
5. **运行麦麦**
|
5. **运行麦麦**
|
||||||
```bash
|
```bash
|
||||||
conda activate 你的环境
|
conda activate 你的环境
|
||||||
|
|||||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@@ -73,7 +73,7 @@ class ReasoningGUI:
|
|||||||
self.frame.pack(pady=20, padx=20, fill="both", expand=True)
|
self.frame.pack(pady=20, padx=20, fill="both", expand=True)
|
||||||
|
|
||||||
# 添加标题
|
# 添加标题
|
||||||
self.title = ctk.CTkLabel(self.frame, text="AI推理监控系统", font=("Arial", 24))
|
self.title = ctk.CTkLabel(self.frame, text="麦麦的脑内所想", font=("Arial", 24))
|
||||||
self.title.pack(pady=10, padx=10)
|
self.title.pack(pady=10, padx=10)
|
||||||
|
|
||||||
# 创建左右分栏
|
# 创建左右分栏
|
||||||
@@ -87,8 +87,14 @@ class ReasoningGUI:
|
|||||||
self.group_label = ctk.CTkLabel(self.left_frame, text="群组列表", font=("Arial", 16))
|
self.group_label = ctk.CTkLabel(self.left_frame, text="群组列表", font=("Arial", 16))
|
||||||
self.group_label.pack(pady=5)
|
self.group_label.pack(pady=5)
|
||||||
|
|
||||||
self.group_listbox = ctk.CTkTextbox(self.left_frame, width=180, height=400)
|
# 创建可滚动框架来容纳群组按钮
|
||||||
self.group_listbox.pack(pady=5, padx=5)
|
self.group_scroll_frame = ctk.CTkScrollableFrame(self.left_frame, width=180, height=400)
|
||||||
|
self.group_scroll_frame.pack(pady=5, padx=5, fill="both", expand=True)
|
||||||
|
|
||||||
|
# 存储群组按钮的字典
|
||||||
|
self.group_buttons: Dict[str, ctk.CTkButton] = {}
|
||||||
|
# 当前选中的群组ID
|
||||||
|
self.selected_group_id: Optional[str] = None
|
||||||
|
|
||||||
# 右侧内容显示
|
# 右侧内容显示
|
||||||
self.right_frame = ctk.CTkFrame(self.paned)
|
self.right_frame = ctk.CTkFrame(self.paned)
|
||||||
@@ -106,6 +112,7 @@ class ReasoningGUI:
|
|||||||
self.content_text.tag_config("user", foreground="#4CAF50") # 用户名使用绿色
|
self.content_text.tag_config("user", foreground="#4CAF50") # 用户名使用绿色
|
||||||
self.content_text.tag_config("message", foreground="#2196F3") # 消息使用蓝色
|
self.content_text.tag_config("message", foreground="#2196F3") # 消息使用蓝色
|
||||||
self.content_text.tag_config("model", foreground="#9C27B0") # 模型名称使用紫色
|
self.content_text.tag_config("model", foreground="#9C27B0") # 模型名称使用紫色
|
||||||
|
self.content_text.tag_config("prompt", foreground="#FF9800") # prompt内容使用橙色
|
||||||
self.content_text.tag_config("reasoning", foreground="#FF9800") # 推理过程使用橙色
|
self.content_text.tag_config("reasoning", foreground="#FF9800") # 推理过程使用橙色
|
||||||
self.content_text.tag_config("response", foreground="#E91E63") # 回复使用粉色
|
self.content_text.tag_config("response", foreground="#E91E63") # 回复使用粉色
|
||||||
self.content_text.tag_config("separator", foreground="#666666") # 分隔符使用深灰色
|
self.content_text.tag_config("separator", foreground="#666666") # 分隔符使用深灰色
|
||||||
@@ -122,9 +129,6 @@ class ReasoningGUI:
|
|||||||
)
|
)
|
||||||
self.clear_button.pack(side="left", padx=5)
|
self.clear_button.pack(side="left", padx=5)
|
||||||
|
|
||||||
# 添加群组点击事件
|
|
||||||
self.group_listbox.bind('<Button-1>', self._on_group_click)
|
|
||||||
|
|
||||||
# 启动自动更新线程
|
# 启动自动更新线程
|
||||||
self.update_thread = threading.Thread(target=self._auto_update, daemon=True)
|
self.update_thread = threading.Thread(target=self._auto_update, daemon=True)
|
||||||
self.update_thread.start()
|
self.update_thread.start()
|
||||||
@@ -154,9 +158,45 @@ class ReasoningGUI:
|
|||||||
|
|
||||||
def _update_group_list_gui(self):
|
def _update_group_list_gui(self):
|
||||||
"""在主线程中更新群组列表"""
|
"""在主线程中更新群组列表"""
|
||||||
self.group_listbox.delete("1.0", "end")
|
# 清除现有按钮
|
||||||
|
for button in self.group_buttons.values():
|
||||||
|
button.destroy()
|
||||||
|
self.group_buttons.clear()
|
||||||
|
|
||||||
|
# 创建新的群组按钮
|
||||||
for group_id in self.group_data.keys():
|
for group_id in self.group_data.keys():
|
||||||
self.group_listbox.insert("end", f"群号: {group_id}\n")
|
button = ctk.CTkButton(
|
||||||
|
self.group_scroll_frame,
|
||||||
|
text=f"群号: {group_id}",
|
||||||
|
width=160,
|
||||||
|
height=30,
|
||||||
|
corner_radius=8,
|
||||||
|
command=lambda gid=group_id: self._on_group_select(gid)
|
||||||
|
)
|
||||||
|
button.pack(pady=2, padx=5)
|
||||||
|
self.group_buttons[group_id] = button
|
||||||
|
|
||||||
|
# 如果有选中的群组,保持其高亮状态
|
||||||
|
if self.selected_group_id and self.selected_group_id in self.group_buttons:
|
||||||
|
self._highlight_selected_group(self.selected_group_id)
|
||||||
|
|
||||||
|
def _on_group_select(self, group_id: str):
|
||||||
|
"""处理群组选择事件"""
|
||||||
|
self._highlight_selected_group(group_id)
|
||||||
|
self._update_display_gui(group_id)
|
||||||
|
|
||||||
|
def _highlight_selected_group(self, group_id: str):
|
||||||
|
"""高亮显示选中的群组按钮"""
|
||||||
|
# 重置所有按钮的颜色
|
||||||
|
for gid, button in self.group_buttons.items():
|
||||||
|
if gid == group_id:
|
||||||
|
# 设置选中按钮的颜色
|
||||||
|
button.configure(fg_color="#1E88E5", hover_color="#1976D2")
|
||||||
|
else:
|
||||||
|
# 恢复其他按钮的默认颜色
|
||||||
|
button.configure(fg_color="#2B2B2B", hover_color="#404040")
|
||||||
|
|
||||||
|
self.selected_group_id = group_id
|
||||||
|
|
||||||
def _update_display_gui(self, group_id: str):
|
def _update_display_gui(self, group_id: str):
|
||||||
"""在主线程中更新显示内容"""
|
"""在主线程中更新显示内容"""
|
||||||
@@ -179,15 +219,27 @@ class ReasoningGUI:
|
|||||||
self.content_text.insert("end", "模型: ", "timestamp")
|
self.content_text.insert("end", "模型: ", "timestamp")
|
||||||
self.content_text.insert("end", f"{item.get('model', '')}\n", "model")
|
self.content_text.insert("end", f"{item.get('model', '')}\n", "model")
|
||||||
|
|
||||||
|
# Prompt内容
|
||||||
|
self.content_text.insert("end", "Prompt内容:\n", "timestamp")
|
||||||
|
prompt_text = item.get('prompt', '')
|
||||||
|
if prompt_text and prompt_text.lower() != 'none':
|
||||||
|
lines = prompt_text.split('\n')
|
||||||
|
for line in lines:
|
||||||
|
if line.strip():
|
||||||
|
self.content_text.insert("end", " " + line + "\n", "prompt")
|
||||||
|
else:
|
||||||
|
self.content_text.insert("end", " 无Prompt内容\n", "prompt")
|
||||||
|
|
||||||
# 推理过程
|
# 推理过程
|
||||||
self.content_text.insert("end", "推理过程:\n", "timestamp")
|
self.content_text.insert("end", "推理过程:\n", "timestamp")
|
||||||
reasoning_text = item.get('reasoning', '')
|
reasoning_text = item.get('reasoning', '')
|
||||||
# 处理推理过程中的Markdown格式
|
if reasoning_text and reasoning_text.lower() != 'none':
|
||||||
lines = reasoning_text.split('\n')
|
lines = reasoning_text.split('\n')
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.strip():
|
if line.strip():
|
||||||
# 添加缩进
|
|
||||||
self.content_text.insert("end", " " + line + "\n", "reasoning")
|
self.content_text.insert("end", " " + line + "\n", "reasoning")
|
||||||
|
else:
|
||||||
|
self.content_text.insert("end", " 无推理过程\n", "reasoning")
|
||||||
|
|
||||||
# 回复内容
|
# 回复内容
|
||||||
self.content_text.insert("end", "回复: ", "timestamp")
|
self.content_text.insert("end", "回复: ", "timestamp")
|
||||||
@@ -237,11 +289,12 @@ class ReasoningGUI:
|
|||||||
|
|
||||||
new_data[group_id].append({
|
new_data[group_id].append({
|
||||||
'time': time_obj,
|
'time': time_obj,
|
||||||
'user': item.get('user_nickname', item.get('user_id', '未知')),
|
'user': item.get('user', '未知'),
|
||||||
'message': item.get('message', ''),
|
'message': item.get('message', ''),
|
||||||
'model': item.get('model', '未知'),
|
'model': item.get('model', '未知'),
|
||||||
'reasoning': item.get('reasoning', ''),
|
'reasoning': item.get('reasoning', ''),
|
||||||
'response': item.get('response', ''),
|
'response': item.get('response', ''),
|
||||||
|
'prompt': item.get('prompt', '') # 添加prompt字段
|
||||||
})
|
})
|
||||||
|
|
||||||
print(f"从数据库加载了 {total_count} 条记录,分布在 {len(new_data)} 个群组中")
|
print(f"从数据库加载了 {total_count} 条记录,分布在 {len(new_data)} 个群组中")
|
||||||
@@ -253,10 +306,12 @@ class ReasoningGUI:
|
|||||||
# 将更新任务添加到队列
|
# 将更新任务添加到队列
|
||||||
self.update_queue.put({'type': 'update_group_list'})
|
self.update_queue.put({'type': 'update_group_list'})
|
||||||
if self.group_data:
|
if self.group_data:
|
||||||
latest_group = next(iter(self.group_data))
|
# 如果没有选中的群组,选择最新的群组
|
||||||
|
if not self.selected_group_id or self.selected_group_id not in self.group_data:
|
||||||
|
self.selected_group_id = next(iter(self.group_data))
|
||||||
self.update_queue.put({
|
self.update_queue.put({
|
||||||
'type': 'update_display',
|
'type': 'update_display',
|
||||||
'group_id': latest_group
|
'group_id': self.selected_group_id
|
||||||
})
|
})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"自动更新出错: {e}")
|
print(f"自动更新出错: {e}")
|
||||||
@@ -264,59 +319,6 @@ class ReasoningGUI:
|
|||||||
# 每5秒更新一次
|
# 每5秒更新一次
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
def _on_group_click(self, event):
|
|
||||||
"""处理群组点击事件"""
|
|
||||||
try:
|
|
||||||
# 获取点击位置的文本行
|
|
||||||
index = self.group_listbox.index(f"@{event.x},{event.y}")
|
|
||||||
line = self.group_listbox.get(f"{index} linestart", f"{index} lineend")
|
|
||||||
if line.startswith("群号: "):
|
|
||||||
group_id = line.replace("群号: ", "").strip()
|
|
||||||
self.update_display(group_id)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"处理群组点击事件出错: {e}")
|
|
||||||
|
|
||||||
def update_display(self, group_id: str):
|
|
||||||
"""更新显示指定群组的内容"""
|
|
||||||
if group_id in self.group_data:
|
|
||||||
self.content_text.delete("1.0", "end")
|
|
||||||
for item in self.group_data[group_id]:
|
|
||||||
# 时间戳
|
|
||||||
time_str = item['time'].strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
self.content_text.insert("end", f"[{time_str}]\n", "timestamp")
|
|
||||||
|
|
||||||
# 用户信息
|
|
||||||
self.content_text.insert("end", "用户: ", "timestamp")
|
|
||||||
self.content_text.insert("end", f"** {item.get('user', '未知')} **\n", "user")
|
|
||||||
|
|
||||||
# 消息内容
|
|
||||||
self.content_text.insert("end", "消息: ", "timestamp")
|
|
||||||
self.content_text.insert("end", f"{item.get('message', '')}\n", "message")
|
|
||||||
|
|
||||||
# 模型信息
|
|
||||||
self.content_text.insert("end", "模型: ", "timestamp")
|
|
||||||
self.content_text.insert("end", f"{item.get('model', '')}\n", "model")
|
|
||||||
|
|
||||||
# 推理过程
|
|
||||||
self.content_text.insert("end", "推理过程:\n", "timestamp")
|
|
||||||
reasoning_text = item.get('reasoning', '')
|
|
||||||
# 处理推理过程中的Markdown格式
|
|
||||||
lines = reasoning_text.split('\n')
|
|
||||||
for line in lines:
|
|
||||||
if line.strip():
|
|
||||||
# 添加缩进
|
|
||||||
self.content_text.insert("end", " " + line + "\n", "reasoning")
|
|
||||||
|
|
||||||
# 回复内容
|
|
||||||
self.content_text.insert("end", "回复: ", "timestamp")
|
|
||||||
self.content_text.insert("end", f"{item.get('response', '')}\n", "response")
|
|
||||||
|
|
||||||
# 分隔符
|
|
||||||
self.content_text.insert("end", f"\n{'='*50}\n\n", "separator")
|
|
||||||
|
|
||||||
# 滚动到顶部
|
|
||||||
self.content_text.see("1.0")
|
|
||||||
|
|
||||||
def clear_display(self):
|
def clear_display(self):
|
||||||
"""清除显示内容"""
|
"""清除显示内容"""
|
||||||
self.content_text.delete("1.0", "end")
|
self.content_text.delete("1.0", "end")
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ check_interval = 120
|
|||||||
register_interval = 10
|
register_interval = 10
|
||||||
|
|
||||||
[cq_code]
|
[cq_code]
|
||||||
enable_pic_translate = true
|
enable_pic_translate = false
|
||||||
|
|
||||||
|
|
||||||
[response]
|
[response]
|
||||||
@@ -30,7 +30,7 @@ model_v3_probability = 0.1 # 麦麦回答时选择V3模型的概率
|
|||||||
model_r1_distill_probability = 0.1 # 麦麦回答时选择R1蒸馏模型的概率
|
model_r1_distill_probability = 0.1 # 麦麦回答时选择R1蒸馏模型的概率
|
||||||
|
|
||||||
[others]
|
[others]
|
||||||
enable_advance_output = false # 开启后输出更多日志,false关闭true开启
|
enable_advance_output = true # 开启后输出更多日志,false关闭true开启
|
||||||
|
|
||||||
|
|
||||||
[groups]
|
[groups]
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ class LLMResponseGenerator:
|
|||||||
content = response.choices[0].message.content
|
content = response.choices[0].message.content
|
||||||
|
|
||||||
# 获取推理内容
|
# 获取推理内容
|
||||||
reasoning_content = "模型思考过程:\n" + prompt
|
reasoning_content = ""
|
||||||
if hasattr(response.choices[0].message, "reasoning"):
|
if hasattr(response.choices[0].message, "reasoning"):
|
||||||
reasoning_content = response.choices[0].message.reasoning or reasoning_content
|
reasoning_content = response.choices[0].message.reasoning or reasoning_content
|
||||||
elif hasattr(response.choices[0].message, "reasoning_content"):
|
elif hasattr(response.choices[0].message, "reasoning_content"):
|
||||||
|
|||||||
Reference in New Issue
Block a user