From 7cb546c816e831fc6268da65429a3312af09bb37 Mon Sep 17 00:00:00 2001 From: tcmofashi Date: Sun, 1 Jun 2025 00:55:26 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0vtb=5Faction?= =?UTF-8?q?=EF=BC=8C=E6=90=AD=E9=85=8DAmaidesu=E5=8F=AF=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=AF=B9live2d=E5=8A=A8=E4=BD=9C=E7=9A=84=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/focus_chat/planners/planner.py | 23 +++--- src/plugins/vtb_action/__init__.py | 0 src/plugins/vtb_action/actions/__init__.py | 1 + src/plugins/vtb_action/actions/vtb_action.py | 74 ++++++++++++++++++++ 4 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 src/plugins/vtb_action/__init__.py create mode 100644 src/plugins/vtb_action/actions/__init__.py create mode 100644 src/plugins/vtb_action/actions/vtb_action.py diff --git a/src/chat/focus_chat/planners/planner.py b/src/chat/focus_chat/planners/planner.py index a0b0ccf9c..298da3115 100644 --- a/src/chat/focus_chat/planners/planner.py +++ b/src/chat/focus_chat/planners/planner.py @@ -29,14 +29,6 @@ def init_prompt(): {self_info_block} {extra_info_block} {memory_str} -你需要基于以下信息决定如何参与对话 -这些信息可能会有冲突,请你整合这些信息,并选择一个最合适的action: -{chat_content_block} - -{mind_info_block} -{cycle_info_block} - -请综合分析聊天内容和你看到的新消息,参考聊天规划,选择合适的action: 注意,除了下面动作选项之外,你在群聊里不能做其他任何事情,这是你能力的边界,现在请你选择合适的action: {action_options_text} @@ -46,6 +38,15 @@ def init_prompt(): {moderation_prompt} +你需要基于以下信息决定如何参与对话 +这些信息可能会有冲突,请你整合这些信息,并选择一个最合适的action: +{chat_content_block} + +{mind_info_block} +{cycle_info_block} + +请综合分析聊天内容和你看到的新消息,参考聊天规划,选择合适的action: + 请你以下面格式输出你选择的action: {{ "action": "action_name", @@ -270,7 +271,6 @@ class ActionPlanner: ) -> str: """构建 Planner LLM 的提示词 (获取模板并填充数据)""" try: - memory_str = "" if global_config.focus_chat.parallel_processing: memory_str = "" @@ -278,10 +278,7 @@ class ActionPlanner: memory_str = "以下是当前在聊天中,你回忆起的记忆:\n" for running_memory in running_memorys: memory_str += f"{running_memory['topic']}: {running_memory['content']}\n" - - - - + chat_context_description = "你现在正在一个群聊中" chat_target_name = None # Only relevant for private if not is_group_chat and chat_target_info: diff --git a/src/plugins/vtb_action/__init__.py b/src/plugins/vtb_action/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/plugins/vtb_action/actions/__init__.py b/src/plugins/vtb_action/actions/__init__.py new file mode 100644 index 000000000..7a85b034b --- /dev/null +++ b/src/plugins/vtb_action/actions/__init__.py @@ -0,0 +1 @@ +from . import vtb_action # noqa diff --git a/src/plugins/vtb_action/actions/vtb_action.py b/src/plugins/vtb_action/actions/vtb_action.py new file mode 100644 index 000000000..79d6914fb --- /dev/null +++ b/src/plugins/vtb_action/actions/vtb_action.py @@ -0,0 +1,74 @@ +from src.common.logger_manager import get_logger +from src.chat.focus_chat.planners.actions.plugin_action import PluginAction, register_action +from typing import Tuple + +logger = get_logger("vtb_action") + + +@register_action +class VTBAction(PluginAction): + """VTB虚拟主播动作处理类""" + + action_name = "vtb_action" + action_description = "使用虚拟主播预设动作表达心情或感觉,适用于需要生动表达情感的场景" + action_parameters = { + "text": "描述想要表达的心情或感觉的文本内容,必填,应当是对情感状态的自然描述", + } + action_require = [ + "当需要表达特定情感或心情时使用", + "当用户明确要求使用虚拟主播动作时使用", + "当回应内容需要更生动的情感表达时使用", + "当想要通过预设动作增强互动体验时使用", + ] + default = True # 设为默认动作 + associated_types = ["vtb_text"] + + async def process(self) -> Tuple[bool, str]: + """处理VTB虚拟主播动作""" + logger.info(f"{self.log_prefix} 执行VTB动作: {self.reasoning}") + + # 获取要表达的心情或感觉文本 + text = self.action_data.get("text") + + if not text: + logger.error(f"{self.log_prefix} 执行VTB动作时未提供文本内容") + return False, "执行VTB动作失败:未提供文本内容" + + # 处理文本使其更适合VTB动作表达 + processed_text = self._process_text_for_vtb(text) + + try: + # 发送VTB动作消息 + await self.send_message(type="vtb_text", data=processed_text) + + logger.info(f"{self.log_prefix} VTB动作执行成功,文本内容: {processed_text}") + return True, "VTB动作执行成功" + + except Exception as e: + logger.error(f"{self.log_prefix} 执行VTB动作时出错: {e}") + return False, f"执行VTB动作时出错: {e}" + + def _process_text_for_vtb(self, text: str) -> str: + """ + 处理文本使其更适合VTB动作表达 + - 优化情感表达的准确性 + - 规范化心情描述格式 + - 确保文本适合虚拟主播动作系统理解 + """ + # 简单示例实现 + processed_text = text.strip() + + # 移除多余的空格和换行 + import re + + processed_text = re.sub(r"\s+", " ", processed_text) + + # 确保文本长度适中,避免过长的描述 + if len(processed_text) > 100: + processed_text = processed_text[:100] + "..." + + # 如果文本为空,提供默认的情感描述 + if not processed_text: + processed_text = "平静" + + return processed_text From 48adf192d08c1f099fa3fe318b6aa5fbe1e73b01 Mon Sep 17 00:00:00 2001 From: tcmofashi Date: Sun, 1 Jun 2025 08:09:31 +0800 Subject: [PATCH 2/4] ruff format --- scripts/070configexe.py | 300 ++++++++++-------- src/chat/focus_chat/heartFC_Cycleinfo.py | 39 ++- src/chat/focus_chat/heartFC_chat.py | 18 +- .../focus_chat/planners/modify_actions.py | 25 +- .../observation/actions_observation.py | 2 +- .../observation/chatting_observation.py | 2 +- .../observation/hfcloop_observation.py | 20 +- .../heart_flow/observation/observation.py | 2 +- .../observation/structure_observation.py | 2 +- .../observation/working_observation.py | 8 +- src/config/official_configs.py | 8 +- src/llm_models/utils_model.py | 2 +- 12 files changed, 239 insertions(+), 189 deletions(-) diff --git a/scripts/070configexe.py b/scripts/070configexe.py index be1f56e42..d66e857c0 100644 --- a/scripts/070configexe.py +++ b/scripts/070configexe.py @@ -8,6 +8,7 @@ import threading import time import sys + class ConfigEditor: def __init__(self, root): self.root = root @@ -21,10 +22,10 @@ class ConfigEditor: # 加载配置 self.load_config() - + # 加载环境变量 self.load_env_vars() - + # 自动保存相关 self.last_save_time = time.time() self.save_timer = None @@ -114,40 +115,40 @@ class ConfigEditor: 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: + with open(env_path, "r", encoding="utf-8") as f: env_content = f.read() - + # 解析环境变量 env_vars = {} - for line in env_content.split('\n'): + for line in env_content.split("\n"): line = line.strip() - if not line or line.startswith('#'): + if not line or line.startswith("#"): continue - - if '=' in line: - key, value = line.split('=', 1) + + if "=" in line: + key, value = line.split("=", 1) key = key.strip() value = value.strip() - + # 检查是否是目标变量 - if key.endswith('_BASE_URL') or key.endswith('_KEY'): + if key.endswith("_BASE_URL") or key.endswith("_KEY"): # 提取前缀(去掉_BASE_URL或_KEY) - prefix = key[:-9] if key.endswith('_BASE_URL') else key[:-4] + 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) - + 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)}") @@ -156,11 +157,11 @@ class ConfigEditor: 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)) - + # 添加配置按钮 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) @@ -175,13 +176,22 @@ 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 not in ("inner", "env_vars", "telemetry", "experimental", "maim_message", "keyword_reaction", "message_receive", "relationship"): + 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,)) @@ -196,7 +206,7 @@ class ConfigEditor: # 创建编辑区标题 # 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) @@ -245,15 +255,15 @@ class ConfigEditor: # --- 修改开始: 改进翻译查找逻辑 --- full_config_path_key = ".".join(path + [key]) # 例如 "chinese_typo.enable" - + model_item_translations = { "name": ("模型名称", "模型的唯一标识或名称"), "provider": ("模型提供商", "模型API的提供商"), "pri_in": ("输入价格", "模型输入的价格/消耗"), "pri_out": ("输出价格", "模型输出的价格/消耗"), - "temp": ("模型温度", "控制模型输出的多样性") + "temp": ("模型温度", "控制模型输出的多样性"), } - + item_name_to_display = key # 默认显示原始键名 item_desc_to_display = "" # 默认无描述 @@ -294,9 +304,15 @@ class ConfigEditor: # 判断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": + 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 @@ -318,15 +334,17 @@ class ConfigEditor: desc_row = 1 if item_desc_to_display: 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 # 内容控件在描述下方 + 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=("微软雅黑", 16)) - value_label.grid(row=widget_row, column=0, columnspan=content_col_offset_for_star +1, sticky=tk.W, padx=5) + 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): @@ -341,7 +359,7 @@ class ConfigEditor: # 数字使用数字输入框 var = tk.StringVar(value=str(value)) 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) + 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" @@ -380,7 +398,7 @@ class ConfigEditor: else: # 其他类型(字符串等)使用普通文本框 var = tk.StringVar(value=str(value)) - + # 特殊处理provider字段 full_path = ".".join(path + [key]) if key == "provider" and full_path.startswith("model."): @@ -397,37 +415,45 @@ class ConfigEditor: 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": "专注模式:自我识别模型" - } + # 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 = 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" @@ -436,14 +462,18 @@ class ConfigEditor: # 如果没有可用的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) + 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) + 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" @@ -468,7 +498,7 @@ class ConfigEditor: "model.focus_tool_use": "工具调用模型", "model.focus_planner": "决策模型", "model.focus_expressor": "表达器模型", - "model.focus_self_recognize": "自我识别模型" + "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 @@ -490,7 +520,7 @@ class ConfigEditor: 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): @@ -518,7 +548,7 @@ class ConfigEditor: section = self.tree.item(selection[0])["values"][0] # 使用values中的原始节名 self.current_section = section - + # 清空编辑器 for widget in self.content_frame.winfo_children(): widget.destroy() @@ -557,7 +587,7 @@ class ConfigEditor: # 创建描述标签 if setting.get("description"): - desc_label = ttk.Label(frame, text=setting['description'], foreground="gray", font=("微软雅黑", 10)) + desc_label = ttk.Label(frame, text=setting["description"], foreground="gray", font=("微软雅黑", 10)) desc_label.pack(fill=tk.X, padx=5, pady=(0, 2)) # 根据类型创建不同的控件 @@ -575,14 +605,14 @@ class ConfigEditor: value = str(value) if value is not None else "" var = tk.StringVar(value=value) entry = ttk.Entry(frame, textvariable=var, width=40, font=("微软雅黑", 12)) - entry.pack(fill=tk.X, padx=5, pady=(0,5)) + 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=("微软雅黑", 12)) - entry.pack(fill=tk.X, padx=5, pady=(0,5)) + 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": @@ -659,7 +689,7 @@ class ConfigEditor: # 获取所有控件的值 for path, widget in self.widgets.items(): # 跳过 env_vars 的控件赋值(只用于.env,不写回config) - if len(path) >= 2 and path[0] == 'env_vars': + if len(path) >= 2 and path[0] == "env_vars": continue value = self.get_widget_value(widget) current = self.config @@ -669,11 +699,11 @@ class ConfigEditor: current[final_key] = value # === 只保存 TOML,不包含 env_vars === - env_vars = self.config.pop('env_vars', None) + 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 + self.config["env_vars"] = env_vars # === 保存 env_vars 到 .env 文件(只覆盖特定key,其他内容保留) === env_path = self.editor_config["config"].get("env_file", ".env") @@ -687,7 +717,7 @@ class ConfigEditor: # 2. 收集所有目标key的新值(直接从widgets取) new_env_dict = {} for path, widget in self.widgets.items(): - if len(path) == 2 and path[0] == 'env_vars': + 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) @@ -715,15 +745,15 @@ class ConfigEditor: # === 保存完 .env 后,同步 widgets 的值回 self.config['env_vars'] === for path, widget in self.widgets.items(): - if len(path) == 2 and path[0] == 'env_vars': + 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) + 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 @@ -862,62 +892,60 @@ class ConfigEditor: """创建环境变量组""" 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 = 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 = 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 = 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']) + 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): """添加新的环境变量组""" @@ -925,42 +953,39 @@ class ConfigEditor: 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": "" - } + 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] + if "env_vars" in self.config: + del self.config["env_vars"][prefix] # 刷新显示 self.refresh_env_vars_section() self.on_value_changed() @@ -971,7 +996,7 @@ class ConfigEditor: for widget in self.content_frame.winfo_children(): widget.destroy() self.widgets.clear() - + # 重新创建编辑区 self.create_env_vars_section(self.content_frame) @@ -980,10 +1005,10 @@ class ConfigEditor: 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) @@ -1003,7 +1028,9 @@ class ConfigEditor: 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"]) + self.create_section_widgets( + recv_frame, "message_receive", self.config["message_receive"], ["message_receive"] + ) # 关系栏 if "relationship" in self.config: rel_frame = ttk.Frame(notebook) @@ -1015,96 +1042,95 @@ class ConfigEditor: 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) - + os.execv(sys.executable, ["python"] + sys.argv) + def browse_bot_config(): file_path = filedialog.askopenfilename( - title="选择bot_config.toml文件", - filetypes=[("TOML文件", "*.toml"), ("所有文件", "*.*")] + 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"), ("所有文件", "*.*")] + 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() _app = ConfigEditor(root) diff --git a/src/chat/focus_chat/heartFC_Cycleinfo.py b/src/chat/focus_chat/heartFC_Cycleinfo.py index 5a9a52fd8..129a58af8 100644 --- a/src/chat/focus_chat/heartFC_Cycleinfo.py +++ b/src/chat/focus_chat/heartFC_Cycleinfo.py @@ -1,9 +1,10 @@ import time import os -from typing import List, Optional, Dict, Any +from typing import Optional, Dict, Any log_dir = "log/log_cycle_debug/" + class CycleDetail: """循环信息记录类""" @@ -23,35 +24,40 @@ class CycleDetail: def to_dict(self) -> Dict[str, Any]: """将循环信息转换为字典格式""" + def convert_to_serializable(obj, depth=0, seen=None): if seen is None: seen = set() - + # 防止递归过深 if depth > 5: # 降低递归深度限制 return str(obj) - + # 防止循环引用 obj_id = id(obj) if obj_id in seen: return str(obj) seen.add(obj_id) - + try: - if hasattr(obj, 'to_dict'): + if hasattr(obj, "to_dict"): # 对于有to_dict方法的对象,直接调用其to_dict方法 return obj.to_dict() elif isinstance(obj, dict): # 对于字典,只保留基本类型和可序列化的值 - return {k: convert_to_serializable(v, depth + 1, seen) - for k, v in obj.items() - if isinstance(k, (str, int, float, bool))} + return { + k: convert_to_serializable(v, depth + 1, seen) + for k, v in obj.items() + if isinstance(k, (str, int, float, bool)) + } elif isinstance(obj, (list, tuple)): # 对于列表和元组,只保留可序列化的元素 - return [convert_to_serializable(item, depth + 1, seen) - for item in obj - if not isinstance(item, (dict, list, tuple)) or - isinstance(item, (str, int, float, bool, type(None)))] + return [ + convert_to_serializable(item, depth + 1, seen) + for item in obj + if not isinstance(item, (dict, list, tuple)) + or isinstance(item, (str, int, float, bool, type(None))) + ] elif isinstance(obj, (str, int, float, bool, type(None))): return obj else: @@ -74,19 +80,19 @@ class CycleDetail: def complete_cycle(self): """完成循环,记录结束时间""" self.end_time = time.time() - + # 处理 prefix,只保留中英文字符 if not self.prefix: self.prefix = "group" else: # 只保留中文和英文字符 - self.prefix = ''.join(char for char in self.prefix if '\u4e00' <= char <= '\u9fff' or char.isascii()) + self.prefix = "".join(char for char in self.prefix if "\u4e00" <= char <= "\u9fff" or char.isascii()) if not self.prefix: self.prefix = "group" - + current_time_minute = time.strftime("%Y%m%d_%H%M", time.localtime()) self.log_cycle_to_file(log_dir + self.prefix + f"/{current_time_minute}_cycle_" + str(self.cycle_id) + ".json") - + def log_cycle_to_file(self, file_path: str): """将循环信息写入文件""" # 如果目录不存在,则创建目录 @@ -95,6 +101,7 @@ class CycleDetail: os.makedirs(dir_name, exist_ok=True) # 写入文件 import json + with open(file_path, "a", encoding="utf-8") as f: f.write(json.dumps(self.to_dict(), ensure_ascii=False) + "\n") diff --git a/src/chat/focus_chat/heartFC_chat.py b/src/chat/focus_chat/heartFC_chat.py index c69dea6b7..2fef2a448 100644 --- a/src/chat/focus_chat/heartFC_chat.py +++ b/src/chat/focus_chat/heartFC_chat.py @@ -418,7 +418,9 @@ class HeartFChatting: # 记录耗时 processor_time_costs[processor_name] = duration_since_parallel_start except asyncio.TimeoutError: - logger.info(f"{self.log_prefix} 处理器 {processor_name} 超时(>{global_config.focus_chat.processor_max_time}s),已跳过") + logger.info( + f"{self.log_prefix} 处理器 {processor_name} 超时(>{global_config.focus_chat.processor_max_time}s),已跳过" + ) processor_time_costs[processor_name] = global_config.focus_chat.processor_max_time except Exception as e: logger.error( @@ -462,7 +464,7 @@ class HeartFChatting: } self.all_observations = observations - + with Timer("调整动作", cycle_timers): # 处理特殊的观察 await self.action_modifier.modify_actions(observations=observations) @@ -476,26 +478,24 @@ class HeartFChatting: with Timer("并行回忆和处理", cycle_timers): memory_task = asyncio.create_task(self.memory_activator.activate_memory(observations)) processor_task = asyncio.create_task(self._process_processors(observations, [])) - + # 等待两个任务完成 - running_memorys, (all_plan_info, processor_time_costs) = await asyncio.gather(memory_task, processor_task) + running_memorys, (all_plan_info, processor_time_costs) = await asyncio.gather( + memory_task, processor_task + ) else: # 串行执行 with Timer("回忆", cycle_timers): running_memorys = await self.memory_activator.activate_memory(observations) with Timer("执行 信息处理器", cycle_timers): - all_plan_info, processor_time_costs = await self._process_processors( - observations, running_memorys - ) + all_plan_info, processor_time_costs = await self._process_processors(observations, running_memorys) loop_processor_info = { "all_plan_info": all_plan_info, "processor_time_costs": processor_time_costs, } - - with Timer("规划器", cycle_timers): plan_result = await self.action_planner.plan(all_plan_info, running_memorys) diff --git a/src/chat/focus_chat/planners/modify_actions.py b/src/chat/focus_chat/planners/modify_actions.py index 731fe5f90..6e7afa65f 100644 --- a/src/chat/focus_chat/planners/modify_actions.py +++ b/src/chat/focus_chat/planners/modify_actions.py @@ -30,7 +30,6 @@ class ActionModifier: observations: Optional[List[Observation]] = None, **kwargs: Any, ): - # 处理Observation对象 if observations: # action_info = ActionInfo() @@ -163,22 +162,34 @@ class ActionModifier: if len(last_max_reply_num) >= max_reply_num and all(last_max_reply_num): # 如果最近max_reply_num次都是reply,直接移除 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,直接移除") + 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") - 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}概率移除,移除") + 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}概率移除,不移除") + 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}概率移除,移除") + 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}概率移除,不移除") + 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,无需移除") + 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/heart_flow/observation/actions_observation.py b/src/chat/heart_flow/observation/actions_observation.py index 6f0cd81c3..6550ddb72 100644 --- a/src/chat/heart_flow/observation/actions_observation.py +++ b/src/chat/heart_flow/observation/actions_observation.py @@ -42,5 +42,5 @@ class ActionObservation: "observe_id": self.observe_id, "last_observe_time": self.last_observe_time, "all_actions": self.all_actions, - "all_using_actions": self.all_using_actions + "all_using_actions": self.all_using_actions, } diff --git a/src/chat/heart_flow/observation/chatting_observation.py b/src/chat/heart_flow/observation/chatting_observation.py index 7e9e562d0..ba98a8e50 100644 --- a/src/chat/heart_flow/observation/chatting_observation.py +++ b/src/chat/heart_flow/observation/chatting_observation.py @@ -81,7 +81,7 @@ class ChattingObservation(Observation): "person_list": self.person_list, "oldest_messages_str": self.oldest_messages_str, "compressor_prompt": self.compressor_prompt, - "last_observe_time": self.last_observe_time + "last_observe_time": self.last_observe_time, } async def initialize(self): diff --git a/src/chat/heart_flow/observation/hfcloop_observation.py b/src/chat/heart_flow/observation/hfcloop_observation.py index 48bf33ede..1e1c7fe07 100644 --- a/src/chat/heart_flow/observation/hfcloop_observation.py +++ b/src/chat/heart_flow/observation/hfcloop_observation.py @@ -39,7 +39,7 @@ class HFCloopObservation: responses_for_prompt = [] cycle_last_reason = "" - + # 检查这最近的活动循环中有多少是连续的文本回复 (从最近的开始看) for cycle in recent_active_cycles: action_type = cycle.loop_plan_info["action_result"]["action_type"] @@ -57,29 +57,33 @@ class HFCloopObservation: action_reasoning_str = f"你选择这个action的原因是:{action_reasoning}" else: action_reasoning_str = "" - + if action_type == "reply": consecutive_text_replies += 1 response_text = cycle.loop_plan_info["action_result"]["action_data"].get("text", "[空回复]") responses_for_prompt.append(response_text) - + if is_taken: action_detailed_str += f"{action_taken_time_str}时,你选择回复(action:{action_type},内容是:'{response_text}')。{action_reasoning_str}\n" else: action_detailed_str += f"{action_taken_time_str}时,你选择回复(action:{action_type},内容是:'{response_text}'),但是动作失败了。{action_reasoning_str}\n" elif action_type == "no_reply": - action_detailed_str += f"{action_taken_time_str}时,你选择不回复(action:{action_type}),{action_reasoning_str}\n" + action_detailed_str += ( + f"{action_taken_time_str}时,你选择不回复(action:{action_type}),{action_reasoning_str}\n" + ) else: if is_taken: - action_detailed_str += f"{action_taken_time_str}时,你选择执行了(action:{action_type}),{action_reasoning_str}\n" + action_detailed_str += ( + f"{action_taken_time_str}时,你选择执行了(action:{action_type}),{action_reasoning_str}\n" + ) else: action_detailed_str += f"{action_taken_time_str}时,你选择执行了(action:{action_type}),但是动作失败了。{action_reasoning_str}\n" - + if action_detailed_str: cycle_info_block = f"\n你最近做的事:\n{action_detailed_str}\n" else: cycle_info_block = "\n" - + # 根据连续文本回复的数量构建提示信息 if consecutive_text_replies >= 3: # 如果最近的三个活动都是文本回复 cycle_info_block = f'你已经连续回复了三条消息(最近: "{responses_for_prompt[0]}",第二近: "{responses_for_prompt[1]}",第三近: "{responses_for_prompt[2]}")。你回复的有点多了,请注意' @@ -116,5 +120,5 @@ class HFCloopObservation: "observe_id": self.observe_id, "last_observe_time": self.last_observe_time, # 不序列化history_loop,避免循环引用 - "history_loop_count": len(self.history_loop) + "history_loop_count": len(self.history_loop), } diff --git a/src/chat/heart_flow/observation/observation.py b/src/chat/heart_flow/observation/observation.py index 5c8b5fda4..6396cda06 100644 --- a/src/chat/heart_flow/observation/observation.py +++ b/src/chat/heart_flow/observation/observation.py @@ -18,7 +18,7 @@ class Observation: return { "observe_info": self.observe_info, "observe_id": self.observe_id, - "last_observe_time": self.last_observe_time + "last_observe_time": self.last_observe_time, } async def observe(self): diff --git a/src/chat/heart_flow/observation/structure_observation.py b/src/chat/heart_flow/observation/structure_observation.py index 6e670f5e9..cfe06e435 100644 --- a/src/chat/heart_flow/observation/structure_observation.py +++ b/src/chat/heart_flow/observation/structure_observation.py @@ -22,7 +22,7 @@ class StructureObservation: "observe_id": self.observe_id, "last_observe_time": self.last_observe_time, "history_loop": self.history_loop, - "structured_info": self.structured_info + "structured_info": self.structured_info, } def get_observe_info(self): diff --git a/src/chat/heart_flow/observation/working_observation.py b/src/chat/heart_flow/observation/working_observation.py index 3cab4a375..e94343b01 100644 --- a/src/chat/heart_flow/observation/working_observation.py +++ b/src/chat/heart_flow/observation/working_observation.py @@ -39,6 +39,10 @@ class WorkingMemoryObservation: "observe_info": self.observe_info, "observe_id": self.observe_id, "last_observe_time": self.last_observe_time, - "working_memory": self.working_memory.to_dict() if hasattr(self.working_memory, 'to_dict') else str(self.working_memory), - "retrieved_working_memory": [item.to_dict() if hasattr(item, 'to_dict') else str(item) for item in self.retrieved_working_memory] + "working_memory": self.working_memory.to_dict() + if hasattr(self.working_memory, "to_dict") + else str(self.working_memory), + "retrieved_working_memory": [ + item.to_dict() if hasattr(item, "to_dict") else str(item) for item in self.retrieved_working_memory + ], } diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 1a1469fe0..274ec99e6 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -146,10 +146,10 @@ class FocusChatConfig(ConfigBase): consecutive_replies: float = 1 """连续回复能力,值越高,麦麦连续回复的概率越高""" - + parallel_processing: bool = False """是否允许处理器阶段和回忆阶段并行执行""" - + processor_max_time: int = 25 """处理器最大时间,单位秒,如果超过这个时间,处理器会自动停止""" @@ -166,13 +166,11 @@ class FocusChatProcessorConfig(ConfigBase): working_memory_processor: bool = True """是否启用工作记忆处理器""" - + lite_chat_mind_processor: bool = False """是否启用轻量级聊天思维处理器,可以节省token消耗和时间""" - - @dataclass class ExpressionConfig(ConfigBase): """表达配置类""" diff --git a/src/llm_models/utils_model.py b/src/llm_models/utils_model.py index 3df45460f..96212c725 100644 --- a/src/llm_models/utils_model.py +++ b/src/llm_models/utils_model.py @@ -753,7 +753,7 @@ class LLMRequest: response = await self._execute_request(endpoint="/chat/completions", payload=data, prompt=prompt) # 原样返回响应,不做处理 - + if len(response) == 3: content, reasoning_content, tool_calls = response return content, (reasoning_content, self.model_name, tool_calls) From c6a222e6a5b41dd7c99c80c2a8f361918e4bd5c9 Mon Sep 17 00:00:00 2001 From: tcmofashi Date: Sun, 1 Jun 2025 17:49:13 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dfocus=E5=90=9E?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/heart_flow/observation/chatting_observation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/chat/heart_flow/observation/chatting_observation.py b/src/chat/heart_flow/observation/chatting_observation.py index ba98a8e50..6fd180af5 100644 --- a/src/chat/heart_flow/observation/chatting_observation.py +++ b/src/chat/heart_flow/observation/chatting_observation.py @@ -89,6 +89,8 @@ class ChattingObservation(Observation): logger.debug(f"初始化observation: self.is_group_chat: {self.is_group_chat}") logger.debug(f"初始化observation: self.chat_target_info: {self.chat_target_info}") initial_messages = get_raw_msg_before_timestamp_with_chat(self.chat_id, self.last_observe_time, 10) + self.last_observe_time = initial_messages[-1]["time"] if initial_messages else self.last_observe_time + # logger.error(f"初始化observation: initial_messages: {initial_messages}\n\n\n\n{self.last_observe_time}") self.talking_message = initial_messages self.talking_message_str = await build_readable_messages(self.talking_message) From 2b6bd3b6274b857b72a81a00594971133b047bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A2=A8=E6=A2=93=E6=9F=92?= <1787882683@qq.com> Date: Sun, 1 Jun 2025 18:34:04 +0800 Subject: [PATCH 4/4] update --- README.md | 4 +++- src/config/config.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ceafd8c43..b29cfc5a0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ - MaiBot + MaiBot # 麦麦!MaiCore-MaiBot (编辑中) @@ -14,6 +14,7 @@ ![issues](https://img.shields.io/github/issues/MaiM-with-u/MaiBot) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/DrSmoothl/MaiBot) +
🌟 演示视频 | 🚀 快速入门 | @@ -21,6 +22,7 @@ 💬 讨论 | 🙋 贡献指南 +
## 🎉 介绍 diff --git a/src/config/config.py b/src/config/config.py index fc4ea0fca..4557c6d39 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -46,7 +46,7 @@ TEMPLATE_DIR = "template" # 考虑到,实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码 # 对该字段的更新,请严格参照语义化版本规范:https://semver.org/lang/zh-CN/ -MMC_VERSION = "0.7.0-snapshot.2" +MMC_VERSION = "0.7.0" def update_config():