mirror of https://github.com/Mai-with-u/MaiBot.git
Merge branch 'dev' of https://github.com/SnowindMe/MaiBot into dev
commit
f36def3e25
|
|
@ -106,7 +106,7 @@ class DefaultExpressor:
|
|||
|
||||
if reply:
|
||||
with Timer("发送消息", cycle_timers):
|
||||
await self._send_response_messages(
|
||||
sent_msg_list = await self._send_response_messages(
|
||||
anchor_message=anchor_message,
|
||||
thinking_id=thinking_id,
|
||||
response_set=reply,
|
||||
|
|
@ -118,7 +118,7 @@ class DefaultExpressor:
|
|||
if not has_sent_something:
|
||||
logger.warning(f"{self.log_prefix} 回复动作未包含任何有效内容")
|
||||
|
||||
return has_sent_something, reply
|
||||
return has_sent_something, sent_msg_list
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"回复失败: {e}")
|
||||
|
|
@ -250,6 +250,8 @@ class DefaultExpressor:
|
|||
mark_head = False
|
||||
first_bot_msg: Optional[MessageSending] = None
|
||||
reply_message_ids = [] # 记录实际发送的消息ID
|
||||
|
||||
sent_msg_list = []
|
||||
|
||||
for i, msg_text in enumerate(response_set):
|
||||
# 为每个消息片段生成唯一ID
|
||||
|
|
@ -285,9 +287,11 @@ class DefaultExpressor:
|
|||
if type == "emoji":
|
||||
typing = False
|
||||
|
||||
await self.heart_fc_sender.send_message(bot_message, has_thinking=True, typing=typing)
|
||||
sent_msg = await self.heart_fc_sender.send_message(bot_message, has_thinking=True, typing=typing)
|
||||
|
||||
reply_message_ids.append(part_message_id) # 记录我们生成的ID
|
||||
|
||||
sent_msg_list.append((type, sent_msg))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix}发送回复片段 {i} ({part_message_id}) 时失败: {e}")
|
||||
|
|
@ -296,10 +300,11 @@ class DefaultExpressor:
|
|||
# 在尝试发送完所有片段后,完成原始的 thinking_id 状态
|
||||
try:
|
||||
await self.heart_fc_sender.complete_thinking(chat_id, thinking_id)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix}完成思考状态 {thinking_id} 时出错: {e}")
|
||||
|
||||
return first_bot_msg # 返回第一个成功发送的消息对象
|
||||
return sent_msg_list
|
||||
|
||||
async def _choose_emoji(self, send_emoji: str):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from typing import List, Dict, Optional, Any, Tuple
|
|||
from src.common.logger_manager import get_logger
|
||||
from src.chat.models.utils_model import LLMRequest
|
||||
from src.config.config import global_config
|
||||
from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_random, build_readable_messages
|
||||
from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_random, build_readable_messages, build_anonymous_messages
|
||||
from src.chat.focus_chat.heartflow_prompt_builder import Prompt, global_prompt_manager
|
||||
import os
|
||||
import json
|
||||
|
|
@ -225,14 +225,15 @@ class ExpressionLearner:
|
|||
return None
|
||||
# 转化成str
|
||||
chat_id: str = random_msg[0]["chat_id"]
|
||||
random_msg_str: str = await build_readable_messages(random_msg, timestamp_mode="normal")
|
||||
# random_msg_str: str = await build_readable_messages(random_msg, timestamp_mode="normal")
|
||||
random_msg_str: str = await build_anonymous_messages(random_msg)
|
||||
|
||||
prompt: str = await global_prompt_manager.format_prompt(
|
||||
prompt,
|
||||
chat_str=random_msg_str,
|
||||
)
|
||||
|
||||
logger.debug(f"学习{type_str}的prompt: {prompt}")
|
||||
logger.info(f"学习{type_str}的prompt: {prompt}")
|
||||
|
||||
try:
|
||||
response, _ = await self.express_learn_model.generate_response_async(prompt)
|
||||
|
|
@ -240,7 +241,7 @@ class ExpressionLearner:
|
|||
logger.error(f"学习{type_str}失败: {e}")
|
||||
return None
|
||||
|
||||
logger.debug(f"学习{type_str}的response: {response}")
|
||||
logger.info(f"学习{type_str}的response: {response}")
|
||||
|
||||
expressions: List[Tuple[str, str, str]] = self.parse_expression_response(response, chat_id)
|
||||
|
||||
|
|
|
|||
|
|
@ -907,15 +907,19 @@ class HeartFChatting:
|
|||
)
|
||||
|
||||
# --- 概率性忽略文本回复附带的表情 (逻辑保持不变) ---
|
||||
emoji = action_data.get("emojis")
|
||||
if action == "reply" and emoji:
|
||||
logger.debug(f"{self.log_prefix}[Planner] 大模型建议文字回复带表情: '{emoji}'")
|
||||
if random.random() > EMOJI_SEND_PRO:
|
||||
logger.info(f"{self.log_prefix}但是麦麦这次不想加表情 ({1 - EMOJI_SEND_PRO:.0%}),忽略表情 '{emoji}'")
|
||||
action_data["emojis"] = "" # 清空表情请求
|
||||
else:
|
||||
logger.info(f"{self.log_prefix}好吧,加上表情 '{emoji}'")
|
||||
# --- 结束概率性忽略 ---
|
||||
try:
|
||||
emoji = action_data.get("emojis")
|
||||
if action == "reply" and emoji:
|
||||
logger.debug(f"{self.log_prefix}[Planner] 大模型建议文字回复带表情: '{emoji}'")
|
||||
if random.random() > EMOJI_SEND_PRO:
|
||||
logger.info(f"{self.log_prefix}但是麦麦这次不想加表情 ({1 - EMOJI_SEND_PRO:.0%}),忽略表情 '{emoji}'")
|
||||
action_data["emojis"] = "" # 清空表情请求
|
||||
else:
|
||||
logger.info(f"{self.log_prefix}好吧,加上表情 '{emoji}'")
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix}[Planner] 概率性忽略表情时发生错误: {e}")
|
||||
traceback.print_exc()
|
||||
# --- 结束概率性忽略 ---
|
||||
|
||||
# 返回结果字典
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ install(extra_lines=3)
|
|||
logger = get_logger("sender")
|
||||
|
||||
|
||||
async def send_message(message: MessageSending) -> None:
|
||||
async def send_message(message: MessageSending) -> str:
|
||||
"""合并后的消息发送函数,包含WS发送和日志记录"""
|
||||
message_preview = truncate_message(message.processed_plain_text, max_length=40)
|
||||
|
||||
|
|
@ -23,6 +23,7 @@ async def send_message(message: MessageSending) -> None:
|
|||
# 直接调用API发送消息
|
||||
await global_api.send_message(message)
|
||||
logger.success(f"已将消息 '{message_preview}' 发往平台'{message.message_info.platform}'")
|
||||
return message.processed_plain_text
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"发送消息 '{message_preview}' 发往平台'{message.message_info.platform}' 失败: {str(e)}")
|
||||
|
|
@ -120,8 +121,13 @@ class HeartFCSender:
|
|||
else:
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
await send_message(message)
|
||||
sent_msg = await send_message(message)
|
||||
await self.storage.store_message(message, message.chat_stream)
|
||||
|
||||
if sent_msg:
|
||||
return sent_msg
|
||||
else:
|
||||
return "发送失败"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[{chat_id}] 处理或存储消息 {message_id} 时出错: {e}")
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ class LLMRequest:
|
|||
)
|
||||
# 安全地检查和记录请求详情
|
||||
handled_payload = await _safely_record(request_content, payload)
|
||||
logger.critical(f"请求头: {await self._build_headers(no_key=True)} 请求体: {handled_payload}")
|
||||
logger.critical(f"请求头: {await self._build_headers(no_key=True)} 请求体: {handled_payload[:100]}")
|
||||
raise RuntimeError(
|
||||
f"模型 {self.model_name} API请求失败: 状态码 {exception.status}, {exception.message}"
|
||||
)
|
||||
|
|
@ -591,7 +591,7 @@ class LLMRequest:
|
|||
logger.critical(f"模型 {self.model_name} 请求失败: {str(exception)}")
|
||||
# 安全地检查和记录请求详情
|
||||
handled_payload = await _safely_record(request_content, payload)
|
||||
logger.critical(f"请求头: {await self._build_headers(no_key=True)} 请求体: {handled_payload}")
|
||||
logger.critical(f"请求头: {await self._build_headers(no_key=True)} 请求体: {handled_payload[:100]}")
|
||||
raise RuntimeError(f"模型 {self.model_name} API请求失败: {str(exception)}")
|
||||
|
||||
async def _transform_parameters(self, params: dict) -> dict:
|
||||
|
|
|
|||
|
|
@ -413,6 +413,53 @@ async def build_readable_messages(
|
|||
return read_mark_line.strip() # 如果前后都无消息,只返回标记行
|
||||
|
||||
|
||||
async def build_anonymous_messages(messages: List[Dict[str, Any]]) -> str:
|
||||
"""
|
||||
构建匿名可读消息,将不同人的名称转为唯一占位符(A、B、C...),bot自己用SELF。
|
||||
"""
|
||||
if not messages:
|
||||
return ""
|
||||
|
||||
# 分配占位符
|
||||
person_map = {}
|
||||
current_char = ord('A')
|
||||
output_lines = []
|
||||
|
||||
for msg in messages:
|
||||
user_info = msg.get("user_info", {})
|
||||
platform = user_info.get("platform")
|
||||
user_id = user_info.get("user_id")
|
||||
timestamp = msg.get("time")
|
||||
content = msg.get("processed_plain_text", "")
|
||||
|
||||
if not all([platform, user_id, timestamp is not None]):
|
||||
continue
|
||||
|
||||
# 判断是否为bot
|
||||
if user_id == global_config.BOT_QQ:
|
||||
anon_name = "SELF"
|
||||
else:
|
||||
person_id = person_info_manager.get_person_id(platform, user_id)
|
||||
if person_id not in person_map:
|
||||
person_map[person_id] = chr(current_char)
|
||||
current_char += 1
|
||||
anon_name = person_map[person_id]
|
||||
|
||||
# 格式化时间
|
||||
readable_time = translate_timestamp_to_human_readable(timestamp, mode="relative")
|
||||
header = f"{readable_time}{anon_name}说:"
|
||||
output_lines.append(header)
|
||||
stripped_line = content.strip()
|
||||
if stripped_line:
|
||||
if stripped_line.endswith("。"):
|
||||
stripped_line = stripped_line[:-1]
|
||||
output_lines.append(f"{stripped_line};")
|
||||
output_lines.append("\n")
|
||||
|
||||
formatted_string = "".join(output_lines).strip()
|
||||
return formatted_string
|
||||
|
||||
|
||||
async def get_person_id_list(messages: List[Dict[str, Any]]) -> List[str]:
|
||||
"""
|
||||
从消息列表中提取不重复的 person_id 列表 (忽略机器人自身)。
|
||||
|
|
|
|||
Loading…
Reference in New Issue