🤖 自动格式化代码 [skip ci]
This commit is contained in:
@@ -1183,4 +1183,3 @@ def main():
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|||||||
@@ -370,7 +370,6 @@ class VirtualLogDisplay:
|
|||||||
self.text_widget.tag_add(tag_name, f"{start_pos}+{tag_info[1]}c", f"{start_pos}+{tag_info[2]}c")
|
self.text_widget.tag_add(tag_name, f"{start_pos}+{tag_info[1]}c", f"{start_pos}+{tag_info[2]}c")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AsyncLogLoader:
|
class AsyncLogLoader:
|
||||||
"""异步日志加载器"""
|
"""异步日志加载器"""
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ class HeartFCSender:
|
|||||||
message.build_reply()
|
message.build_reply()
|
||||||
logger.debug(f"[{chat_id}] 选择回复引用消息: {message.processed_plain_text[:20]}...")
|
logger.debug(f"[{chat_id}] 选择回复引用消息: {message.processed_plain_text[:20]}...")
|
||||||
|
|
||||||
|
|
||||||
await message.process()
|
await message.process()
|
||||||
|
|
||||||
if typing:
|
if typing:
|
||||||
@@ -110,7 +109,6 @@ class HeartFCSender:
|
|||||||
)
|
)
|
||||||
await asyncio.sleep(typing_time)
|
await asyncio.sleep(typing_time)
|
||||||
|
|
||||||
|
|
||||||
sent_msg = await send_message(message)
|
sent_msg = await send_message(message)
|
||||||
if not sent_msg:
|
if not sent_msg:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ ActionInfo = Dict[str, Any]
|
|||||||
class ActionManager:
|
class ActionManager:
|
||||||
"""
|
"""
|
||||||
动作管理器,用于管理各种类型的动作
|
动作管理器,用于管理各种类型的动作
|
||||||
|
|
||||||
现在统一使用新插件系统,简化了原有的新旧兼容逻辑。
|
现在统一使用新插件系统,简化了原有的新旧兼容逻辑。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ class BasePlanner(ABC):
|
|||||||
self.action_manager = action_manager
|
self.action_manager = action_manager
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def plan(self, all_plan_info: List[InfoBase], running_memorys: List[Dict[str, Any]], loop_start_time: float) -> Dict[str, Any]:
|
async def plan(
|
||||||
|
self, all_plan_info: List[InfoBase], running_memorys: List[Dict[str, Any]], loop_start_time: float
|
||||||
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
规划下一步行动
|
规划下一步行动
|
||||||
|
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ class ActionModifier:
|
|||||||
|
|
||||||
for action_name, action_info in actions_with_info.items():
|
for action_name, action_info in actions_with_info.items():
|
||||||
activation_type = action_info.get("focus_activation_type", "always")
|
activation_type = action_info.get("focus_activation_type", "always")
|
||||||
|
|
||||||
print(f"action_name: {action_name}, activation_type: {activation_type}")
|
print(f"action_name: {action_name}, activation_type: {activation_type}")
|
||||||
|
|
||||||
# 现在统一是字符串格式的激活类型值
|
# 现在统一是字符串格式的激活类型值
|
||||||
|
|||||||
@@ -82,7 +82,9 @@ class ActionPlanner(BasePlanner):
|
|||||||
request_type="focus.planner", # 用于动作规划
|
request_type="focus.planner", # 用于动作规划
|
||||||
)
|
)
|
||||||
|
|
||||||
async def plan(self, all_plan_info: List[InfoBase], running_memorys: List[Dict[str, Any]], loop_start_time: float) -> Dict[str, Any]:
|
async def plan(
|
||||||
|
self, all_plan_info: List[InfoBase], running_memorys: List[Dict[str, Any]], loop_start_time: float
|
||||||
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
规划器 (Planner): 使用LLM根据上下文决定做出什么动作。
|
规划器 (Planner): 使用LLM根据上下文决定做出什么动作。
|
||||||
|
|
||||||
@@ -243,7 +245,7 @@ class ActionPlanner(BasePlanner):
|
|||||||
if selected_expressions:
|
if selected_expressions:
|
||||||
action_data["selected_expressions"] = selected_expressions
|
action_data["selected_expressions"] = selected_expressions
|
||||||
logger.debug(f"{self.log_prefix} 传递{len(selected_expressions)}个选中的表达方式到action_data")
|
logger.debug(f"{self.log_prefix} 传递{len(selected_expressions)}个选中的表达方式到action_data")
|
||||||
|
|
||||||
action_data["loop_start_time"] = loop_start_time
|
action_data["loop_start_time"] = loop_start_time
|
||||||
|
|
||||||
# 对于reply动作不需要额外处理,因为相关字段已经在上面的循环中添加到action_data
|
# 对于reply动作不需要额外处理,因为相关字段已经在上面的循环中添加到action_data
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ def init_prompt():
|
|||||||
""",
|
""",
|
||||||
"default_generator_private_prompt",
|
"default_generator_private_prompt",
|
||||||
)
|
)
|
||||||
|
|
||||||
Prompt(
|
Prompt(
|
||||||
"""
|
"""
|
||||||
你可以参考你的以下的语言习惯,如果情景合适就使用,不要盲目使用,不要生硬使用,而是结合到表达中:
|
你可以参考你的以下的语言习惯,如果情景合适就使用,不要盲目使用,不要生硬使用,而是结合到表达中:
|
||||||
@@ -156,7 +156,7 @@ class DefaultReplyer:
|
|||||||
|
|
||||||
await self.heart_fc_sender.register_thinking(thinking_message)
|
await self.heart_fc_sender.register_thinking(thinking_message)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def generate_reply_with_context(
|
async def generate_reply_with_context(
|
||||||
self,
|
self,
|
||||||
reply_data: Dict[str, Any],
|
reply_data: Dict[str, Any],
|
||||||
@@ -166,8 +166,6 @@ class DefaultReplyer:
|
|||||||
(已整合原 HeartFCGenerator 的功能)
|
(已整合原 HeartFCGenerator 的功能)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
|
||||||
# 3. 构建 Prompt
|
# 3. 构建 Prompt
|
||||||
with Timer("构建Prompt", {}): # 内部计时器,可选保留
|
with Timer("构建Prompt", {}): # 内部计时器,可选保留
|
||||||
prompt = await self.build_prompt_reply_context(
|
prompt = await self.build_prompt_reply_context(
|
||||||
@@ -206,13 +204,13 @@ class DefaultReplyer:
|
|||||||
reply_seg = ("text", str)
|
reply_seg = ("text", str)
|
||||||
reply_set.append(reply_seg)
|
reply_set.append(reply_seg)
|
||||||
|
|
||||||
return True , reply_set
|
return True, reply_set
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"{self.log_prefix}回复生成意外失败: {e}")
|
logger.error(f"{self.log_prefix}回复生成意外失败: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
async def rewrite_reply_with_context(
|
async def rewrite_reply_with_context(
|
||||||
self,
|
self,
|
||||||
reply_data: Dict[str, Any],
|
reply_data: Dict[str, Any],
|
||||||
@@ -221,8 +219,6 @@ class DefaultReplyer:
|
|||||||
表达器 (Expressor): 核心逻辑,负责生成回复文本。
|
表达器 (Expressor): 核心逻辑,负责生成回复文本。
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
|
||||||
reply_to = reply_data.get("reply_to", "")
|
reply_to = reply_data.get("reply_to", "")
|
||||||
raw_reply = reply_data.get("raw_reply", "")
|
raw_reply = reply_data.get("raw_reply", "")
|
||||||
reason = reply_data.get("reason", "")
|
reason = reply_data.get("reason", "")
|
||||||
@@ -275,24 +271,20 @@ class DefaultReplyer:
|
|||||||
logger.error(f"{self.log_prefix}回复生成意外失败: {e}")
|
logger.error(f"{self.log_prefix}回复生成意外失败: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def build_prompt_reply_context(
|
async def build_prompt_reply_context(
|
||||||
self,
|
self,
|
||||||
reply_data=None,
|
reply_data=None,
|
||||||
) -> str:
|
) -> str:
|
||||||
chat_stream = self.chat_stream
|
chat_stream = self.chat_stream
|
||||||
|
|
||||||
is_group_chat = bool(chat_stream.group_info)
|
is_group_chat = bool(chat_stream.group_info)
|
||||||
|
|
||||||
identity = reply_data.get("identity", "")
|
identity = reply_data.get("identity", "")
|
||||||
extra_info_block = reply_data.get("extra_info_block", "")
|
extra_info_block = reply_data.get("extra_info_block", "")
|
||||||
relation_info_block = reply_data.get("relation_info_block", "")
|
relation_info_block = reply_data.get("relation_info_block", "")
|
||||||
reply_to = reply_data.get("reply_to", "none")
|
reply_to = reply_data.get("reply_to", "none")
|
||||||
|
|
||||||
sender = ""
|
sender = ""
|
||||||
target = ""
|
target = ""
|
||||||
if ":" in reply_to or ":" in reply_to:
|
if ":" in reply_to or ":" in reply_to:
|
||||||
@@ -301,7 +293,6 @@ class DefaultReplyer:
|
|||||||
if len(parts) == 2:
|
if len(parts) == 2:
|
||||||
sender = parts[0].strip()
|
sender = parts[0].strip()
|
||||||
target = parts[1].strip()
|
target = parts[1].strip()
|
||||||
|
|
||||||
|
|
||||||
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
|
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
|
||||||
chat_id=chat_stream.stream_id,
|
chat_id=chat_stream.stream_id,
|
||||||
@@ -379,9 +370,7 @@ class DefaultReplyer:
|
|||||||
# logger.debug("开始构建 focus prompt")
|
# logger.debug("开始构建 focus prompt")
|
||||||
|
|
||||||
if sender:
|
if sender:
|
||||||
reply_target_block = (
|
reply_target_block = f"现在{sender}说的:{target}。引起了你的注意,你想要在群里发言或者回复这条消息。"
|
||||||
f"现在{sender}说的:{target}。引起了你的注意,你想要在群里发言或者回复这条消息。"
|
|
||||||
)
|
|
||||||
elif target:
|
elif target:
|
||||||
reply_target_block = f"现在{target}引起了你的注意,你想要在群里发言或者回复这条消息。"
|
reply_target_block = f"现在{target}引起了你的注意,你想要在群里发言或者回复这条消息。"
|
||||||
else:
|
else:
|
||||||
@@ -436,9 +425,6 @@ class DefaultReplyer:
|
|||||||
raw_reply,
|
raw_reply,
|
||||||
reply_to,
|
reply_to,
|
||||||
) -> str:
|
) -> str:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sender = ""
|
sender = ""
|
||||||
target = ""
|
target = ""
|
||||||
if ":" in reply_to or ":" in reply_to:
|
if ":" in reply_to or ":" in reply_to:
|
||||||
@@ -447,9 +433,9 @@ class DefaultReplyer:
|
|||||||
if len(parts) == 2:
|
if len(parts) == 2:
|
||||||
sender = parts[0].strip()
|
sender = parts[0].strip()
|
||||||
target = parts[1].strip()
|
target = parts[1].strip()
|
||||||
|
|
||||||
chat_stream = self.chat_stream
|
chat_stream = self.chat_stream
|
||||||
|
|
||||||
is_group_chat = bool(chat_stream.group_info)
|
is_group_chat = bool(chat_stream.group_info)
|
||||||
|
|
||||||
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
|
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
|
||||||
@@ -608,23 +594,22 @@ class DefaultReplyer:
|
|||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if (bot_message.is_private_message() or
|
if (
|
||||||
bot_message.reply.processed_plain_text != "[System Trigger Context]" or
|
bot_message.is_private_message()
|
||||||
mark_head):
|
or bot_message.reply.processed_plain_text != "[System Trigger Context]"
|
||||||
|
or mark_head
|
||||||
|
):
|
||||||
set_reply = False
|
set_reply = False
|
||||||
else:
|
else:
|
||||||
set_reply = True
|
set_reply = True
|
||||||
|
|
||||||
if not mark_head:
|
if not mark_head:
|
||||||
mark_head = True
|
mark_head = True
|
||||||
typing = False
|
typing = False
|
||||||
else:
|
else:
|
||||||
typing = True
|
typing = True
|
||||||
|
|
||||||
|
sent_msg = await self.heart_fc_sender.send_message(bot_message, typing=typing, set_reply=set_reply)
|
||||||
sent_msg = await self.heart_fc_sender.send_message(
|
|
||||||
bot_message, typing=typing, set_reply=set_reply
|
|
||||||
)
|
|
||||||
|
|
||||||
reply_message_ids.append(part_message_id) # 记录我们生成的ID
|
reply_message_ids.append(part_message_id) # 记录我们生成的ID
|
||||||
|
|
||||||
@@ -652,7 +637,7 @@ class DefaultReplyer:
|
|||||||
is_emoji: bool,
|
is_emoji: bool,
|
||||||
thinking_start_time: float,
|
thinking_start_time: float,
|
||||||
display_message: str,
|
display_message: str,
|
||||||
anchor_message: MessageRecv = None
|
anchor_message: MessageRecv = None,
|
||||||
) -> MessageSending:
|
) -> MessageSending:
|
||||||
"""构建单个发送消息"""
|
"""构建单个发送消息"""
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from src.common.logger import get_logger
|
|||||||
from src.chat.heart_flow.utils_chat import get_chat_type_and_target_info
|
from src.chat.heart_flow.utils_chat import get_chat_type_and_target_info
|
||||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||||
from src.person_info.person_info import get_person_info_manager
|
from src.person_info.person_info import get_person_info_manager
|
||||||
|
|
||||||
logger = get_logger("observation")
|
logger = get_logger("observation")
|
||||||
|
|
||||||
# 定义提示模板
|
# 定义提示模板
|
||||||
@@ -71,7 +72,7 @@ class ChattingObservation(Observation):
|
|||||||
self.oldest_messages = []
|
self.oldest_messages = []
|
||||||
self.oldest_messages_str = ""
|
self.oldest_messages_str = ""
|
||||||
|
|
||||||
self.last_observe_time = datetime.now().timestamp() -1
|
self.last_observe_time = datetime.now().timestamp() - 1
|
||||||
print(f"last_observe_time: {self.last_observe_time}")
|
print(f"last_observe_time: {self.last_observe_time}")
|
||||||
initial_messages = get_raw_msg_before_timestamp_with_chat(self.chat_id, self.last_observe_time, 10)
|
initial_messages = get_raw_msg_before_timestamp_with_chat(self.chat_id, self.last_observe_time, 10)
|
||||||
self.last_observe_time = initial_messages[-1]["time"] if initial_messages else self.last_observe_time
|
self.last_observe_time = initial_messages[-1]["time"] if initial_messages else self.last_observe_time
|
||||||
@@ -159,10 +160,9 @@ class ChattingObservation(Observation):
|
|||||||
"processed_plain_text": find_msg.get("processed_plain_text"),
|
"processed_plain_text": find_msg.get("processed_plain_text"),
|
||||||
}
|
}
|
||||||
find_rec_msg = MessageRecv(message_dict)
|
find_rec_msg = MessageRecv(message_dict)
|
||||||
|
|
||||||
find_rec_msg.update_chat_stream(get_chat_manager().get_or_create_stream(self.chat_id))
|
find_rec_msg.update_chat_stream(get_chat_manager().get_or_create_stream(self.chat_id))
|
||||||
|
|
||||||
|
|
||||||
return find_rec_msg
|
return find_rec_msg
|
||||||
|
|
||||||
async def observe(self):
|
async def observe(self):
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ class ChatManager:
|
|||||||
# 使用MD5生成唯一ID
|
# 使用MD5生成唯一ID
|
||||||
key = "_".join(components)
|
key = "_".join(components)
|
||||||
return hashlib.md5(key.encode()).hexdigest()
|
return hashlib.md5(key.encode()).hexdigest()
|
||||||
|
|
||||||
def get_stream_id(self, platform: str, chat_id: str, is_group: bool = True) -> str:
|
def get_stream_id(self, platform: str, chat_id: str, is_group: bool = True) -> str:
|
||||||
"""获取聊天流ID"""
|
"""获取聊天流ID"""
|
||||||
if is_group:
|
if is_group:
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from src.plugin_system.apis import (
|
|||||||
message_api,
|
message_api,
|
||||||
person_api,
|
person_api,
|
||||||
send_api,
|
send_api,
|
||||||
utils_api
|
utils_api,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 导出所有API模块,使它们可以通过 apis.xxx 方式访问
|
# 导出所有API模块,使它们可以通过 apis.xxx 方式访问
|
||||||
@@ -29,5 +29,5 @@ __all__ = [
|
|||||||
"message_api",
|
"message_api",
|
||||||
"person_api",
|
"person_api",
|
||||||
"send_api",
|
"send_api",
|
||||||
"utils_api"
|
"utils_api",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
from src.plugin_system.apis import chat_api
|
from src.plugin_system.apis import chat_api
|
||||||
streams = chat_api.get_all_group_streams()
|
streams = chat_api.get_all_group_streams()
|
||||||
chat_type = chat_api.get_stream_type(stream)
|
chat_type = chat_api.get_stream_type(stream)
|
||||||
|
|
||||||
或者:
|
或者:
|
||||||
from src.plugin_system.apis.chat_api import ChatManager as chat
|
from src.plugin_system.apis.chat_api import ChatManager as chat
|
||||||
streams = chat.get_all_group_streams()
|
streams = chat.get_all_group_streams()
|
||||||
@@ -24,14 +24,14 @@ logger = get_logger("chat_api")
|
|||||||
|
|
||||||
class ChatManager:
|
class ChatManager:
|
||||||
"""聊天管理器 - 专门负责聊天信息的查询和管理"""
|
"""聊天管理器 - 专门负责聊天信息的查询和管理"""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_streams(platform: str = "qq") -> List[ChatStream]:
|
def get_all_streams(platform: str = "qq") -> List[ChatStream]:
|
||||||
"""获取所有聊天流
|
"""获取所有聊天流
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
platform: 平台筛选,默认为"qq"
|
platform: 平台筛选,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[ChatStream]: 聊天流列表
|
List[ChatStream]: 聊天流列表
|
||||||
"""
|
"""
|
||||||
@@ -44,14 +44,14 @@ class ChatManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[ChatAPI] 获取聊天流失败: {e}")
|
logger.error(f"[ChatAPI] 获取聊天流失败: {e}")
|
||||||
return streams
|
return streams
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_group_streams(platform: str = "qq") -> List[ChatStream]:
|
def get_group_streams(platform: str = "qq") -> List[ChatStream]:
|
||||||
"""获取所有群聊聊天流
|
"""获取所有群聊聊天流
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
platform: 平台筛选,默认为"qq"
|
platform: 平台筛选,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[ChatStream]: 群聊聊天流列表
|
List[ChatStream]: 群聊聊天流列表
|
||||||
"""
|
"""
|
||||||
@@ -64,14 +64,14 @@ class ChatManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[ChatAPI] 获取群聊流失败: {e}")
|
logger.error(f"[ChatAPI] 获取群聊流失败: {e}")
|
||||||
return streams
|
return streams
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_private_streams(platform: str = "qq") -> List[ChatStream]:
|
def get_private_streams(platform: str = "qq") -> List[ChatStream]:
|
||||||
"""获取所有私聊聊天流
|
"""获取所有私聊聊天流
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
platform: 平台筛选,默认为"qq"
|
platform: 平台筛选,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[ChatStream]: 私聊聊天流列表
|
List[ChatStream]: 私聊聊天流列表
|
||||||
"""
|
"""
|
||||||
@@ -84,15 +84,15 @@ class ChatManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[ChatAPI] 获取私聊流失败: {e}")
|
logger.error(f"[ChatAPI] 获取私聊流失败: {e}")
|
||||||
return streams
|
return streams
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_stream_by_group_id(group_id: str, platform: str = "qq") -> Optional[ChatStream]:
|
def get_stream_by_group_id(group_id: str, platform: str = "qq") -> Optional[ChatStream]:
|
||||||
"""根据群ID获取聊天流
|
"""根据群ID获取聊天流
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
group_id: 群聊ID
|
group_id: 群聊ID
|
||||||
platform: 平台,默认为"qq"
|
platform: 平台,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[ChatStream]: 聊天流对象,如果未找到返回None
|
Optional[ChatStream]: 聊天流对象,如果未找到返回None
|
||||||
"""
|
"""
|
||||||
@@ -109,15 +109,15 @@ class ChatManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[ChatAPI] 查找群聊流失败: {e}")
|
logger.error(f"[ChatAPI] 查找群聊流失败: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_stream_by_user_id(user_id: str, platform: str = "qq") -> Optional[ChatStream]:
|
def get_stream_by_user_id(user_id: str, platform: str = "qq") -> Optional[ChatStream]:
|
||||||
"""根据用户ID获取私聊流
|
"""根据用户ID获取私聊流
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user_id: 用户ID
|
user_id: 用户ID
|
||||||
platform: 平台,默认为"qq"
|
platform: 平台,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[ChatStream]: 聊天流对象,如果未找到返回None
|
Optional[ChatStream]: 聊天流对象,如果未找到返回None
|
||||||
"""
|
"""
|
||||||
@@ -134,74 +134,78 @@ class ChatManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[ChatAPI] 查找私聊流失败: {e}")
|
logger.error(f"[ChatAPI] 查找私聊流失败: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_stream_type(chat_stream: ChatStream) -> str:
|
def get_stream_type(chat_stream: ChatStream) -> str:
|
||||||
"""获取聊天流类型
|
"""获取聊天流类型
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_stream: 聊天流对象
|
chat_stream: 聊天流对象
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: 聊天类型 ("group", "private", "unknown")
|
str: 聊天类型 ("group", "private", "unknown")
|
||||||
"""
|
"""
|
||||||
if not chat_stream:
|
if not chat_stream:
|
||||||
return "unknown"
|
return "unknown"
|
||||||
|
|
||||||
if hasattr(chat_stream, "group_info"):
|
if hasattr(chat_stream, "group_info"):
|
||||||
return "group" if chat_stream.group_info else "private"
|
return "group" if chat_stream.group_info else "private"
|
||||||
return "unknown"
|
return "unknown"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_stream_info(chat_stream: ChatStream) -> Dict[str, Any]:
|
def get_stream_info(chat_stream: ChatStream) -> Dict[str, Any]:
|
||||||
"""获取聊天流详细信息
|
"""获取聊天流详细信息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_stream: 聊天流对象
|
chat_stream: 聊天流对象
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict[str, Any]: 聊天流信息字典
|
Dict[str, Any]: 聊天流信息字典
|
||||||
"""
|
"""
|
||||||
if not chat_stream:
|
if not chat_stream:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
info = {
|
info = {
|
||||||
"stream_id": chat_stream.stream_id,
|
"stream_id": chat_stream.stream_id,
|
||||||
"platform": chat_stream.platform,
|
"platform": chat_stream.platform,
|
||||||
"type": ChatManager.get_stream_type(chat_stream),
|
"type": ChatManager.get_stream_type(chat_stream),
|
||||||
}
|
}
|
||||||
|
|
||||||
if chat_stream.group_info:
|
if chat_stream.group_info:
|
||||||
info.update({
|
info.update(
|
||||||
"group_id": chat_stream.group_info.group_id,
|
{
|
||||||
"group_name": getattr(chat_stream.group_info, "group_name", "未知群聊"),
|
"group_id": chat_stream.group_info.group_id,
|
||||||
})
|
"group_name": getattr(chat_stream.group_info, "group_name", "未知群聊"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if chat_stream.user_info:
|
if chat_stream.user_info:
|
||||||
info.update({
|
info.update(
|
||||||
"user_id": chat_stream.user_info.user_id,
|
{
|
||||||
"user_name": chat_stream.user_info.user_nickname,
|
"user_id": chat_stream.user_info.user_id,
|
||||||
})
|
"user_name": chat_stream.user_info.user_nickname,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return info
|
return info
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[ChatAPI] 获取聊天流信息失败: {e}")
|
logger.error(f"[ChatAPI] 获取聊天流信息失败: {e}")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_recent_messages_from_obs(observations: List[Any], count: int = 5) -> List[Dict[str, Any]]:
|
def get_recent_messages_from_obs(observations: List[Any], count: int = 5) -> List[Dict[str, Any]]:
|
||||||
"""从观察对象获取最近的消息
|
"""从观察对象获取最近的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
observations: 观察对象列表
|
observations: 观察对象列表
|
||||||
count: 要获取的消息数量
|
count: 要获取的消息数量
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Dict]: 消息列表,每个消息包含发送者、内容等信息
|
List[Dict]: 消息列表,每个消息包含发送者、内容等信息
|
||||||
"""
|
"""
|
||||||
messages = []
|
messages = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if observations and len(observations) > 0:
|
if observations and len(observations) > 0:
|
||||||
obs = observations[0]
|
obs = observations[0]
|
||||||
@@ -219,13 +223,13 @@ class ChatManager:
|
|||||||
logger.debug(f"[ChatAPI] 获取到 {len(messages)} 条最近消息")
|
logger.debug(f"[ChatAPI] 获取到 {len(messages)} 条最近消息")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[ChatAPI] 获取最近消息失败: {e}")
|
logger.error(f"[ChatAPI] 获取最近消息失败: {e}")
|
||||||
|
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_streams_summary() -> Dict[str, int]:
|
def get_streams_summary() -> Dict[str, int]:
|
||||||
"""获取聊天流统计摘要
|
"""获取聊天流统计摘要
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict[str, int]: 包含各种统计信息的字典
|
Dict[str, int]: 包含各种统计信息的字典
|
||||||
"""
|
"""
|
||||||
@@ -233,14 +237,14 @@ class ChatManager:
|
|||||||
all_streams = ChatManager.get_all_streams()
|
all_streams = ChatManager.get_all_streams()
|
||||||
group_streams = ChatManager.get_group_streams()
|
group_streams = ChatManager.get_group_streams()
|
||||||
private_streams = ChatManager.get_private_streams()
|
private_streams = ChatManager.get_private_streams()
|
||||||
|
|
||||||
summary = {
|
summary = {
|
||||||
"total_streams": len(all_streams),
|
"total_streams": len(all_streams),
|
||||||
"group_streams": len(group_streams),
|
"group_streams": len(group_streams),
|
||||||
"private_streams": len(private_streams),
|
"private_streams": len(private_streams),
|
||||||
"qq_streams": len([s for s in all_streams if s.platform == "qq"]),
|
"qq_streams": len([s for s in all_streams if s.platform == "qq"]),
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(f"[ChatAPI] 聊天流统计: {summary}")
|
logger.debug(f"[ChatAPI] 聊天流统计: {summary}")
|
||||||
return summary
|
return summary
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -252,6 +256,7 @@ class ChatManager:
|
|||||||
# 模块级别的便捷函数 - 类似 requests.get(), requests.post() 的设计
|
# 模块级别的便捷函数 - 类似 requests.get(), requests.post() 的设计
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def get_all_streams(platform: str = "qq") -> List[ChatStream]:
|
def get_all_streams(platform: str = "qq") -> List[ChatStream]:
|
||||||
"""获取所有聊天流的便捷函数"""
|
"""获取所有聊天流的便捷函数"""
|
||||||
return ChatManager.get_all_streams(platform)
|
return ChatManager.get_all_streams(platform)
|
||||||
@@ -289,4 +294,4 @@ def get_stream_info(chat_stream: ChatStream) -> Dict[str, Any]:
|
|||||||
|
|
||||||
def get_streams_summary() -> Dict[str, int]:
|
def get_streams_summary() -> Dict[str, int]:
|
||||||
"""获取聊天流统计摘要的便捷函数"""
|
"""获取聊天流统计摘要的便捷函数"""
|
||||||
return ChatManager.get_streams_summary()
|
return ChatManager.get_streams_summary()
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ logger = get_logger("config_api")
|
|||||||
# 配置访问API函数
|
# 配置访问API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def get_global_config(key: str, default: Any = None) -> Any:
|
def get_global_config(key: str, default: Any = None) -> Any:
|
||||||
"""
|
"""
|
||||||
安全地从全局配置中获取一个值。
|
安全地从全局配置中获取一个值。
|
||||||
@@ -34,7 +35,7 @@ def get_global_config(key: str, default: Any = None) -> Any:
|
|||||||
# 支持嵌套键访问
|
# 支持嵌套键访问
|
||||||
keys = key.split(".")
|
keys = key.split(".")
|
||||||
current = global_config
|
current = global_config
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for k in keys:
|
for k in keys:
|
||||||
if hasattr(current, k):
|
if hasattr(current, k):
|
||||||
@@ -79,6 +80,7 @@ def get_plugin_config(plugin_config: dict, key: str, default: Any = None) -> Any
|
|||||||
# 用户信息API函数
|
# 用户信息API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
async def get_user_id_by_person_name(person_name: str) -> tuple[str, str]:
|
async def get_user_id_by_person_name(person_name: str) -> tuple[str, str]:
|
||||||
"""根据用户名获取用户ID
|
"""根据用户名获取用户ID
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ logger = get_logger("database_api")
|
|||||||
# 通用数据库查询API函数
|
# 通用数据库查询API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
async def db_query(
|
async def db_query(
|
||||||
model_class: Type[Model],
|
model_class: Type[Model],
|
||||||
query_type: str = "get",
|
query_type: str = "get",
|
||||||
@@ -202,9 +203,7 @@ async def db_save(
|
|||||||
# 如果提供了key_field和key_value,尝试更新现有记录
|
# 如果提供了key_field和key_value,尝试更新现有记录
|
||||||
if key_field and key_value is not None:
|
if key_field and key_value is not None:
|
||||||
# 查找现有记录
|
# 查找现有记录
|
||||||
existing_records = list(
|
existing_records = list(model_class.select().where(getattr(model_class, key_field) == key_value).limit(1))
|
||||||
model_class.select().where(getattr(model_class, key_field) == key_value).limit(1)
|
|
||||||
)
|
|
||||||
|
|
||||||
if existing_records:
|
if existing_records:
|
||||||
# 更新现有记录
|
# 更新现有记录
|
||||||
@@ -307,9 +306,9 @@ async def store_action_info(
|
|||||||
action_name: str = "",
|
action_name: str = "",
|
||||||
) -> Union[Dict[str, Any], None]:
|
) -> Union[Dict[str, Any], None]:
|
||||||
"""存储动作信息到数据库
|
"""存储动作信息到数据库
|
||||||
|
|
||||||
将Action执行的相关信息保存到ActionRecords表中,用于后续的记忆和上下文构建。
|
将Action执行的相关信息保存到ActionRecords表中,用于后续的记忆和上下文构建。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_stream: 聊天流对象,包含聊天相关信息
|
chat_stream: 聊天流对象,包含聊天相关信息
|
||||||
action_build_into_prompt: 是否将此动作构建到提示中
|
action_build_into_prompt: 是否将此动作构建到提示中
|
||||||
@@ -318,11 +317,11 @@ async def store_action_info(
|
|||||||
thinking_id: 关联的思考ID
|
thinking_id: 关联的思考ID
|
||||||
action_data: 动作数据字典
|
action_data: 动作数据字典
|
||||||
action_name: 动作名称
|
action_name: 动作名称
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict[str, Any]: 保存的记录数据
|
Dict[str, Any]: 保存的记录数据
|
||||||
None: 如果保存失败
|
None: 如果保存失败
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
record = await database_api.store_action_info(
|
record = await database_api.store_action_info(
|
||||||
chat_stream=chat_stream,
|
chat_stream=chat_stream,
|
||||||
@@ -338,7 +337,7 @@ async def store_action_info(
|
|||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
from src.common.database.database_model import ActionRecords
|
from src.common.database.database_model import ActionRecords
|
||||||
|
|
||||||
# 构建动作记录数据
|
# 构建动作记录数据
|
||||||
record_data = {
|
record_data = {
|
||||||
"action_id": thinking_id or str(int(time.time() * 1000000)), # 使用thinking_id或生成唯一ID
|
"action_id": thinking_id or str(int(time.time() * 1000000)), # 使用thinking_id或生成唯一ID
|
||||||
@@ -349,38 +348,39 @@ async def store_action_info(
|
|||||||
"action_build_into_prompt": action_build_into_prompt,
|
"action_build_into_prompt": action_build_into_prompt,
|
||||||
"action_prompt_display": action_prompt_display,
|
"action_prompt_display": action_prompt_display,
|
||||||
}
|
}
|
||||||
|
|
||||||
# 从chat_stream获取聊天信息
|
# 从chat_stream获取聊天信息
|
||||||
if chat_stream:
|
if chat_stream:
|
||||||
record_data.update({
|
record_data.update(
|
||||||
"chat_id": getattr(chat_stream, 'stream_id', ''),
|
{
|
||||||
"chat_info_stream_id": getattr(chat_stream, 'stream_id', ''),
|
"chat_id": getattr(chat_stream, "stream_id", ""),
|
||||||
"chat_info_platform": getattr(chat_stream, 'platform', ''),
|
"chat_info_stream_id": getattr(chat_stream, "stream_id", ""),
|
||||||
})
|
"chat_info_platform": getattr(chat_stream, "platform", ""),
|
||||||
|
}
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# 如果没有chat_stream,设置默认值
|
# 如果没有chat_stream,设置默认值
|
||||||
record_data.update({
|
record_data.update(
|
||||||
"chat_id": "",
|
{
|
||||||
"chat_info_stream_id": "",
|
"chat_id": "",
|
||||||
"chat_info_platform": "",
|
"chat_info_stream_id": "",
|
||||||
})
|
"chat_info_platform": "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
# 使用已有的db_save函数保存记录
|
# 使用已有的db_save函数保存记录
|
||||||
saved_record = await db_save(
|
saved_record = await db_save(
|
||||||
ActionRecords,
|
ActionRecords, data=record_data, key_field="action_id", key_value=record_data["action_id"]
|
||||||
data=record_data,
|
|
||||||
key_field="action_id",
|
|
||||||
key_value=record_data["action_id"]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if saved_record:
|
if saved_record:
|
||||||
logger.info(f"[DatabaseAPI] 成功存储动作信息: {action_name} (ID: {record_data['action_id']})")
|
logger.info(f"[DatabaseAPI] 成功存储动作信息: {action_name} (ID: {record_data['action_id']})")
|
||||||
else:
|
else:
|
||||||
logger.error(f"[DatabaseAPI] 存储动作信息失败: {action_name}")
|
logger.error(f"[DatabaseAPI] 存储动作信息失败: {action_name}")
|
||||||
|
|
||||||
return saved_record
|
return saved_record
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[DatabaseAPI] 存储动作信息时发生错误: {e}")
|
logger.error(f"[DatabaseAPI] 存储动作信息时发生错误: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -20,35 +20,36 @@ logger = get_logger("emoji_api")
|
|||||||
# 表情包获取API函数
|
# 表情包获取API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
async def get_by_description(description: str) -> Optional[Tuple[str, str, str]]:
|
async def get_by_description(description: str) -> Optional[Tuple[str, str, str]]:
|
||||||
"""根据描述选择表情包
|
"""根据描述选择表情包
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
description: 表情包的描述文本,例如"开心"、"难过"、"愤怒"等
|
description: 表情包的描述文本,例如"开心"、"难过"、"愤怒"等
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 匹配的情感标签) 或 None
|
Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 匹配的情感标签) 或 None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
logger.info(f"[EmojiAPI] 根据描述获取表情包: {description}")
|
logger.info(f"[EmojiAPI] 根据描述获取表情包: {description}")
|
||||||
|
|
||||||
emoji_manager = get_emoji_manager()
|
emoji_manager = get_emoji_manager()
|
||||||
emoji_result = await emoji_manager.get_emoji_for_text(description)
|
emoji_result = await emoji_manager.get_emoji_for_text(description)
|
||||||
|
|
||||||
if not emoji_result:
|
if not emoji_result:
|
||||||
logger.warning(f"[EmojiAPI] 未找到匹配描述 '{description}' 的表情包")
|
logger.warning(f"[EmojiAPI] 未找到匹配描述 '{description}' 的表情包")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
emoji_path, emoji_description, matched_emotion = emoji_result
|
emoji_path, emoji_description, matched_emotion = emoji_result
|
||||||
emoji_base64 = image_path_to_base64(emoji_path)
|
emoji_base64 = image_path_to_base64(emoji_path)
|
||||||
|
|
||||||
if not emoji_base64:
|
if not emoji_base64:
|
||||||
logger.error(f"[EmojiAPI] 无法将表情包文件转换为base64: {emoji_path}")
|
logger.error(f"[EmojiAPI] 无法将表情包文件转换为base64: {emoji_path}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
logger.info(f"[EmojiAPI] 成功获取表情包: {emoji_description}, 匹配情感: {matched_emotion}")
|
logger.info(f"[EmojiAPI] 成功获取表情包: {emoji_description}, 匹配情感: {matched_emotion}")
|
||||||
return emoji_base64, emoji_description, matched_emotion
|
return emoji_base64, emoji_description, matched_emotion
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[EmojiAPI] 获取表情包失败: {e}")
|
logger.error(f"[EmojiAPI] 获取表情包失败: {e}")
|
||||||
return None
|
return None
|
||||||
@@ -56,43 +57,44 @@ async def get_by_description(description: str) -> Optional[Tuple[str, str, str]]
|
|||||||
|
|
||||||
async def get_random() -> Optional[Tuple[str, str, str]]:
|
async def get_random() -> Optional[Tuple[str, str, str]]:
|
||||||
"""随机获取表情包
|
"""随机获取表情包
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 随机情感标签) 或 None
|
Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 随机情感标签) 或 None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
logger.info("[EmojiAPI] 随机获取表情包")
|
logger.info("[EmojiAPI] 随机获取表情包")
|
||||||
|
|
||||||
emoji_manager = get_emoji_manager()
|
emoji_manager = get_emoji_manager()
|
||||||
all_emojis = emoji_manager.emoji_objects
|
all_emojis = emoji_manager.emoji_objects
|
||||||
|
|
||||||
if not all_emojis:
|
if not all_emojis:
|
||||||
logger.warning("[EmojiAPI] 没有可用的表情包")
|
logger.warning("[EmojiAPI] 没有可用的表情包")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 过滤有效表情包
|
# 过滤有效表情包
|
||||||
valid_emojis = [emoji for emoji in all_emojis if not emoji.is_deleted]
|
valid_emojis = [emoji for emoji in all_emojis if not emoji.is_deleted]
|
||||||
if not valid_emojis:
|
if not valid_emojis:
|
||||||
logger.warning("[EmojiAPI] 没有有效的表情包")
|
logger.warning("[EmojiAPI] 没有有效的表情包")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 随机选择
|
# 随机选择
|
||||||
import random
|
import random
|
||||||
|
|
||||||
selected_emoji = random.choice(valid_emojis)
|
selected_emoji = random.choice(valid_emojis)
|
||||||
emoji_base64 = image_path_to_base64(selected_emoji.full_path)
|
emoji_base64 = image_path_to_base64(selected_emoji.full_path)
|
||||||
|
|
||||||
if not emoji_base64:
|
if not emoji_base64:
|
||||||
logger.error(f"[EmojiAPI] 无法转换表情包为base64: {selected_emoji.full_path}")
|
logger.error(f"[EmojiAPI] 无法转换表情包为base64: {selected_emoji.full_path}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
matched_emotion = random.choice(selected_emoji.emotion) if selected_emoji.emotion else "随机表情"
|
matched_emotion = random.choice(selected_emoji.emotion) if selected_emoji.emotion else "随机表情"
|
||||||
|
|
||||||
# 记录使用次数
|
# 记录使用次数
|
||||||
emoji_manager.record_usage(selected_emoji.hash)
|
emoji_manager.record_usage(selected_emoji.hash)
|
||||||
|
|
||||||
logger.info(f"[EmojiAPI] 成功获取随机表情包: {selected_emoji.description}")
|
logger.info(f"[EmojiAPI] 成功获取随机表情包: {selected_emoji.description}")
|
||||||
return emoji_base64, selected_emoji.description, matched_emotion
|
return emoji_base64, selected_emoji.description, matched_emotion
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[EmojiAPI] 获取随机表情包失败: {e}")
|
logger.error(f"[EmojiAPI] 获取随机表情包失败: {e}")
|
||||||
return None
|
return None
|
||||||
@@ -100,44 +102,45 @@ async def get_random() -> Optional[Tuple[str, str, str]]:
|
|||||||
|
|
||||||
async def get_by_emotion(emotion: str) -> Optional[Tuple[str, str, str]]:
|
async def get_by_emotion(emotion: str) -> Optional[Tuple[str, str, str]]:
|
||||||
"""根据情感标签获取表情包
|
"""根据情感标签获取表情包
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
emotion: 情感标签,如"happy"、"sad"、"angry"等
|
emotion: 情感标签,如"happy"、"sad"、"angry"等
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 匹配的情感标签) 或 None
|
Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 匹配的情感标签) 或 None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
logger.info(f"[EmojiAPI] 根据情感获取表情包: {emotion}")
|
logger.info(f"[EmojiAPI] 根据情感获取表情包: {emotion}")
|
||||||
|
|
||||||
emoji_manager = get_emoji_manager()
|
emoji_manager = get_emoji_manager()
|
||||||
all_emojis = emoji_manager.emoji_objects
|
all_emojis = emoji_manager.emoji_objects
|
||||||
|
|
||||||
# 筛选匹配情感的表情包
|
# 筛选匹配情感的表情包
|
||||||
matching_emojis = []
|
matching_emojis = []
|
||||||
for emoji_obj in all_emojis:
|
for emoji_obj in all_emojis:
|
||||||
if not emoji_obj.is_deleted and emotion.lower() in [e.lower() for e in emoji_obj.emotion]:
|
if not emoji_obj.is_deleted and emotion.lower() in [e.lower() for e in emoji_obj.emotion]:
|
||||||
matching_emojis.append(emoji_obj)
|
matching_emojis.append(emoji_obj)
|
||||||
|
|
||||||
if not matching_emojis:
|
if not matching_emojis:
|
||||||
logger.warning(f"[EmojiAPI] 未找到匹配情感 '{emotion}' 的表情包")
|
logger.warning(f"[EmojiAPI] 未找到匹配情感 '{emotion}' 的表情包")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 随机选择匹配的表情包
|
# 随机选择匹配的表情包
|
||||||
import random
|
import random
|
||||||
|
|
||||||
selected_emoji = random.choice(matching_emojis)
|
selected_emoji = random.choice(matching_emojis)
|
||||||
emoji_base64 = image_path_to_base64(selected_emoji.full_path)
|
emoji_base64 = image_path_to_base64(selected_emoji.full_path)
|
||||||
|
|
||||||
if not emoji_base64:
|
if not emoji_base64:
|
||||||
logger.error(f"[EmojiAPI] 无法转换表情包为base64: {selected_emoji.full_path}")
|
logger.error(f"[EmojiAPI] 无法转换表情包为base64: {selected_emoji.full_path}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 记录使用次数
|
# 记录使用次数
|
||||||
emoji_manager.record_usage(selected_emoji.hash)
|
emoji_manager.record_usage(selected_emoji.hash)
|
||||||
|
|
||||||
logger.info(f"[EmojiAPI] 成功获取情感表情包: {selected_emoji.description}")
|
logger.info(f"[EmojiAPI] 成功获取情感表情包: {selected_emoji.description}")
|
||||||
return emoji_base64, selected_emoji.description, emotion
|
return emoji_base64, selected_emoji.description, emotion
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[EmojiAPI] 根据情感获取表情包失败: {e}")
|
logger.error(f"[EmojiAPI] 根据情感获取表情包失败: {e}")
|
||||||
return None
|
return None
|
||||||
@@ -147,9 +150,10 @@ async def get_by_emotion(emotion: str) -> Optional[Tuple[str, str, str]]:
|
|||||||
# 表情包信息查询API函数
|
# 表情包信息查询API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def get_count() -> int:
|
def get_count() -> int:
|
||||||
"""获取表情包数量
|
"""获取表情包数量
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: 当前可用的表情包数量
|
int: 当前可用的表情包数量
|
||||||
"""
|
"""
|
||||||
@@ -163,7 +167,7 @@ def get_count() -> int:
|
|||||||
|
|
||||||
def get_info() -> dict:
|
def get_info() -> dict:
|
||||||
"""获取表情包系统信息
|
"""获取表情包系统信息
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: 包含表情包数量、最大数量等信息
|
dict: 包含表情包数量、最大数量等信息
|
||||||
"""
|
"""
|
||||||
@@ -181,18 +185,18 @@ def get_info() -> dict:
|
|||||||
|
|
||||||
def get_emotions() -> list:
|
def get_emotions() -> list:
|
||||||
"""获取所有可用的情感标签
|
"""获取所有可用的情感标签
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list: 所有表情包的情感标签列表(去重)
|
list: 所有表情包的情感标签列表(去重)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
emoji_manager = get_emoji_manager()
|
emoji_manager = get_emoji_manager()
|
||||||
emotions = set()
|
emotions = set()
|
||||||
|
|
||||||
for emoji_obj in emoji_manager.emoji_objects:
|
for emoji_obj in emoji_manager.emoji_objects:
|
||||||
if not emoji_obj.is_deleted and emoji_obj.emotion:
|
if not emoji_obj.is_deleted and emoji_obj.emotion:
|
||||||
emotions.update(emoji_obj.emotion)
|
emotions.update(emoji_obj.emotion)
|
||||||
|
|
||||||
return sorted(list(emotions))
|
return sorted(list(emotions))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[EmojiAPI] 获取情感标签失败: {e}")
|
logger.error(f"[EmojiAPI] 获取情感标签失败: {e}")
|
||||||
@@ -201,18 +205,18 @@ def get_emotions() -> list:
|
|||||||
|
|
||||||
def get_descriptions() -> list:
|
def get_descriptions() -> list:
|
||||||
"""获取所有表情包描述
|
"""获取所有表情包描述
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list: 所有可用表情包的描述列表
|
list: 所有可用表情包的描述列表
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
emoji_manager = get_emoji_manager()
|
emoji_manager = get_emoji_manager()
|
||||||
descriptions = []
|
descriptions = []
|
||||||
|
|
||||||
for emoji_obj in emoji_manager.emoji_objects:
|
for emoji_obj in emoji_manager.emoji_objects:
|
||||||
if not emoji_obj.is_deleted and emoji_obj.description:
|
if not emoji_obj.is_deleted and emoji_obj.description:
|
||||||
descriptions.append(emoji_obj.description)
|
descriptions.append(emoji_obj.description)
|
||||||
|
|
||||||
return descriptions
|
return descriptions
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[EmojiAPI] 获取表情包描述失败: {e}")
|
logger.error(f"[EmojiAPI] 获取表情包描述失败: {e}")
|
||||||
|
|||||||
@@ -16,22 +16,22 @@ from src.chat.message_receive.chat_stream import get_chat_manager
|
|||||||
logger = get_logger("generator_api")
|
logger = get_logger("generator_api")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 回复器获取API函数
|
# 回复器获取API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def get_replyer(chat_stream=None, platform: str = None, chat_id: str = None, is_group: bool = True) -> DefaultReplyer:
|
def get_replyer(chat_stream=None, platform: str = None, chat_id: str = None, is_group: bool = True) -> DefaultReplyer:
|
||||||
"""获取回复器对象
|
"""获取回复器对象
|
||||||
|
|
||||||
优先使用chat_stream,如果没有则使用platform和chat_id组合
|
优先使用chat_stream,如果没有则使用platform和chat_id组合
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_stream: 聊天流对象(优先)
|
chat_stream: 聊天流对象(优先)
|
||||||
platform: 平台名称,如"qq"
|
platform: 平台名称,如"qq"
|
||||||
chat_id: 聊天ID(群ID或用户ID)
|
chat_id: 聊天ID(群ID或用户ID)
|
||||||
is_group: 是否为群聊
|
is_group: 是否为群聊
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[Any]: 回复器对象,如果获取失败则返回None
|
Optional[Any]: 回复器对象,如果获取失败则返回None
|
||||||
"""
|
"""
|
||||||
@@ -40,7 +40,7 @@ def get_replyer(chat_stream=None, platform: str = None, chat_id: str = None, is_
|
|||||||
if chat_stream:
|
if chat_stream:
|
||||||
logger.debug("[GeneratorAPI] 使用聊天流获取回复器")
|
logger.debug("[GeneratorAPI] 使用聊天流获取回复器")
|
||||||
return DefaultReplyer(chat_stream=chat_stream)
|
return DefaultReplyer(chat_stream=chat_stream)
|
||||||
|
|
||||||
# 使用平台和ID组合
|
# 使用平台和ID组合
|
||||||
if platform and chat_id:
|
if platform and chat_id:
|
||||||
logger.debug("[GeneratorAPI] 使用平台和ID获取回复器")
|
logger.debug("[GeneratorAPI] 使用平台和ID获取回复器")
|
||||||
@@ -48,7 +48,7 @@ def get_replyer(chat_stream=None, platform: str = None, chat_id: str = None, is_
|
|||||||
if not chat_manager:
|
if not chat_manager:
|
||||||
logger.warning("[GeneratorAPI] 无法获取聊天管理器")
|
logger.warning("[GeneratorAPI] 无法获取聊天管理器")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 查找对应的聊天流
|
# 查找对应的聊天流
|
||||||
target_stream = None
|
target_stream = None
|
||||||
for _stream_id, stream in chat_manager.streams.items():
|
for _stream_id, stream in chat_manager.streams.items():
|
||||||
@@ -61,29 +61,31 @@ def get_replyer(chat_stream=None, platform: str = None, chat_id: str = None, is_
|
|||||||
if str(stream.user_info.user_id) == str(chat_id):
|
if str(stream.user_info.user_id) == str(chat_id):
|
||||||
target_stream = stream
|
target_stream = stream
|
||||||
break
|
break
|
||||||
|
|
||||||
return DefaultReplyer(chat_stream=target_stream)
|
return DefaultReplyer(chat_stream=target_stream)
|
||||||
|
|
||||||
logger.warning("[GeneratorAPI] 缺少必要参数,无法获取回复器")
|
logger.warning("[GeneratorAPI] 缺少必要参数,无法获取回复器")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[GeneratorAPI] 获取回复器失败: {e}")
|
logger.error(f"[GeneratorAPI] 获取回复器失败: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 回复生成API函数
|
# 回复生成API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
async def generate_reply(
|
async def generate_reply(
|
||||||
chat_stream=None,
|
chat_stream=None,
|
||||||
action_data: Dict[str, Any] = None,
|
action_data: Dict[str, Any] = None,
|
||||||
platform: str = None,
|
platform: str = None,
|
||||||
chat_id: str = None,
|
chat_id: str = None,
|
||||||
is_group: bool = True
|
is_group: bool = True,
|
||||||
) -> Tuple[bool, List[Tuple[str, Any]]]:
|
) -> Tuple[bool, List[Tuple[str, Any]]]:
|
||||||
"""生成回复
|
"""生成回复
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_stream: 聊天流对象(优先)
|
chat_stream: 聊天流对象(优先)
|
||||||
action_data: 动作数据
|
action_data: 动作数据
|
||||||
@@ -94,7 +96,7 @@ async def generate_reply(
|
|||||||
platform: 平台名称(备用)
|
platform: 平台名称(备用)
|
||||||
chat_id: 聊天ID(备用)
|
chat_id: 聊天ID(备用)
|
||||||
is_group: 是否为群聊(备用)
|
is_group: 是否为群聊(备用)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple[bool, List[Tuple[str, Any]]]: (是否成功, 回复集合)
|
Tuple[bool, List[Tuple[str, Any]]]: (是否成功, 回复集合)
|
||||||
"""
|
"""
|
||||||
@@ -104,41 +106,42 @@ async def generate_reply(
|
|||||||
if not replyer:
|
if not replyer:
|
||||||
logger.error("[GeneratorAPI] 无法获取回复器")
|
logger.error("[GeneratorAPI] 无法获取回复器")
|
||||||
return False, []
|
return False, []
|
||||||
|
|
||||||
logger.info("[GeneratorAPI] 开始生成回复")
|
logger.info("[GeneratorAPI] 开始生成回复")
|
||||||
|
|
||||||
# 调用回复器生成回复
|
# 调用回复器生成回复
|
||||||
success, reply_set = await replyer.generate_reply_with_context(
|
success, reply_set = await replyer.generate_reply_with_context(
|
||||||
reply_data=action_data or {},
|
reply_data=action_data or {},
|
||||||
)
|
)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
logger.info(f"[GeneratorAPI] 回复生成成功,生成了 {len(reply_set)} 个回复项")
|
logger.info(f"[GeneratorAPI] 回复生成成功,生成了 {len(reply_set)} 个回复项")
|
||||||
else:
|
else:
|
||||||
logger.warning("[GeneratorAPI] 回复生成失败")
|
logger.warning("[GeneratorAPI] 回复生成失败")
|
||||||
|
|
||||||
return success, reply_set or []
|
return success, reply_set or []
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[GeneratorAPI] 生成回复时出错: {e}")
|
logger.error(f"[GeneratorAPI] 生成回复时出错: {e}")
|
||||||
return False, []
|
return False, []
|
||||||
|
|
||||||
|
|
||||||
async def rewrite_reply(
|
async def rewrite_reply(
|
||||||
chat_stream=None,
|
chat_stream=None,
|
||||||
reply_data: Dict[str, Any] = None,
|
reply_data: Dict[str, Any] = None,
|
||||||
platform: str = None,
|
platform: str = None,
|
||||||
chat_id: str = None,
|
chat_id: str = None,
|
||||||
is_group: bool = True
|
is_group: bool = True,
|
||||||
) -> Tuple[bool, List[Tuple[str, Any]]]:
|
) -> Tuple[bool, List[Tuple[str, Any]]]:
|
||||||
"""重写回复
|
"""重写回复
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_stream: 聊天流对象(优先)
|
chat_stream: 聊天流对象(优先)
|
||||||
action_data: 动作数据
|
action_data: 动作数据
|
||||||
platform: 平台名称(备用)
|
platform: 平台名称(备用)
|
||||||
chat_id: 聊天ID(备用)
|
chat_id: 聊天ID(备用)
|
||||||
is_group: 是否为群聊(备用)
|
is_group: 是否为群聊(备用)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple[bool, List[Tuple[str, Any]]]: (是否成功, 回复集合)
|
Tuple[bool, List[Tuple[str, Any]]]: (是否成功, 回复集合)
|
||||||
"""
|
"""
|
||||||
@@ -148,23 +151,21 @@ async def rewrite_reply(
|
|||||||
if not replyer:
|
if not replyer:
|
||||||
logger.error("[GeneratorAPI] 无法获取回复器")
|
logger.error("[GeneratorAPI] 无法获取回复器")
|
||||||
return False, []
|
return False, []
|
||||||
|
|
||||||
logger.info("[GeneratorAPI] 开始重写回复")
|
logger.info("[GeneratorAPI] 开始重写回复")
|
||||||
|
|
||||||
# 调用回复器重写回复
|
# 调用回复器重写回复
|
||||||
success, reply_set = await replyer.rewrite_reply_with_context(
|
success, reply_set = await replyer.rewrite_reply_with_context(
|
||||||
reply_data=reply_data or {},
|
reply_data=reply_data or {},
|
||||||
)
|
)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
logger.info(f"[GeneratorAPI] 重写回复成功,生成了 {len(reply_set)} 个回复项")
|
logger.info(f"[GeneratorAPI] 重写回复成功,生成了 {len(reply_set)} 个回复项")
|
||||||
else:
|
else:
|
||||||
logger.warning("[GeneratorAPI] 重写回复失败")
|
logger.warning("[GeneratorAPI] 重写回复失败")
|
||||||
|
|
||||||
return success, reply_set or []
|
return success, reply_set or []
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[GeneratorAPI] 重写回复时出错: {e}")
|
logger.error(f"[GeneratorAPI] 重写回复时出错: {e}")
|
||||||
return False, []
|
return False, []
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ logger = get_logger("llm_api")
|
|||||||
# LLM模型API函数
|
# LLM模型API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def get_available_models() -> Dict[str, Any]:
|
def get_available_models() -> Dict[str, Any]:
|
||||||
"""获取所有可用的模型配置
|
"""获取所有可用的模型配置
|
||||||
|
|
||||||
|
|||||||
@@ -32,18 +32,19 @@ from src.chat.utils.chat_message_builder import (
|
|||||||
# 消息查询API函数
|
# 消息查询API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def get_messages_by_time(
|
def get_messages_by_time(
|
||||||
start_time: float, end_time: float, limit: int = 0, limit_mode: str = "latest"
|
start_time: float, end_time: float, limit: int = 0, limit_mode: str = "latest"
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
获取指定时间范围内的消息
|
获取指定时间范围内的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
start_time: 开始时间戳
|
start_time: 开始时间戳
|
||||||
end_time: 结束时间戳
|
end_time: 结束时间戳
|
||||||
limit: 限制返回的消息数量,0为不限制
|
limit: 限制返回的消息数量,0为不限制
|
||||||
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
消息列表
|
消息列表
|
||||||
"""
|
"""
|
||||||
@@ -55,14 +56,14 @@ def get_messages_by_time_in_chat(
|
|||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
获取指定聊天中指定时间范围内的消息
|
获取指定聊天中指定时间范围内的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_id: 聊天ID
|
chat_id: 聊天ID
|
||||||
start_time: 开始时间戳
|
start_time: 开始时间戳
|
||||||
end_time: 结束时间戳
|
end_time: 结束时间戳
|
||||||
limit: 限制返回的消息数量,0为不限制
|
limit: 限制返回的消息数量,0为不限制
|
||||||
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
消息列表
|
消息列表
|
||||||
"""
|
"""
|
||||||
@@ -74,14 +75,14 @@ def get_messages_by_time_in_chat_inclusive(
|
|||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
获取指定聊天中指定时间范围内的消息(包含边界)
|
获取指定聊天中指定时间范围内的消息(包含边界)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_id: 聊天ID
|
chat_id: 聊天ID
|
||||||
start_time: 开始时间戳(包含)
|
start_time: 开始时间戳(包含)
|
||||||
end_time: 结束时间戳(包含)
|
end_time: 结束时间戳(包含)
|
||||||
limit: 限制返回的消息数量,0为不限制
|
limit: 限制返回的消息数量,0为不限制
|
||||||
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
消息列表
|
消息列表
|
||||||
"""
|
"""
|
||||||
@@ -98,7 +99,7 @@ def get_messages_by_time_in_chat_for_users(
|
|||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
获取指定聊天中指定用户在指定时间范围内的消息
|
获取指定聊天中指定用户在指定时间范围内的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_id: 聊天ID
|
chat_id: 聊天ID
|
||||||
start_time: 开始时间戳
|
start_time: 开始时间戳
|
||||||
@@ -106,7 +107,7 @@ def get_messages_by_time_in_chat_for_users(
|
|||||||
person_ids: 用户ID列表
|
person_ids: 用户ID列表
|
||||||
limit: 限制返回的消息数量,0为不限制
|
limit: 限制返回的消息数量,0为不限制
|
||||||
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
消息列表
|
消息列表
|
||||||
"""
|
"""
|
||||||
@@ -118,13 +119,13 @@ def get_random_chat_messages(
|
|||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
随机选择一个聊天,返回该聊天在指定时间范围内的消息
|
随机选择一个聊天,返回该聊天在指定时间范围内的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
start_time: 开始时间戳
|
start_time: 开始时间戳
|
||||||
end_time: 结束时间戳
|
end_time: 结束时间戳
|
||||||
limit: 限制返回的消息数量,0为不限制
|
limit: 限制返回的消息数量,0为不限制
|
||||||
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
消息列表
|
消息列表
|
||||||
"""
|
"""
|
||||||
@@ -136,14 +137,14 @@ def get_messages_by_time_for_users(
|
|||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
获取指定用户在所有聊天中指定时间范围内的消息
|
获取指定用户在所有聊天中指定时间范围内的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
start_time: 开始时间戳
|
start_time: 开始时间戳
|
||||||
end_time: 结束时间戳
|
end_time: 结束时间戳
|
||||||
person_ids: 用户ID列表
|
person_ids: 用户ID列表
|
||||||
limit: 限制返回的消息数量,0为不限制
|
limit: 限制返回的消息数量,0为不限制
|
||||||
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
消息列表
|
消息列表
|
||||||
"""
|
"""
|
||||||
@@ -153,11 +154,11 @@ def get_messages_by_time_for_users(
|
|||||||
def get_messages_before_time(timestamp: float, limit: int = 0) -> List[Dict[str, Any]]:
|
def get_messages_before_time(timestamp: float, limit: int = 0) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
获取指定时间戳之前的消息
|
获取指定时间戳之前的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
timestamp: 时间戳
|
timestamp: 时间戳
|
||||||
limit: 限制返回的消息数量,0为不限制
|
limit: 限制返回的消息数量,0为不限制
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
消息列表
|
消息列表
|
||||||
"""
|
"""
|
||||||
@@ -167,29 +168,27 @@ def get_messages_before_time(timestamp: float, limit: int = 0) -> List[Dict[str,
|
|||||||
def get_messages_before_time_in_chat(chat_id: str, timestamp: float, limit: int = 0) -> List[Dict[str, Any]]:
|
def get_messages_before_time_in_chat(chat_id: str, timestamp: float, limit: int = 0) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
获取指定聊天中指定时间戳之前的消息
|
获取指定聊天中指定时间戳之前的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_id: 聊天ID
|
chat_id: 聊天ID
|
||||||
timestamp: 时间戳
|
timestamp: 时间戳
|
||||||
limit: 限制返回的消息数量,0为不限制
|
limit: 限制返回的消息数量,0为不限制
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
消息列表
|
消息列表
|
||||||
"""
|
"""
|
||||||
return get_raw_msg_before_timestamp_with_chat(chat_id, timestamp, limit)
|
return get_raw_msg_before_timestamp_with_chat(chat_id, timestamp, limit)
|
||||||
|
|
||||||
|
|
||||||
def get_messages_before_time_for_users(
|
def get_messages_before_time_for_users(timestamp: float, person_ids: list, limit: int = 0) -> List[Dict[str, Any]]:
|
||||||
timestamp: float, person_ids: list, limit: int = 0
|
|
||||||
) -> List[Dict[str, Any]]:
|
|
||||||
"""
|
"""
|
||||||
获取指定用户在指定时间戳之前的消息
|
获取指定用户在指定时间戳之前的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
timestamp: 时间戳
|
timestamp: 时间戳
|
||||||
person_ids: 用户ID列表
|
person_ids: 用户ID列表
|
||||||
limit: 限制返回的消息数量,0为不限制
|
limit: 限制返回的消息数量,0为不限制
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
消息列表
|
消息列表
|
||||||
"""
|
"""
|
||||||
@@ -197,20 +196,17 @@ def get_messages_before_time_for_users(
|
|||||||
|
|
||||||
|
|
||||||
def get_recent_messages(
|
def get_recent_messages(
|
||||||
chat_id: str,
|
chat_id: str, hours: float = 24.0, limit: int = 100, limit_mode: str = "latest"
|
||||||
hours: float = 24.0,
|
|
||||||
limit: int = 100,
|
|
||||||
limit_mode: str = "latest"
|
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
获取指定聊天中最近一段时间的消息
|
获取指定聊天中最近一段时间的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_id: 聊天ID
|
chat_id: 聊天ID
|
||||||
hours: 最近多少小时,默认24小时
|
hours: 最近多少小时,默认24小时
|
||||||
limit: 限制返回的消息数量,默认100条
|
limit: 限制返回的消息数量,默认100条
|
||||||
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
limit_mode: 当limit>0时生效,'earliest'表示获取最早的记录,'latest'表示获取最新的记录
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
消息列表
|
消息列表
|
||||||
"""
|
"""
|
||||||
@@ -223,35 +219,32 @@ def get_recent_messages(
|
|||||||
# 消息计数API函数
|
# 消息计数API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
def count_new_messages(
|
|
||||||
chat_id: str, start_time: float = 0.0, end_time: Optional[float] = None
|
def count_new_messages(chat_id: str, start_time: float = 0.0, end_time: Optional[float] = None) -> int:
|
||||||
) -> int:
|
|
||||||
"""
|
"""
|
||||||
计算指定聊天中从开始时间到结束时间的新消息数量
|
计算指定聊天中从开始时间到结束时间的新消息数量
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_id: 聊天ID
|
chat_id: 聊天ID
|
||||||
start_time: 开始时间戳
|
start_time: 开始时间戳
|
||||||
end_time: 结束时间戳,如果为None则使用当前时间
|
end_time: 结束时间戳,如果为None则使用当前时间
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
新消息数量
|
新消息数量
|
||||||
"""
|
"""
|
||||||
return num_new_messages_since(chat_id, start_time, end_time)
|
return num_new_messages_since(chat_id, start_time, end_time)
|
||||||
|
|
||||||
|
|
||||||
def count_new_messages_for_users(
|
def count_new_messages_for_users(chat_id: str, start_time: float, end_time: float, person_ids: list) -> int:
|
||||||
chat_id: str, start_time: float, end_time: float, person_ids: list
|
|
||||||
) -> int:
|
|
||||||
"""
|
"""
|
||||||
计算指定聊天中指定用户从开始时间到结束时间的新消息数量
|
计算指定聊天中指定用户从开始时间到结束时间的新消息数量
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_id: 聊天ID
|
chat_id: 聊天ID
|
||||||
start_time: 开始时间戳
|
start_time: 开始时间戳
|
||||||
end_time: 结束时间戳
|
end_time: 结束时间戳
|
||||||
person_ids: 用户ID列表
|
person_ids: 用户ID列表
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
新消息数量
|
新消息数量
|
||||||
"""
|
"""
|
||||||
@@ -262,6 +255,7 @@ def count_new_messages_for_users(
|
|||||||
# 消息格式化API函数
|
# 消息格式化API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def build_readable_messages_to_str(
|
def build_readable_messages_to_str(
|
||||||
messages: List[Dict[str, Any]],
|
messages: List[Dict[str, Any]],
|
||||||
replace_bot_name: bool = True,
|
replace_bot_name: bool = True,
|
||||||
@@ -273,7 +267,7 @@ def build_readable_messages_to_str(
|
|||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
将消息列表构建成可读的字符串
|
将消息列表构建成可读的字符串
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
messages: 消息列表
|
messages: 消息列表
|
||||||
replace_bot_name: 是否将机器人的名称替换为"你"
|
replace_bot_name: 是否将机器人的名称替换为"你"
|
||||||
@@ -282,7 +276,7 @@ def build_readable_messages_to_str(
|
|||||||
read_mark: 已读标记时间戳,用于分割已读和未读消息
|
read_mark: 已读标记时间戳,用于分割已读和未读消息
|
||||||
truncate: 是否截断长消息
|
truncate: 是否截断长消息
|
||||||
show_actions: 是否显示动作记录
|
show_actions: 是否显示动作记录
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
格式化后的可读字符串
|
格式化后的可读字符串
|
||||||
"""
|
"""
|
||||||
@@ -300,29 +294,27 @@ async def build_readable_messages_with_details(
|
|||||||
) -> Tuple[str, List[Tuple[float, str, str]]]:
|
) -> Tuple[str, List[Tuple[float, str, str]]]:
|
||||||
"""
|
"""
|
||||||
将消息列表构建成可读的字符串,并返回详细信息
|
将消息列表构建成可读的字符串,并返回详细信息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
messages: 消息列表
|
messages: 消息列表
|
||||||
replace_bot_name: 是否将机器人的名称替换为"你"
|
replace_bot_name: 是否将机器人的名称替换为"你"
|
||||||
merge_messages: 是否合并连续消息
|
merge_messages: 是否合并连续消息
|
||||||
timestamp_mode: 时间戳显示模式,'relative'或'absolute'
|
timestamp_mode: 时间戳显示模式,'relative'或'absolute'
|
||||||
truncate: 是否截断长消息
|
truncate: 是否截断长消息
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
格式化后的可读字符串和详细信息元组列表(时间戳, 昵称, 内容)
|
格式化后的可读字符串和详细信息元组列表(时间戳, 昵称, 内容)
|
||||||
"""
|
"""
|
||||||
return await build_readable_messages_with_list(
|
return await build_readable_messages_with_list(messages, replace_bot_name, merge_messages, timestamp_mode, truncate)
|
||||||
messages, replace_bot_name, merge_messages, timestamp_mode, truncate
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def get_person_ids_from_messages(messages: List[Dict[str, Any]]) -> List[str]:
|
async def get_person_ids_from_messages(messages: List[Dict[str, Any]]) -> List[str]:
|
||||||
"""
|
"""
|
||||||
从消息列表中提取不重复的用户ID列表
|
从消息列表中提取不重复的用户ID列表
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
messages: 消息列表
|
messages: 消息列表
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
用户ID列表
|
用户ID列表
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -18,16 +18,17 @@ logger = get_logger("person_api")
|
|||||||
# 个人信息API函数
|
# 个人信息API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def get_person_id(platform: str, user_id: int) -> str:
|
def get_person_id(platform: str, user_id: int) -> str:
|
||||||
"""根据平台和用户ID获取person_id
|
"""根据平台和用户ID获取person_id
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
platform: 平台名称,如 "qq", "telegram" 等
|
platform: 平台名称,如 "qq", "telegram" 等
|
||||||
user_id: 用户ID
|
user_id: 用户ID
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: 唯一的person_id(MD5哈希值)
|
str: 唯一的person_id(MD5哈希值)
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
person_id = person_api.get_person_id("qq", 123456)
|
person_id = person_api.get_person_id("qq", 123456)
|
||||||
"""
|
"""
|
||||||
@@ -40,15 +41,15 @@ def get_person_id(platform: str, user_id: int) -> str:
|
|||||||
|
|
||||||
async def get_person_value(person_id: str, field_name: str, default: Any = None) -> Any:
|
async def get_person_value(person_id: str, field_name: str, default: Any = None) -> Any:
|
||||||
"""根据person_id和字段名获取某个值
|
"""根据person_id和字段名获取某个值
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
person_id: 用户的唯一标识ID
|
person_id: 用户的唯一标识ID
|
||||||
field_name: 要获取的字段名,如 "nickname", "impression" 等
|
field_name: 要获取的字段名,如 "nickname", "impression" 等
|
||||||
default: 当字段不存在或获取失败时返回的默认值
|
default: 当字段不存在或获取失败时返回的默认值
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Any: 字段值或默认值
|
Any: 字段值或默认值
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
nickname = await person_api.get_person_value(person_id, "nickname", "未知用户")
|
nickname = await person_api.get_person_value(person_id, "nickname", "未知用户")
|
||||||
impression = await person_api.get_person_value(person_id, "impression")
|
impression = await person_api.get_person_value(person_id, "impression")
|
||||||
@@ -64,18 +65,18 @@ async def get_person_value(person_id: str, field_name: str, default: Any = None)
|
|||||||
|
|
||||||
async def get_person_values(person_id: str, field_names: list, default_dict: dict = None) -> dict:
|
async def get_person_values(person_id: str, field_names: list, default_dict: dict = None) -> dict:
|
||||||
"""批量获取用户信息字段值
|
"""批量获取用户信息字段值
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
person_id: 用户的唯一标识ID
|
person_id: 用户的唯一标识ID
|
||||||
field_names: 要获取的字段名列表
|
field_names: 要获取的字段名列表
|
||||||
default_dict: 默认值字典,键为字段名,值为默认值
|
default_dict: 默认值字典,键为字段名,值为默认值
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: 字段名到值的映射字典
|
dict: 字段名到值的映射字典
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
values = await person_api.get_person_values(
|
values = await person_api.get_person_values(
|
||||||
person_id,
|
person_id,
|
||||||
["nickname", "impression", "know_times"],
|
["nickname", "impression", "know_times"],
|
||||||
{"nickname": "未知用户", "know_times": 0}
|
{"nickname": "未知用户", "know_times": 0}
|
||||||
)
|
)
|
||||||
@@ -83,11 +84,11 @@ async def get_person_values(person_id: str, field_names: list, default_dict: dic
|
|||||||
try:
|
try:
|
||||||
person_info_manager = get_person_info_manager()
|
person_info_manager = get_person_info_manager()
|
||||||
values = await person_info_manager.get_values(person_id, field_names)
|
values = await person_info_manager.get_values(person_id, field_names)
|
||||||
|
|
||||||
# 如果获取成功,返回结果
|
# 如果获取成功,返回结果
|
||||||
if values:
|
if values:
|
||||||
return values
|
return values
|
||||||
|
|
||||||
# 如果获取失败,构建默认值字典
|
# 如果获取失败,构建默认值字典
|
||||||
result = {}
|
result = {}
|
||||||
if default_dict:
|
if default_dict:
|
||||||
@@ -96,9 +97,9 @@ async def get_person_values(person_id: str, field_names: list, default_dict: dic
|
|||||||
else:
|
else:
|
||||||
for field in field_names:
|
for field in field_names:
|
||||||
result[field] = None
|
result[field] = None
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[PersonAPI] 批量获取用户信息失败: person_id={person_id}, fields={field_names}, error={e}")
|
logger.error(f"[PersonAPI] 批量获取用户信息失败: person_id={person_id}, fields={field_names}, error={e}")
|
||||||
# 返回默认值字典
|
# 返回默认值字典
|
||||||
@@ -114,14 +115,14 @@ async def get_person_values(person_id: str, field_names: list, default_dict: dic
|
|||||||
|
|
||||||
async def is_person_known(platform: str, user_id: int) -> bool:
|
async def is_person_known(platform: str, user_id: int) -> bool:
|
||||||
"""判断是否认识某个用户
|
"""判断是否认识某个用户
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
platform: 平台名称
|
platform: 平台名称
|
||||||
user_id: 用户ID
|
user_id: 用户ID
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否认识该用户
|
bool: 是否认识该用户
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
known = await person_api.is_person_known("qq", 123456)
|
known = await person_api.is_person_known("qq", 123456)
|
||||||
"""
|
"""
|
||||||
@@ -135,13 +136,13 @@ async def is_person_known(platform: str, user_id: int) -> bool:
|
|||||||
|
|
||||||
def get_person_id_by_name(person_name: str) -> str:
|
def get_person_id_by_name(person_name: str) -> str:
|
||||||
"""根据用户名获取person_id
|
"""根据用户名获取person_id
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
person_name: 用户名
|
person_name: 用户名
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: person_id,如果未找到返回空字符串
|
str: person_id,如果未找到返回空字符串
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
person_id = person_api.get_person_id_by_name("张三")
|
person_id = person_api.get_person_id_by_name("张三")
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ logger = get_logger("send_api")
|
|||||||
# 内部实现函数(不暴露给外部)
|
# 内部实现函数(不暴露给外部)
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
async def _send_to_target(
|
async def _send_to_target(
|
||||||
message_type: str,
|
message_type: str,
|
||||||
content: str,
|
content: str,
|
||||||
@@ -41,7 +42,7 @@ async def _send_to_target(
|
|||||||
storage_message: bool = True,
|
storage_message: bool = True,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""向指定目标发送消息的内部实现
|
"""向指定目标发送消息的内部实现
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message_type: 消息类型,如"text"、"image"、"emoji"等
|
message_type: 消息类型,如"text"、"image"、"emoji"等
|
||||||
content: 消息内容
|
content: 消息内容
|
||||||
@@ -49,41 +50,41 @@ async def _send_to_target(
|
|||||||
display_message: 显示消息
|
display_message: 显示消息
|
||||||
typing: 是否显示正在输入
|
typing: 是否显示正在输入
|
||||||
reply_to: 回复消息的格式,如"发送者:消息内容"
|
reply_to: 回复消息的格式,如"发送者:消息内容"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
logger.info(f"[SendAPI] 发送{message_type}消息到 {stream_id}")
|
logger.info(f"[SendAPI] 发送{message_type}消息到 {stream_id}")
|
||||||
|
|
||||||
# 查找目标聊天流
|
# 查找目标聊天流
|
||||||
target_stream = get_chat_manager().get_stream(stream_id)
|
target_stream = get_chat_manager().get_stream(stream_id)
|
||||||
if not target_stream:
|
if not target_stream:
|
||||||
logger.error(f"[SendAPI] 未找到聊天流: {stream_id}")
|
logger.error(f"[SendAPI] 未找到聊天流: {stream_id}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 创建发送器
|
# 创建发送器
|
||||||
heart_fc_sender = HeartFCSender()
|
heart_fc_sender = HeartFCSender()
|
||||||
|
|
||||||
# 生成消息ID
|
# 生成消息ID
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
message_id = f"send_api_{int(current_time * 1000)}"
|
message_id = f"send_api_{int(current_time * 1000)}"
|
||||||
|
|
||||||
# 构建机器人用户信息
|
# 构建机器人用户信息
|
||||||
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=target_stream.platform,
|
platform=target_stream.platform,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 创建消息段
|
# 创建消息段
|
||||||
message_segment = Seg(type=message_type, data=content)
|
message_segment = Seg(type=message_type, data=content)
|
||||||
|
|
||||||
# 处理回复消息
|
# 处理回复消息
|
||||||
anchor_message = None
|
anchor_message = None
|
||||||
if reply_to:
|
if reply_to:
|
||||||
anchor_message = await _find_reply_message(target_stream, reply_to)
|
anchor_message = await _find_reply_message(target_stream, reply_to)
|
||||||
|
|
||||||
# 构建发送消息对象
|
# 构建发送消息对象
|
||||||
bot_message = MessageSending(
|
bot_message = MessageSending(
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
@@ -97,19 +98,19 @@ async def _send_to_target(
|
|||||||
is_emoji=(message_type == "emoji"),
|
is_emoji=(message_type == "emoji"),
|
||||||
thinking_start_time=current_time,
|
thinking_start_time=current_time,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 发送消息
|
# 发送消息
|
||||||
sent_msg = await heart_fc_sender.send_message(
|
sent_msg = await heart_fc_sender.send_message(
|
||||||
bot_message, typing=typing, set_reply=(anchor_message is not None), storage_message=storage_message
|
bot_message, typing=typing, set_reply=(anchor_message is not None), storage_message=storage_message
|
||||||
)
|
)
|
||||||
|
|
||||||
if sent_msg:
|
if sent_msg:
|
||||||
logger.info(f"[SendAPI] 成功发送消息到 {stream_id}")
|
logger.info(f"[SendAPI] 成功发送消息到 {stream_id}")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.error("[SendAPI] 发送消息失败")
|
logger.error("[SendAPI] 发送消息失败")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[SendAPI] 发送消息时出错: {e}")
|
logger.error(f"[SendAPI] 发送消息时出错: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@@ -118,11 +119,11 @@ async def _send_to_target(
|
|||||||
|
|
||||||
async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageRecv]:
|
async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageRecv]:
|
||||||
"""查找要回复的消息
|
"""查找要回复的消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
target_stream: 目标聊天流
|
target_stream: 目标聊天流
|
||||||
reply_to: 回复格式,如"发送者:消息内容"或"发送者:消息内容"
|
reply_to: 回复格式,如"发送者:消息内容"或"发送者:消息内容"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[MessageRecv]: 找到的消息,如果没找到则返回None
|
Optional[MessageRecv]: 找到的消息,如果没找到则返回None
|
||||||
"""
|
"""
|
||||||
@@ -139,20 +140,20 @@ async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageR
|
|||||||
if len(parts) != 2:
|
if len(parts) != 2:
|
||||||
logger.warning(f"[SendAPI] reply_to格式不正确: {reply_to}")
|
logger.warning(f"[SendAPI] reply_to格式不正确: {reply_to}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
sender = parts[0].strip()
|
sender = parts[0].strip()
|
||||||
text = parts[1].strip()
|
text = parts[1].strip()
|
||||||
|
|
||||||
# 获取聊天流的最新20条消息
|
# 获取聊天流的最新20条消息
|
||||||
reverse_talking_message = get_raw_msg_before_timestamp_with_chat(
|
reverse_talking_message = get_raw_msg_before_timestamp_with_chat(
|
||||||
target_stream.stream_id,
|
target_stream.stream_id,
|
||||||
time.time(), # 当前时间之前的消息
|
time.time(), # 当前时间之前的消息
|
||||||
20 # 最新的20条消息
|
20, # 最新的20条消息
|
||||||
)
|
)
|
||||||
|
|
||||||
# 反转列表,使最新的消息在前面
|
# 反转列表,使最新的消息在前面
|
||||||
reverse_talking_message = list(reversed(reverse_talking_message))
|
reverse_talking_message = list(reversed(reverse_talking_message))
|
||||||
|
|
||||||
find_msg = None
|
find_msg = None
|
||||||
for message in reverse_talking_message:
|
for message in reverse_talking_message:
|
||||||
user_id = message["user_id"]
|
user_id = message["user_id"]
|
||||||
@@ -198,20 +199,20 @@ async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageR
|
|||||||
"format_info": format_info,
|
"format_info": format_info,
|
||||||
"template_info": template_info,
|
"template_info": template_info,
|
||||||
}
|
}
|
||||||
|
|
||||||
message_dict = {
|
message_dict = {
|
||||||
"message_info": message_info,
|
"message_info": message_info,
|
||||||
"raw_message": find_msg.get("processed_plain_text"),
|
"raw_message": find_msg.get("processed_plain_text"),
|
||||||
"detailed_plain_text": find_msg.get("processed_plain_text"),
|
"detailed_plain_text": find_msg.get("processed_plain_text"),
|
||||||
"processed_plain_text": find_msg.get("processed_plain_text"),
|
"processed_plain_text": find_msg.get("processed_plain_text"),
|
||||||
}
|
}
|
||||||
|
|
||||||
find_rec_msg = MessageRecv(message_dict)
|
find_rec_msg = MessageRecv(message_dict)
|
||||||
find_rec_msg.update_chat_stream(target_stream)
|
find_rec_msg.update_chat_stream(target_stream)
|
||||||
|
|
||||||
logger.info(f"[SendAPI] 找到匹配的回复消息,发送者: {sender}")
|
logger.info(f"[SendAPI] 找到匹配的回复消息,发送者: {sender}")
|
||||||
return find_rec_msg
|
return find_rec_msg
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[SendAPI] 查找回复消息时出错: {e}")
|
logger.error(f"[SendAPI] 查找回复消息时出错: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@@ -222,34 +223,49 @@ async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageR
|
|||||||
# 公共API函数 - 预定义类型的发送函数
|
# 公共API函数 - 预定义类型的发送函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
async def text_to_group(text: str, group_id: str, platform: str = "qq", typing: bool = False, reply_to: str = "", storage_message: bool = True) -> bool:
|
|
||||||
|
async def text_to_group(
|
||||||
|
text: str,
|
||||||
|
group_id: str,
|
||||||
|
platform: str = "qq",
|
||||||
|
typing: bool = False,
|
||||||
|
reply_to: str = "",
|
||||||
|
storage_message: bool = True,
|
||||||
|
) -> bool:
|
||||||
"""向群聊发送文本消息
|
"""向群聊发送文本消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
text: 要发送的文本内容
|
text: 要发送的文本内容
|
||||||
group_id: 群聊ID
|
group_id: 群聊ID
|
||||||
platform: 平台,默认为"qq"
|
platform: 平台,默认为"qq"
|
||||||
typing: 是否显示正在输入
|
typing: 是否显示正在输入
|
||||||
reply_to: 回复消息,格式为"发送者:消息内容"
|
reply_to: 回复消息,格式为"发送者:消息内容"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
stream_id = get_chat_manager().get_stream_id(platform, group_id, True)
|
stream_id = get_chat_manager().get_stream_id(platform, group_id, True)
|
||||||
|
|
||||||
return await _send_to_target("text", text, stream_id, "", typing, reply_to, storage_message)
|
return await _send_to_target("text", text, stream_id, "", typing, reply_to, storage_message)
|
||||||
|
|
||||||
|
|
||||||
async def text_to_user(text: str, user_id: str, platform: str = "qq", typing: bool = False, reply_to: str = "", storage_message: bool = True) -> bool:
|
async def text_to_user(
|
||||||
|
text: str,
|
||||||
|
user_id: str,
|
||||||
|
platform: str = "qq",
|
||||||
|
typing: bool = False,
|
||||||
|
reply_to: str = "",
|
||||||
|
storage_message: bool = True,
|
||||||
|
) -> bool:
|
||||||
"""向用户发送私聊文本消息
|
"""向用户发送私聊文本消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
text: 要发送的文本内容
|
text: 要发送的文本内容
|
||||||
user_id: 用户ID
|
user_id: 用户ID
|
||||||
platform: 平台,默认为"qq"
|
platform: 平台,默认为"qq"
|
||||||
typing: 是否显示正在输入
|
typing: 是否显示正在输入
|
||||||
reply_to: 回复消息,格式为"发送者:消息内容"
|
reply_to: 回复消息,格式为"发送者:消息内容"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
@@ -259,12 +275,12 @@ async def text_to_user(text: str, user_id: str, platform: str = "qq", typing: bo
|
|||||||
|
|
||||||
async def emoji_to_group(emoji_base64: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
async def emoji_to_group(emoji_base64: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
||||||
"""向群聊发送表情包
|
"""向群聊发送表情包
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
emoji_base64: 表情包的base64编码
|
emoji_base64: 表情包的base64编码
|
||||||
group_id: 群聊ID
|
group_id: 群聊ID
|
||||||
platform: 平台,默认为"qq"
|
platform: 平台,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
@@ -274,12 +290,12 @@ async def emoji_to_group(emoji_base64: str, group_id: str, platform: str = "qq",
|
|||||||
|
|
||||||
async def emoji_to_user(emoji_base64: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
async def emoji_to_user(emoji_base64: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
||||||
"""向用户发送表情包
|
"""向用户发送表情包
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
emoji_base64: 表情包的base64编码
|
emoji_base64: 表情包的base64编码
|
||||||
user_id: 用户ID
|
user_id: 用户ID
|
||||||
platform: 平台,默认为"qq"
|
platform: 平台,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
@@ -289,12 +305,12 @@ async def emoji_to_user(emoji_base64: str, user_id: str, platform: str = "qq", s
|
|||||||
|
|
||||||
async def image_to_group(image_base64: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
async def image_to_group(image_base64: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
||||||
"""向群聊发送图片
|
"""向群聊发送图片
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
image_base64: 图片的base64编码
|
image_base64: 图片的base64编码
|
||||||
group_id: 群聊ID
|
group_id: 群聊ID
|
||||||
platform: 平台,默认为"qq"
|
platform: 平台,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
@@ -304,40 +320,42 @@ async def image_to_group(image_base64: str, group_id: str, platform: str = "qq",
|
|||||||
|
|
||||||
async def image_to_user(image_base64: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
async def image_to_user(image_base64: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
||||||
"""向用户发送图片
|
"""向用户发送图片
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
image_base64: 图片的base64编码
|
image_base64: 图片的base64编码
|
||||||
user_id: 用户ID
|
user_id: 用户ID
|
||||||
platform: 平台,默认为"qq"
|
platform: 平台,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
stream_id = get_chat_manager().get_stream_id(platform, user_id, False)
|
stream_id = get_chat_manager().get_stream_id(platform, user_id, False)
|
||||||
return await _send_to_target("image", image_base64, stream_id, "", typing=False)
|
return await _send_to_target("image", image_base64, stream_id, "", typing=False)
|
||||||
|
|
||||||
|
|
||||||
async def command_to_group(command: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
async def command_to_group(command: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
||||||
"""向群聊发送命令
|
"""向群聊发送命令
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
command: 命令
|
command: 命令
|
||||||
group_id: 群聊ID
|
group_id: 群聊ID
|
||||||
platform: 平台,默认为"qq"
|
platform: 平台,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
stream_id = get_chat_manager().get_stream_id(platform, group_id, True)
|
stream_id = get_chat_manager().get_stream_id(platform, group_id, True)
|
||||||
return await _send_to_target("command", command, stream_id, "", typing=False, storage_message=storage_message)
|
return await _send_to_target("command", command, stream_id, "", typing=False, storage_message=storage_message)
|
||||||
|
|
||||||
|
|
||||||
async def command_to_user(command: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
async def command_to_user(command: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
|
||||||
"""向用户发送命令
|
"""向用户发送命令
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
command: 命令
|
command: 命令
|
||||||
user_id: 用户ID
|
user_id: 用户ID
|
||||||
platform: 平台,默认为"qq"
|
platform: 平台,默认为"qq"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
@@ -349,18 +367,19 @@ async def command_to_user(command: str, user_id: str, platform: str = "qq", stor
|
|||||||
# 通用发送函数 - 支持任意消息类型
|
# 通用发送函数 - 支持任意消息类型
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
async def custom_to_group(
|
async def custom_to_group(
|
||||||
message_type: str,
|
message_type: str,
|
||||||
content: str,
|
content: str,
|
||||||
group_id: str,
|
group_id: str,
|
||||||
platform: str = "qq",
|
platform: str = "qq",
|
||||||
display_message: str = "",
|
display_message: str = "",
|
||||||
typing: bool = False,
|
typing: bool = False,
|
||||||
reply_to: str = "",
|
reply_to: str = "",
|
||||||
storage_message: bool = True
|
storage_message: bool = True,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""向群聊发送自定义类型消息
|
"""向群聊发送自定义类型消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message_type: 消息类型,如"text"、"image"、"emoji"、"video"、"file"等
|
message_type: 消息类型,如"text"、"image"、"emoji"、"video"、"file"等
|
||||||
content: 消息内容(通常是base64编码或文本)
|
content: 消息内容(通常是base64编码或文本)
|
||||||
@@ -369,7 +388,7 @@ async def custom_to_group(
|
|||||||
display_message: 显示消息
|
display_message: 显示消息
|
||||||
typing: 是否显示正在输入
|
typing: 是否显示正在输入
|
||||||
reply_to: 回复消息,格式为"发送者:消息内容"
|
reply_to: 回复消息,格式为"发送者:消息内容"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
@@ -378,17 +397,17 @@ async def custom_to_group(
|
|||||||
|
|
||||||
|
|
||||||
async def custom_to_user(
|
async def custom_to_user(
|
||||||
message_type: str,
|
message_type: str,
|
||||||
content: str,
|
content: str,
|
||||||
user_id: str,
|
user_id: str,
|
||||||
platform: str = "qq",
|
platform: str = "qq",
|
||||||
display_message: str = "",
|
display_message: str = "",
|
||||||
typing: bool = False,
|
typing: bool = False,
|
||||||
reply_to: str = "",
|
reply_to: str = "",
|
||||||
storage_message: bool = True
|
storage_message: bool = True,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""向用户发送自定义类型消息
|
"""向用户发送自定义类型消息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message_type: 消息类型,如"text"、"image"、"emoji"、"video"、"file"等
|
message_type: 消息类型,如"text"、"image"、"emoji"、"video"、"file"等
|
||||||
content: 消息内容(通常是base64编码或文本)
|
content: 消息内容(通常是base64编码或文本)
|
||||||
@@ -397,7 +416,7 @@ async def custom_to_user(
|
|||||||
display_message: 显示消息
|
display_message: 显示消息
|
||||||
typing: 是否显示正在输入
|
typing: 是否显示正在输入
|
||||||
reply_to: 回复消息,格式为"发送者:消息内容"
|
reply_to: 回复消息,格式为"发送者:消息内容"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
@@ -414,10 +433,10 @@ async def custom_message(
|
|||||||
display_message: str = "",
|
display_message: str = "",
|
||||||
typing: bool = False,
|
typing: bool = False,
|
||||||
reply_to: str = "",
|
reply_to: str = "",
|
||||||
storage_message: bool = True
|
storage_message: bool = True,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""发送自定义消息的通用接口
|
"""发送自定义消息的通用接口
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message_type: 消息类型,如"text"、"image"、"emoji"、"video"、"file"、"audio"等
|
message_type: 消息类型,如"text"、"image"、"emoji"、"video"、"file"、"audio"等
|
||||||
content: 消息内容
|
content: 消息内容
|
||||||
@@ -427,19 +446,19 @@ async def custom_message(
|
|||||||
display_message: 显示消息
|
display_message: 显示消息
|
||||||
typing: 是否显示正在输入
|
typing: 是否显示正在输入
|
||||||
reply_to: 回复消息,格式为"发送者:消息内容"
|
reply_to: 回复消息,格式为"发送者:消息内容"
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
# 发送视频到群聊
|
# 发送视频到群聊
|
||||||
await send_api.custom_message("video", video_base64, "123456", True)
|
await send_api.custom_message("video", video_base64, "123456", True)
|
||||||
|
|
||||||
# 发送文件到用户
|
# 发送文件到用户
|
||||||
await send_api.custom_message("file", file_base64, "987654", False)
|
await send_api.custom_message("file", file_base64, "987654", False)
|
||||||
|
|
||||||
# 发送音频到群聊并回复特定消息
|
# 发送音频到群聊并回复特定消息
|
||||||
await send_api.custom_message("audio", audio_base64, "123456", True, reply_to="张三:你好")
|
await send_api.custom_message("audio", audio_base64, "123456", True, reply_to="张三:你好")
|
||||||
"""
|
"""
|
||||||
stream_id = get_chat_manager().get_stream_id(platform, target_id, is_group)
|
stream_id = get_chat_manager().get_stream_id(platform, target_id, is_group)
|
||||||
return await _send_to_target(message_type, content, stream_id, display_message, typing, reply_to, storage_message)
|
return await _send_to_target(message_type, content, stream_id, display_message, typing, reply_to, storage_message)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ logger = get_logger("utils_api")
|
|||||||
# 文件操作API函数
|
# 文件操作API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def get_plugin_path(caller_frame=None) -> str:
|
def get_plugin_path(caller_frame=None) -> str:
|
||||||
"""获取调用者插件的路径
|
"""获取调用者插件的路径
|
||||||
|
|
||||||
@@ -106,6 +107,7 @@ def write_json_file(file_path: str, data: Any, indent: int = 2) -> bool:
|
|||||||
# 时间相关API函数
|
# 时间相关API函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def get_timestamp() -> int:
|
def get_timestamp() -> int:
|
||||||
"""获取当前时间戳
|
"""获取当前时间戳
|
||||||
|
|
||||||
@@ -156,6 +158,7 @@ def parse_time(time_str: str, format_str: str = "%Y-%m-%d %H:%M:%S") -> int:
|
|||||||
# 其他工具函数
|
# 其他工具函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
def generate_unique_id() -> str:
|
def generate_unique_id() -> str:
|
||||||
"""生成唯一ID
|
"""生成唯一ID
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from abc import ABC, abstractmethod
|
|||||||
from typing import Tuple, Optional
|
from typing import Tuple, Optional
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.plugin_system.base.component_types import ActionActivationType, ChatMode, ActionInfo, ComponentType
|
from src.plugin_system.base.component_types import ActionActivationType, ChatMode, ActionInfo, ComponentType
|
||||||
from src.plugin_system.apis import send_api, database_api,message_api
|
from src.plugin_system.apis import send_api, database_api, message_api
|
||||||
import time
|
import time
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ class BaseAction(ABC):
|
|||||||
self.thinking_id = thinking_id
|
self.thinking_id = thinking_id
|
||||||
self.log_prefix = log_prefix
|
self.log_prefix = log_prefix
|
||||||
self.shutting_down = shutting_down
|
self.shutting_down = shutting_down
|
||||||
|
|
||||||
# 保存插件配置
|
# 保存插件配置
|
||||||
self.plugin_config = plugin_config or {}
|
self.plugin_config = plugin_config or {}
|
||||||
|
|
||||||
@@ -83,11 +83,10 @@ class BaseAction(ABC):
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 便捷属性 - 直接在初始化时获取常用聊天信息(带类型注解)
|
# 便捷属性 - 直接在初始化时获取常用聊天信息(带类型注解)
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
# 获取聊天流对象
|
# 获取聊天流对象
|
||||||
self.chat_stream = chat_stream or kwargs.get("chat_stream")
|
self.chat_stream = chat_stream or kwargs.get("chat_stream")
|
||||||
|
|
||||||
self.chat_id = self.chat_stream.stream_id
|
self.chat_id = self.chat_stream.stream_id
|
||||||
# 初始化基础信息(带类型注解)
|
# 初始化基础信息(带类型注解)
|
||||||
self.is_group: bool = False
|
self.is_group: bool = False
|
||||||
@@ -97,28 +96,30 @@ class BaseAction(ABC):
|
|||||||
self.target_id: Optional[str] = None
|
self.target_id: Optional[str] = None
|
||||||
self.group_name: Optional[str] = None
|
self.group_name: Optional[str] = None
|
||||||
self.user_nickname: Optional[str] = None
|
self.user_nickname: Optional[str] = None
|
||||||
|
|
||||||
# 如果有聊天流,提取所有信息
|
# 如果有聊天流,提取所有信息
|
||||||
if self.chat_stream:
|
if self.chat_stream:
|
||||||
self.platform = getattr(self.chat_stream, 'platform', None)
|
self.platform = getattr(self.chat_stream, "platform", None)
|
||||||
|
|
||||||
# 获取群聊信息
|
# 获取群聊信息
|
||||||
# print(self.chat_stream)
|
# print(self.chat_stream)
|
||||||
# print(self.chat_stream.group_info)
|
# print(self.chat_stream.group_info)
|
||||||
if self.chat_stream.group_info:
|
if self.chat_stream.group_info:
|
||||||
self.is_group = True
|
self.is_group = True
|
||||||
self.group_id = str(self.chat_stream.group_info.group_id)
|
self.group_id = str(self.chat_stream.group_info.group_id)
|
||||||
self.group_name = getattr(self.chat_stream.group_info, 'group_name', None)
|
self.group_name = getattr(self.chat_stream.group_info, "group_name", None)
|
||||||
else:
|
else:
|
||||||
self.is_group = False
|
self.is_group = False
|
||||||
self.user_id = str(self.chat_stream.user_info.user_id)
|
self.user_id = str(self.chat_stream.user_info.user_id)
|
||||||
self.user_nickname = getattr(self.chat_stream.user_info, 'user_nickname', None)
|
self.user_nickname = getattr(self.chat_stream.user_info, "user_nickname", None)
|
||||||
|
|
||||||
# 设置目标ID(群聊用群ID,私聊用户ID)
|
# 设置目标ID(群聊用群ID,私聊用户ID)
|
||||||
self.target_id = self.group_id if self.is_group else self.user_id
|
self.target_id = self.group_id if self.is_group else self.user_id
|
||||||
|
|
||||||
logger.debug(f"{self.log_prefix} Action组件初始化完成")
|
logger.debug(f"{self.log_prefix} Action组件初始化完成")
|
||||||
logger.debug(f"{self.log_prefix} 聊天信息: 类型={'群聊' if self.is_group else '私聊'}, 平台={self.platform}, 目标={self.target_id}")
|
logger.debug(
|
||||||
|
f"{self.log_prefix} 聊天信息: 类型={'群聊' if self.is_group else '私聊'}, 平台={self.platform}, 目标={self.target_id}"
|
||||||
|
)
|
||||||
|
|
||||||
def _get_activation_type_value(self, attr_name: str, default: str) -> str:
|
def _get_activation_type_value(self, attr_name: str, default: str) -> str:
|
||||||
"""获取激活类型的字符串值"""
|
"""获取激活类型的字符串值"""
|
||||||
@@ -138,10 +139,9 @@ class BaseAction(ABC):
|
|||||||
return attr.value
|
return attr.value
|
||||||
return str(attr)
|
return str(attr)
|
||||||
|
|
||||||
|
|
||||||
async def wait_for_new_message(self, timeout: int = 1200) -> Tuple[bool, str]:
|
async def wait_for_new_message(self, timeout: int = 1200) -> Tuple[bool, str]:
|
||||||
"""等待新消息或超时
|
"""等待新消息或超时
|
||||||
|
|
||||||
在loop_start_time之后等待新消息,如果没有新消息且没有超时,就一直等待。
|
在loop_start_time之后等待新消息,如果没有新消息且没有超时,就一直等待。
|
||||||
使用message_api检查self.chat_id对应的聊天中是否有新消息。
|
使用message_api检查self.chat_id对应的聊天中是否有新消息。
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ class BaseAction(ABC):
|
|||||||
# 获取循环开始时间,如果没有则使用当前时间
|
# 获取循环开始时间,如果没有则使用当前时间
|
||||||
loop_start_time = self.action_data.get("loop_start_time", time.time())
|
loop_start_time = self.action_data.get("loop_start_time", time.time())
|
||||||
logger.info(f"{self.log_prefix} 开始等待新消息... (最长等待: {timeout}秒, 从时间点: {loop_start_time})")
|
logger.info(f"{self.log_prefix} 开始等待新消息... (最长等待: {timeout}秒, 从时间点: {loop_start_time})")
|
||||||
|
|
||||||
# 确保有有效的chat_id
|
# 确保有有效的chat_id
|
||||||
if not self.chat_id:
|
if not self.chat_id:
|
||||||
logger.error(f"{self.log_prefix} 等待新消息失败: 没有有效的chat_id")
|
logger.error(f"{self.log_prefix} 等待新消息失败: 没有有效的chat_id")
|
||||||
@@ -166,17 +166,15 @@ class BaseAction(ABC):
|
|||||||
# 检查关闭标志
|
# 检查关闭标志
|
||||||
# shutting_down = self.get_action_context("shutting_down", False)
|
# shutting_down = self.get_action_context("shutting_down", False)
|
||||||
# if shutting_down:
|
# if shutting_down:
|
||||||
# logger.info(f"{self.log_prefix} 等待新消息时检测到关闭信号,中断等待")
|
# logger.info(f"{self.log_prefix} 等待新消息时检测到关闭信号,中断等待")
|
||||||
# return False, ""
|
# return False, ""
|
||||||
|
|
||||||
# 检查新消息
|
# 检查新消息
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
new_message_count = message_api.count_new_messages(
|
new_message_count = message_api.count_new_messages(
|
||||||
chat_id=self.chat_id,
|
chat_id=self.chat_id, start_time=loop_start_time, end_time=current_time
|
||||||
start_time=loop_start_time,
|
|
||||||
end_time=current_time
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if new_message_count > 0:
|
if new_message_count > 0:
|
||||||
logger.info(f"{self.log_prefix} 检测到{new_message_count}条新消息,聊天ID: {self.chat_id}")
|
logger.info(f"{self.log_prefix} 检测到{new_message_count}条新消息,聊天ID: {self.chat_id}")
|
||||||
return True, ""
|
return True, ""
|
||||||
@@ -186,7 +184,7 @@ class BaseAction(ABC):
|
|||||||
if elapsed_time > timeout:
|
if elapsed_time > timeout:
|
||||||
logger.warning(f"{self.log_prefix} 等待新消息超时({timeout}秒),聊天ID: {self.chat_id}")
|
logger.warning(f"{self.log_prefix} 等待新消息超时({timeout}秒),聊天ID: {self.chat_id}")
|
||||||
return False, ""
|
return False, ""
|
||||||
|
|
||||||
# 每30秒记录一次等待状态
|
# 每30秒记录一次等待状态
|
||||||
if int(elapsed_time) % 15 == 0 and int(elapsed_time) > 0:
|
if int(elapsed_time) % 15 == 0 and int(elapsed_time) > 0:
|
||||||
logger.debug(f"{self.log_prefix} 已等待{int(elapsed_time)}秒,继续等待新消息...")
|
logger.debug(f"{self.log_prefix} 已等待{int(elapsed_time)}秒,继续等待新消息...")
|
||||||
@@ -234,7 +232,7 @@ class BaseAction(ABC):
|
|||||||
"""
|
"""
|
||||||
# 导入send_api
|
# 导入send_api
|
||||||
from src.plugin_system.apis import send_api
|
from src.plugin_system.apis import send_api
|
||||||
|
|
||||||
if not self.target_id or not self.platform:
|
if not self.target_id or not self.platform:
|
||||||
logger.error(f"{self.log_prefix} 缺少发送消息所需的信息")
|
logger.error(f"{self.log_prefix} 缺少发送消息所需的信息")
|
||||||
return False
|
return False
|
||||||
@@ -255,7 +253,7 @@ class BaseAction(ABC):
|
|||||||
"""
|
"""
|
||||||
# 导入send_api
|
# 导入send_api
|
||||||
from src.plugin_system.apis import send_api
|
from src.plugin_system.apis import send_api
|
||||||
|
|
||||||
if not self.target_id or not self.platform:
|
if not self.target_id or not self.platform:
|
||||||
logger.error(f"{self.log_prefix} 缺少发送消息所需的信息")
|
logger.error(f"{self.log_prefix} 缺少发送消息所需的信息")
|
||||||
return False
|
return False
|
||||||
@@ -278,7 +276,7 @@ class BaseAction(ABC):
|
|||||||
"""
|
"""
|
||||||
# 导入send_api
|
# 导入send_api
|
||||||
from src.plugin_system.apis import send_api
|
from src.plugin_system.apis import send_api
|
||||||
|
|
||||||
if not self.target_id or not self.platform:
|
if not self.target_id or not self.platform:
|
||||||
logger.error(f"{self.log_prefix} 缺少发送消息所需的信息")
|
logger.error(f"{self.log_prefix} 缺少发送消息所需的信息")
|
||||||
return False
|
return False
|
||||||
@@ -289,7 +287,7 @@ class BaseAction(ABC):
|
|||||||
target_id=self.target_id,
|
target_id=self.target_id,
|
||||||
is_group=self.is_group,
|
is_group=self.is_group,
|
||||||
platform=self.platform,
|
platform=self.platform,
|
||||||
typing=typing
|
typing=typing,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def store_action_info(
|
async def store_action_info(
|
||||||
@@ -299,7 +297,7 @@ class BaseAction(ABC):
|
|||||||
action_done: bool = True,
|
action_done: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""存储动作信息到数据库
|
"""存储动作信息到数据库
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
action_build_into_prompt: 是否构建到提示中
|
action_build_into_prompt: 是否构建到提示中
|
||||||
action_prompt_display: 显示的action提示信息
|
action_prompt_display: 显示的action提示信息
|
||||||
@@ -315,7 +313,9 @@ class BaseAction(ABC):
|
|||||||
action_name=self.action_name,
|
action_name=self.action_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def send_command(self, command_name: str, args: dict = None, display_message: str = None, storage_message: bool = True) -> bool:
|
async def send_command(
|
||||||
|
self, command_name: str, args: dict = None, display_message: str = None, storage_message: bool = True
|
||||||
|
) -> bool:
|
||||||
"""发送命令消息
|
"""发送命令消息
|
||||||
|
|
||||||
使用和send_text相同的方式通过MessageAPI发送命令
|
使用和send_text相同的方式通过MessageAPI发送命令
|
||||||
@@ -338,7 +338,7 @@ class BaseAction(ABC):
|
|||||||
command=command_data,
|
command=command_data,
|
||||||
group_id=str(self.group_id),
|
group_id=str(self.group_id),
|
||||||
platform=self.platform,
|
platform=self.platform,
|
||||||
storage_message=storage_message
|
storage_message=storage_message,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# 私聊
|
# 私聊
|
||||||
@@ -346,7 +346,7 @@ class BaseAction(ABC):
|
|||||||
command=command_data,
|
command=command_data,
|
||||||
user_id=str(self.user_id),
|
user_id=str(self.user_id),
|
||||||
platform=self.platform,
|
platform=self.platform,
|
||||||
storage_message=storage_message
|
storage_message=storage_message,
|
||||||
)
|
)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
@@ -433,11 +433,11 @@ class BaseAction(ABC):
|
|||||||
|
|
||||||
def get_action_context(self, key: str, default=None):
|
def get_action_context(self, key: str, default=None):
|
||||||
"""获取action上下文信息
|
"""获取action上下文信息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: 上下文键名
|
key: 上下文键名
|
||||||
default: 默认值
|
default: 默认值
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Any: 上下文值或默认值
|
Any: 上下文值或默认值
|
||||||
"""
|
"""
|
||||||
@@ -445,17 +445,17 @@ class BaseAction(ABC):
|
|||||||
|
|
||||||
def get_config(self, key: str, default=None):
|
def get_config(self, key: str, default=None):
|
||||||
"""获取插件配置值,支持嵌套键访问
|
"""获取插件配置值,支持嵌套键访问
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: 配置键名,支持嵌套访问如 "section.subsection.key"
|
key: 配置键名,支持嵌套访问如 "section.subsection.key"
|
||||||
default: 默认值
|
default: 默认值
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Any: 配置值或默认值
|
Any: 配置值或默认值
|
||||||
"""
|
"""
|
||||||
if not self.plugin_config:
|
if not self.plugin_config:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
# 支持嵌套键访问
|
# 支持嵌套键访问
|
||||||
keys = key.split(".")
|
keys = key.split(".")
|
||||||
current = self.plugin_config
|
current = self.plugin_config
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class BaseCommand(ABC):
|
|||||||
|
|
||||||
command_name: str = ""
|
command_name: str = ""
|
||||||
command_description: str = ""
|
command_description: str = ""
|
||||||
|
|
||||||
# 默认命令设置(子类可以覆盖)
|
# 默认命令设置(子类可以覆盖)
|
||||||
command_pattern: str = ""
|
command_pattern: str = ""
|
||||||
command_help: str = ""
|
command_help: str = ""
|
||||||
@@ -63,17 +63,17 @@ class BaseCommand(ABC):
|
|||||||
|
|
||||||
def get_config(self, key: str, default=None):
|
def get_config(self, key: str, default=None):
|
||||||
"""获取插件配置值,支持嵌套键访问
|
"""获取插件配置值,支持嵌套键访问
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: 配置键名,支持嵌套访问如 "section.subsection.key"
|
key: 配置键名,支持嵌套访问如 "section.subsection.key"
|
||||||
default: 默认值
|
default: 默认值
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Any: 配置值或默认值
|
Any: 配置值或默认值
|
||||||
"""
|
"""
|
||||||
if not self.plugin_config:
|
if not self.plugin_config:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
# 支持嵌套键访问
|
# 支持嵌套键访问
|
||||||
keys = key.split(".")
|
keys = key.split(".")
|
||||||
current = self.plugin_config
|
current = self.plugin_config
|
||||||
@@ -97,19 +97,15 @@ class BaseCommand(ABC):
|
|||||||
|
|
||||||
if chat_stream.group_info:
|
if chat_stream.group_info:
|
||||||
# 群聊
|
# 群聊
|
||||||
|
|
||||||
await send_api.text_to_group(
|
await send_api.text_to_group(
|
||||||
text=content,
|
text=content, group_id=str(chat_stream.group_info.group_id), platform=chat_stream.platform
|
||||||
group_id=str(chat_stream.group_info.group_id),
|
|
||||||
platform=chat_stream.platform
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# 私聊
|
# 私聊
|
||||||
|
|
||||||
await send_api.text_to_user(
|
await send_api.text_to_user(
|
||||||
text=content,
|
text=content, user_id=str(chat_stream.user_info.user_id), platform=chat_stream.platform
|
||||||
user_id=str(chat_stream.user_info.user_id),
|
|
||||||
platform=chat_stream.platform
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async def send_type(
|
async def send_type(
|
||||||
@@ -131,6 +127,7 @@ class BaseCommand(ABC):
|
|||||||
if chat_stream.group_info:
|
if chat_stream.group_info:
|
||||||
# 群聊
|
# 群聊
|
||||||
from src.plugin_system.apis import send_api
|
from src.plugin_system.apis import send_api
|
||||||
|
|
||||||
return await send_api.custom_message(
|
return await send_api.custom_message(
|
||||||
message_type=message_type,
|
message_type=message_type,
|
||||||
content=content,
|
content=content,
|
||||||
@@ -142,6 +139,7 @@ class BaseCommand(ABC):
|
|||||||
else:
|
else:
|
||||||
# 私聊
|
# 私聊
|
||||||
from src.plugin_system.apis import send_api
|
from src.plugin_system.apis import send_api
|
||||||
|
|
||||||
return await send_api.custom_message(
|
return await send_api.custom_message(
|
||||||
message_type=message_type,
|
message_type=message_type,
|
||||||
content=content,
|
content=content,
|
||||||
@@ -172,6 +170,7 @@ class BaseCommand(ABC):
|
|||||||
if chat_stream.group_info:
|
if chat_stream.group_info:
|
||||||
# 群聊
|
# 群聊
|
||||||
from src.plugin_system.apis import send_api
|
from src.plugin_system.apis import send_api
|
||||||
|
|
||||||
success = await send_api.custom_message(
|
success = await send_api.custom_message(
|
||||||
message_type="command",
|
message_type="command",
|
||||||
content=command_data,
|
content=command_data,
|
||||||
@@ -182,6 +181,7 @@ class BaseCommand(ABC):
|
|||||||
else:
|
else:
|
||||||
# 私聊
|
# 私聊
|
||||||
from src.plugin_system.apis import send_api
|
from src.plugin_system.apis import send_api
|
||||||
|
|
||||||
success = await send_api.custom_message(
|
success = await send_api.custom_message(
|
||||||
message_type="command",
|
message_type="command",
|
||||||
content=command_data,
|
content=command_data,
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class ComponentRegistry:
|
|||||||
"""
|
"""
|
||||||
component_name = component_info.name
|
component_name = component_info.name
|
||||||
component_type = component_info.component_type
|
component_type = component_info.component_type
|
||||||
plugin_name = getattr(component_info, 'plugin_name', 'unknown')
|
plugin_name = getattr(component_info, "plugin_name", "unknown")
|
||||||
|
|
||||||
# 🔥 系统级别自动区分:为不同类型的组件添加命名空间前缀
|
# 🔥 系统级别自动区分:为不同类型的组件添加命名空间前缀
|
||||||
if component_type == ComponentType.ACTION:
|
if component_type == ComponentType.ACTION:
|
||||||
@@ -68,8 +68,8 @@ class ComponentRegistry:
|
|||||||
# 检查命名空间化的名称是否冲突
|
# 检查命名空间化的名称是否冲突
|
||||||
if namespaced_name in self._components:
|
if namespaced_name in self._components:
|
||||||
existing_info = self._components[namespaced_name]
|
existing_info = self._components[namespaced_name]
|
||||||
existing_plugin = getattr(existing_info, 'plugin_name', 'unknown')
|
existing_plugin = getattr(existing_info, "plugin_name", "unknown")
|
||||||
|
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"组件冲突: {component_type.value}组件 '{component_name}' "
|
f"组件冲突: {component_type.value}组件 '{component_name}' "
|
||||||
f"已被插件 '{existing_plugin}' 注册,跳过插件 '{plugin_name}' 的注册"
|
f"已被插件 '{existing_plugin}' 注册,跳过插件 '{plugin_name}' 的注册"
|
||||||
@@ -116,18 +116,18 @@ class ComponentRegistry:
|
|||||||
|
|
||||||
def get_component_info(self, component_name: str, component_type: ComponentType = None) -> Optional[ComponentInfo]:
|
def get_component_info(self, component_name: str, component_type: ComponentType = None) -> Optional[ComponentInfo]:
|
||||||
"""获取组件信息,支持自动命名空间解析
|
"""获取组件信息,支持自动命名空间解析
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
component_name: 组件名称,可以是原始名称或命名空间化的名称
|
component_name: 组件名称,可以是原始名称或命名空间化的名称
|
||||||
component_type: 组件类型,如果提供则优先在该类型中查找
|
component_type: 组件类型,如果提供则优先在该类型中查找
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[ComponentInfo]: 组件信息或None
|
Optional[ComponentInfo]: 组件信息或None
|
||||||
"""
|
"""
|
||||||
# 1. 如果已经是命名空间化的名称,直接查找
|
# 1. 如果已经是命名空间化的名称,直接查找
|
||||||
if '.' in component_name:
|
if "." in component_name:
|
||||||
return self._components.get(component_name)
|
return self._components.get(component_name)
|
||||||
|
|
||||||
# 2. 如果指定了组件类型,构造命名空间化的名称查找
|
# 2. 如果指定了组件类型,构造命名空间化的名称查找
|
||||||
if component_type:
|
if component_type:
|
||||||
if component_type == ComponentType.ACTION:
|
if component_type == ComponentType.ACTION:
|
||||||
@@ -136,9 +136,9 @@ class ComponentRegistry:
|
|||||||
namespaced_name = f"command.{component_name}"
|
namespaced_name = f"command.{component_name}"
|
||||||
else:
|
else:
|
||||||
namespaced_name = f"{component_type.value}.{component_name}"
|
namespaced_name = f"{component_type.value}.{component_name}"
|
||||||
|
|
||||||
return self._components.get(namespaced_name)
|
return self._components.get(namespaced_name)
|
||||||
|
|
||||||
# 3. 如果没有指定类型,尝试在所有命名空间中查找
|
# 3. 如果没有指定类型,尝试在所有命名空间中查找
|
||||||
candidates = []
|
candidates = []
|
||||||
for namespace_prefix in ["action", "command"]:
|
for namespace_prefix in ["action", "command"]:
|
||||||
@@ -146,7 +146,7 @@ class ComponentRegistry:
|
|||||||
component_info = self._components.get(namespaced_name)
|
component_info = self._components.get(namespaced_name)
|
||||||
if component_info:
|
if component_info:
|
||||||
candidates.append((namespace_prefix, namespaced_name, component_info))
|
candidates.append((namespace_prefix, namespaced_name, component_info))
|
||||||
|
|
||||||
if len(candidates) == 1:
|
if len(candidates) == 1:
|
||||||
# 只有一个匹配,直接返回
|
# 只有一个匹配,直接返回
|
||||||
return candidates[0][2]
|
return candidates[0][2]
|
||||||
@@ -154,28 +154,27 @@ class ComponentRegistry:
|
|||||||
# 多个匹配,记录警告并返回第一个
|
# 多个匹配,记录警告并返回第一个
|
||||||
namespaces = [ns for ns, _, _ in candidates]
|
namespaces = [ns for ns, _, _ in candidates]
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"组件名称 '{component_name}' 在多个命名空间中存在: {namespaces},"
|
f"组件名称 '{component_name}' 在多个命名空间中存在: {namespaces},使用第一个匹配项: {candidates[0][1]}"
|
||||||
f"使用第一个匹配项: {candidates[0][1]}"
|
|
||||||
)
|
)
|
||||||
return candidates[0][2]
|
return candidates[0][2]
|
||||||
|
|
||||||
# 4. 都没找到
|
# 4. 都没找到
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_component_class(self, component_name: str, component_type: ComponentType = None) -> Optional[Type]:
|
def get_component_class(self, component_name: str, component_type: ComponentType = None) -> Optional[Type]:
|
||||||
"""获取组件类,支持自动命名空间解析
|
"""获取组件类,支持自动命名空间解析
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
component_name: 组件名称,可以是原始名称或命名空间化的名称
|
component_name: 组件名称,可以是原始名称或命名空间化的名称
|
||||||
component_type: 组件类型,如果提供则优先在该类型中查找
|
component_type: 组件类型,如果提供则优先在该类型中查找
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[Type]: 组件类或None
|
Optional[Type]: 组件类或None
|
||||||
"""
|
"""
|
||||||
# 1. 如果已经是命名空间化的名称,直接查找
|
# 1. 如果已经是命名空间化的名称,直接查找
|
||||||
if '.' in component_name:
|
if "." in component_name:
|
||||||
return self._component_classes.get(component_name)
|
return self._component_classes.get(component_name)
|
||||||
|
|
||||||
# 2. 如果指定了组件类型,构造命名空间化的名称查找
|
# 2. 如果指定了组件类型,构造命名空间化的名称查找
|
||||||
if component_type:
|
if component_type:
|
||||||
if component_type == ComponentType.ACTION:
|
if component_type == ComponentType.ACTION:
|
||||||
@@ -184,9 +183,9 @@ class ComponentRegistry:
|
|||||||
namespaced_name = f"command.{component_name}"
|
namespaced_name = f"command.{component_name}"
|
||||||
else:
|
else:
|
||||||
namespaced_name = f"{component_type.value}.{component_name}"
|
namespaced_name = f"{component_type.value}.{component_name}"
|
||||||
|
|
||||||
return self._component_classes.get(namespaced_name)
|
return self._component_classes.get(namespaced_name)
|
||||||
|
|
||||||
# 3. 如果没有指定类型,尝试在所有命名空间中查找
|
# 3. 如果没有指定类型,尝试在所有命名空间中查找
|
||||||
candidates = []
|
candidates = []
|
||||||
for namespace_prefix in ["action", "command"]:
|
for namespace_prefix in ["action", "command"]:
|
||||||
@@ -194,7 +193,7 @@ class ComponentRegistry:
|
|||||||
component_class = self._component_classes.get(namespaced_name)
|
component_class = self._component_classes.get(namespaced_name)
|
||||||
if component_class:
|
if component_class:
|
||||||
candidates.append((namespace_prefix, namespaced_name, component_class))
|
candidates.append((namespace_prefix, namespaced_name, component_class))
|
||||||
|
|
||||||
if len(candidates) == 1:
|
if len(candidates) == 1:
|
||||||
# 只有一个匹配,直接返回
|
# 只有一个匹配,直接返回
|
||||||
namespace, full_name, cls = candidates[0]
|
namespace, full_name, cls = candidates[0]
|
||||||
@@ -204,11 +203,10 @@ class ComponentRegistry:
|
|||||||
# 多个匹配,记录警告并返回第一个
|
# 多个匹配,记录警告并返回第一个
|
||||||
namespaces = [ns for ns, _, _ in candidates]
|
namespaces = [ns for ns, _, _ in candidates]
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"组件名称 '{component_name}' 在多个命名空间中存在: {namespaces},"
|
f"组件名称 '{component_name}' 在多个命名空间中存在: {namespaces},使用第一个匹配项: {candidates[0][1]}"
|
||||||
f"使用第一个匹配项: {candidates[0][1]}"
|
|
||||||
)
|
)
|
||||||
return candidates[0][2]
|
return candidates[0][2]
|
||||||
|
|
||||||
# 4. 都没找到
|
# 4. 都没找到
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -262,7 +260,6 @@ class ComponentRegistry:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
for pattern, command_class in self._command_patterns.items():
|
for pattern, command_class in self._command_patterns.items():
|
||||||
|
|
||||||
match = pattern.match(text)
|
match = pattern.match(text)
|
||||||
if match:
|
if match:
|
||||||
command_name = None
|
command_name = None
|
||||||
@@ -271,7 +268,7 @@ class ComponentRegistry:
|
|||||||
if cls == command_class:
|
if cls == command_class:
|
||||||
command_name = name
|
command_name = name
|
||||||
break
|
break
|
||||||
|
|
||||||
# 检查命令是否启用
|
# 检查命令是否启用
|
||||||
if command_name:
|
if command_name:
|
||||||
command_info = self.get_command_info(command_name)
|
command_info = self.get_command_info(command_name)
|
||||||
@@ -346,15 +343,19 @@ class ComponentRegistry:
|
|||||||
component_info = self.get_component_info(component_name, component_type)
|
component_info = self.get_component_info(component_name, component_type)
|
||||||
if not component_info:
|
if not component_info:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 根据组件类型构造正确的命名空间化名称
|
# 根据组件类型构造正确的命名空间化名称
|
||||||
if component_info.component_type == ComponentType.ACTION:
|
if component_info.component_type == ComponentType.ACTION:
|
||||||
namespaced_name = f"action.{component_name}" if '.' not in component_name else component_name
|
namespaced_name = f"action.{component_name}" if "." not in component_name else component_name
|
||||||
elif component_info.component_type == ComponentType.COMMAND:
|
elif component_info.component_type == ComponentType.COMMAND:
|
||||||
namespaced_name = f"command.{component_name}" if '.' not in component_name else component_name
|
namespaced_name = f"command.{component_name}" if "." not in component_name else component_name
|
||||||
else:
|
else:
|
||||||
namespaced_name = f"{component_info.component_type.value}.{component_name}" if '.' not in component_name else component_name
|
namespaced_name = (
|
||||||
|
f"{component_info.component_type.value}.{component_name}"
|
||||||
|
if "." not in component_name
|
||||||
|
else component_name
|
||||||
|
)
|
||||||
|
|
||||||
if namespaced_name in self._components:
|
if namespaced_name in self._components:
|
||||||
self._components[namespaced_name].enabled = True
|
self._components[namespaced_name].enabled = True
|
||||||
# 如果是Action,更新默认动作集
|
# 如果是Action,更新默认动作集
|
||||||
@@ -370,15 +371,19 @@ class ComponentRegistry:
|
|||||||
component_info = self.get_component_info(component_name, component_type)
|
component_info = self.get_component_info(component_name, component_type)
|
||||||
if not component_info:
|
if not component_info:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 根据组件类型构造正确的命名空间化名称
|
# 根据组件类型构造正确的命名空间化名称
|
||||||
if component_info.component_type == ComponentType.ACTION:
|
if component_info.component_type == ComponentType.ACTION:
|
||||||
namespaced_name = f"action.{component_name}" if '.' not in component_name else component_name
|
namespaced_name = f"action.{component_name}" if "." not in component_name else component_name
|
||||||
elif component_info.component_type == ComponentType.COMMAND:
|
elif component_info.component_type == ComponentType.COMMAND:
|
||||||
namespaced_name = f"command.{component_name}" if '.' not in component_name else component_name
|
namespaced_name = f"command.{component_name}" if "." not in component_name else component_name
|
||||||
else:
|
else:
|
||||||
namespaced_name = f"{component_info.component_type.value}.{component_name}" if '.' not in component_name else component_name
|
namespaced_name = (
|
||||||
|
f"{component_info.component_type.value}.{component_name}"
|
||||||
|
if "." not in component_name
|
||||||
|
else component_name
|
||||||
|
)
|
||||||
|
|
||||||
if namespaced_name in self._components:
|
if namespaced_name in self._components:
|
||||||
self._components[namespaced_name].enabled = False
|
self._components[namespaced_name].enabled = False
|
||||||
# 如果是Action,从默认动作集中移除
|
# 如果是Action,从默认动作集中移除
|
||||||
|
|||||||
@@ -38,9 +38,7 @@ class ReplyAction(BaseAction):
|
|||||||
action_description = "参与聊天回复,发送文本进行表达"
|
action_description = "参与聊天回复,发送文本进行表达"
|
||||||
|
|
||||||
# 动作参数定义
|
# 动作参数定义
|
||||||
action_parameters = {
|
action_parameters = {"reply_to": "你要回复的对方的发言内容,格式:(用户名:发言内容),可以为none"}
|
||||||
"reply_to": "你要回复的对方的发言内容,格式:(用户名:发言内容),可以为none"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 动作使用场景
|
# 动作使用场景
|
||||||
action_require = ["你想要闲聊或者随便附和", "有人提到你", "如果你刚刚进行了回复,不要对同一个话题重复回应"]
|
action_require = ["你想要闲聊或者随便附和", "有人提到你", "如果你刚刚进行了回复,不要对同一个话题重复回应"]
|
||||||
@@ -53,45 +51,40 @@ class ReplyAction(BaseAction):
|
|||||||
logger.info(f"{self.log_prefix} 决定回复: {self.reasoning}")
|
logger.info(f"{self.log_prefix} 决定回复: {self.reasoning}")
|
||||||
|
|
||||||
start_time = self.action_data.get("loop_start_time", time.time())
|
start_time = self.action_data.get("loop_start_time", time.time())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
success, reply_set = await generator_api.generate_reply(
|
success, reply_set = await generator_api.generate_reply(
|
||||||
chat_stream=self.chat_stream,
|
chat_stream=self.chat_stream,
|
||||||
action_data=self.action_data,
|
action_data=self.action_data,
|
||||||
platform=self.platform,
|
platform=self.platform,
|
||||||
chat_id=self.chat_id,
|
chat_id=self.chat_id,
|
||||||
is_group=self.is_group
|
is_group=self.is_group,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 检查从start_time以来的新消息数量
|
# 检查从start_time以来的新消息数量
|
||||||
# 获取动作触发时间或使用默认值
|
# 获取动作触发时间或使用默认值
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
new_message_count = message_api.count_new_messages(
|
new_message_count = message_api.count_new_messages(
|
||||||
chat_id=self.chat_id,
|
chat_id=self.chat_id, start_time=start_time, end_time=current_time
|
||||||
start_time=start_time,
|
|
||||||
end_time=current_time
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 根据新消息数量决定是否使用reply_to
|
# 根据新消息数量决定是否使用reply_to
|
||||||
need_reply = new_message_count >= 4
|
need_reply = new_message_count >= 4
|
||||||
logger.info(f"{self.log_prefix} 从{start_time}到{current_time}共有{new_message_count}条新消息,{'使用' if need_reply else '不使用'}reply_to")
|
logger.info(
|
||||||
|
f"{self.log_prefix} 从{start_time}到{current_time}共有{new_message_count}条新消息,{'使用' if need_reply else '不使用'}reply_to"
|
||||||
|
)
|
||||||
|
|
||||||
# 构建回复文本
|
# 构建回复文本
|
||||||
reply_text = ""
|
reply_text = ""
|
||||||
first_reply = False
|
first_reply = False
|
||||||
for reply_seg in reply_set:
|
for reply_seg in reply_set:
|
||||||
data = reply_seg[1]
|
data = reply_seg[1]
|
||||||
if not first_reply and need_reply:
|
if not first_reply and need_reply:
|
||||||
await self.send_text(
|
await self.send_text(content=data, reply_to=self.action_data.get("reply_to", ""))
|
||||||
content=data,
|
|
||||||
reply_to=self.action_data.get("reply_to", "")
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await self.send_text(content=data)
|
await self.send_text(content=data)
|
||||||
first_reply = True
|
first_reply = True
|
||||||
reply_text += data
|
reply_text += data
|
||||||
|
|
||||||
|
|
||||||
# 存储动作记录
|
# 存储动作记录
|
||||||
await self.store_action_info(
|
await self.store_action_info(
|
||||||
@@ -110,7 +103,6 @@ class ReplyAction(BaseAction):
|
|||||||
return False, f"回复失败: {str(e)}"
|
return False, f"回复失败: {str(e)}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class NoReplyAction(BaseAction):
|
class NoReplyAction(BaseAction):
|
||||||
"""不回复动作,继承时会等待新消息或超时"""
|
"""不回复动作,继承时会等待新消息或超时"""
|
||||||
|
|
||||||
@@ -168,7 +160,7 @@ class NoReplyAction(BaseAction):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"{self.log_prefix} 不回复动作执行失败: {e}")
|
logger.error(f"{self.log_prefix} 不回复动作执行失败: {e}")
|
||||||
return False, f"不回复动作执行失败: {e}"
|
return False, f"不回复动作执行失败: {e}"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def reset_consecutive_count(cls):
|
def reset_consecutive_count(cls):
|
||||||
@@ -218,17 +210,17 @@ class EmojiAction(BaseAction):
|
|||||||
# 1. 根据描述选择表情包
|
# 1. 根据描述选择表情包
|
||||||
description = self.action_data.get("description", "")
|
description = self.action_data.get("description", "")
|
||||||
emoji_result = await emoji_api.get_by_description(description)
|
emoji_result = await emoji_api.get_by_description(description)
|
||||||
|
|
||||||
if not emoji_result:
|
if not emoji_result:
|
||||||
logger.warning(f"{self.log_prefix} 未找到匹配描述 '{description}' 的表情包")
|
logger.warning(f"{self.log_prefix} 未找到匹配描述 '{description}' 的表情包")
|
||||||
return False, f"未找到匹配 '{description}' 的表情包"
|
return False, f"未找到匹配 '{description}' 的表情包"
|
||||||
|
|
||||||
emoji_base64, emoji_description, matched_emotion = emoji_result
|
emoji_base64, emoji_description, matched_emotion = emoji_result
|
||||||
logger.info(f"{self.log_prefix} 找到表情包: {emoji_description}, 匹配情感: {matched_emotion}")
|
logger.info(f"{self.log_prefix} 找到表情包: {emoji_description}, 匹配情感: {matched_emotion}")
|
||||||
|
|
||||||
# 使用BaseAction的便捷方法发送表情包
|
# 使用BaseAction的便捷方法发送表情包
|
||||||
success = await self.send_emoji(emoji_base64)
|
success = await self.send_emoji(emoji_base64)
|
||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
logger.error(f"{self.log_prefix} 表情包发送失败")
|
logger.error(f"{self.log_prefix} 表情包发送失败")
|
||||||
return False, "表情包发送失败"
|
return False, "表情包发送失败"
|
||||||
@@ -430,10 +422,6 @@ class CoreActionsPlugin(BasePlugin):
|
|||||||
return components
|
return components
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# class DeepReplyAction(BaseAction):
|
# class DeepReplyAction(BaseAction):
|
||||||
# """回复动作 - 参与聊天回复"""
|
# """回复动作 - 参与聊天回复"""
|
||||||
|
|
||||||
@@ -467,42 +455,39 @@ class CoreActionsPlugin(BasePlugin):
|
|||||||
# chatting_observation = self._get_chatting_observation()
|
# chatting_observation = self._get_chatting_observation()
|
||||||
# if not chatting_observation:
|
# if not chatting_observation:
|
||||||
# return False, "未找到聊天观察"
|
# return False, "未找到聊天观察"
|
||||||
|
|
||||||
# talking_message_str = chatting_observation.talking_message_str
|
# talking_message_str = chatting_observation.talking_message_str
|
||||||
|
|
||||||
# # 处理回复目标
|
# # 处理回复目标
|
||||||
# chat_stream = self.api.get_service("chat_stream")
|
# chat_stream = self.api.get_service("chat_stream")
|
||||||
# anchor_message = await create_empty_anchor_message(chat_stream.platform, chat_stream.group_info, chat_stream)
|
# anchor_message = await create_empty_anchor_message(chat_stream.platform, chat_stream.group_info, chat_stream)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# llm_model = self.api.get_available_models().replyer_1
|
# llm_model = self.api.get_available_models().replyer_1
|
||||||
|
|
||||||
# prompt = f"""
|
# prompt = f"""
|
||||||
# {talking_message_str}
|
# {talking_message_str}
|
||||||
|
|
||||||
# 在上面的聊天中,你对{self.action_data.get("topic", "")}感兴趣,形成深刻观点,请你思考,总结成一份学术论文,APA标准格式
|
# 在上面的聊天中,你对{self.action_data.get("topic", "")}感兴趣,形成深刻观点,请你思考,总结成一份学术论文,APA标准格式
|
||||||
# """
|
# """
|
||||||
|
|
||||||
# success, response, reasoning, model_name = await self.api.generate_with_model(prompt, llm_model)
|
# success, response, reasoning, model_name = await self.api.generate_with_model(prompt, llm_model)
|
||||||
|
|
||||||
# print(prompt)
|
# print(prompt)
|
||||||
# print(f"DeepReplyAction: {response}")
|
# print(f"DeepReplyAction: {response}")
|
||||||
|
|
||||||
# # prompt = f"""
|
# # prompt = f"""
|
||||||
# # {talking_message_str}
|
# # {talking_message_str}
|
||||||
|
|
||||||
# # 在上面的聊天中,你对{self.action_data.get("topic", "")}感兴趣,请你思考
|
# # 在上面的聊天中,你对{self.action_data.get("topic", "")}感兴趣,请你思考
|
||||||
# # """
|
# # """
|
||||||
|
|
||||||
# extra_info_block = self.action_data.get("extra_info_block", "")
|
# extra_info_block = self.action_data.get("extra_info_block", "")
|
||||||
# extra_info_block += response
|
# extra_info_block += response
|
||||||
# # extra_info_block += f"\n--------------------------------\n注意,这是最重要的内容!!!!!你现在可以用比较长的篇幅来表达你的观点,不要只回复一个字或者几个字\n由于你进入了深度思考模式,所以下方聊天记录的回复要求不再适用,请你自由的表达,不论字数长短限制\n\n--------------------------------\n注意,你现在可以用比较长的篇幅来表达你的观点,不要只回复一个字或者几个字\n由于你进入了深度思考模式,所以下方聊天记录的回复要求不再适用,请你自由的表达,不论字数长短限制\n"
|
# # extra_info_block += f"\n--------------------------------\n注意,这是最重要的内容!!!!!你现在可以用比较长的篇幅来表达你的观点,不要只回复一个字或者几个字\n由于你进入了深度思考模式,所以下方聊天记录的回复要求不再适用,请你自由的表达,不论字数长短限制\n\n--------------------------------\n注意,你现在可以用比较长的篇幅来表达你的观点,不要只回复一个字或者几个字\n由于你进入了深度思考模式,所以下方聊天记录的回复要求不再适用,请你自由的表达,不论字数长短限制\n"
|
||||||
# # extra_info_block += f"\n--------------------------------\n注意,优先关注这句!!!!你现在可以用比较长的篇幅来表达你的观点,不要只回复一个字或者几个字\n由于你进入了深度思考模式,所以下方聊天记录的回复要求不再适用,请你自由的表达,不论字数长短限制\n\n--------------------------------\n注意,你现在可以用比较长的篇幅来表达你的观点,不要只回复一个字或者几个字\n由于你进入了深度思考模式,所以其他的回复要求不再适用,请你自由的表达,不论字数长短限制\n"
|
# # extra_info_block += f"\n--------------------------------\n注意,优先关注这句!!!!你现在可以用比较长的篇幅来表达你的观点,不要只回复一个字或者几个字\n由于你进入了深度思考模式,所以下方聊天记录的回复要求不再适用,请你自由的表达,不论字数长短限制\n\n--------------------------------\n注意,你现在可以用比较长的篇幅来表达你的观点,不要只回复一个字或者几个字\n由于你进入了深度思考模式,所以其他的回复要求不再适用,请你自由的表达,不论字数长短限制\n"
|
||||||
# self.action_data["extra_info_block"] = extra_info_block
|
# self.action_data["extra_info_block"] = extra_info_block
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# # 获取回复器服务
|
# # 获取回复器服务
|
||||||
# # replyer = self.api.get_service("replyer")
|
# # replyer = self.api.get_service("replyer")
|
||||||
@@ -558,4 +543,4 @@ class CoreActionsPlugin(BasePlugin):
|
|||||||
# for reply in reply_set:
|
# for reply in reply_set:
|
||||||
# data = reply[1]
|
# data = reply[1]
|
||||||
# reply_text += data
|
# reply_text += data
|
||||||
# return reply_text
|
# return reply_text
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from src.plugin_system.base.base_command import BaseCommand
|
|||||||
from src.plugin_system.base.component_types import ComponentInfo, ActionActivationType, ChatMode
|
from src.plugin_system.base.component_types import ComponentInfo, ActionActivationType, ChatMode
|
||||||
from src.plugin_system.base.config_types import ConfigField
|
from src.plugin_system.base.config_types import ConfigField
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
|
|
||||||
# 导入配置API(可选的简便方法)
|
# 导入配置API(可选的简便方法)
|
||||||
from src.plugin_system.apis import person_api, generator_api
|
from src.plugin_system.apis import person_api, generator_api
|
||||||
|
|
||||||
@@ -140,28 +141,28 @@ class MuteAction(BaseAction):
|
|||||||
|
|
||||||
# 获取用户ID
|
# 获取用户ID
|
||||||
person_id = person_api.get_person_id_by_name(target)
|
person_id = person_api.get_person_id_by_name(target)
|
||||||
user_id = await person_api.get_person_value(person_id,"user_id")
|
user_id = await person_api.get_person_value(person_id, "user_id")
|
||||||
if not user_id:
|
if not user_id:
|
||||||
error_msg = f"未找到用户 {target} 的ID"
|
error_msg = f"未找到用户 {target} 的ID"
|
||||||
await self.send_text(f"找不到 {target} 这个人呢~")
|
await self.send_text(f"找不到 {target} 这个人呢~")
|
||||||
logger.error(f"{self.log_prefix} {error_msg}")
|
logger.error(f"{self.log_prefix} {error_msg}")
|
||||||
return False, error_msg
|
return False, error_msg
|
||||||
|
|
||||||
# 格式化时长显示
|
# 格式化时长显示
|
||||||
enable_formatting = self.get_config("mute.enable_duration_formatting", True)
|
enable_formatting = self.get_config("mute.enable_duration_formatting", True)
|
||||||
time_str = self._format_duration(duration_int) if enable_formatting else f"{duration_int}秒"
|
time_str = self._format_duration(duration_int) if enable_formatting else f"{duration_int}秒"
|
||||||
|
|
||||||
# 获取模板化消息
|
# 获取模板化消息
|
||||||
message = self._get_template_message(target, time_str, reason)
|
message = self._get_template_message(target, time_str, reason)
|
||||||
|
|
||||||
result_status,result_message = await generator_api.rewrite_reply(
|
result_status, result_message = await generator_api.rewrite_reply(
|
||||||
chat_stream=self.chat_stream,
|
chat_stream=self.chat_stream,
|
||||||
reply_data={
|
reply_data={
|
||||||
"raw_reply": message,
|
"raw_reply": message,
|
||||||
"reason": reason,
|
"reason": reason,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if result_status:
|
if result_status:
|
||||||
for reply_seg in result_message:
|
for reply_seg in result_message:
|
||||||
data = reply_seg[1]
|
data = reply_seg[1]
|
||||||
@@ -169,9 +170,7 @@ class MuteAction(BaseAction):
|
|||||||
|
|
||||||
# 发送群聊禁言命令
|
# 发送群聊禁言命令
|
||||||
success = await self.send_command(
|
success = await self.send_command(
|
||||||
command_name="GROUP_BAN",
|
command_name="GROUP_BAN", args={"qq_id": str(user_id), "duration": str(duration_int)}, storage_message=False
|
||||||
args={"qq_id": str(user_id), "duration": str(duration_int)},
|
|
||||||
storage_message=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
@@ -186,15 +185,13 @@ class MuteAction(BaseAction):
|
|||||||
else:
|
else:
|
||||||
error_msg = "发送禁言命令失败"
|
error_msg = "发送禁言命令失败"
|
||||||
logger.error(f"{self.log_prefix} {error_msg}")
|
logger.error(f"{self.log_prefix} {error_msg}")
|
||||||
|
|
||||||
await self.send_text("执行禁言动作失败")
|
await self.send_text("执行禁言动作失败")
|
||||||
return False, error_msg
|
return False, error_msg
|
||||||
|
|
||||||
def _get_template_message(self, target: str, duration_str: str, reason: str) -> str:
|
def _get_template_message(self, target: str, duration_str: str, reason: str) -> str:
|
||||||
"""获取模板化的禁言消息"""
|
"""获取模板化的禁言消息"""
|
||||||
templates = self.get_config(
|
templates = self.get_config("mute.templates")
|
||||||
"mute.templates"
|
|
||||||
)
|
|
||||||
|
|
||||||
template = random.choice(templates)
|
template = random.choice(templates)
|
||||||
return template.format(target=target, duration=duration_str, reason=reason)
|
return template.format(target=target, duration=duration_str, reason=reason)
|
||||||
|
|||||||
Reference in New Issue
Block a user