mirror of https://github.com/Mai-with-u/MaiBot.git
fix:表情包管理插件可工作
parent
174cbbf2a4
commit
0964676bfb
|
|
@ -18,18 +18,84 @@ from src.plugin_system import (
|
|||
)
|
||||
from maim_message import Seg
|
||||
from src.config.config import global_config
|
||||
from src.common.logger import get_logger
|
||||
logger = get_logger("emoji_manage_plugin")
|
||||
|
||||
class AddEmojiCommand(BaseCommand):
|
||||
command_name = "add_emoji"
|
||||
command_description = "添加表情包"
|
||||
command_pattern = r".*/emoji add.*"
|
||||
|
||||
|
||||
async def execute(self) -> Tuple[bool, str, bool]:
|
||||
# 查找消息中的表情包
|
||||
logger.info(f"查找消息中的表情包: {self.message.message_segment}")
|
||||
|
||||
emoji_base64_list = self.find_and_return_emoji_in_message(self.message.message_segment)
|
||||
return True, f"找到了{len(emoji_base64_list)}个表情包", True
|
||||
|
||||
def find_and_return_emoji_in_message(self, message_segments: List[Seg]) -> List[str]:
|
||||
|
||||
if not emoji_base64_list:
|
||||
return False, "未在消息中找到表情包或图片", False
|
||||
|
||||
# 注册找到的表情包
|
||||
success_count = 0
|
||||
fail_count = 0
|
||||
results = []
|
||||
|
||||
for i, emoji_base64 in enumerate(emoji_base64_list):
|
||||
try:
|
||||
# 使用emoji_api注册表情包
|
||||
result = await emoji_api.register_emoji(emoji_base64, filename=f"emoji_{i+1}")
|
||||
|
||||
if result["success"]:
|
||||
success_count += 1
|
||||
description = result.get("description", "未知描述")
|
||||
emotions = result.get("emotions", [])
|
||||
replaced = result.get("replaced", False)
|
||||
|
||||
result_msg = f"表情包 {i+1} 注册成功{'(替换旧表情包)' if replaced else '(新增表情包)'}"
|
||||
if description:
|
||||
result_msg += f"\n描述: {description}"
|
||||
if emotions:
|
||||
result_msg += f"\n情感标签: {', '.join(emotions)}"
|
||||
|
||||
results.append(result_msg)
|
||||
else:
|
||||
fail_count += 1
|
||||
error_msg = result.get("message", "注册失败")
|
||||
results.append(f"表情包 {i+1} 注册失败: {error_msg}")
|
||||
|
||||
except Exception as e:
|
||||
fail_count += 1
|
||||
results.append(f"表情包 {i+1} 注册时发生错误: {str(e)}")
|
||||
|
||||
# 构建返回消息
|
||||
total_count = success_count + fail_count
|
||||
summary_msg = f"表情包注册完成: 成功 {success_count} 个,失败 {fail_count} 个,共处理 {total_count} 个"
|
||||
|
||||
# 如果有结果详情,添加到返回消息中
|
||||
if results:
|
||||
details_msg = "\n" + "\n".join(results)
|
||||
final_msg = summary_msg + details_msg
|
||||
else:
|
||||
final_msg = summary_msg
|
||||
|
||||
return success_count > 0, final_msg, success_count > 0
|
||||
|
||||
def find_and_return_emoji_in_message(self, message_segments) -> List[str]:
|
||||
emoji_base64_list = []
|
||||
|
||||
# 处理单个Seg对象的情况
|
||||
if isinstance(message_segments, Seg):
|
||||
if message_segments.type == "emoji":
|
||||
emoji_base64_list.append(message_segments.data)
|
||||
elif message_segments.type == "image":
|
||||
# 假设图片数据是base64编码的
|
||||
emoji_base64_list.append(message_segments.data)
|
||||
elif message_segments.type == "seglist":
|
||||
# 递归处理嵌套的Seg列表
|
||||
emoji_base64_list.extend(self.find_and_return_emoji_in_message(message_segments.data))
|
||||
return emoji_base64_list
|
||||
|
||||
# 处理Seg列表的情况
|
||||
for seg in message_segments:
|
||||
if seg.type == "emoji":
|
||||
emoji_base64_list.append(seg.data)
|
||||
|
|
@ -66,67 +132,6 @@ class ListEmojiCommand(BaseCommand):
|
|||
return True, f"显示了当前时间: {time_str}", True
|
||||
|
||||
|
||||
class PrintMessage(BaseEventHandler):
|
||||
"""打印消息事件处理器 - 处理打印消息事件"""
|
||||
|
||||
event_type = EventType.ON_MESSAGE
|
||||
handler_name = "print_message_handler"
|
||||
handler_description = "打印接收到的消息"
|
||||
|
||||
async def execute(self, message: MaiMessages | None) -> Tuple[bool, bool, str | None, None, None]:
|
||||
"""执行打印消息事件处理"""
|
||||
# 打印接收到的消息
|
||||
if self.get_config("print_message.enabled", False):
|
||||
print(f"接收到消息: {message.raw_message if message else '无效消息'}")
|
||||
return True, True, "消息已打印", None, None
|
||||
|
||||
|
||||
class ForwardMessages(BaseEventHandler):
|
||||
"""
|
||||
把接收到的消息转发到指定聊天ID
|
||||
|
||||
此组件是HYBRID消息和FORWARD消息的使用示例。
|
||||
每收到10条消息,就会以1%的概率使用HYBRID消息转发,否则使用FORWARD消息转发。
|
||||
"""
|
||||
|
||||
event_type = EventType.ON_MESSAGE
|
||||
handler_name = "forward_messages_handler"
|
||||
handler_description = "把接收到的消息转发到指定聊天ID"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.counter = 0 # 用于计数转发的消息数量
|
||||
self.messages: List[str] = []
|
||||
|
||||
async def execute(self, message: MaiMessages | None) -> Tuple[bool, bool, None, None, None]:
|
||||
if not message:
|
||||
return True, True, None, None, None
|
||||
stream_id = message.stream_id or ""
|
||||
|
||||
if message.plain_text:
|
||||
self.messages.append(message.plain_text)
|
||||
self.counter += 1
|
||||
if self.counter % 10 == 0:
|
||||
if random.random() < 0.01:
|
||||
success = await self.send_hybrid(stream_id, [(ReplyContentType.TEXT, msg) for msg in self.messages])
|
||||
else:
|
||||
success = await self.send_forward(
|
||||
stream_id,
|
||||
[
|
||||
(
|
||||
str(global_config.bot.qq_account),
|
||||
str(global_config.bot.nickname),
|
||||
[(ReplyContentType.TEXT, msg)],
|
||||
)
|
||||
for msg in self.messages
|
||||
],
|
||||
)
|
||||
if not success:
|
||||
raise ValueError("转发消息失败")
|
||||
self.messages = []
|
||||
return True, True, None, None, None
|
||||
|
||||
|
||||
class RandomEmojis(BaseCommand):
|
||||
command_name = "random_emojis"
|
||||
command_description = "发送多张随机表情包"
|
||||
|
|
@ -169,36 +174,13 @@ class EmojiManagePlugin(BasePlugin):
|
|||
# 配置Schema定义
|
||||
config_schema: dict = {
|
||||
"plugin": {
|
||||
"version": ConfigField(type=str, default="1.0.0", description="插件版本"),
|
||||
"enabled": ConfigField(type=bool, default=False, description="是否启用插件"),
|
||||
"enabled": ConfigField(type=bool, default=True, description="是否启用插件"),
|
||||
"config_version": ConfigField(type=str, default="1.0.1", description="配置文件版本"),
|
||||
},
|
||||
}
|
||||
|
||||
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
|
||||
return [
|
||||
(PrintMessage.get_handler_info(), PrintMessage),
|
||||
(ForwardMessages.get_handler_info(), ForwardMessages),
|
||||
(RandomEmojis.get_command_info(), RandomEmojis),
|
||||
]
|
||||
|
||||
|
||||
# @register_plugin
|
||||
# class HelloWorldEventPlugin(BaseEPlugin):
|
||||
# """Hello World事件插件 - 处理问候和告别事件"""
|
||||
|
||||
# plugin_name = "hello_world_event_plugin"
|
||||
# enable_plugin = False
|
||||
# dependencies = []
|
||||
# python_dependencies = []
|
||||
# config_file_name = "event_config.toml"
|
||||
|
||||
# config_schema = {
|
||||
# "plugin": {
|
||||
# "name": ConfigField(type=str, default="hello_world_event_plugin", description="插件名称"),
|
||||
# "version": ConfigField(type=str, default="1.0.0", description="插件版本"),
|
||||
# "enabled": ConfigField(type=bool, default=True, description="是否启用插件"),
|
||||
# },
|
||||
# }
|
||||
|
||||
# def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
|
||||
# return [(PrintMessage.get_handler_info(), PrintMessage)]
|
||||
(AddEmojiCommand.get_command_info(), AddEmojiCommand),
|
||||
]
|
||||
|
|
@ -237,8 +237,7 @@ class HelloWorldPlugin(BasePlugin):
|
|||
# 配置Schema定义
|
||||
config_schema: dict = {
|
||||
"plugin": {
|
||||
"name": ConfigField(type=str, default="hello_world_plugin", description="插件名称"),
|
||||
"version": ConfigField(type=str, default="1.0.0", description="插件版本"),
|
||||
"config_version": ConfigField(type=str, default="1.0.0", description="配置文件版本"),
|
||||
"enabled": ConfigField(type=bool, default=False, description="是否启用插件"),
|
||||
},
|
||||
"greeting": {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ class ExpressionLearner:
|
|||
model_set=model_config.model_task_config.replyer, request_type="expression.learner"
|
||||
)
|
||||
self.chat_id = chat_id
|
||||
self.chat_stream = get_chat_manager().get_stream(chat_id)
|
||||
self.chat_name = get_chat_manager().get_stream_name(chat_id) or chat_id
|
||||
|
||||
# 维护每个chat的上次学习时间
|
||||
|
|
@ -69,24 +70,8 @@ class ExpressionLearner:
|
|||
|
||||
# 学习参数
|
||||
self.min_messages_for_learning = 25 # 触发学习所需的最少消息数
|
||||
self.min_learning_interval = 300 # 最短学习时间间隔(秒)
|
||||
|
||||
def can_learn_for_chat(self) -> bool:
|
||||
"""
|
||||
检查指定聊天流是否允许学习表达
|
||||
|
||||
Args:
|
||||
chat_id: 聊天流ID
|
||||
|
||||
Returns:
|
||||
bool: 是否允许学习
|
||||
"""
|
||||
try:
|
||||
use_expression, enable_learning, _ = global_config.expression.get_expression_config_for_chat(self.chat_id)
|
||||
return enable_learning
|
||||
except Exception as e:
|
||||
logger.error(f"检查学习权限失败: {e}")
|
||||
return False
|
||||
_, self.enable_learning, self.learning_intensity = global_config.expression.get_expression_config_for_chat(self.chat_id)
|
||||
self.min_learning_interval = 300 / self.learning_intensity
|
||||
|
||||
def should_trigger_learning(self) -> bool:
|
||||
"""
|
||||
|
|
@ -98,27 +83,13 @@ class ExpressionLearner:
|
|||
Returns:
|
||||
bool: 是否应该触发学习
|
||||
"""
|
||||
current_time = time.time()
|
||||
|
||||
# 获取该聊天流的学习强度
|
||||
try:
|
||||
_, enable_learning, learning_intensity = global_config.expression.get_expression_config_for_chat(
|
||||
self.chat_id
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"获取聊天流 {self.chat_id} 的学习配置失败: {e}")
|
||||
return False
|
||||
|
||||
# 检查是否允许学习
|
||||
if not enable_learning:
|
||||
if not self.enable_learning:
|
||||
return False
|
||||
|
||||
# 根据学习强度计算最短学习时间间隔
|
||||
min_interval = self.min_learning_interval / learning_intensity
|
||||
|
||||
# 检查时间间隔
|
||||
time_diff = current_time - self.last_learning_time
|
||||
if time_diff < min_interval:
|
||||
time_diff = time.time() - self.last_learning_time
|
||||
if time_diff < self.min_learning_interval:
|
||||
return False
|
||||
|
||||
# 检查消息数量(只检查指定聊天流的消息)
|
||||
|
|
@ -228,32 +199,17 @@ class ExpressionLearner:
|
|||
"""
|
||||
学习并存储表达方式
|
||||
"""
|
||||
# 检查是否允许在此聊天流中学习(在函数最前面检查)
|
||||
if not self.can_learn_for_chat():
|
||||
logger.debug(f"聊天流 {self.chat_name} 不允许学习表达,跳过学习")
|
||||
return []
|
||||
|
||||
res = await self.learn_expression(num)
|
||||
|
||||
if res is None:
|
||||
logger.info("没有学习到表达风格")
|
||||
return []
|
||||
learnt_expressions, chat_id = res
|
||||
|
||||
chat_stream = get_chat_manager().get_stream(chat_id)
|
||||
if chat_stream is None:
|
||||
group_name = f"聊天流 {chat_id}"
|
||||
elif chat_stream.group_info:
|
||||
group_name = chat_stream.group_info.group_name
|
||||
else:
|
||||
group_name = f"{chat_stream.user_info.user_nickname}的私聊"
|
||||
learnt_expressions_str = ""
|
||||
for _chat_id, situation, style in learnt_expressions:
|
||||
learnt_expressions_str += f"{situation}->{style}\n"
|
||||
logger.info(f"在 {group_name} 学习到表达风格:\n{learnt_expressions_str}")
|
||||
|
||||
if not learnt_expressions:
|
||||
logger.info("没有学习到表达风格")
|
||||
return []
|
||||
|
||||
logger.info(f"在 {self.chat_name} 学习到表达风格:\n{learnt_expressions_str}")
|
||||
|
||||
# 按chat_id分组
|
||||
chat_dict: Dict[str, List[Dict[str, Any]]] = {}
|
||||
|
|
@ -316,7 +272,7 @@ class ExpressionLearner:
|
|||
|
||||
current_time = time.time()
|
||||
|
||||
# 获取上次学习时间
|
||||
# 获取上次学习之后的消息
|
||||
random_msg = get_raw_msg_by_timestamp_with_chat_inclusive(
|
||||
chat_id=self.chat_id,
|
||||
timestamp_start=self.last_learning_time,
|
||||
|
|
@ -330,14 +286,15 @@ class ExpressionLearner:
|
|||
chat_id: str = random_msg[0].chat_id
|
||||
# random_msg_str: str = build_readable_messages(random_msg, timestamp_mode="normal")
|
||||
random_msg_str: str = await build_anonymous_messages(random_msg)
|
||||
# print(f"random_msg_str:{random_msg_str}")
|
||||
|
||||
|
||||
prompt: str = await global_prompt_manager.format_prompt(
|
||||
prompt,
|
||||
chat_str=random_msg_str,
|
||||
)
|
||||
|
||||
logger.debug(f"学习{type_str}的prompt: {prompt}")
|
||||
print(f"random_msg_str:{random_msg_str}")
|
||||
logger.info(f"学习{type_str}的prompt: {prompt}")
|
||||
|
||||
try:
|
||||
response, _ = await self.express_learn_model.generate_response_async(prompt, temperature=0.3)
|
||||
|
|
|
|||
|
|
@ -344,6 +344,10 @@ class HeartFChatting:
|
|||
available_actions=available_actions,
|
||||
)
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"{self.log_prefix}决定执行{len(action_to_use_info)}个动作: {' '.join([a.action_type for a in action_to_use_info])}"
|
||||
)
|
||||
|
||||
# 3. 并行执行所有动作
|
||||
action_tasks = [
|
||||
|
|
|
|||
|
|
@ -502,8 +502,8 @@ class ActionPlanner:
|
|||
action.action_data = action.action_data or {}
|
||||
action.action_data["loop_start_time"] = loop_start_time
|
||||
|
||||
logger.info(
|
||||
f"{self.log_prefix}规划器决定执行{len(actions)}个动作: {' '.join([a.action_type for a in actions])}"
|
||||
logger.debug(
|
||||
f"{self.log_prefix}规划器选择了{len(actions)}个动作: {' '.join([a.action_type for a in actions])}"
|
||||
)
|
||||
|
||||
return actions
|
||||
|
|
|
|||
|
|
@ -46,8 +46,9 @@ class EmojiAction(BaseAction):
|
|||
"""执行表情动作"""
|
||||
try:
|
||||
# 1. 获取发送表情的原因
|
||||
reason = self.action_data.get("reason", "表达当前情绪")
|
||||
|
||||
# reason = self.action_data.get("reason", "表达当前情绪")
|
||||
reason = self.reasoning
|
||||
|
||||
# 2. 随机获取20个表情包
|
||||
sampled_emojis = await emoji_api.get_random(30)
|
||||
if not sampled_emojis:
|
||||
|
|
@ -62,6 +63,9 @@ class EmojiAction(BaseAction):
|
|||
emotion_map[emo].append((b64, desc))
|
||||
|
||||
available_emotions = list(emotion_map.keys())
|
||||
available_emotions_str = ""
|
||||
for emotion in available_emotions:
|
||||
available_emotions_str += f"{emotion}\n"
|
||||
|
||||
if not available_emotions:
|
||||
logger.warning(f"{self.log_prefix} 获取到的表情包均无情感标签, 将随机发送")
|
||||
|
|
@ -80,14 +84,15 @@ class EmojiAction(BaseAction):
|
|||
)
|
||||
|
||||
# 4. 构建prompt让LLM选择情感
|
||||
prompt = f"""
|
||||
你是一个正在进行聊天的网友,你需要根据一个理由和最近的聊天记录,从一个情感标签列表中选择最匹配的一个。
|
||||
这是最近的聊天记录:
|
||||
{messages_text}
|
||||
|
||||
这是理由:“{reason}”
|
||||
这里是可用的情感标签:{available_emotions}
|
||||
请直接返回最匹配的那个情感标签,不要进行任何解释或添加其他多余的文字。
|
||||
prompt = f"""你正在进行QQ聊天,你需要根据聊天记录,选出一个合适的情感标签。
|
||||
请你根据以下原因和聊天记录进行选择
|
||||
原因:{reason}
|
||||
聊天记录:
|
||||
{messages_text}
|
||||
|
||||
这里是可用的情感标签:
|
||||
{available_emotions_str}
|
||||
请直接返回最匹配的那个情感标签,不要进行任何解释或添加其他多余的文字。
|
||||
"""
|
||||
|
||||
if global_config.debug.show_prompt:
|
||||
|
|
@ -97,10 +102,10 @@ class EmojiAction(BaseAction):
|
|||
|
||||
# 5. 调用LLM
|
||||
models = llm_api.get_available_models()
|
||||
chat_model_config = models.get("utils_small") # 使用字典访问方式
|
||||
chat_model_config = models.get("replyer") # 使用字典访问方式
|
||||
if not chat_model_config:
|
||||
logger.error(f"{self.log_prefix} 未找到'utils_small'模型配置,无法调用LLM")
|
||||
return False, "未找到'utils_small'模型配置"
|
||||
logger.error(f"{self.log_prefix} 未找到'replyer'模型配置,无法调用LLM")
|
||||
return False, "未找到'replyer'模型配置"
|
||||
|
||||
success, chosen_emotion, _, _ = await llm_api.generate_with_model(
|
||||
prompt, model_config=chat_model_config, request_type="emoji"
|
||||
|
|
|
|||
Loading…
Reference in New Issue