更新说明

123
This commit is contained in:
SengokuCola
2025-03-01 12:55:02 +08:00
parent 691099f993
commit d9327d47fc
5 changed files with 170 additions and 73 deletions

View File

@@ -22,6 +22,15 @@
关于麦麦的开发和部署相关的讨论群(不建议发布无关消息)这里不会有麦麦发言! 关于麦麦的开发和部署相关的讨论群(不建议发布无关消息)这里不会有麦麦发言!
## 开发计划TODOLIST
- 兼容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" # 回复使用的APIsiliconflow/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 你的环境

Binary file not shown.

View File

@@ -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")

View File

@@ -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]

View File

@@ -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"):