mirror of https://github.com/Mai-with-u/MaiBot.git
Merge branch 'dev' of https://github.com/MaiM-with-u/MaiBot into dev
commit
cec2c1830e
|
|
@ -1,26 +1,19 @@
|
|||
import random
|
||||
from typing import List, Tuple, Type, Any
|
||||
from typing import List, Tuple, Type
|
||||
from src.plugin_system import (
|
||||
BasePlugin,
|
||||
register_plugin,
|
||||
BaseAction,
|
||||
BaseCommand,
|
||||
BaseTool,
|
||||
ComponentInfo,
|
||||
ActionActivationType,
|
||||
ConfigField,
|
||||
BaseEventHandler,
|
||||
EventType,
|
||||
MaiMessages,
|
||||
ToolParamType,
|
||||
ReplyContentType,
|
||||
emoji_api,
|
||||
)
|
||||
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 = "添加表情包"
|
||||
|
|
@ -29,7 +22,7 @@ class AddEmojiCommand(BaseCommand):
|
|||
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)
|
||||
|
||||
if not emoji_base64_list:
|
||||
|
|
@ -51,7 +44,7 @@ class AddEmojiCommand(BaseCommand):
|
|||
emotions = result.get("emotions", [])
|
||||
replaced = result.get("replaced", False)
|
||||
|
||||
result_msg = f"表情包 {i+1} 注册成功{'(替换旧表情包)' if replaced else '(新增表情包)'}"
|
||||
result_msg = f"表情包 {i + 1} 注册成功{'(替换旧表情包)' if replaced else '(新增表情包)'}"
|
||||
if description:
|
||||
result_msg += f"\n描述: {description}"
|
||||
if emotions:
|
||||
|
|
@ -61,11 +54,11 @@ class AddEmojiCommand(BaseCommand):
|
|||
else:
|
||||
fail_count += 1
|
||||
error_msg = result.get("message", "注册失败")
|
||||
results.append(f"表情包 {i+1} 注册失败: {error_msg}")
|
||||
results.append(f"表情包 {i + 1} 注册失败: {error_msg}")
|
||||
|
||||
except Exception as e:
|
||||
fail_count += 1
|
||||
results.append(f"表情包 {i+1} 注册时发生错误: {str(e)}")
|
||||
results.append(f"表情包 {i + 1} 注册时发生错误: {str(e)}")
|
||||
|
||||
# 构建返回消息
|
||||
total_count = success_count + fail_count
|
||||
|
|
@ -140,6 +133,7 @@ class AddEmojiCommand(BaseCommand):
|
|||
emoji_base64_list.extend(self.find_and_return_emoji_in_message(seg.data))
|
||||
return emoji_base64_list
|
||||
|
||||
|
||||
class ListEmojiCommand(BaseCommand):
|
||||
"""列表表情包Command - 响应/emoji list命令"""
|
||||
|
||||
|
|
@ -156,6 +150,7 @@ class ListEmojiCommand(BaseCommand):
|
|||
|
||||
# 解析命令参数
|
||||
import re
|
||||
|
||||
match = re.match(r"^/emoji list(?:\s+(\d+))?$", self.message.raw_message)
|
||||
max_count = 10 # 默认显示10个
|
||||
if match and match.group(1):
|
||||
|
|
@ -195,7 +190,7 @@ class ListEmojiCommand(BaseCommand):
|
|||
display_emojis = all_emojis[:max_count]
|
||||
message_lines.append(f"\n📋 显示前 {len(display_emojis)} 个表情包:")
|
||||
|
||||
for i, (emoji_base64, description, emotion) in enumerate(display_emojis, 1):
|
||||
for i, (_, description, emotion) in enumerate(display_emojis, 1):
|
||||
# 截断过长的描述
|
||||
short_desc = description[:50] + "..." if len(description) > 50 else description
|
||||
message_lines.append(f"{i}. {short_desc} [{emotion}]")
|
||||
|
|
@ -257,7 +252,7 @@ class DeleteEmojiCommand(BaseCommand):
|
|||
count_after = result.get("count_after", 0)
|
||||
emotions = result.get("emotions", [])
|
||||
|
||||
result_msg = f"表情包 {i+1} 删除成功"
|
||||
result_msg = f"表情包 {i + 1} 删除成功"
|
||||
if description:
|
||||
result_msg += f"\n描述: {description}"
|
||||
if emotions:
|
||||
|
|
@ -268,11 +263,11 @@ class DeleteEmojiCommand(BaseCommand):
|
|||
else:
|
||||
fail_count += 1
|
||||
error_msg = result.get("message", "删除失败")
|
||||
results.append(f"表情包 {i+1} 删除失败: {error_msg}")
|
||||
results.append(f"表情包 {i + 1} 删除失败: {error_msg}")
|
||||
|
||||
except Exception as e:
|
||||
fail_count += 1
|
||||
results.append(f"表情包 {i+1} 删除时发生错误: {str(e)}")
|
||||
results.append(f"表情包 {i + 1} 删除时发生错误: {str(e)}")
|
||||
|
||||
# 构建返回消息
|
||||
total_count = success_count + fail_count
|
||||
|
|
@ -401,4 +396,4 @@ class EmojiManagePlugin(BasePlugin):
|
|||
(AddEmojiCommand.get_command_info(), AddEmojiCommand),
|
||||
(ListEmojiCommand.get_command_info(), ListEmojiCommand),
|
||||
(DeleteEmojiCommand.get_command_info(), DeleteEmojiCommand),
|
||||
]
|
||||
]
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ from src.chat.brain_chat.brain_planner import BrainPlanner
|
|||
from src.chat.planner_actions.action_modifier import ActionModifier
|
||||
from src.chat.planner_actions.action_manager import ActionManager
|
||||
from src.chat.heart_flow.hfc_utils import CycleDetail
|
||||
from src.chat.heart_flow.hfc_utils import send_typing, stop_typing
|
||||
from src.chat.express.expression_learner import expression_learner_manager
|
||||
from src.person_info.person_info import Person
|
||||
from src.plugin_system.base.component_types import EventType, ActionInfo
|
||||
|
|
@ -96,7 +95,6 @@ class BrainChatting:
|
|||
self.last_read_time = time.time() - 2
|
||||
|
||||
self.more_plan = False
|
||||
|
||||
|
||||
async def start(self):
|
||||
"""检查是否需要启动主循环,如果未激活则启动。"""
|
||||
|
|
@ -171,10 +169,8 @@ class BrainChatting:
|
|||
|
||||
if len(recent_messages_list) >= 1:
|
||||
self.last_read_time = time.time()
|
||||
await self._observe(
|
||||
recent_messages_list=recent_messages_list
|
||||
)
|
||||
|
||||
await self._observe(recent_messages_list=recent_messages_list)
|
||||
|
||||
else:
|
||||
# Normal模式:消息数量不足,等待
|
||||
await asyncio.sleep(0.2)
|
||||
|
|
@ -233,11 +229,11 @@ class BrainChatting:
|
|||
|
||||
async def _observe(
|
||||
self, # interest_value: float = 0.0,
|
||||
recent_messages_list: Optional[List["DatabaseMessages"]] = None
|
||||
recent_messages_list: Optional[List["DatabaseMessages"]] = None,
|
||||
) -> bool: # sourcery skip: merge-else-if-into-elif, remove-redundant-if
|
||||
if recent_messages_list is None:
|
||||
recent_messages_list = []
|
||||
reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
||||
_reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
||||
|
||||
async with global_prompt_manager.async_message_scope(self.chat_stream.context.get_template_name()):
|
||||
await self.expression_learner.trigger_learning_for_chat()
|
||||
|
|
@ -334,7 +330,7 @@ class BrainChatting:
|
|||
"taken_time": time.time(),
|
||||
}
|
||||
)
|
||||
reply_text = reply_text_from_reply
|
||||
_reply_text = reply_text_from_reply
|
||||
else:
|
||||
# 没有回复信息,构建纯动作的loop_info
|
||||
loop_info = {
|
||||
|
|
@ -347,7 +343,7 @@ class BrainChatting:
|
|||
"taken_time": time.time(),
|
||||
},
|
||||
}
|
||||
reply_text = action_reply_text
|
||||
_reply_text = action_reply_text
|
||||
|
||||
self.end_cycle(loop_info, cycle_timers)
|
||||
self.print_cycle_info(cycle_timers)
|
||||
|
|
@ -484,7 +480,6 @@ class BrainChatting:
|
|||
"""执行单个动作的通用函数"""
|
||||
try:
|
||||
with Timer(f"动作{action_planner_info.action_type}", cycle_timers):
|
||||
|
||||
if action_planner_info.action_type == "no_reply":
|
||||
# 直接处理no_action逻辑,不再通过动作系统
|
||||
reason = action_planner_info.reasoning or "选择不回复"
|
||||
|
|
@ -517,7 +512,9 @@ class BrainChatting:
|
|||
|
||||
if not success or not llm_response or not llm_response.reply_set:
|
||||
if action_planner_info.action_message:
|
||||
logger.info(f"对 {action_planner_info.action_message.processed_plain_text} 的回复生成失败")
|
||||
logger.info(
|
||||
f"对 {action_planner_info.action_message.processed_plain_text} 的回复生成失败"
|
||||
)
|
||||
else:
|
||||
logger.info("回复生成失败")
|
||||
return {"action_type": "reply", "success": False, "reply_text": "", "loop_info": None}
|
||||
|
|
|
|||
|
|
@ -307,7 +307,9 @@ class BrainPlanner:
|
|||
|
||||
if chat_target_info:
|
||||
# 构建聊天上下文描述
|
||||
chat_context_description = f"你正在和 {chat_target_info.person_name or chat_target_info.user_nickname or '对方'} 聊天中"
|
||||
chat_context_description = (
|
||||
f"你正在和 {chat_target_info.person_name or chat_target_info.user_nickname or '对方'} 聊天中"
|
||||
)
|
||||
|
||||
# 构建动作选项块
|
||||
action_options_block = await self._build_action_options_block(current_available_actions)
|
||||
|
|
|
|||
|
|
@ -10,11 +10,14 @@ from src.common.logger import get_logger
|
|||
from src.common.database.database_model import Expression
|
||||
from src.llm_models.utils_model import LLMRequest
|
||||
from src.config.config import model_config, global_config
|
||||
from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_with_chat_inclusive, build_anonymous_messages, build_bare_messages
|
||||
from src.chat.utils.chat_message_builder import (
|
||||
get_raw_msg_by_timestamp_with_chat_inclusive,
|
||||
build_anonymous_messages,
|
||||
build_bare_messages,
|
||||
)
|
||||
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
|
||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||
from json_repair import repair_json
|
||||
from src.chat.utils.utils import get_embedding
|
||||
|
||||
|
||||
MAX_EXPRESSION_COUNT = 300
|
||||
|
|
@ -99,7 +102,9 @@ class ExpressionLearner:
|
|||
self.last_learning_time: float = time.time()
|
||||
|
||||
# 学习参数
|
||||
_, self.enable_learning, self.learning_intensity = global_config.expression.get_expression_config_for_chat(self.chat_id)
|
||||
_, self.enable_learning, self.learning_intensity = global_config.expression.get_expression_config_for_chat(
|
||||
self.chat_id
|
||||
)
|
||||
self.min_messages_for_learning = 15 / self.learning_intensity # 触发学习所需的最少消息数
|
||||
self.min_learning_interval = 150 / self.learning_intensity
|
||||
|
||||
|
|
@ -237,17 +242,42 @@ class ExpressionLearner:
|
|||
return []
|
||||
learnt_expressions = res
|
||||
learnt_expressions_str = ""
|
||||
for _chat_id, situation, style, context, context_words, full_context, full_context_embedding in learnt_expressions:
|
||||
for (
|
||||
_chat_id,
|
||||
situation,
|
||||
style,
|
||||
_context,
|
||||
_context_words,
|
||||
_full_context,
|
||||
_full_context_embedding,
|
||||
) in learnt_expressions:
|
||||
learnt_expressions_str += f"{situation}->{style}\n"
|
||||
|
||||
|
||||
logger.info(f"在 {self.chat_name} 学习到表达风格:\n{learnt_expressions_str}")
|
||||
|
||||
# 按chat_id分组
|
||||
chat_dict: Dict[str, List[Dict[str, Any]]] = {}
|
||||
for chat_id, situation, style, context, context_words, full_context, full_context_embedding in learnt_expressions:
|
||||
for (
|
||||
chat_id,
|
||||
situation,
|
||||
style,
|
||||
context,
|
||||
context_words,
|
||||
full_context,
|
||||
full_context_embedding,
|
||||
) in learnt_expressions:
|
||||
if chat_id not in chat_dict:
|
||||
chat_dict[chat_id] = []
|
||||
chat_dict[chat_id].append({"situation": situation, "style": style, "context": context, "context_words": context_words, "full_context": full_context, "full_context_embedding": full_context_embedding})
|
||||
chat_dict[chat_id].append(
|
||||
{
|
||||
"situation": situation,
|
||||
"style": style,
|
||||
"context": context,
|
||||
"context_words": context_words,
|
||||
"full_context": full_context,
|
||||
"full_context_embedding": full_context_embedding,
|
||||
}
|
||||
)
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
|
|
@ -300,11 +330,13 @@ class ExpressionLearner:
|
|||
expr.delete_instance()
|
||||
return learnt_expressions
|
||||
|
||||
async def match_expression_context(self, expression_pairs: List[Tuple[str, str]], random_msg_match_str: str) -> List[Tuple[str, str, str]]:
|
||||
async def match_expression_context(
|
||||
self, expression_pairs: List[Tuple[str, str]], random_msg_match_str: str
|
||||
) -> List[Tuple[str, str, str]]:
|
||||
# 为expression_pairs逐个条目赋予编号,并构建成字符串
|
||||
numbered_pairs = []
|
||||
for i, (situation, style) in enumerate(expression_pairs, 1):
|
||||
numbered_pairs.append(f"{i}. 当\"{situation}\"时,使用\"{style}\"")
|
||||
numbered_pairs.append(f'{i}. 当"{situation}"时,使用"{style}"')
|
||||
|
||||
expression_pairs_str = "\n".join(numbered_pairs)
|
||||
|
||||
|
|
@ -319,20 +351,20 @@ class ExpressionLearner:
|
|||
|
||||
print(f"match_expression_context_prompt: {prompt}")
|
||||
print(f"random_msg_match_str: {response}")
|
||||
|
||||
|
||||
# 解析JSON响应
|
||||
match_responses = []
|
||||
try:
|
||||
response = response.strip()
|
||||
# 检查是否已经是标准JSON数组格式
|
||||
if response.startswith('[') and response.endswith(']'):
|
||||
if response.startswith("[") and response.endswith("]"):
|
||||
match_responses = json.loads(response)
|
||||
else:
|
||||
# 尝试直接解析多个JSON对象
|
||||
try:
|
||||
# 如果是多个JSON对象用逗号分隔,包装成数组
|
||||
if response.startswith('{') and not response.startswith('['):
|
||||
response = '[' + response + ']'
|
||||
if response.startswith("{") and not response.startswith("["):
|
||||
response = "[" + response + "]"
|
||||
match_responses = json.loads(response)
|
||||
else:
|
||||
# 使用repair_json处理响应
|
||||
|
|
@ -394,7 +426,9 @@ class ExpressionLearner:
|
|||
|
||||
return matched_expressions
|
||||
|
||||
async def learn_expression(self, num: int = 10) -> Optional[List[Tuple[str, str, str, List[str], str, List[float]]]]:
|
||||
async def learn_expression(
|
||||
self, num: int = 10
|
||||
) -> Optional[List[Tuple[str, str, str, List[str], str, List[float]]]]:
|
||||
"""从指定聊天流学习表达方式
|
||||
|
||||
Args:
|
||||
|
|
@ -416,11 +450,10 @@ class ExpressionLearner:
|
|||
if not random_msg or random_msg == []:
|
||||
return None
|
||||
# 转化成str
|
||||
chat_id: str = random_msg[0].chat_id
|
||||
_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)
|
||||
random_msg_match_str: str = await build_bare_messages(random_msg)
|
||||
|
||||
|
||||
prompt: str = await global_prompt_manager.format_prompt(
|
||||
prompt,
|
||||
|
|
@ -440,24 +473,31 @@ class ExpressionLearner:
|
|||
|
||||
expressions: List[Tuple[str, str]] = self.parse_expression_response(response)
|
||||
|
||||
matched_expressions: List[Tuple[str, str, str]] = await self.match_expression_context(expressions, random_msg_match_str)
|
||||
matched_expressions: List[Tuple[str, str, str]] = await self.match_expression_context(
|
||||
expressions, random_msg_match_str
|
||||
)
|
||||
|
||||
split_matched_expressions: List[Tuple[str, str, str, List[str]]] = self.split_expression_context(
|
||||
matched_expressions
|
||||
)
|
||||
|
||||
split_matched_expressions: List[Tuple[str, str, str, List[str]]] = self.split_expression_context(matched_expressions)
|
||||
|
||||
split_matched_expressions_w_emb = []
|
||||
full_context_embedding: List[float] = await self.get_full_context_embedding(random_msg_match_str)
|
||||
|
||||
for situation, style, context, context_words in split_matched_expressions:
|
||||
split_matched_expressions_w_emb.append((self.chat_id, situation, style, context, context_words, random_msg_match_str,full_context_embedding))
|
||||
|
||||
for situation, style, context, context_words in split_matched_expressions:
|
||||
split_matched_expressions_w_emb.append(
|
||||
(self.chat_id, situation, style, context, context_words, random_msg_match_str, full_context_embedding)
|
||||
)
|
||||
|
||||
return split_matched_expressions_w_emb
|
||||
|
||||
|
||||
async def get_full_context_embedding(self, context: str) -> List[float]:
|
||||
embedding, _ = await self.embedding_model.get_embedding(context)
|
||||
return embedding
|
||||
|
||||
def split_expression_context(self, matched_expressions: List[Tuple[str, str, str]]) -> List[Tuple[str, str, str, List[str]]]:
|
||||
|
||||
def split_expression_context(
|
||||
self, matched_expressions: List[Tuple[str, str, str]]
|
||||
) -> List[Tuple[str, str, str, List[str]]]:
|
||||
"""
|
||||
对matched_expressions中的context部分进行jieba分词
|
||||
|
||||
|
|
|
|||
|
|
@ -114,10 +114,10 @@ class ExpressionSelector:
|
|||
def get_related_chat_ids(self, chat_id: str) -> List[str]:
|
||||
"""根据expression_groups配置,获取与当前chat_id相关的所有chat_id(包括自身)"""
|
||||
groups = global_config.expression.expression_groups
|
||||
|
||||
|
||||
# 检查是否存在全局共享组(包含"*"的组)
|
||||
global_group_exists = any("*" in group for group in groups)
|
||||
|
||||
|
||||
if global_group_exists:
|
||||
# 如果存在全局共享组,则返回所有可用的chat_id
|
||||
all_chat_ids = set()
|
||||
|
|
@ -126,7 +126,7 @@ class ExpressionSelector:
|
|||
if chat_id_candidate := self._parse_stream_config_to_chat_id(stream_config_str):
|
||||
all_chat_ids.add(chat_id_candidate)
|
||||
return list(all_chat_ids) if all_chat_ids else [chat_id]
|
||||
|
||||
|
||||
# 否则使用现有的组逻辑
|
||||
for group in groups:
|
||||
group_chat_ids = []
|
||||
|
|
|
|||
|
|
@ -43,4 +43,4 @@ class FrequencyControlManager:
|
|||
|
||||
|
||||
# 创建全局实例
|
||||
frequency_control_manager = FrequencyControlManager()
|
||||
frequency_control_manager = FrequencyControlManager()
|
||||
|
|
|
|||
|
|
@ -208,7 +208,11 @@ class HeartFChatting:
|
|||
# *控制频率用
|
||||
if mentioned_message:
|
||||
await self._observe(recent_messages_list=recent_messages_list, force_reply_message=mentioned_message)
|
||||
elif random.random() < global_config.chat.talk_value * frequency_control_manager.get_or_create_frequency_control(self.stream_id).get_talk_frequency_adjust():
|
||||
elif (
|
||||
random.random()
|
||||
< global_config.chat.talk_value
|
||||
* frequency_control_manager.get_or_create_frequency_control(self.stream_id).get_talk_frequency_adjust()
|
||||
):
|
||||
await self._observe(recent_messages_list=recent_messages_list)
|
||||
else:
|
||||
# 没有提到,继续保持沉默,等待5秒防止频繁触发
|
||||
|
|
@ -278,9 +282,8 @@ class HeartFChatting:
|
|||
recent_messages_list = []
|
||||
reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
||||
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
|
||||
if s4u_config.enable_s4u:
|
||||
await send_typing()
|
||||
|
||||
|
|
@ -356,7 +359,7 @@ 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])}"
|
||||
)
|
||||
|
|
@ -418,7 +421,7 @@ class HeartFChatting:
|
|||
},
|
||||
}
|
||||
reply_text = action_reply_text
|
||||
|
||||
|
||||
self.end_cycle(loop_info, cycle_timers)
|
||||
self.print_cycle_info(cycle_timers)
|
||||
|
||||
|
|
@ -429,11 +432,6 @@ class HeartFChatting:
|
|||
else:
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
"""S4U内容,暂时保留"""
|
||||
if s4u_config.enable_s4u:
|
||||
await stop_typing()
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
import asyncio
|
||||
import re
|
||||
import traceback
|
||||
|
||||
from typing import Tuple, TYPE_CHECKING
|
||||
|
||||
from src.config.config import global_config
|
||||
from src.chat.message_receive.message import MessageRecv
|
||||
from src.chat.message_receive.storage import MessageStorage
|
||||
from src.chat.heart_flow.heartflow import heartflow
|
||||
|
|
@ -74,7 +72,7 @@ class HeartFCMessageReceiver:
|
|||
|
||||
await self.storage.store_message(message, chat)
|
||||
|
||||
heartflow_chat: HeartFChatting = await heartflow.get_or_create_heartflow_chat(chat.stream_id) # type: ignore
|
||||
_heartflow_chat: HeartFChatting = await heartflow.get_or_create_heartflow_chat(chat.stream_id) # type: ignore
|
||||
|
||||
# 3. 日志记录
|
||||
mes_name = chat.group_info.group_name if chat.group_info else "私聊"
|
||||
|
|
@ -102,7 +100,7 @@ class HeartFCMessageReceiver:
|
|||
replace_bot_name=True,
|
||||
)
|
||||
# if not processed_plain_text:
|
||||
# print(message)
|
||||
# print(message)
|
||||
|
||||
logger.info(f"[{mes_name}]{userinfo.user_nickname}:{processed_plain_text}") # type: ignore
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from maim_message import UserInfo, Seg, GroupInfo
|
|||
from src.common.logger import get_logger
|
||||
from src.config.config import global_config
|
||||
from src.mood.mood_manager import mood_manager # 导入情绪管理器
|
||||
from src.chat.message_receive.chat_stream import get_chat_manager, ChatStream
|
||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||
from src.chat.message_receive.message import MessageRecv, MessageRecvS4U
|
||||
from src.chat.message_receive.storage import MessageStorage
|
||||
from src.chat.heart_flow.heartflow_message_processor import HeartFCMessageReceiver
|
||||
|
|
|
|||
|
|
@ -343,7 +343,6 @@ class ActionPlanner:
|
|||
interest=interest,
|
||||
plan_style=global_config.personality.plan_style,
|
||||
)
|
||||
|
||||
|
||||
return prompt, message_id_list
|
||||
except Exception as e:
|
||||
|
|
@ -508,9 +507,7 @@ class ActionPlanner:
|
|||
action.action_data = action.action_data or {}
|
||||
action.action_data["loop_start_time"] = loop_start_time
|
||||
|
||||
logger.debug(
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ from src.chat.utils.chat_message_builder import (
|
|||
from src.chat.express.expression_selector import expression_selector
|
||||
|
||||
# from src.chat.memory_system.memory_activator import MemoryActivator
|
||||
from src.person_info.person_info import Person, is_person_known
|
||||
from src.person_info.person_info import Person
|
||||
from src.plugin_system.base.component_types import ActionInfo, EventType
|
||||
from src.plugin_system.apis import llm_api
|
||||
|
||||
|
|
@ -43,6 +43,7 @@ init_rewrite_prompt()
|
|||
|
||||
logger = get_logger("replyer")
|
||||
|
||||
|
||||
class DefaultReplyer:
|
||||
def __init__(
|
||||
self,
|
||||
|
|
@ -216,7 +217,7 @@ class DefaultReplyer:
|
|||
traceback.print_exc()
|
||||
return False, llm_response
|
||||
|
||||
#移动到 relation插件中构建
|
||||
# 移动到 relation插件中构建
|
||||
# async def build_relation_info(self, chat_content: str, sender: str, person_list: List[Person]):
|
||||
# if not global_config.relationship.enable_relationship:
|
||||
# return ""
|
||||
|
|
@ -278,9 +279,7 @@ class DefaultReplyer:
|
|||
expression_habits_block = ""
|
||||
expression_habits_title = ""
|
||||
if style_habits_str.strip():
|
||||
expression_habits_title = (
|
||||
"在回复时,你可以参考以下的语言习惯,不要生硬使用:"
|
||||
)
|
||||
expression_habits_title = "在回复时,你可以参考以下的语言习惯,不要生硬使用:"
|
||||
expression_habits_block += f"{style_habits_str}\n"
|
||||
|
||||
return f"{expression_habits_title}\n{expression_habits_block}", selected_ids
|
||||
|
|
@ -510,7 +509,6 @@ class DefaultReplyer:
|
|||
--------------------------------
|
||||
"""
|
||||
|
||||
|
||||
# 构建背景对话 prompt
|
||||
all_dialogue_prompt = ""
|
||||
if message_list_before_now:
|
||||
|
|
@ -536,7 +534,6 @@ class DefaultReplyer:
|
|||
time_block: str,
|
||||
chat_target_1: str,
|
||||
chat_target_2: str,
|
||||
|
||||
identity_block: str,
|
||||
sender: str,
|
||||
target: str,
|
||||
|
|
@ -774,13 +771,9 @@ class DefaultReplyer:
|
|||
|
||||
if sender:
|
||||
if is_group_chat:
|
||||
reply_target_block = (
|
||||
f"现在{sender}说的:{target}。引起了你的注意"
|
||||
)
|
||||
reply_target_block = f"现在{sender}说的:{target}。引起了你的注意"
|
||||
else: # private chat
|
||||
reply_target_block = (
|
||||
f"现在{sender}说的:{target}。引起了你的注意"
|
||||
)
|
||||
reply_target_block = f"现在{sender}说的:{target}。引起了你的注意"
|
||||
else:
|
||||
reply_target_block = ""
|
||||
|
||||
|
|
@ -1061,6 +1054,3 @@ def weighted_sample_no_replacement(items, weights, k) -> list:
|
|||
pool.pop(idx)
|
||||
break
|
||||
return selected
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
|
||||
from src.chat.utils.prompt_builder import Prompt
|
||||
# from src.chat.memory_system.memory_activator import MemoryActivator
|
||||
|
||||
|
||||
|
||||
def init_lpmm_prompt():
|
||||
Prompt(
|
||||
"""
|
||||
|
|
@ -20,5 +18,3 @@ If you need to use the search tool, please directly call the function "lpmm_sear
|
|||
""",
|
||||
name="lpmm_get_knowledge_prompt",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
|
||||
from src.chat.utils.prompt_builder import Prompt
|
||||
# from src.chat.memory_system.memory_activator import MemoryActivator
|
||||
|
||||
|
||||
|
||||
def init_rewrite_prompt():
|
||||
Prompt("你正在qq群里聊天,下面是群里正在聊的内容:", "chat_target_group1")
|
||||
Prompt("你正在和{sender_name}聊天,这是你们之前聊的内容:", "chat_target_private1")
|
||||
|
|
@ -31,4 +29,4 @@ def init_rewrite_prompt():
|
|||
现在,你说:
|
||||
""",
|
||||
"default_expressor_prompt",
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -859,7 +859,6 @@ async def build_anonymous_messages(messages: List[DatabaseMessages]) -> str:
|
|||
# 处理图片ID
|
||||
content = process_pic_ids(content)
|
||||
|
||||
|
||||
anon_name = get_anon_name(platform, user_id)
|
||||
# print(f"anon_name:{anon_name}")
|
||||
|
||||
|
|
@ -945,11 +944,12 @@ async def build_bare_messages(messages: List[DatabaseMessages]) -> str:
|
|||
# 获取纯文本内容
|
||||
content = msg.processed_plain_text or ""
|
||||
|
||||
|
||||
# 处理图片ID
|
||||
pic_pattern = r"\[picid:[^\]]+\]"
|
||||
|
||||
def replace_pic_id(match):
|
||||
return "[图片]"
|
||||
|
||||
content = re.sub(pic_pattern, replace_pic_id, content)
|
||||
|
||||
# 处理用户引用格式,移除回复和@标记
|
||||
|
|
|
|||
|
|
@ -16,4 +16,4 @@ class LLMGenerationDataModel(BaseDataModel):
|
|||
tool_calls: Optional[List["ToolCall"]] = None
|
||||
prompt: Optional[str] = None
|
||||
selected_expressions: Optional[List[int]] = None
|
||||
reply_set: Optional["ReplySetModel"] = None
|
||||
reply_set: Optional["ReplySetModel"] = None
|
||||
|
|
|
|||
|
|
@ -748,11 +748,14 @@ def check_field_constraints():
|
|||
logger.exception(f"检查字段约束时出错: {e}")
|
||||
|
||||
return inconsistencies
|
||||
|
||||
|
||||
def fix_image_id():
|
||||
"""
|
||||
修复表情包的 image_id 字段
|
||||
"""
|
||||
import uuid
|
||||
|
||||
try:
|
||||
with db:
|
||||
for img in Images.select():
|
||||
|
|
@ -763,6 +766,7 @@ def fix_image_id():
|
|||
except Exception as e:
|
||||
logger.exception(f"修复 image_id 时出错: {e}")
|
||||
|
||||
|
||||
# 模块加载时调用初始化函数
|
||||
initialize_database(sync_constraints=True)
|
||||
fix_image_id()
|
||||
fix_image_id()
|
||||
|
|
|
|||
|
|
@ -46,13 +46,13 @@ class PersonalityConfig(ConfigBase):
|
|||
|
||||
interest: str = ""
|
||||
"""兴趣"""
|
||||
|
||||
|
||||
plan_style: str = ""
|
||||
"""说话规则,行为风格"""
|
||||
|
||||
|
||||
visual_style: str = ""
|
||||
"""图片提示词"""
|
||||
|
||||
|
||||
private_plan_style: str = ""
|
||||
"""私聊说话规则,行为风格"""
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ class ChatConfig(ConfigBase):
|
|||
|
||||
planner_smooth: float = 3
|
||||
"""规划器平滑,增大数值会减小planner负荷,略微降低反应速度,推荐2-5,0为关闭,必须大于等于0"""
|
||||
|
||||
|
||||
talk_value: float = 1
|
||||
"""思考频率"""
|
||||
|
||||
|
|
@ -302,6 +302,7 @@ class EmojiConfig(ConfigBase):
|
|||
filtration_prompt: str = "符合公序良俗"
|
||||
"""表情包过滤要求"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class KeywordRuleConfig(ConfigBase):
|
||||
"""关键词规则配置类"""
|
||||
|
|
|
|||
|
|
@ -85,4 +85,4 @@ class ModelAttemptFailed(Exception):
|
|||
self.original_exception = original_exception
|
||||
|
||||
def __str__(self):
|
||||
return self.message
|
||||
return self.message
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ def _process_delta(
|
|||
|
||||
if delta.text:
|
||||
fc_delta_buffer.write(delta.text)
|
||||
|
||||
|
||||
# 处理 thought(Gemini 的特殊字段)
|
||||
for c in getattr(delta, "candidates", []):
|
||||
if c.content and getattr(c.content, "parts", None):
|
||||
|
|
@ -190,7 +190,7 @@ def _process_delta(
|
|||
if getattr(p, "thought", False) and getattr(p, "text", None):
|
||||
# 把 thought 写入 buffer,避免 resp.content 永远为空
|
||||
fc_delta_buffer.write(p.text)
|
||||
|
||||
|
||||
if delta.function_calls: # 为什么不用hasattr呢,是因为这个属性一定有,即使是个空的
|
||||
for call in delta.function_calls:
|
||||
try:
|
||||
|
|
@ -250,11 +250,8 @@ def _build_stream_api_resp(
|
|||
" 可能会对回复内容造成影响,建议修改模型 max_tokens 配置!"
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"⚠ Gemini 响应因达到 max_tokens 限制被截断,\n"
|
||||
" 请修改模型 max_tokens 配置!"
|
||||
)
|
||||
|
||||
logger.warning("⚠ Gemini 响应因达到 max_tokens 限制被截断,\n 请修改模型 max_tokens 配置!")
|
||||
|
||||
if not resp.content and not resp.tool_calls:
|
||||
raise EmptyResponseException()
|
||||
|
||||
|
|
@ -387,10 +384,7 @@ def _default_normal_response_parser(
|
|||
" 可能会对回复内容造成影响,建议修改模型 max_tokens 配置!"
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"⚠ Gemini 响应因达到 max_tokens 限制被截断,\n"
|
||||
" 请修改模型 max_tokens 配置!"
|
||||
)
|
||||
logger.warning("⚠ Gemini 响应因达到 max_tokens 限制被截断,\n 请修改模型 max_tokens 配置!")
|
||||
|
||||
return api_response, _usage_record
|
||||
except Exception as e:
|
||||
|
|
@ -447,7 +441,7 @@ class GeminiClient(BaseClient):
|
|||
logger.warning(
|
||||
f"无效的 thinking_budget 值 {extra_params['thinking_budget']},将使用模型自动预算模式 {tb}"
|
||||
)
|
||||
|
||||
|
||||
# 优先尝试精确匹配
|
||||
if model_id in THINKING_BUDGET_LIMITS:
|
||||
limits = THINKING_BUDGET_LIMITS[model_id]
|
||||
|
|
@ -532,7 +526,7 @@ class GeminiClient(BaseClient):
|
|||
tools = _convert_tool_options(tool_options) if tool_options else None
|
||||
# 解析并裁剪 thinking_budget
|
||||
tb = self.clamp_thinking_budget(extra_params, model_info.model_identifier)
|
||||
|
||||
|
||||
# 将response_format转换为Gemini API所需的格式
|
||||
generation_config_dict = {
|
||||
"max_output_tokens": max_tokens,
|
||||
|
|
|
|||
|
|
@ -487,7 +487,7 @@ class OpenaiClient(BaseClient):
|
|||
req_task.cancel()
|
||||
raise ReqAbortException("请求被外部信号中断")
|
||||
await asyncio.sleep(0.1) # 等待0.5秒后再次检查任务&中断信号量状态
|
||||
|
||||
|
||||
# logger.
|
||||
logger.debug(f"OpenAI API响应(非流式): {req_task.result()}")
|
||||
|
||||
|
|
@ -511,7 +511,7 @@ class OpenaiClient(BaseClient):
|
|||
)
|
||||
|
||||
# logger.debug(f"OpenAI API响应: {resp}")
|
||||
|
||||
|
||||
return resp
|
||||
|
||||
async def get_embedding(
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ class LLMRequest:
|
|||
|
||||
logger.debug(f"LLM请求总耗时: {time.time() - start_time}")
|
||||
logger.debug(f"LLM生成内容: {response}")
|
||||
|
||||
|
||||
content = response.content
|
||||
reasoning_content = response.reasoning_content or ""
|
||||
tool_calls = response.tool_calls
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ def init_prompt():
|
|||
""",
|
||||
"get_mood_prompt",
|
||||
)
|
||||
|
||||
|
||||
Prompt(
|
||||
"""
|
||||
{chat_talking_prompt}
|
||||
|
|
@ -103,9 +103,7 @@ class ChatMood:
|
|||
if random.random() > update_probability:
|
||||
return
|
||||
|
||||
logger.debug(
|
||||
f"{self.log_prefix} 更新情绪状态,更新概率: {update_probability:.2f}"
|
||||
)
|
||||
logger.debug(f"{self.log_prefix} 更新情绪状态,更新概率: {update_probability:.2f}")
|
||||
|
||||
message_time: float = message.message_info.time # type: ignore
|
||||
message_list_before_now = get_raw_msg_by_timestamp_with_chat_inclusive(
|
||||
|
|
@ -154,12 +152,12 @@ class ChatMood:
|
|||
self.mood_state = response
|
||||
|
||||
self.last_change_time = message_time
|
||||
|
||||
|
||||
async def get_mood(self) -> str:
|
||||
self.regression_count = 0
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
|
||||
logger.info(f"{self.log_prefix} 获取情绪状态")
|
||||
message_list_before_now = get_raw_msg_by_timestamp_with_chat_inclusive(
|
||||
chat_id=self.chat_id,
|
||||
|
|
@ -207,7 +205,7 @@ class ChatMood:
|
|||
self.mood_state = response
|
||||
|
||||
self.last_change_time = current_time
|
||||
|
||||
|
||||
return response
|
||||
|
||||
async def regress_mood(self):
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ from src.config.config import global_config, model_config
|
|||
|
||||
logger = get_logger("person_info")
|
||||
|
||||
relation_selection_model = LLMRequest(model_set=model_config.model_task_config.utils_small, request_type="relation_selection")
|
||||
relation_selection_model = LLMRequest(
|
||||
model_set=model_config.model_task_config.utils_small, request_type="relation_selection"
|
||||
)
|
||||
|
||||
|
||||
def get_person_id(platform: str, user_id: Union[int, str]) -> str:
|
||||
|
|
@ -91,9 +93,10 @@ def extract_categories_from_response(response: str) -> list[str]:
|
|||
"""从response中提取所有<>包裹的内容"""
|
||||
if not isinstance(response, str):
|
||||
return []
|
||||
|
||||
|
||||
import re
|
||||
pattern = r'<([^<>]+)>'
|
||||
|
||||
pattern = r"<([^<>]+)>"
|
||||
matches = re.findall(pattern, response)
|
||||
return matches
|
||||
|
||||
|
|
@ -420,7 +423,7 @@ class Person:
|
|||
except Exception as e:
|
||||
logger.error(f"同步用户 {self.person_id} 信息到数据库时出错: {e}")
|
||||
|
||||
async def build_relationship(self,chat_content:str = "",info_type = ""):
|
||||
async def build_relationship(self, chat_content: str = "", info_type=""):
|
||||
if not self.is_known:
|
||||
return ""
|
||||
# 构建points文本
|
||||
|
|
@ -433,7 +436,7 @@ class Person:
|
|||
|
||||
points_text = ""
|
||||
category_list = self.get_all_category()
|
||||
|
||||
|
||||
if chat_content:
|
||||
prompt = f"""当前聊天内容:
|
||||
{chat_content}
|
||||
|
|
@ -449,11 +452,13 @@ class Person:
|
|||
# print(prompt)
|
||||
# print(response)
|
||||
category_list = extract_categories_from_response(response)
|
||||
if "none" not in category_list:
|
||||
if "none" not in category_list:
|
||||
for category in category_list:
|
||||
random_memory = self.get_random_memory_by_category(category, 2)
|
||||
if random_memory:
|
||||
random_memory_str = "\n".join([get_memory_content_from_memory(memory) for memory in random_memory])
|
||||
random_memory_str = "\n".join(
|
||||
[get_memory_content_from_memory(memory) for memory in random_memory]
|
||||
)
|
||||
points_text = f"有关 {category} 的内容:{random_memory_str}"
|
||||
break
|
||||
elif info_type:
|
||||
|
|
@ -469,15 +474,16 @@ class Person:
|
|||
# print(prompt)
|
||||
# print(response)
|
||||
category_list = extract_categories_from_response(response)
|
||||
if "none" not in category_list:
|
||||
if "none" not in category_list:
|
||||
for category in category_list:
|
||||
random_memory = self.get_random_memory_by_category(category, 3)
|
||||
if random_memory:
|
||||
random_memory_str = "\n".join([get_memory_content_from_memory(memory) for memory in random_memory])
|
||||
random_memory_str = "\n".join(
|
||||
[get_memory_content_from_memory(memory) for memory in random_memory]
|
||||
)
|
||||
points_text = f"有关 {category} 的内容:{random_memory_str}"
|
||||
break
|
||||
else:
|
||||
|
||||
for category in category_list:
|
||||
random_memory = self.get_random_memory_by_category(category, 1)[0]
|
||||
if random_memory:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import random
|
|||
import base64
|
||||
import os
|
||||
import uuid
|
||||
import time
|
||||
|
||||
from typing import Optional, Tuple, List, Dict, Any
|
||||
from src.common.logger import get_logger
|
||||
|
|
@ -358,7 +357,7 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
"description": None,
|
||||
"emotions": None,
|
||||
"replaced": None,
|
||||
"hash": None
|
||||
"hash": None,
|
||||
}
|
||||
|
||||
# 3. 确保emoji目录存在
|
||||
|
|
@ -368,19 +367,21 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
if not filename:
|
||||
# 基于时间戳、微秒和短base64生成唯一文件名
|
||||
import time
|
||||
|
||||
timestamp = int(time.time())
|
||||
microseconds = int(time.time() * 1000000) % 1000000 # 添加微秒级精度
|
||||
|
||||
# 生成12位随机标识符,使用base64编码(增加随机性)
|
||||
import random
|
||||
random_bytes = random.getrandbits(72).to_bytes(9, 'big') # 72位 = 9字节 = 12位base64
|
||||
short_id = base64.b64encode(random_bytes).decode('ascii')[:12].rstrip('=')
|
||||
|
||||
random_bytes = random.getrandbits(72).to_bytes(9, "big") # 72位 = 9字节 = 12位base64
|
||||
short_id = base64.b64encode(random_bytes).decode("ascii")[:12].rstrip("=")
|
||||
# 确保base64编码适合文件名(替换/和-)
|
||||
short_id = short_id.replace('/', '_').replace('+', '-')
|
||||
short_id = short_id.replace("/", "_").replace("+", "-")
|
||||
filename = f"emoji_{timestamp}_{microseconds}_{short_id}"
|
||||
|
||||
# 确保文件名有扩展名
|
||||
if not filename.lower().endswith(('.jpg', '.jpeg', '.png', '.gif')):
|
||||
if not filename.lower().endswith((".jpg", ".jpeg", ".png", ".gif")):
|
||||
filename = f"{filename}.png" # 默认使用png格式
|
||||
|
||||
# 检查文件名是否已存在,如果存在则重新生成短标识符
|
||||
|
|
@ -390,14 +391,15 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
while os.path.exists(temp_file_path) and attempts < max_attempts:
|
||||
# 重新生成短标识符
|
||||
import random
|
||||
random_bytes = random.getrandbits(48).to_bytes(6, 'big')
|
||||
short_id = base64.b64encode(random_bytes).decode('ascii')[:8].rstrip('=')
|
||||
short_id = short_id.replace('/', '_').replace('+', '-')
|
||||
|
||||
random_bytes = random.getrandbits(48).to_bytes(6, "big")
|
||||
short_id = base64.b64encode(random_bytes).decode("ascii")[:8].rstrip("=")
|
||||
short_id = short_id.replace("/", "_").replace("+", "-")
|
||||
|
||||
# 分离文件名和扩展名,重新生成文件名
|
||||
name_part, ext = os.path.splitext(filename)
|
||||
# 去掉原来的标识符,添加新的
|
||||
base_name = name_part.rsplit('_', 1)[0] # 移除最后一个_后的部分
|
||||
base_name = name_part.rsplit("_", 1)[0] # 移除最后一个_后的部分
|
||||
filename = f"{base_name}_{short_id}{ext}"
|
||||
temp_file_path = os.path.join(EMOJI_DIR, filename)
|
||||
attempts += 1
|
||||
|
|
@ -406,7 +408,7 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
if os.path.exists(temp_file_path):
|
||||
uuid_short = str(uuid.uuid4())[:8]
|
||||
name_part, ext = os.path.splitext(filename)
|
||||
base_name = name_part.rsplit('_', 1)[0]
|
||||
base_name = name_part.rsplit("_", 1)[0]
|
||||
filename = f"{base_name}_{uuid_short}{ext}"
|
||||
temp_file_path = os.path.join(EMOJI_DIR, filename)
|
||||
|
||||
|
|
@ -428,7 +430,7 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
"description": None,
|
||||
"emotions": None,
|
||||
"replaced": None,
|
||||
"hash": None
|
||||
"hash": None,
|
||||
}
|
||||
|
||||
# 5. 保存base64图片到emoji目录
|
||||
|
|
@ -443,7 +445,7 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
"description": None,
|
||||
"emotions": None,
|
||||
"replaced": None,
|
||||
"hash": None
|
||||
"hash": None,
|
||||
}
|
||||
|
||||
logger.debug(f"[EmojiAPI] 图片已保存到临时文件: {temp_file_path}")
|
||||
|
|
@ -456,7 +458,7 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
"description": None,
|
||||
"emotions": None,
|
||||
"replaced": None,
|
||||
"hash": None
|
||||
"hash": None,
|
||||
}
|
||||
|
||||
# 6. 调用注册方法
|
||||
|
|
@ -483,8 +485,8 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
# 通过文件名查找新注册的表情包(注意:文件名在注册后可能已经改变)
|
||||
for emoji_obj in reversed(emoji_manager.emoji_objects):
|
||||
if not emoji_obj.is_deleted and (
|
||||
emoji_obj.filename == filename or # 直接匹配
|
||||
(hasattr(emoji_obj, 'full_path') and filename in emoji_obj.full_path) # 路径包含匹配
|
||||
emoji_obj.filename == filename # 直接匹配
|
||||
or (hasattr(emoji_obj, "full_path") and filename in emoji_obj.full_path) # 路径包含匹配
|
||||
):
|
||||
new_emoji_info = emoji_obj
|
||||
break
|
||||
|
|
@ -501,7 +503,7 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
"description": description,
|
||||
"emotions": emotions,
|
||||
"replaced": replaced,
|
||||
"hash": emoji_hash
|
||||
"hash": emoji_hash,
|
||||
}
|
||||
else:
|
||||
return {
|
||||
|
|
@ -510,7 +512,7 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
"description": None,
|
||||
"emotions": None,
|
||||
"replaced": None,
|
||||
"hash": None
|
||||
"hash": None,
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -521,7 +523,7 @@ async def register_emoji(image_base64: str, filename: Optional[str] = None) -> D
|
|||
"description": None,
|
||||
"emotions": None,
|
||||
"replaced": None,
|
||||
"hash": None
|
||||
"hash": None,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -585,16 +587,16 @@ async def delete_emoji(emoji_hash: str) -> Dict[str, Any]:
|
|||
"count_before": count_before,
|
||||
"count_after": count_after,
|
||||
"description": description,
|
||||
"emotions": emotions
|
||||
"emotions": emotions,
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"表情包删除失败,可能因为哈希值不存在或删除过程出错",
|
||||
"message": "表情包删除失败,可能因为哈希值不存在或删除过程出错",
|
||||
"count_before": count_before,
|
||||
"count_after": count_after,
|
||||
"description": None,
|
||||
"emotions": None
|
||||
"emotions": None,
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -605,7 +607,7 @@ async def delete_emoji(emoji_hash: str) -> Dict[str, Any]:
|
|||
"count_before": None,
|
||||
"count_after": None,
|
||||
"description": None,
|
||||
"emotions": None
|
||||
"emotions": None,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -659,7 +661,7 @@ async def delete_emoji_by_description(description: str, exact_match: bool = Fals
|
|||
"message": f"未找到匹配描述 '{description}' 的表情包",
|
||||
"deleted_count": 0,
|
||||
"deleted_hashes": [],
|
||||
"matched_count": 0
|
||||
"matched_count": 0,
|
||||
}
|
||||
|
||||
# 删除匹配的表情包
|
||||
|
|
@ -681,7 +683,7 @@ async def delete_emoji_by_description(description: str, exact_match: bool = Fals
|
|||
"message": f"成功删除 {deleted_count} 个表情包 (匹配到 {matched_count} 个)",
|
||||
"deleted_count": deleted_count,
|
||||
"deleted_hashes": deleted_hashes,
|
||||
"matched_count": matched_count
|
||||
"matched_count": matched_count,
|
||||
}
|
||||
else:
|
||||
return {
|
||||
|
|
@ -689,7 +691,7 @@ async def delete_emoji_by_description(description: str, exact_match: bool = Fals
|
|||
"message": f"匹配到 {matched_count} 个表情包,但删除全部失败",
|
||||
"deleted_count": 0,
|
||||
"deleted_hashes": [],
|
||||
"matched_count": matched_count
|
||||
"matched_count": matched_count,
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -699,5 +701,5 @@ async def delete_emoji_by_description(description: str, exact_match: bool = Fals
|
|||
"message": f"删除过程中发生错误: {str(e)}",
|
||||
"deleted_count": 0,
|
||||
"deleted_hashes": [],
|
||||
"matched_count": 0
|
||||
"matched_count": 0,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ from src.chat.frequency_control.frequency_control import frequency_control_manag
|
|||
|
||||
logger = get_logger("frequency_api")
|
||||
|
||||
|
||||
def get_current_talk_frequency(chat_id: str) -> float:
|
||||
return frequency_control_manager.get_or_create_frequency_control(chat_id).get_talk_frequency_adjust()
|
||||
|
||||
|
||||
def set_talk_frequency_adjust(chat_id: str, talk_frequency_adjust: float) -> None:
|
||||
frequency_control_manager.get_or_create_frequency_control(
|
||||
chat_id
|
||||
).set_talk_frequency_adjust(talk_frequency_adjust)
|
||||
frequency_control_manager.get_or_create_frequency_control(chat_id).set_talk_frequency_adjust(talk_frequency_adjust)
|
||||
|
||||
|
||||
def get_talk_frequency_adjust(chat_id: str) -> float:
|
||||
return frequency_control_manager.get_or_create_frequency_control(chat_id).get_talk_frequency_adjust()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import asyncio
|
||||
import traceback
|
||||
import time
|
||||
from typing import Optional, Union, Dict, List, TYPE_CHECKING, Tuple
|
||||
from typing import Optional
|
||||
|
||||
from src.chat.message_receive import message
|
||||
from src.common.logger import get_logger
|
||||
from src.mood.mood_manager import mood_manager
|
||||
|
||||
|
|
@ -12,5 +9,5 @@ logger = get_logger("mood_api")
|
|||
|
||||
async def get_mood_by_chat_id(chat_id: str) -> Optional[float]:
|
||||
chat_mood = mood_manager.get_mood_by_chat_id(chat_id)
|
||||
mood = asyncio.create_task(chat_mood.get_mood())
|
||||
return mood
|
||||
mood = asyncio.create_task(chat_mood.get_mood())
|
||||
return mood
|
||||
|
|
|
|||
|
|
@ -363,7 +363,7 @@ async def custom_reply_set_to_stream(
|
|||
) -> bool:
|
||||
"""
|
||||
向指定流发送混合型消息集
|
||||
|
||||
|
||||
Args:
|
||||
reply_set: ReplySetModel 对象,包含多个 ReplyContent
|
||||
stream_id: 聊天流ID
|
||||
|
|
@ -451,7 +451,9 @@ def _parse_content_to_seg(reply_content: "ReplyContent") -> Tuple[Seg, bool]:
|
|||
single_node_content.append(sub_seg)
|
||||
message_segment = Seg(type="seglist", data=single_node_content)
|
||||
forward_message_list.append(
|
||||
MessageBase(message_segment=message_segment, message_info=BaseMessageInfo(user_info=user_info)).to_dict()
|
||||
MessageBase(
|
||||
message_segment=message_segment, message_info=BaseMessageInfo(user_info=user_info)
|
||||
).to_dict()
|
||||
)
|
||||
return Seg(type="forward", data=forward_message_list), False # type: ignore
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class ToolExecutor:
|
|||
# 缓存未命中,执行工具调用
|
||||
# 获取可用工具
|
||||
tools = self._get_tool_definitions()
|
||||
|
||||
|
||||
# print(f"tools: {tools}")
|
||||
|
||||
# 获取当前时间
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class EmojiAction(BaseAction):
|
|||
# 1. 获取发送表情的原因
|
||||
# reason = self.action_data.get("reason", "表达当前情绪")
|
||||
reason = self.reasoning
|
||||
|
||||
|
||||
# 2. 随机获取20个表情包
|
||||
sampled_emojis = await emoji_api.get_random(30)
|
||||
if not sampled_emojis:
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ from src.plugins.built_in.relation.relation import BuildRelationAction
|
|||
logger = get_logger("relation_actions")
|
||||
|
||||
|
||||
|
||||
class GetPersonInfoTool(BaseTool):
|
||||
"""获取用户信息"""
|
||||
|
||||
|
|
@ -24,7 +23,7 @@ class GetPersonInfoTool(BaseTool):
|
|||
("person_name", ToolParamType.STRING, "需要获取信息的人的名称", True, None),
|
||||
("info_type", ToolParamType.STRING, "需要获取信息的类型", True, None),
|
||||
]
|
||||
|
||||
|
||||
available_for_llm = True
|
||||
|
||||
async def execute(self, function_args: dict[str, Any]) -> dict[str, Any]:
|
||||
|
|
@ -44,7 +43,7 @@ class GetPersonInfoTool(BaseTool):
|
|||
return {"content": f"用户 {person_name} 不存在"}
|
||||
if not person.is_known:
|
||||
return {"content": f"不认识用户 {person_name}"}
|
||||
|
||||
|
||||
relation_str = await person.build_relationship(info_type=info_type)
|
||||
|
||||
return {"content": relation_str}
|
||||
|
|
|
|||
Loading…
Reference in New Issue