Add files via upload

This commit is contained in:
A0000Xz
2025-06-13 23:52:55 +08:00
committed by GitHub
parent e6f93d7dbe
commit 92613792bd

View File

@@ -1,261 +1,260 @@
""" """
Normal Chat Expressor Normal Chat Expressor
为Normal Chat专门设计的表达器不需要经过LLM风格化处理 为Normal Chat专门设计的表达器不需要经过LLM风格化处理
直接发送消息,主要用于插件动作中需要发送消息的场景。 直接发送消息,主要用于插件动作中需要发送消息的场景。
""" """
import time import time
from typing import List, Optional, Tuple, Dict, Any from typing import List, Optional, Tuple, Dict, Any
from src.chat.message_receive.message import MessageRecv, MessageSending, MessageThinking, Seg from src.chat.message_receive.message import MessageRecv, MessageSending, MessageThinking, Seg
from src.chat.message_receive.message import UserInfo from src.chat.message_receive.message import UserInfo
from src.chat.message_receive.chat_stream import ChatStream, get_chat_manager from src.chat.message_receive.chat_stream import ChatStream, get_chat_manager
from src.chat.message_receive.message_sender import message_manager from src.chat.message_receive.message_sender import message_manager
from src.config.config import global_config from src.config.config import global_config
from src.common.logger import get_logger from src.common.logger import get_logger
logger = get_logger("normal_chat_expressor") logger = get_logger("normal_chat_expressor")
class NormalChatExpressor: class NormalChatExpressor:
"""Normal Chat专用表达器 """Normal Chat专用表达器
特点: 特点:
1. 不经过LLM风格化直接发送消息 1. 不经过LLM风格化直接发送消息
2. 支持文本和表情包发送 2. 支持文本和表情包发送
3. 为插件动作提供简化的消息发送接口 3. 为插件动作提供简化的消息发送接口
4. 保持与focus_chat expressor相似的API但去掉复杂的风格化流程 4. 保持与focus_chat expressor相似的API但去掉复杂的风格化流程
""" """
def __init__(self, chat_stream: ChatStream): def __init__(self, chat_stream: ChatStream):
"""初始化Normal Chat表达器 """初始化Normal Chat表达器
Args: Args:
chat_stream: 聊天流对象 chat_stream: 聊天流对象
stream_name: 流名称 stream_name: 流名称
""" """
self.chat_stream = chat_stream self.chat_stream = chat_stream
self.stream_name = get_chat_manager().get_stream_name(self.chat_stream.stream_id) or self.chat_stream.stream_id self.stream_name = get_chat_manager().get_stream_name(self.chat_stream.stream_id) or self.chat_stream.stream_id
self.log_prefix = f"[{self.stream_name}]Normal表达器" self.log_prefix = f"[{self.stream_name}]Normal表达器"
logger.debug(f"{self.log_prefix} 初始化完成") logger.debug(f"{self.log_prefix} 初始化完成")
async def create_thinking_message( async def create_thinking_message(
self, anchor_message: Optional[MessageRecv], thinking_id: str self, anchor_message: Optional[MessageRecv], thinking_id: str
) -> Optional[MessageThinking]: ) -> Optional[MessageThinking]:
"""创建思考消息 """创建思考消息
Args: Args:
anchor_message: 锚点消息 anchor_message: 锚点消息
thinking_id: 思考ID thinking_id: 思考ID
Returns: Returns:
MessageThinking: 创建的思考消息如果失败返回None MessageThinking: 创建的思考消息如果失败返回None
""" """
if not anchor_message or not anchor_message.chat_stream: if not anchor_message or not anchor_message.chat_stream:
logger.error(f"{self.log_prefix} 无法创建思考消息,缺少有效的锚点消息或聊天流") logger.error(f"{self.log_prefix} 无法创建思考消息,缺少有效的锚点消息或聊天流")
return None return None
messageinfo = anchor_message.message_info messageinfo = anchor_message.message_info
thinking_time_point = time.time() thinking_time_point = time.time()
bot_user_info = UserInfo( bot_user_info = UserInfo(
user_id=global_config.bot.qq_account, user_id=global_config.bot.qq_account,
user_nickname=global_config.bot.nickname, user_nickname=global_config.bot.nickname,
platform=messageinfo.platform, platform=messageinfo.platform,
) )
thinking_message = MessageThinking( thinking_message = MessageThinking(
message_id=thinking_id, message_id=thinking_id,
chat_stream=self.chat_stream, chat_stream=self.chat_stream,
bot_user_info=bot_user_info, bot_user_info=bot_user_info,
reply=anchor_message, reply=anchor_message,
thinking_start_time=thinking_time_point, thinking_start_time=thinking_time_point,
) )
await message_manager.add_message(thinking_message) await message_manager.add_message(thinking_message)
logger.debug(f"{self.log_prefix} 创建思考消息: {thinking_id}") logger.debug(f"{self.log_prefix} 创建思考消息: {thinking_id}")
return thinking_message return thinking_message
async def send_response_messages( async def send_response_messages(
self, self,
anchor_message: Optional[MessageRecv], anchor_message: Optional[MessageRecv],
response_set: List[Tuple[str, str]], response_set: List[Tuple[str, str]],
thinking_id: str = "", thinking_id: str = "",
display_message: str = "", display_message: str = "",
) -> Optional[MessageSending]: ) -> Optional[MessageSending]:
"""发送回复消息 """发送回复消息
Args: Args:
anchor_message: 锚点消息 anchor_message: 锚点消息
response_set: 回复内容集合,格式为 [(type, content), ...] response_set: 回复内容集合,格式为 [(type, content), ...]
thinking_id: 思考ID thinking_id: 思考ID
display_message: 显示消息 display_message: 显示消息
Returns: Returns:
MessageSending: 发送的第一条消息如果失败返回None MessageSending: 发送的第一条消息如果失败返回None
""" """
try: try:
if not response_set: if not response_set:
logger.warning(f"{self.log_prefix} 回复内容为空") logger.warning(f"{self.log_prefix} 回复内容为空")
return None return None
# 如果没有thinking_id生成一个 # 如果没有thinking_id生成一个
if not thinking_id: if not thinking_id:
thinking_time_point = round(time.time(), 2) thinking_time_point = round(time.time(), 2)
thinking_id = "mt" + str(thinking_time_point) thinking_id = "mt" + str(thinking_time_point)
# 创建思考消息 # 创建思考消息
if anchor_message: if anchor_message:
await self.create_thinking_message(anchor_message, thinking_id) await self.create_thinking_message(anchor_message, thinking_id)
# 创建消息集 # 创建消息集
first_bot_msg = None mark_head = False
mark_head = False is_emoji = False
is_emoji = False if len(response_set) == 0:
if len(response_set) == 0: return None
return None message_id = f"{thinking_id}_{len(response_set)}"
message_id = f"{thinking_id}_{len(response_set)}" response_type, content = response_set[0]
response_type, content = response_set[0] if len(response_set) > 1:
if len(response_set) > 1: message_segment = Seg(type="seglist", data=[Seg(type=t, data=c) for t, c in response_set])
message_segment = Seg(type="seglist", data=[Seg(type=t, data=c) for t, c in response_set]) else:
else: message_segment = Seg(type=response_type, data=content)
message_segment = Seg(type=response_type, data=content) if response_type == "emoji":
if response_type == "emoji": is_emoji = True
is_emoji = True
bot_msg = await self._build_sending_message(
bot_msg = await self._build_sending_message( message_id=message_id,
message_id=message_id, message_segment=message_segment,
message_segment=message_segment, thinking_id=thinking_id,
thinking_id=thinking_id, anchor_message=anchor_message,
anchor_message=anchor_message, thinking_start_time=time.time(),
thinking_start_time=time.time(), reply_to=mark_head,
reply_to=mark_head, is_emoji=is_emoji,
is_emoji=is_emoji, display_message=display_message,
display_message=display_message, )
) logger.debug(f"{self.log_prefix} 添加{response_type}类型消息: {content}")
logger.debug(f"{self.log_prefix} 添加{response_type}类型消息: {content}")
# 提交消息集
# 提交消息集 if bot_msg:
if bot_msg: await message_manager.add_message(bot_msg)
await message_manager.add_message(bot_msg) logger.info(f"{self.log_prefix} 成功发送 {response_type}类型消息: {str(content)[:200] + '...' if len(str(content)) > 200 else content}")
logger.info(f"{self.log_prefix} 成功发送 {response_type}类型消息: {content}") container = await message_manager.get_container(self.chat_stream.stream_id) # 使用 self.stream_id
container = await message_manager.get_container(self.chat_stream.stream_id) # 使用 self.stream_id for msg in container.messages[:]:
for msg in container.messages[:]: if isinstance(msg, MessageThinking) and msg.message_info.message_id == thinking_id:
if isinstance(msg, MessageThinking) and msg.message_info.message_id == thinking_id: container.messages.remove(msg)
container.messages.remove(msg) logger.debug(f"[{self.stream_name}] 已移除未产生回复的思考消息 {thinking_id}")
logger.debug(f"[{self.stream_name}] 已移除未产生回复的思考消息 {thinking_id}") break
break return bot_msg
return first_bot_msg else:
else: logger.warning(f"{self.log_prefix} 没有有效的消息被创建")
logger.warning(f"{self.log_prefix} 没有有效的消息被创建") return None
return None
except Exception as e:
except Exception as e: logger.error(f"{self.log_prefix} 发送消息失败: {e}")
logger.error(f"{self.log_prefix} 发送消息失败: {e}") import traceback
import traceback
traceback.print_exc()
traceback.print_exc() return None
return None
async def _build_sending_message(
async def _build_sending_message( self,
self, message_id: str,
message_id: str, message_segment: Seg,
message_segment: Seg, thinking_id: str,
thinking_id: str, anchor_message: Optional[MessageRecv],
anchor_message: Optional[MessageRecv], thinking_start_time: float,
thinking_start_time: float, reply_to: bool = False,
reply_to: bool = False, is_emoji: bool = False,
is_emoji: bool = False, display_message: str = "",
display_message: str = "", ) -> MessageSending:
) -> MessageSending: """构建发送消息
"""构建发送消息
Args:
Args: message_id: 消息ID
message_id: 消息ID message_segment: 消息
message_segment: 消息段 thinking_id: 思考ID
thinking_id: 思考ID anchor_message: 锚点消息
anchor_message: 锚点消息 thinking_start_time: 思考开始时间
thinking_start_time: 思考开始时间 reply_to: 是否回复
reply_to: 是否回复 is_emoji: 是否为表情包
is_emoji: 是否为表情包
Returns:
Returns: MessageSending: 构建的发送消息
MessageSending: 构建的发送消息 """
""" bot_user_info = UserInfo(
bot_user_info = UserInfo( user_id=global_config.bot.qq_account,
user_id=global_config.bot.qq_account, user_nickname=global_config.bot.nickname,
user_nickname=global_config.bot.nickname, platform=anchor_message.message_info.platform if anchor_message else "unknown",
platform=anchor_message.message_info.platform if anchor_message else "unknown", )
)
message_sending = MessageSending(
message_sending = MessageSending( message_id=message_id,
message_id=message_id, chat_stream=self.chat_stream,
chat_stream=self.chat_stream, bot_user_info=bot_user_info,
bot_user_info=bot_user_info, message_segment=message_segment,
message_segment=message_segment, sender_info=self.chat_stream.user_info,
sender_info=self.chat_stream.user_info, reply=anchor_message if reply_to else None,
reply=anchor_message if reply_to else None, thinking_start_time=thinking_start_time,
thinking_start_time=thinking_start_time, is_emoji=is_emoji,
is_emoji=is_emoji, display_message=display_message,
display_message=display_message, )
)
return message_sending
return message_sending
async def deal_reply(
async def deal_reply( self,
self, cycle_timers: dict,
cycle_timers: dict, action_data: Dict[str, Any],
action_data: Dict[str, Any], reasoning: str,
reasoning: str, anchor_message: MessageRecv,
anchor_message: MessageRecv, thinking_id: str,
thinking_id: str, ) -> Tuple[bool, Optional[str]]:
) -> Tuple[bool, Optional[str]]: """处理回复动作 - 兼容focus_chat expressor API
"""处理回复动作 - 兼容focus_chat expressor API
Args:
Args: cycle_timers: 周期计时器normal_chat中不使用
cycle_timers: 周期计时器normal_chat中不使用 action_data: 动作数据包含text、target、emojis等
action_data: 动作数据包含text、target、emojis等 reasoning: 推理说明
reasoning: 推理说明 anchor_message: 锚点消息
anchor_message: 锚点消息 thinking_id: 思考ID
thinking_id: 思考ID
Returns:
Returns: Tuple[bool, Optional[str]]: (是否成功, 回复文本)
Tuple[bool, Optional[str]]: (是否成功, 回复文本) """
""" try:
try: response_set = []
response_set = []
# 处理文本内容
# 处理文本内容 text_content = action_data.get("text", "")
text_content = action_data.get("text", "") if text_content:
if text_content: response_set.append(("text", text_content))
response_set.append(("text", text_content))
# 处理表情包
# 处理表情包 emoji_content = action_data.get("emojis", "")
emoji_content = action_data.get("emojis", "") if emoji_content:
if emoji_content: response_set.append(("emoji", emoji_content))
response_set.append(("emoji", emoji_content))
if not response_set:
if not response_set: logger.warning(f"{self.log_prefix} deal_reply: 没有有效的回复内容")
logger.warning(f"{self.log_prefix} deal_reply: 没有有效的回复内容") return False, None
return False, None
# 发送消息
# 发送消息 result = await self.send_response_messages(
result = await self.send_response_messages( anchor_message=anchor_message,
anchor_message=anchor_message, response_set=response_set,
response_set=response_set, thinking_id=thinking_id,
thinking_id=thinking_id, )
)
if result:
if result: return True, text_content if text_content else "发送成功"
return True, text_content if text_content else "发送成功" else:
else: return False, None
return False, None
except Exception as e:
except Exception as e: logger.error(f"{self.log_prefix} deal_reply执行失败: {e}")
logger.error(f"{self.log_prefix} deal_reply执行失败: {e}") import traceback
import traceback
traceback.print_exc()
traceback.print_exc() return False, None
return False, None