diff --git a/src/chat/focus_chat/heartFC_chat.py b/src/chat/focus_chat/heartFC_chat.py index a0144294..7463791b 100644 --- a/src/chat/focus_chat/heartFC_chat.py +++ b/src/chat/focus_chat/heartFC_chat.py @@ -16,6 +16,7 @@ from src.chat.focus_chat.info.info_base import InfoBase from src.chat.focus_chat.info_processors.chattinginfo_processor import ChattingInfoProcessor from src.chat.focus_chat.info_processors.mind_processor import MindProcessor from src.chat.focus_chat.info_processors.working_memory_processor import WorkingMemoryProcessor +from src.chat.focus_chat.info_processors.action_processor import ActionProcessor from src.chat.heart_flow.observation.hfcloop_observation import HFCloopObservation from src.chat.heart_flow.observation.working_observation import WorkingMemoryObservation from src.chat.focus_chat.info_processors.tool_processor import ToolProcessor @@ -39,6 +40,7 @@ PROCESSOR_CLASSES = { "ToolProcessor": (ToolProcessor, "tool_use_processor"), "WorkingMemoryProcessor": (WorkingMemoryProcessor, "working_memory_processor"), "SelfProcessor": (SelfProcessor, "self_identify_processor"), + "ActionProcessor": (ActionProcessor, "action_processor"), # 这个处理器不需要配置键名,默认启用 } @@ -425,10 +427,7 @@ class HeartFChatting: self.all_observations = observations with Timer("回忆", cycle_timers): - logger.debug(f"{self.log_prefix} 开始回忆") running_memorys = await self.memory_activator.activate_memory(observations) - logger.debug(f"{self.log_prefix} 回忆完成") - print(running_memorys) with Timer("执行 信息处理器", cycle_timers): all_plan_info = await self._process_processors(observations, running_memorys, cycle_timers) diff --git a/src/chat/focus_chat/info_processors/action_processor.py b/src/chat/focus_chat/info_processors/action_processor.py index 83eed5a4..3ef38914 100644 --- a/src/chat/focus_chat/info_processors/action_processor.py +++ b/src/chat/focus_chat/info_processors/action_processor.py @@ -5,6 +5,8 @@ from src.chat.focus_chat.info.action_info import ActionInfo from .base_processor import BaseProcessor from src.common.logger_manager import get_logger from src.chat.heart_flow.observation.hfcloop_observation import HFCloopObservation +from src.chat.heart_flow.observation.chatting_observation import ChattingObservation +from src.chat.message_receive.chat_stream import chat_manager from typing import Dict from src.llm_models.utils_model import LLMRequest from src.config.config import global_config @@ -50,21 +52,51 @@ class ActionProcessor(BaseProcessor): # 处理Observation对象 if observations: + action_info = ActionInfo() + all_actions = None + hfc_obs = None + chat_obs = None for obs in observations: if isinstance(obs, HFCloopObservation): - # 创建动作信息 - action_info = ActionInfo() - action_changes = await self.analyze_loop_actions(obs) - if action_changes["add"] or action_changes["remove"]: - action_info.set_action_changes(action_changes) - # 设置变更原因 - reasons = [] - if action_changes["add"]: - reasons.append(f"添加动作{action_changes['add']}因为检测到大量无回复") - if action_changes["remove"]: - reasons.append(f"移除动作{action_changes['remove']}因为检测到连续回复") - action_info.set_reason(" | ".join(reasons)) - processed_infos.append(action_info) + hfc_obs = obs + if isinstance(obs, ChattingObservation): + chat_obs = obs + if hfc_obs: + obs = hfc_obs + # 创建动作信息 + all_actions = obs.all_actions + action_changes = await self.analyze_loop_actions(obs) + if action_changes["add"] or action_changes["remove"]: + action_info.set_action_changes(action_changes) + # 设置变更原因 + reasons = [] + if action_changes["add"]: + reasons.append(f"添加动作{action_changes['add']}因为检测到大量无回复") + if action_changes["remove"]: + reasons.append(f"移除动作{action_changes['remove']}因为检测到连续回复") + action_info.set_reason(" | ".join(reasons)) + if chat_obs and all_actions is not None: + obs = chat_obs + action_changes = {"add": [], "remove": []} + # 检查动作的关联类型 + chat_context = chat_manager.get_stream(obs.chat_id).context + for action_name in all_actions.keys(): + data = all_actions[action_name] + if data.get("associated_types"): + if not chat_context.check_types(data["associated_types"]): + action_changes["remove"].append(action_name) + logger.debug(f"{self.log_prefix} 动作 {action_name} 关联类型不匹配,移除该动作") + if len(action_changes["remove"]) > 0: + action_info.set_action_changes(action_changes) + # 设置变更原因 + reasons = [] + if action_info.get_reason(): + reasons.append(action_info.get_reason()) + if action_changes["remove"]: + reasons.append(f"移除动作{action_changes['remove']}因为关联类型不匹配") + action_info.set_reason(" | ".join(reasons)) + + processed_infos.append(action_info) return processed_infos diff --git a/src/chat/focus_chat/planners/action_manager.py b/src/chat/focus_chat/planners/action_manager.py index a10c4884..6cf8de6d 100644 --- a/src/chat/focus_chat/planners/action_manager.py +++ b/src/chat/focus_chat/planners/action_manager.py @@ -59,6 +59,7 @@ class ActionManager: action_description: str = getattr(action_class, "action_description", "") action_parameters: dict[str:str] = getattr(action_class, "action_parameters", {}) action_require: list[str] = getattr(action_class, "action_require", []) + associated_types: list[str] = getattr(action_class, "associated_types", []) is_default: bool = getattr(action_class, "default", False) if action_name and action_description: @@ -67,6 +68,7 @@ class ActionManager: "description": action_description, "parameters": action_parameters, "require": action_require, + "associated_types": associated_types, } # 添加到所有已注册的动作 diff --git a/src/chat/focus_chat/planners/actions/base_action.py b/src/chat/focus_chat/planners/actions/base_action.py index 82d25967..87cd96e2 100644 --- a/src/chat/focus_chat/planners/actions/base_action.py +++ b/src/chat/focus_chat/planners/actions/base_action.py @@ -66,6 +66,8 @@ class BaseAction(ABC): self.action_parameters: dict = {} self.action_require: list[str] = [] + self.associated_types: list[str] = [] + self.default: bool = False self.action_data = action_data diff --git a/src/chat/focus_chat/planners/actions/reply_action.py b/src/chat/focus_chat/planners/actions/reply_action.py index 45a4340d..3eacf518 100644 --- a/src/chat/focus_chat/planners/actions/reply_action.py +++ b/src/chat/focus_chat/planners/actions/reply_action.py @@ -36,6 +36,9 @@ class ReplyAction(BaseAction): "避免重复或评价自己的发言,不要和自己聊天", "注意:回复尽量简短一些。可以参考贴吧,知乎和微博的回复风格,回复不要浮夸,不要用夸张修辞,平淡一些。不要有额外的符号,尽量简单简短", ] + + associated_types: list[str] = ["text", "emoji"] + default = True def __init__( diff --git a/src/chat/message_receive/chat_stream.py b/src/chat/message_receive/chat_stream.py index 1f2ebbf8..edbc733a 100644 --- a/src/chat/message_receive/chat_stream.py +++ b/src/chat/message_receive/chat_stream.py @@ -38,6 +38,15 @@ class ChatMessageContext: """获取最后一条消息""" return self.message + def check_types(self, types: list) -> bool: + """检查消息类型""" + if not self.message.message_info.format_info.accept_format: + return False + for t in types: + if t not in self.message.message_info.format_info.accept_format: + return False + return True + class ChatStream: """聊天流对象,存储一个完整的聊天上下文""" diff --git a/src/plugins/test_plugin/actions/mute_action.py b/src/plugins/test_plugin/actions/mute_action.py index 0a47bafd..d0f947c4 100644 --- a/src/plugins/test_plugin/actions/mute_action.py +++ b/src/plugins/test_plugin/actions/mute_action.py @@ -25,7 +25,8 @@ class MuteAction(PluginAction): "当千石可乐或可乐酱要求你禁言时使用", "当你想回避某个话题时使用", ] - default = False # 不是默认动作,需要手动添加到使用集 + default = True # 不是默认动作,需要手动添加到使用集 + associated_types = ["command", "text"] async def process(self) -> Tuple[bool, str]: """处理测试动作""" @@ -41,8 +42,8 @@ class MuteAction(PluginAction): try: await self.send_message( - type="text", - data=f"[command]mute,{user_id},{duration}", + type="command", + data={"name": "GROUP_BAN", "args": {"qq_id": f"{user_id}", "duration": f"{duration}"}}, # target = target ) diff --git a/src/plugins/test_plugin/actions/online_action.py b/src/plugins/test_plugin/actions/online_action.py index 7f667431..c6a2fe6c 100644 --- a/src/plugins/test_plugin/actions/online_action.py +++ b/src/plugins/test_plugin/actions/online_action.py @@ -18,6 +18,7 @@ class CheckOnlineAction(PluginAction): "mode参数为type时查看在线系统类型分布", ] default = False # 不是默认动作,需要手动添加到使用集 + associated_types = ["text"] async def process(self) -> Tuple[bool, str]: """处理测试动作""" @@ -30,9 +31,9 @@ class CheckOnlineAction(PluginAction): try: if mode == "type": - await self.send_message("#online detail") + await self.send_message("text", "#online detail") elif mode == "version": - await self.send_message("#online") + await self.send_message("text", "#online") except Exception as e: logger.error(f"{self.log_prefix} 执行online动作时出错: {e}") diff --git a/src/plugins/tts_plgin/__init__.py b/src/plugins/tts_plgin/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/plugins/tts_plgin/actions/__init__.py b/src/plugins/tts_plgin/actions/__init__.py new file mode 100644 index 00000000..00737d90 --- /dev/null +++ b/src/plugins/tts_plgin/actions/__init__.py @@ -0,0 +1 @@ +from . import tts_action # noqa diff --git a/src/plugins/tts_plgin/actions/tts_action.py b/src/plugins/tts_plgin/actions/tts_action.py new file mode 100644 index 00000000..a029d035 --- /dev/null +++ b/src/plugins/tts_plgin/actions/tts_action.py @@ -0,0 +1,73 @@ +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("tts_action") + + +@register_action +class TTSAction(PluginAction): + """TTS语音转换动作处理类""" + + action_name = "tts_action" + action_description = "将文本转换为语音进行播放,适用于需要语音输出的场景" + action_parameters = { + "text": "需要转换为语音的文本内容,必填,内容应当适合语音播报,语句流畅、清晰", + } + action_require = [ + "当需要发送语音信息时使用", + "当用户明确要求使用语音功能时使用", + "当表达内容更适合用语音而不是文字传达时使用", + "当用户想听到语音回答而非阅读文本时使用", + ] + default = True # 设为默认动作 + associated_types = ["tts_text"] + + async def process(self) -> Tuple[bool, str]: + """处理TTS文本转语音动作""" + logger.info(f"{self.log_prefix} 执行TTS动作: {self.reasoning}") + + # 获取要转换的文本 + text = self.action_data.get("text") + + if not text: + logger.error(f"{self.log_prefix} 执行TTS动作时未提供文本内容") + return False, "执行TTS动作失败:未提供文本内容" + + # 确保文本适合TTS使用 + processed_text = self._process_text_for_tts(text) + + try: + # 发送TTS消息 + await self.send_message(type="tts_text", data=processed_text) + + logger.info(f"{self.log_prefix} TTS动作执行成功,文本长度: {len(processed_text)}") + return True, "TTS动作执行成功" + + except Exception as e: + logger.error(f"{self.log_prefix} 执行TTS动作时出错: {e}") + return False, f"执行TTS动作时出错: {e}" + + def _process_text_for_tts(self, text: str) -> str: + """ + 处理文本使其更适合TTS使用 + - 移除不必要的特殊字符和表情符号 + - 修正标点符号以提高语音质量 + - 优化文本结构使语音更流畅 + """ + # 这里可以添加文本处理逻辑 + # 例如:移除多余的标点、表情符号,优化语句结构等 + + # 简单示例实现 + processed_text = text + + # 移除多余的标点符号 + import re + + processed_text = re.sub(r"([!?,.;:。!?,、;:])\1+", r"\1", processed_text) + + # 确保句子结尾有合适的标点 + if not any(processed_text.endswith(end) for end in [".", "?", "!", "。", "!", "?"]): + processed_text = processed_text + "。" + + return processed_text