diff --git a/scripts/070configexe.py b/scripts/070configexe.py index 88871aaf..eeba7d63 100644 --- a/scripts/070configexe.py +++ b/scripts/070configexe.py @@ -1,12 +1,12 @@ import tkinter as tk -from tkinter import ttk, messagebox +from tkinter import ttk, messagebox, filedialog import tomli import tomli_w import os from typing import Any, Dict, List import threading import time - +import sys class ConfigEditor: def __init__(self, root): @@ -21,7 +21,10 @@ class ConfigEditor: # 加载配置 self.load_config() - + + # 加载环境变量 + self.load_env_vars() + # 自动保存相关 self.last_save_time = time.time() self.save_timer = None @@ -54,6 +57,15 @@ class ConfigEditor: self.main_frame.columnconfigure(1, weight=1) self.main_frame.rowconfigure(1, weight=1) # 修改为1,因为第0行是版本号 + # 默认选择快捷设置栏 + self.current_section = "quick_settings" + self.create_quick_settings_widgets() + # 选中导航树中的快捷设置项 + for item in self.tree.get_children(): + if self.tree.item(item)["values"][0] == "quick_settings": + self.tree.selection_set(item) + break + def load_editor_config(self): """加载编辑器配置""" try: @@ -92,14 +104,64 @@ class ConfigEditor: except Exception as e: messagebox.showerror("错误", f"加载配置文件失败: {str(e)}") self.config = {} + # 自动打开配置路径窗口 + self.open_path_config() + + def load_env_vars(self): + """加载并解析环境变量文件""" + try: + # 从配置中获取环境文件路径 + env_path = self.config.get("inner", {}).get("env_file", ".env") + if not os.path.isabs(env_path): + env_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), env_path) + + if not os.path.exists(env_path): + print(f"环境文件不存在: {env_path}") + return + + # 读取环境文件 + with open(env_path, 'r', encoding='utf-8') as f: + env_content = f.read() + + # 解析环境变量 + env_vars = {} + for line in env_content.split('\n'): + line = line.strip() + if not line or line.startswith('#'): + continue + + if '=' in line: + key, value = line.split('=', 1) + key = key.strip() + value = value.strip() + + # 检查是否是目标变量 + if key.endswith('_BASE_URL') or key.endswith('_KEY'): + # 提取前缀(去掉_BASE_URL或_KEY) + prefix = key[:-9] if key.endswith('_BASE_URL') else key[:-4] + if prefix not in env_vars: + env_vars[prefix] = {} + env_vars[prefix][key] = value + + # 将解析的环境变量添加到配置中 + if 'env_vars' not in self.config: + self.config['env_vars'] = {} + self.config['env_vars'].update(env_vars) + + except Exception as e: + print(f"加载环境变量失败: {str(e)}") def create_version_label(self): """创建版本号显示标签""" version = self.config.get("inner", {}).get("version", "未知版本") version_frame = ttk.Frame(self.main_frame) version_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 10)) - - version_label = ttk.Label(version_frame, text=f"麦麦版本:{version}", font=("", 10, "bold")) + + # 添加配置按钮 + config_button = ttk.Button(version_frame, text="配置路径", command=self.open_path_config) + config_button.pack(side=tk.LEFT, padx=5) + + version_label = ttk.Label(version_frame, text=f"麦麦版本:{version}", font=("微软雅黑", 10, "bold")) version_label.pack(side=tk.LEFT, padx=5) def create_navbar(self): @@ -113,15 +175,16 @@ class ConfigEditor: # 添加快捷设置节 self.tree.insert("", "end", text="快捷设置", values=("quick_settings",)) - - # 添加配置项到树 + + # 添加env_vars节,显示为"配置你的模型APIKEY" + self.tree.insert("", "end", text="配置你的模型APIKEY", values=("env_vars",)) + + # 只显示bot_config.toml实际存在的section for section in self.config: - if section != "inner": # 跳过inner部分 - # 获取节的中文名称 + if section not in ("inner", "env_vars", "telemetry", "experimental", "maim_message", "keyword_reaction", "message_receive", "relationship"): section_trans = self.translations.get("sections", {}).get(section, {}) section_name = section_trans.get("name", section) self.tree.insert("", "end", text=section_name, values=(section,)) - # 绑定选择事件 self.tree.bind("<>", self.on_section_select) @@ -131,9 +194,9 @@ class ConfigEditor: self.editor_frame.grid(row=1, column=1, sticky=(tk.W, tk.E, tk.N, tk.S)) # 创建编辑区标题 - self.editor_title = ttk.Label(self.editor_frame, text="") - self.editor_title.pack(fill=tk.X) - + # self.editor_title = ttk.Label(self.editor_frame, text="") + # self.editor_title.pack(fill=tk.X) + # 创建编辑区内容 self.editor_content = ttk.Frame(self.editor_frame) self.editor_content.pack(fill=tk.BOTH, expand=True) @@ -168,8 +231,12 @@ class ConfigEditor: self.button_frame.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E)) # 刷新按钮 - self.refresh_button = ttk.Button(self.button_frame, text="刷新", command=self.refresh_config) - self.refresh_button.pack(side=tk.RIGHT, padx=5) + # self.refresh_button = ttk.Button(self.button_frame, text="刷新", command=self.refresh_config) + # self.refresh_button.pack(side=tk.RIGHT, padx=5) + + # 高级选项按钮(左下角) + self.advanced_button = ttk.Button(self.button_frame, text="高级选项", command=self.open_advanced_options) + self.advanced_button.pack(side=tk.LEFT, padx=5) def create_widget_for_value(self, parent: ttk.Frame, key: str, value: Any, path: List[str]) -> None: """为不同类型的值创建对应的编辑控件""" @@ -178,7 +245,15 @@ class ConfigEditor: # --- 修改开始: 改进翻译查找逻辑 --- full_config_path_key = ".".join(path + [key]) # 例如 "chinese_typo.enable" - + + model_item_translations = { + "name": ("模型名称", "模型的唯一标识或名称"), + "provider": ("模型提供商", "模型API的提供商"), + "pri_in": ("输入价格", "模型输入的价格/消耗"), + "pri_out": ("输出价格", "模型输出的价格/消耗"), + "temp": ("模型温度", "控制模型输出的多样性") + } + item_name_to_display = key # 默认显示原始键名 item_desc_to_display = "" # 默认无描述 @@ -193,10 +268,12 @@ class ConfigEditor: if generic_translation and generic_translation.get("name"): item_name_to_display = generic_translation.get("name") item_desc_to_display = generic_translation.get("description", "") + elif key in model_item_translations: + item_name_to_display, item_desc_to_display = model_item_translations[key] # --- 修改结束 --- # 配置名(大号字体) - label = ttk.Label(frame, text=item_name_to_display, font=("", 20, "bold")) + label = ttk.Label(frame, text=item_name_to_display, font=("微软雅黑", 16, "bold")) label.grid(row=0, column=0, sticky=tk.W, padx=5, pady=(0, 0)) # 星星图标快捷设置(与配置名同一行) @@ -214,13 +291,19 @@ class ConfigEditor: for widget in parent.winfo_children(): widget.destroy() self.widgets.clear() - # 重新渲染本分组 - if hasattr(self, "current_section") and self.current_section and self.current_section != "quick_settings": - self.create_section_widgets( - parent, self.current_section, self.config[self.current_section], [self.current_section] - ) - elif hasattr(self, "current_section") and self.current_section == "quick_settings": - self.create_quick_settings_widgets() # 如果当前是快捷设置,也刷新它 + # 判断parent是不是self.content_frame + if parent == self.content_frame: + # 主界面 + if hasattr(self, 'current_section') and self.current_section and self.current_section != "quick_settings": + self.create_section_widgets(parent, self.current_section, self.config[self.current_section], [self.current_section]) + elif hasattr(self, 'current_section') and self.current_section == "quick_settings": + self.create_quick_settings_widgets() + else: + # 弹窗Tab + # 重新渲染当前Tab的内容 + if path: + section = path[0] + self.create_section_widgets(parent, section, self.config[section], path) pin_btn = ttk.Button(frame, text=icon, width=2, command=on_star_click) pin_btn.grid(row=0, column=content_col_offset_for_star, sticky=tk.W, padx=5) @@ -234,18 +317,16 @@ class ConfigEditor: # 配置项描述(第二行) desc_row = 1 if item_desc_to_display: - desc_label = ttk.Label(frame, text=item_desc_to_display, foreground="gray", font=("", 16)) - desc_label.grid( - row=desc_row, column=0, columnspan=content_col_offset_for_star + 1, sticky=tk.W, padx=5, pady=(0, 4) - ) - widget_row = desc_row + 1 # 内容控件在描述下方 + desc_label = ttk.Label(frame, text=item_desc_to_display, foreground="gray", font=("微软雅黑", 10)) + desc_label.grid(row=desc_row, column=0, columnspan=content_col_offset_for_star + 1, sticky=tk.W, padx=5, pady=(0, 4)) + widget_row = desc_row + 1 # 内容控件在描述下方 else: widget_row = desc_row # 内容控件直接在第二行 # 配置内容控件(第三行或第二行) if path[0] == "inner": - value_label = ttk.Label(frame, text=str(value), font=("", 20)) - value_label.grid(row=widget_row, column=0, columnspan=content_col_offset_for_star + 1, sticky=tk.W, padx=5) + value_label = ttk.Label(frame, text=str(value), font=("微软雅黑", 16)) + value_label.grid(row=widget_row, column=0, columnspan=content_col_offset_for_star +1, sticky=tk.W, padx=5) return if isinstance(value, bool): @@ -259,8 +340,8 @@ class ConfigEditor: elif isinstance(value, (int, float)): # 数字使用数字输入框 var = tk.StringVar(value=str(value)) - entry = ttk.Entry(frame, textvariable=var, font=("", 20)) - entry.grid(row=widget_row, column=0, columnspan=content_col_offset_for_star + 1, sticky=tk.W + tk.E, padx=5) + entry = ttk.Entry(frame, textvariable=var, font=("微软雅黑", 16)) + entry.grid(row=widget_row, column=0, columnspan=content_col_offset_for_star +1, sticky=tk.W+tk.E, padx=5) var.trace_add("write", lambda *args: self.on_value_changed()) self.widgets[tuple(path + [key])] = var widget_type = "number" @@ -299,19 +380,98 @@ class ConfigEditor: else: # 其他类型(字符串等)使用普通文本框 var = tk.StringVar(value=str(value)) - entry = ttk.Entry(frame, textvariable=var, font=("", 20)) - entry.grid(row=widget_row, column=0, columnspan=content_col_offset_for_star + 1, sticky=tk.W + tk.E, padx=5) - var.trace_add("write", lambda *args: self.on_value_changed()) - self.widgets[tuple(path + [key])] = var + + # 特殊处理provider字段 + full_path = ".".join(path + [key]) + if key == "provider" and full_path.startswith("model."): + # print(f"处理provider字段,完整路径: {full_path}") + # print(f"当前config中的env_vars: {self.config.get('env_vars', {})}") + # 获取所有可用的provider选项 + providers = [] + if "env_vars" in self.config: + # print(f"找到env_vars节,内容: {self.config['env_vars']}") + # 遍历env_vars中的所有配置对 + for prefix, values in self.config["env_vars"].items(): + # print(f"检查配置对 {prefix}: {values}") + # 检查是否同时有BASE_URL和KEY + if f"{prefix}_BASE_URL" in values and f"{prefix}_KEY" in values: + providers.append(prefix) + # print(f"添加provider: {prefix}") + + # print(f"最终providers列表: {providers}") + if providers: + # 创建模型名称标签(大字体) + model_name = var.get() if var.get() else providers[0] + section_translations = { + "model.utils": "工具模型", + "model.utils_small": "小型工具模型", + "model.memory_summary": "记忆概括模型", + "model.vlm": "图像识别模型", + "model.embedding": "嵌入模型", + "model.normal_chat_1": "普通聊天:主要聊天模型", + "model.normal_chat_2": "普通聊天:次要聊天模型", + "model.focus_working_memory": "专注模式:工作记忆模型", + "model.focus_chat_mind": "专注模式:聊天规划模型", + "model.focus_tool_use": "专注模式:工具调用模型", + "model.focus_planner": "专注模式:决策模型", + "model.focus_expressor": "专注模式:表达器模型", + "model.focus_self_recognize": "专注模式:自我识别模型" + } + # 获取当前节的名称 + # current_section = ".".join(path[:-1]) # 去掉最后一个key + # section_name = section_translations.get(current_section, current_section) + + # 创建节名称标签(大字体) + # section_label = ttk.Label(frame, text="11", font=("微软雅黑", 24, "bold")) + # section_label.grid(row=widget_row, column=0, columnspan=content_col_offset_for_star +1, sticky=tk.W, padx=5, pady=(0, 5)) + + # 创建下拉菜单(小字体) + combo = ttk.Combobox(frame, textvariable=var, values=providers, font=("微软雅黑", 12), state="readonly") + combo.grid(row=widget_row + 1, column=0, columnspan=content_col_offset_for_star +1, sticky=tk.W+tk.E, padx=5) + combo.bind("<>", lambda e: self.on_value_changed()) + self.widgets[tuple(path + [key])] = var + widget_type = "provider" + # print(f"创建了下拉菜单,选项: {providers}") + else: + # 如果没有可用的provider,使用普通文本框 + # print(f"没有可用的provider,使用普通文本框") + entry = ttk.Entry(frame, textvariable=var, font=("微软雅黑", 16)) + entry.grid(row=widget_row, column=0, columnspan=content_col_offset_for_star +1, sticky=tk.W+tk.E, padx=5) + var.trace_add("write", lambda *args: self.on_value_changed()) + self.widgets[tuple(path + [key])] = var + widget_type = "text" + else: + # 普通文本框 + entry = ttk.Entry(frame, textvariable=var, font=("微软雅黑", 16)) + entry.grid(row=widget_row, column=0, columnspan=content_col_offset_for_star +1, sticky=tk.W+tk.E, padx=5) + var.trace_add("write", lambda *args: self.on_value_changed()) + self.widgets[tuple(path + [key])] = var widget_type = "text" def create_section_widgets(self, parent: ttk.Frame, section: str, data: Dict, path=None) -> None: """为配置节创建编辑控件""" if path is None: path = [section] + # section完整路径 + full_section_path = ".".join(path) # 获取节的中文名称和描述 - section_trans = self.translations.get("sections", {}).get(section, {}) - section_name = section_trans.get("name", section) + section_translations = { + "model.utils": "工具模型", + "model.utils_small": "小型工具模型", + "model.memory_summary": "记忆概括模型", + "model.vlm": "图像识别模型", + "model.embedding": "嵌入模型", + "model.normal_chat_1": "主要聊天模型", + "model.normal_chat_2": "次要聊天模型", + "model.focus_working_memory": "工作记忆模型", + "model.focus_chat_mind": "聊天规划模型", + "model.focus_tool_use": "工具调用模型", + "model.focus_planner": "决策模型", + "model.focus_expressor": "表达器模型", + "model.focus_self_recognize": "自我识别模型" + } + section_trans = self.translations.get("sections", {}).get(full_section_path, {}) + section_name = section_trans.get("name") or section_translations.get(full_section_path) or section section_desc = section_trans.get("description", "") # 创建节的标签框架 @@ -319,14 +479,18 @@ class ConfigEditor: section_frame.pack(fill=tk.X, padx=5, pady=10) # 创建节的名称标签 - section_label = ttk.Label(section_frame, text=f"[{section_name}]", font=("", 12, "bold")) + section_label = ttk.Label(section_frame, text=f"[{section_name}]", font=("微软雅黑", 18, "bold")) section_label.pack(side=tk.LEFT, padx=5) # 创建节的描述标签 - if section_desc: - desc_label = ttk.Label(section_frame, text=f"({section_desc})", foreground="gray") - desc_label.pack(side=tk.LEFT, padx=5) - + if isinstance(section_trans.get("description"), dict): + # 如果是多语言描述,优先取en,否则取第一个 + desc_en = section_trans["description"].get("en") or next(iter(section_trans["description"].values()), "") + desc_label = ttk.Label(section_frame, text=desc_en, foreground="gray", font=("微软雅黑", 10)) + else: + desc_label = ttk.Label(section_frame, text=section_desc, foreground="gray", font=("微软雅黑", 10)) + desc_label.pack(side=tk.LEFT, padx=5) + # 为每个配置项创建对应的控件 for key, value in data.items(): if isinstance(value, dict): @@ -354,15 +518,7 @@ class ConfigEditor: section = self.tree.item(selection[0])["values"][0] # 使用values中的原始节名 self.current_section = section - - # 获取节的中文名称 - if section == "quick_settings": - section_name = "快捷设置" - else: - section_trans = self.translations.get("sections", {}).get(section, {}) - section_name = section_trans.get("name", section) - self.editor_title.config(text=f"编辑 {section_name}") - + # 清空编辑器 for widget in self.content_frame.winfo_children(): widget.destroy() @@ -373,6 +529,8 @@ class ConfigEditor: # 创建编辑控件 if section == "quick_settings": self.create_quick_settings_widgets() + elif section == "env_vars": + self.create_env_vars_section(self.content_frame) elif section in self.config: self.create_section_widgets(self.content_frame, section, self.config[section]) @@ -393,13 +551,13 @@ class ConfigEditor: current = current.get(key, {}) value = current.get(path[-1]) # 获取最后一个键的值 - # 创建名称标签 - name_label = ttk.Label(frame, text=setting["name"], font=("", 18)) + # 创建名称标签(加粗) + name_label = ttk.Label(frame, text=setting["name"], font=("微软雅黑", 16, "bold")) name_label.pack(fill=tk.X, padx=5, pady=(2, 0)) # 创建描述标签 if setting.get("description"): - desc_label = ttk.Label(frame, text=setting["description"], foreground="gray", font=("", 16)) + desc_label = ttk.Label(frame, text=setting['description'], foreground="gray", font=("微软雅黑", 10)) desc_label.pack(fill=tk.X, padx=5, pady=(0, 2)) # 根据类型创建不同的控件 @@ -416,15 +574,15 @@ class ConfigEditor: elif setting_type == "text": value = str(value) if value is not None else "" var = tk.StringVar(value=value) - entry = ttk.Entry(frame, textvariable=var, width=40, font=("", 18)) - entry.pack(fill=tk.X, padx=5, pady=(0, 5)) + entry = ttk.Entry(frame, textvariable=var, width=40, font=("微软雅黑", 12)) + entry.pack(fill=tk.X, padx=5, pady=(0,5)) var.trace_add("write", lambda *args, p=path, v=var: self.on_quick_setting_changed(p, v)) elif setting_type == "number": value = str(value) if value is not None else "0" var = tk.StringVar(value=value) - entry = ttk.Entry(frame, textvariable=var, width=10, font=("", 18)) - entry.pack(fill=tk.X, padx=5, pady=(0, 5)) + entry = ttk.Entry(frame, textvariable=var, width=10, font=("微软雅黑", 12)) + entry.pack(fill=tk.X, padx=5, pady=(0,5)) var.trace_add("write", lambda *args, p=path, v=var: self.on_quick_setting_changed(p, v)) elif setting_type == "list": @@ -500,24 +658,75 @@ class ConfigEditor: try: # 获取所有控件的值 for path, widget in self.widgets.items(): + # 跳过 env_vars 的控件赋值(只用于.env,不写回config) + if len(path) >= 2 and path[0] == 'env_vars': + continue value = self.get_widget_value(widget) - # 更新配置 current = self.config for key in path[:-1]: current = current[key] - final_key = path[-1] # 直接用最后一个key + final_key = path[-1] current[final_key] = value - # 保存到文件 + # === 只保存 TOML,不包含 env_vars === + env_vars = self.config.pop('env_vars', None) with open(self.config_path, "wb") as f: tomli_w.dump(self.config, f) + if env_vars is not None: + self.config['env_vars'] = env_vars + + # === 保存 env_vars 到 .env 文件(只覆盖特定key,其他内容保留) === + env_path = self.editor_config["config"].get("env_file", ".env") + if not os.path.isabs(env_path): + env_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), env_path) + # 1. 读取原有.env内容 + old_lines = [] + if os.path.exists(env_path): + with open(env_path, "r", encoding="utf-8") as f: + old_lines = f.readlines() + # 2. 收集所有目标key的新值(直接从widgets取) + new_env_dict = {} + for path, widget in self.widgets.items(): + if len(path) == 2 and path[0] == 'env_vars': + k = path[1] + if k.endswith("_BASE_URL") or k.endswith("_KEY"): + new_env_dict[k] = self.get_widget_value(widget) + # 3. 遍历原有行,替换目标key,保留所有其他内容 + result_lines = [] + found_keys = set() + for line in old_lines: + if "=" in line and not line.strip().startswith("#"): + k = line.split("=", 1)[0].strip() + if k in new_env_dict: + result_lines.append(f"{k}={new_env_dict[k]}\n") + found_keys.add(k) + else: + result_lines.append(line) + else: + result_lines.append(line) + # 4. 新key如果原.env没有,则追加 + for k, v in new_env_dict.items(): + if k not in found_keys: + result_lines.append(f"{k}={v}\n") + # 5. 写回.env + with open(env_path, "w", encoding="utf-8") as f: + f.writelines(result_lines) + # === 结束 === + + # === 保存完 .env 后,同步 widgets 的值回 self.config['env_vars'] === + for path, widget in self.widgets.items(): + if len(path) == 2 and path[0] == 'env_vars': + prefix_key = path[1] + if prefix_key.endswith("_BASE_URL") or prefix_key.endswith("_KEY"): + prefix = prefix_key[:-9] if prefix_key.endswith("_BASE_URL") else prefix_key[:-4] + if 'env_vars' not in self.config: + self.config['env_vars'] = {} + if prefix not in self.config['env_vars']: + self.config['env_vars'][prefix] = {} + self.config['env_vars'][prefix][prefix_key] = self.get_widget_value(widget) self.last_save_time = time.time() self.pending_save = False - self.editor_title.config(text=f"{self.editor_title.cget('text')} (已保存)") - self.root.after( - 2000, lambda: self.editor_title.config(text=self.editor_title.cget("text").replace(" (已保存)", "")) - ) except Exception as e: messagebox.showerror("错误", f"保存配置失败: {str(e)}") @@ -649,6 +858,252 @@ class ConfigEditor: self.widgets.clear() self.create_quick_settings_widgets() + def create_env_var_group(self, parent: ttk.Frame, prefix: str, values: Dict[str, str], path: List[str]) -> None: + """创建环境变量组""" + frame = ttk.Frame(parent) + frame.pack(fill=tk.X, padx=5, pady=2) + + # 创建组标题 + title_frame = ttk.Frame(frame) + title_frame.pack(fill=tk.X, pady=(5, 0)) + + title_label = ttk.Label(title_frame, text=f"API配置组: {prefix}", font=("微软雅黑", 16, "bold")) + title_label.pack(side=tk.LEFT, padx=5) + + # 删除按钮 + del_button = ttk.Button(title_frame, text="删除组", + command=lambda: self.delete_env_var_group(prefix)) + del_button.pack(side=tk.RIGHT, padx=5) + + # 创建BASE_URL输入框 + base_url_frame = ttk.Frame(frame) + base_url_frame.pack(fill=tk.X, padx=5, pady=2) + + base_url_label = ttk.Label(base_url_frame, text="BASE_URL:", font=("微软雅黑", 12)) + base_url_label.pack(side=tk.LEFT, padx=5) + + base_url_var = tk.StringVar(value=values.get(f"{prefix}_BASE_URL", "")) + base_url_entry = ttk.Entry(base_url_frame, textvariable=base_url_var, font=("微软雅黑", 12)) + base_url_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) + base_url_var.trace_add("write", lambda *args: self.on_value_changed()) + + # 创建KEY输入框 + key_frame = ttk.Frame(frame) + key_frame.pack(fill=tk.X, padx=5, pady=2) + + key_label = ttk.Label(key_frame, text="API KEY:", font=("微软雅黑", 12)) + key_label.pack(side=tk.LEFT, padx=5) + + key_var = tk.StringVar(value=values.get(f"{prefix}_KEY", "")) + key_entry = ttk.Entry(key_frame, textvariable=key_var, font=("微软雅黑", 12)) + key_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) + key_var.trace_add("write", lambda *args: self.on_value_changed()) + + # 存储变量引用 + self.widgets[tuple(path + [f"{prefix}_BASE_URL"])] = base_url_var + self.widgets[tuple(path + [f"{prefix}_KEY"])] = key_var + + # 添加分隔线 + separator = ttk.Separator(frame, orient='horizontal') + separator.pack(fill=tk.X, pady=5) + + def create_env_vars_section(self, parent: ttk.Frame) -> None: + """创建环境变量编辑区""" + # 创建添加新组的按钮 + add_button = ttk.Button(parent, text="添加新的API配置组", + command=self.add_new_env_var_group) + add_button.pack(pady=10) + + # 创建现有组的编辑区 + if 'env_vars' in self.config: + for prefix, values in self.config['env_vars'].items(): + self.create_env_var_group(parent, prefix, values, ['env_vars']) + + def add_new_env_var_group(self): + """添加新的环境变量组""" + # 创建新窗口 + dialog = tk.Toplevel(self.root) + dialog.title("添加新的API配置组") + dialog.geometry("400x200") + + # 创建输入框架 + frame = ttk.Frame(dialog, padding="10") + frame.pack(fill=tk.BOTH, expand=True) + + # 前缀输入 + prefix_label = ttk.Label(frame, text="API前缀名称:", font=("微软雅黑", 12)) + prefix_label.pack(pady=5) + + prefix_var = tk.StringVar() + prefix_entry = ttk.Entry(frame, textvariable=prefix_var, font=("微软雅黑", 12)) + prefix_entry.pack(fill=tk.X, pady=5) + + # 确认按钮 + def on_confirm(): + prefix = prefix_var.get().strip() + if prefix: + if 'env_vars' not in self.config: + self.config['env_vars'] = {} + self.config['env_vars'][prefix] = { + f"{prefix}_BASE_URL": "", + f"{prefix}_KEY": "" + } + # 刷新显示 + self.refresh_env_vars_section() + self.on_value_changed() + dialog.destroy() + + confirm_button = ttk.Button(frame, text="确认", command=on_confirm) + confirm_button.pack(pady=10) + + def delete_env_var_group(self, prefix: str): + """删除环境变量组""" + if messagebox.askyesno("确认", f"确定要删除 {prefix} 配置组吗?"): + if 'env_vars' in self.config: + del self.config['env_vars'][prefix] + # 刷新显示 + self.refresh_env_vars_section() + self.on_value_changed() + + def refresh_env_vars_section(self): + """刷新环境变量编辑区""" + # 清空当前显示 + for widget in self.content_frame.winfo_children(): + widget.destroy() + self.widgets.clear() + + # 重新创建编辑区 + self.create_env_vars_section(self.content_frame) + + def open_advanced_options(self): + """弹窗显示高级配置""" + dialog = tk.Toplevel(self.root) + dialog.title("高级选项") + dialog.geometry("700x800") + + notebook = ttk.Notebook(dialog) + notebook.pack(fill=tk.BOTH, expand=True) + + # 遥测栏 + if "telemetry" in self.config: + telemetry_frame = ttk.Frame(notebook) + notebook.add(telemetry_frame, text="遥测") + self.create_section_widgets(telemetry_frame, "telemetry", self.config["telemetry"], ["telemetry"]) + # 实验性功能栏 + if "experimental" in self.config: + exp_frame = ttk.Frame(notebook) + notebook.add(exp_frame, text="实验性功能") + self.create_section_widgets(exp_frame, "experimental", self.config["experimental"], ["experimental"]) + # 消息服务栏 + if "maim_message" in self.config: + msg_frame = ttk.Frame(notebook) + notebook.add(msg_frame, text="消息服务") + self.create_section_widgets(msg_frame, "maim_message", self.config["maim_message"], ["maim_message"]) + # 消息接收栏 + if "message_receive" in self.config: + recv_frame = ttk.Frame(notebook) + notebook.add(recv_frame, text="消息接收") + self.create_section_widgets(recv_frame, "message_receive", self.config["message_receive"], ["message_receive"]) + # 关系栏 + if "relationship" in self.config: + rel_frame = ttk.Frame(notebook) + notebook.add(rel_frame, text="关系") + self.create_section_widgets(rel_frame, "relationship", self.config["relationship"], ["relationship"]) + + def open_path_config(self): + """打开路径配置对话框""" + dialog = tk.Toplevel(self.root) + dialog.title("配置路径") + dialog.geometry("600x200") + + # 创建输入框架 + frame = ttk.Frame(dialog, padding="10") + frame.pack(fill=tk.BOTH, expand=True) + + # bot_config.toml路径配置 + bot_config_frame = ttk.Frame(frame) + bot_config_frame.pack(fill=tk.X, pady=5) + + bot_config_label = ttk.Label(bot_config_frame, text="bot_config.toml路径:", font=("微软雅黑", 12)) + bot_config_label.pack(side=tk.LEFT, padx=5) + + bot_config_var = tk.StringVar(value=self.config_path) + bot_config_entry = ttk.Entry(bot_config_frame, textvariable=bot_config_var, font=("微软雅黑", 12)) + bot_config_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) + + def apply_config(): + new_bot_config_path = bot_config_var.get().strip() + new_env_path = env_var.get().strip() + + if not new_bot_config_path or not new_env_path: + messagebox.showerror("错误", "路径不能为空") + return + + if not os.path.exists(new_bot_config_path): + messagebox.showerror("错误", "bot_config.toml文件不存在") + return + + # 更新配置 + self.config_path = new_bot_config_path + self.editor_config["config"]["bot_config_path"] = new_bot_config_path + self.editor_config["config"]["env_file"] = new_env_path + + # 保存编辑器配置 + config_path = os.path.join(os.path.dirname(__file__), "configexe.toml") + with open(config_path, "wb") as f: + tomli_w.dump(self.editor_config, f) + + # 重新加载配置 + self.load_config() + self.load_env_vars() + + # 刷新显示 + self.refresh_config() + + messagebox.showinfo("成功", "路径配置已更新,程序将重新启动") + dialog.destroy() + + # 重启程序 + self.root.quit() + os.execv(sys.executable, ['python'] + sys.argv) + + def browse_bot_config(): + file_path = filedialog.askopenfilename( + title="选择bot_config.toml文件", + filetypes=[("TOML文件", "*.toml"), ("所有文件", "*.*")] + ) + if file_path: + bot_config_var.set(file_path) + apply_config() + + browse_bot_config_btn = ttk.Button(bot_config_frame, text="浏览", command=browse_bot_config) + browse_bot_config_btn.pack(side=tk.LEFT, padx=5) + + # .env路径配置 + env_frame = ttk.Frame(frame) + env_frame.pack(fill=tk.X, pady=5) + + env_label = ttk.Label(env_frame, text=".env路径:", font=("微软雅黑", 12)) + env_label.pack(side=tk.LEFT, padx=5) + + env_path = self.editor_config["config"].get("env_file", ".env") + if not os.path.isabs(env_path): + env_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), env_path) + env_var = tk.StringVar(value=env_path) + env_entry = ttk.Entry(env_frame, textvariable=env_var, font=("微软雅黑", 12)) + env_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) + + def browse_env(): + file_path = filedialog.askopenfilename( + title="选择.env文件", + filetypes=[("环境变量文件", "*.env"), ("所有文件", "*.*")] + ) + if file_path: + env_var.set(file_path) + apply_config() + + browse_env_btn = ttk.Button(env_frame, text="浏览", command=browse_env) + browse_env_btn.pack(side=tk.LEFT, padx=5) def main(): root = tk.Tk() diff --git a/scripts/configexe.toml b/scripts/configexe.toml index de966519..603393f7 100644 --- a/scripts/configexe.toml +++ b/scripts/configexe.toml @@ -1,11 +1,19 @@ [config] -bot_config_path = "config/bot_config.toml" +bot_config_path = "C:/GitHub/MaiBot-Core/config/bot_config.toml" +env_path = "env.toml" +env_file = "c:\\GitHub\\MaiBot-Core\\.env" [editor] window_width = 1000 window_height = 800 save_delay = 1.0 +[[editor.quick_settings.items]] +name = "核心性格" +description = "麦麦的核心性格描述,建议50字以内" +path = "personality.personality_core" +type = "text" + [[editor.quick_settings.items]] name = "性格细节" description = "麦麦性格的细节描述,条数任意,不能为0" @@ -31,47 +39,61 @@ path = "chat.chat_mode" type = "text" [[editor.quick_settings.items]] -name = "退出专注阈值" -description = "自动退出专注聊天的阈值,越低越容易退出专注聊天" -path = "chat.exit_focus_threshold" +name = "回复频率(normal模式)" +description = "麦麦回复频率,一般为1,默认频率下,30分钟麦麦回复30条(约数)" +path = "normal_chat.talk_frequency" type = "number" [[editor.quick_settings.items]] -name = "偷取表情包" -description = "是否偷取表情包,让麦麦可以发送她保存的这些表情包" -path = "emoji.steal_emoji" -type = "bool" - -[[editor.quick_settings.items]] -name = "核心性格" -description = "麦麦的核心性格描述,建议50字以内" -path = "personality.personality_core" -type = "text" - -[[editor.quick_settings.items]] -name = "自动专注阈值" +name = "自动专注阈值(auto模式)" description = "自动切换到专注聊天的阈值,越低越容易进入专注聊天" path = "chat.auto_focus_threshold" type = "number" [[editor.quick_settings.items]] -name = "自我识别处理器" +name = "退出专注阈值(auto模式)" +description = "自动退出专注聊天的阈值,越低越容易退出专注聊天" +path = "chat.exit_focus_threshold" +type = "number" + +[[editor.quick_settings.items]] +name = "思考间隔(focus模式)" +description = "思考的时间间隔(秒),可以有效减少消耗" +path = "focus_chat.think_interval" +type = "number" + +[[editor.quick_settings.items]] +name = "连续回复能力(focus模式)" +description = "连续回复能力,值越高,麦麦连续回复的概率越高" +path = "focus_chat.consecutive_replies" +type = "number" + +[[editor.quick_settings.items]] +name = "自我识别处理器(focus模式)" description = "是否启用自我识别处理器" path = "focus_chat_processor.self_identify_processor" type = "bool" [[editor.quick_settings.items]] -name = "工具使用处理器" +name = "工具使用处理器(focus模式)" description = "是否启用工具使用处理器" path = "focus_chat_processor.tool_use_processor" type = "bool" [[editor.quick_settings.items]] -name = "工作记忆处理器" +name = "工作记忆处理器(focus模式)" description = "是否启用工作记忆处理器,不稳定,消耗量大" path = "focus_chat_processor.working_memory_processor" type = "bool" +[[editor.quick_settings.items]] +name = "显示聊天模式(debug模式)" +description = "是否在回复后显示当前聊天模式" +path = "experimental.debug_show_chat_mode" +type = "bool" + + + [translations.sections.inner] name = "版本" description = "麦麦的内部配置,包含版本号等信息。此部分仅供显示,不可编辑。" @@ -276,6 +298,10 @@ description = "需要降低回复频率的群组列表" name = "思考间隔" description = "思考的时间间隔(秒),可以有效减少消耗" +[translations.items.consecutive_replies] +name = "连续回复能力" +description = "连续回复能力,值越高,麦麦连续回复的概率越高" + [translations.items.observation_context_size] name = "观察上下文大小" description = "观察到的最长上下文大小,建议15,太短太长都会导致脑袋尖尖" @@ -488,6 +514,10 @@ description = "暂时无效" name = "启用分割器" description = "是否启用回复分割器" +[translations.items."telemetry.enable"] +name = "启用遥测" +description = "是否发送统计信息,主要是看全球有多少只麦麦" + [translations.items."chinese_typo.enable"] name = "启用错别字" description = "是否启用中文错别字生成器" diff --git a/src/chat/focus_chat/planners/actions/no_reply_action.py b/src/chat/focus_chat/planners/actions/no_reply_action.py index 1d9abc7b..1b21a8ce 100644 --- a/src/chat/focus_chat/planners/actions/no_reply_action.py +++ b/src/chat/focus_chat/planners/actions/no_reply_action.py @@ -11,7 +11,7 @@ from src.chat.focus_chat.hfc_utils import parse_thinking_id_to_timestamp logger = get_logger("action_taken") # 常量定义 -WAITING_TIME_THRESHOLD = 300 # 等待新消息时间阈值,单位秒 +WAITING_TIME_THRESHOLD = 1200 # 等待新消息时间阈值,单位秒 @register_action diff --git a/src/chat/focus_chat/planners/actions/reply_action.py b/src/chat/focus_chat/planners/actions/reply_action.py index df341339..349038dc 100644 --- a/src/chat/focus_chat/planners/actions/reply_action.py +++ b/src/chat/focus_chat/planners/actions/reply_action.py @@ -8,6 +8,7 @@ from src.chat.focus_chat.expressors.default_expressor import DefaultExpressor from src.chat.message_receive.chat_stream import ChatStream from src.chat.heart_flow.observation.chatting_observation import ChattingObservation from src.chat.focus_chat.hfc_utils import create_empty_anchor_message +from src.config.config import global_config logger = get_logger("action_taken") @@ -34,7 +35,7 @@ class ReplyAction(BaseAction): "一次只回复一个人,一次只回复一个话题,突出重点", "如果是自己发的消息想继续,需自然衔接", "避免重复或评价自己的发言,不要和自己聊天", - "注意:回复尽量简短一些。可以参考贴吧,知乎和微博的回复风格,回复不要浮夸,不要用夸张修辞,平淡一些。不要有额外的符号,尽量简单简短", + f"注意你的回复要求:{global_config.expression.expression_style}", ] associated_types: list[str] = ["text", "emoji"] diff --git a/src/chat/focus_chat/planners/modify_actions.py b/src/chat/focus_chat/planners/modify_actions.py index c376426a..1648e6cf 100644 --- a/src/chat/focus_chat/planners/modify_actions.py +++ b/src/chat/focus_chat/planners/modify_actions.py @@ -133,7 +133,7 @@ class ActionModifier: reply_sequence.append(action_type == "reply") # 检查no_reply比例 - print(f"no_reply_count: {no_reply_count}, len(recent_cycles): {len(recent_cycles)}") + # print(f"no_reply_count: {no_reply_count}, len(recent_cycles): {len(recent_cycles)}") # print(1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111) if len(recent_cycles) >= (5 * global_config.chat.exit_focus_threshold) and ( no_reply_count / len(recent_cycles) @@ -143,20 +143,45 @@ class ActionModifier: result["remove"].append("no_reply") result["remove"].append("reply") - # 获取最近三次的reply状态 - last_three = reply_sequence[-3:] if len(reply_sequence) >= 3 else reply_sequence + # 计算连续回复的相关阈值 + + max_reply_num = int(global_config.focus_chat.consecutive_replies * 3.2) + sec_thres_reply_num = int(global_config.focus_chat.consecutive_replies * 2) + one_thres_reply_num = int(global_config.focus_chat.consecutive_replies * 1.5) + + # 获取最近max_reply_num次的reply状态 + if len(reply_sequence) >= max_reply_num: + last_max_reply_num = reply_sequence[-max_reply_num:] + else: + last_max_reply_num = reply_sequence[:] + + # 详细打印阈值和序列信息,便于调试 + logger.debug( + f"连续回复阈值: max={max_reply_num}, sec={sec_thres_reply_num}, one={one_thres_reply_num}," + f"最近reply序列: {last_max_reply_num}" + ) + # print(f"consecutive_replies: {consecutive_replies}") # 根据最近的reply情况决定是否移除reply动作 - if len(last_three) >= 3 and all(last_three): - # 如果最近三次都是reply,直接移除 + if len(last_max_reply_num) >= max_reply_num and all(last_max_reply_num): + # 如果最近max_reply_num次都是reply,直接移除 result["remove"].append("reply") - elif len(last_three) >= 2 and all(last_three[-2:]): - # 如果最近两次都是reply,40%概率移除 - if random.random() < 0.4: + logger.info(f"最近{len(last_max_reply_num)}次回复中,有{no_reply_count}次no_reply,{len(last_max_reply_num) - no_reply_count}次reply,直接移除") + elif len(last_max_reply_num) >= sec_thres_reply_num and all(last_max_reply_num[-sec_thres_reply_num:]): + # 如果最近sec_thres_reply_num次都是reply,40%概率移除 + if random.random() < 0.4 / global_config.focus_chat.consecutive_replies: result["remove"].append("reply") - elif last_three and last_three[-1]: - # 如果最近一次是reply,20%概率移除 - if random.random() < 0.2: + logger.info(f"最近{len(last_max_reply_num)}次回复中,有{no_reply_count}次no_reply,{len(last_max_reply_num) - no_reply_count}次reply,{0.4 / global_config.focus_chat.consecutive_replies}概率移除,移除") + else: + logger.debug(f"最近{len(last_max_reply_num)}次回复中,有{no_reply_count}次no_reply,{len(last_max_reply_num) - no_reply_count}次reply,{0.4 / global_config.focus_chat.consecutive_replies}概率移除,不移除") + elif len(last_max_reply_num) >= one_thres_reply_num and all(last_max_reply_num[-one_thres_reply_num:]): + # 如果最近one_thres_reply_num次都是reply,20%概率移除 + if random.random() < 0.2 / global_config.focus_chat.consecutive_replies: result["remove"].append("reply") + logger.info(f"最近{len(last_max_reply_num)}次回复中,有{no_reply_count}次no_reply,{len(last_max_reply_num) - no_reply_count}次reply,{0.2 / global_config.focus_chat.consecutive_replies}概率移除,移除") + else: + logger.debug(f"最近{len(last_max_reply_num)}次回复中,有{no_reply_count}次no_reply,{len(last_max_reply_num) - no_reply_count}次reply,{0.2 / global_config.focus_chat.consecutive_replies}概率移除,不移除") + else: + logger.debug(f"最近{len(last_max_reply_num)}次回复中,有{no_reply_count}次no_reply,{len(last_max_reply_num) - no_reply_count}次reply,无需移除") return result diff --git a/src/chat/memory_system/Hippocampus.py b/src/chat/memory_system/Hippocampus.py index 4ed26e5e..e63840f1 100644 --- a/src/chat/memory_system/Hippocampus.py +++ b/src/chat/memory_system/Hippocampus.py @@ -239,7 +239,7 @@ class Hippocampus: # 不再需要 time_info 参数 prompt = ( f'这是一段文字:\n{text}\n\n我想让你基于这段文字来概括"{topic}"这个概念,帮我总结成一句自然的话,' - f"要求包含对这个概念的定义,内容,知识,可以包含时间和人物。只输出这句话就好" + f"要求包含对这个概念的定义,内容,知识,但是这些信息必须来自这段文字,不能添加信息。\n,请包含时间和人物。只输出这句话就好" ) return prompt diff --git a/src/common/logger.py b/src/common/logger.py index 51d6e6ed..616b4487 100644 --- a/src/common/logger.py +++ b/src/common/logger.py @@ -885,6 +885,17 @@ API_SERVER_STYLE_CONFIG = { }, } +ACTION_MANAGER_STYLE_CONFIG = { + "advanced": { + "console_format": "{time:HH:mm:ss} | 动作选择 | {message}", + "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 动作选择 | {message}", + }, + "simple": { + "console_format": "{time:HH:mm:ss} | 动作选择 | {message}", + "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 动作选择 | {message}", + }, +} + # maim_message 消息服务样式配置 MAIM_MESSAGE_STYLE_CONFIG = { "advanced": { @@ -909,6 +920,9 @@ EMOJI_STYLE_CONFIG = EMOJI_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else EMOJI_ST PFC_ACTION_PLANNER_STYLE_CONFIG = ( PFC_ACTION_PLANNER_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else PFC_ACTION_PLANNER_STYLE_CONFIG["advanced"] ) +ACTION_MANAGER_STYLE_CONFIG = ( + ACTION_MANAGER_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else ACTION_MANAGER_STYLE_CONFIG["advanced"] +) REMOTE_STYLE_CONFIG = REMOTE_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else REMOTE_STYLE_CONFIG["advanced"] BASE_TOOL_STYLE_CONFIG = BASE_TOOL_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else BASE_TOOL_STYLE_CONFIG["advanced"] PERSON_INFO_STYLE_CONFIG = PERSON_INFO_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else PERSON_INFO_STYLE_CONFIG["advanced"] diff --git a/src/common/logger_manager.py b/src/common/logger_manager.py index 317c41e3..be75b001 100644 --- a/src/common/logger_manager.py +++ b/src/common/logger_manager.py @@ -48,6 +48,7 @@ from src.common.logger import ( API_SERVER_STYLE_CONFIG, NORMAL_CHAT_RESPONSE_STYLE_CONFIG, EXPRESS_STYLE_CONFIG, + ACTION_MANAGER_STYLE_CONFIG, ) # 可根据实际需要补充更多模块配置 @@ -100,6 +101,7 @@ MODULE_LOGGER_CONFIGS = { "normal_chat": NORMAL_CHAT_STYLE_CONFIG, # 一般水群 "focus_chat": FOCUS_CHAT_STYLE_CONFIG, # 专注水群 "expressor": EXPRESS_STYLE_CONFIG, # 麦麦表达 + "action_manager": ACTION_MANAGER_STYLE_CONFIG, # 动作选择 # ...如有更多模块,继续添加... } diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 8f98256e..af729db3 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -141,8 +141,11 @@ class FocusChatConfig(ConfigBase): compress_length_limit: int = 5 """最多压缩份数,超过该数值的压缩上下文会被删除""" - think_interval: int = 1 + think_interval: float = 1 """思考间隔(秒)""" + + consecutive_replies: float = 1 + """连续回复能力,值越高,麦麦连续回复的概率越高""" @dataclass diff --git a/src/plugins/test_plugin_pic/actions/pic_action.py b/src/plugins/test_plugin_pic/actions/pic_action.py index abf869e0..a2526d2c 100644 --- a/src/plugins/test_plugin_pic/actions/pic_action.py +++ b/src/plugins/test_plugin_pic/actions/pic_action.py @@ -34,7 +34,7 @@ class PicAction(PluginAction): "当有人要求你生成并发送一张图片时使用", "当有人让你画一张图时使用", ] - default = True + default = False action_config_file_name = "pic_action_config.toml" def __init__( diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index 100e0c6d..95d329cd 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "2.6.0" +version = "2.7.0" #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- #如果你想要修改配置文件,请在修改后将version的值进行变更 @@ -40,7 +40,7 @@ identity_detail = [ [expression] # 表达方式 -expression_style = "描述麦麦说话的表达风格,表达习惯" +expression_style = "描述麦麦说话的表达风格,表达习惯,例如:(回复尽量简短一些。可以参考贴吧,知乎和微博的回复风格,回复不要浮夸,不要用夸张修辞,平淡一些。不要有额外的符号,尽量简单简短)" enable_expression_learning = true # 是否启用表达学习,麦麦会学习人类说话风格 learning_interval = 600 # 学习间隔 单位秒 @@ -92,6 +92,8 @@ talk_frequency_down_groups = [] #降低回复频率的群号码 [focus_chat] #专注聊天 think_interval = 3 # 思考间隔 单位秒,可以有效减少消耗 +consecutive_replies = 1 # 连续回复能力,值越高,麦麦连续回复的概率越高 + observation_context_size = 16 # 观察到的最长上下文大小,建议15,太短太长都会导致脑袋尖尖 compressed_length = 8 # 不能大于observation_context_size,心流上下文压缩的最短压缩长度,超过心流观察到的上下文长度,会压缩,最短压缩长度为5 @@ -194,16 +196,18 @@ temp = 0.2 #模型的温度,新V3建议0.1-0.3 # 强烈建议使用免费的小模型 name = "Qwen/Qwen3-8B" provider = "SILICONFLOW" -enable_thinking = false # 是否启用思考 pri_in = 0 pri_out = 0 +temp = 0.7 +enable_thinking = false # 是否启用思考 [model.memory_summary] # 记忆的概括模型 name = "Qwen/Qwen3-30B-A3B" provider = "SILICONFLOW" -enable_thinking = false # 是否启用思考 pri_in = 0.7 pri_out = 2.8 +temp = 0.7 +enable_thinking = false # 是否启用思考 [model.vlm] # 图像识别模型 name = "Pro/Qwen/Qwen2.5-VL-7B-Instruct" @@ -211,6 +215,7 @@ provider = "SILICONFLOW" pri_in = 0.35 pri_out = 0.35 + #嵌入模型 [model.embedding] name = "BAAI/bge-m3" @@ -225,6 +230,7 @@ name = "Pro/deepseek-ai/DeepSeek-R1" provider = "SILICONFLOW" pri_in = 4.0 #模型的输入价格(非必填,可以记录消耗) pri_out = 16.0 #模型的输出价格(非必填,可以记录消耗) +temp = 0.7 [model.normal_chat_2] # 一般聊天模式的次要回复模型,推荐使用 非推理模型 name = "Pro/deepseek-ai/DeepSeek-V3" @@ -239,9 +245,10 @@ temp = 0.2 #模型的温度,新V3建议0.1-0.3 [model.focus_working_memory] #工作记忆模型 name = "Qwen/Qwen3-30B-A3B" provider = "SILICONFLOW" -enable_thinking = false # 是否启用思考 +enable_thinking = false # 是否启用思考(qwen3 only) pri_in = 0.7 pri_out = 2.8 +temp = 0.7 [model.focus_chat_mind] #聊天规划:认真聊天时,生成麦麦对聊天的规划想法 name = "Pro/deepseek-ai/DeepSeek-V3" @@ -255,15 +262,16 @@ temp = 0.3 [model.focus_tool_use] #工具调用模型,需要使用支持工具调用的模型 name = "Qwen/Qwen3-14B" provider = "SILICONFLOW" -enable_thinking = false # 是否启用思考 pri_in = 0.5 pri_out = 2 +temp = 0.7 +enable_thinking = false # 是否启用思考(qwen3 only) [model.focus_planner] #决策:认真聊天时,负责决定麦麦该做什么 name = "Pro/deepseek-ai/DeepSeek-V3" # name = "Qwen/Qwen3-30B-A3B" provider = "SILICONFLOW" -# enable_thinking = false # 是否启用思考 +# enable_thinking = false # 是否启用思考(qwen3 only) pri_in = 2 pri_out = 8 temp = 0.3 @@ -274,7 +282,7 @@ temp = 0.3 name = "Pro/deepseek-ai/DeepSeek-V3" # name = "Qwen/Qwen3-30B-A3B" provider = "SILICONFLOW" -# enable_thinking = false # 是否启用思考 +# enable_thinking = false # 是否启用思考(qwen3 only) pri_in = 2 pri_out = 8 temp = 0.3 @@ -284,37 +292,10 @@ temp = 0.3 # name = "Pro/deepseek-ai/DeepSeek-V3" name = "Qwen/Qwen3-30B-A3B" provider = "SILICONFLOW" -enable_thinking = false # 是否启用思考 pri_in = 0.7 pri_out = 2.8 temp = 0.7 - - - -#私聊PFC:需要开启PFC功能,默认三个模型均为硅基流动v3,如果需要支持多人同时私聊或频繁调用,建议把其中的一个或两个换成官方v3或其它模型,以免撞到429 - -#PFC决策模型 -[model.pfc_action_planner] -name = "Pro/deepseek-ai/DeepSeek-V3" -provider = "SILICONFLOW" -temp = 0.3 -pri_in = 2 -pri_out = 8 - -#PFC聊天模型 -[model.pfc_chat] -name = "Pro/deepseek-ai/DeepSeek-V3" -provider = "SILICONFLOW" -temp = 0.3 -pri_in = 2 -pri_out = 8 - -#PFC检查模型 -[model.pfc_reply_checker] -name = "Pro/deepseek-ai/DeepSeek-V3" -provider = "SILICONFLOW" -pri_in = 2 -pri_out = 8 +enable_thinking = false # 是否启用思考(qwen3 only) @@ -335,7 +316,6 @@ enable = true [experimental] #实验性功能 debug_show_chat_mode = false # 是否在回复后显示当前聊天模式 enable_friend_chat = false # 是否启用好友聊天 -pfc_chatting = false # 暂时无效