style: 格式化代码
This commit is contained in:
committed by
Windpicker-owo
parent
e7aaafde2f
commit
00ba07e0e1
@@ -12,7 +12,7 @@ from src.common.data_models.info_data_model import InterestScore
|
||||
from src.chat.interest_system import bot_interest_manager
|
||||
from src.common.logger import get_logger
|
||||
from src.config.config import global_config
|
||||
from src.plugins.built_in.affinity_flow_chatter.relationship_tracker import ChatterRelationshipTracker
|
||||
|
||||
logger = get_logger("chatter_interest_scoring")
|
||||
|
||||
# 定义颜色
|
||||
@@ -45,7 +45,7 @@ class ChatterInterestScoringSystem:
|
||||
self.probability_boost_per_no_reply = (
|
||||
affinity_config.no_reply_threshold_adjustment / affinity_config.max_no_reply_count
|
||||
) # 每次不回复增加的概率
|
||||
|
||||
|
||||
# 用户关系数据
|
||||
self.user_relationships: Dict[str, float] = {} # user_id -> relationship_score
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class ChatterPlanExecutor:
|
||||
if not plan.decided_actions:
|
||||
logger.info("没有需要执行的动作。")
|
||||
return {"executed_count": 0, "results": []}
|
||||
|
||||
|
||||
# 像hfc一样,提前打印将要执行的动作
|
||||
action_types = [action.action_type for action in plan.decided_actions]
|
||||
logger.info(f"选择动作: {', '.join(action_types) if action_types else '无'}")
|
||||
@@ -150,17 +150,19 @@ class ChatterPlanExecutor:
|
||||
for i, action_info in enumerate(unique_actions):
|
||||
is_last_action = i == total_actions - 1
|
||||
if total_actions > 1:
|
||||
logger.info(f"[多重回复] 正在执行第 {i+1}/{total_actions} 个回复...")
|
||||
logger.info(f"[多重回复] 正在执行第 {i + 1}/{total_actions} 个回复...")
|
||||
|
||||
# 传递 clear_unread 参数
|
||||
result = await self._execute_single_reply_action(action_info, plan, clear_unread=is_last_action)
|
||||
results.append(result)
|
||||
|
||||
if total_actions > 1:
|
||||
logger.info(f"[多重回复] 所有回复任务执行完毕。")
|
||||
logger.info("[多重回复] 所有回复任务执行完毕。")
|
||||
return {"results": results}
|
||||
|
||||
async def _execute_single_reply_action(self, action_info: ActionPlannerInfo, plan: Plan, clear_unread: bool = True) -> Dict[str, any]:
|
||||
async def _execute_single_reply_action(
|
||||
self, action_info: ActionPlannerInfo, plan: Plan, clear_unread: bool = True
|
||||
) -> Dict[str, any]:
|
||||
"""执行单个回复动作"""
|
||||
start_time = time.time()
|
||||
success = False
|
||||
@@ -201,7 +203,7 @@ class ChatterPlanExecutor:
|
||||
execution_result = await self.action_manager.execute_action(
|
||||
action_name=action_info.action_type, **action_params
|
||||
)
|
||||
|
||||
|
||||
# 从返回结果中提取真正的回复文本
|
||||
if isinstance(execution_result, dict):
|
||||
reply_content = execution_result.get("reply_text", "")
|
||||
@@ -233,7 +235,9 @@ class ChatterPlanExecutor:
|
||||
"error_message": error_message,
|
||||
"execution_time": execution_time,
|
||||
"reasoning": action_info.reasoning,
|
||||
"reply_content": reply_content[:200] + "..." if reply_content and len(reply_content) > 200 else reply_content,
|
||||
"reply_content": reply_content[:200] + "..."
|
||||
if reply_content and len(reply_content) > 200
|
||||
else reply_content,
|
||||
}
|
||||
|
||||
async def _execute_other_actions(self, other_actions: List[ActionPlannerInfo], plan: Plan) -> Dict[str, any]:
|
||||
|
||||
@@ -100,7 +100,7 @@ class ChatterPlanFilter:
|
||||
# 预解析 action_type 来进行判断
|
||||
thinking = item.get("thinking", "未提供思考过程")
|
||||
actions_obj = item.get("actions", {})
|
||||
|
||||
|
||||
# 处理actions字段可能是字典或列表的情况
|
||||
if isinstance(actions_obj, dict):
|
||||
action_type = actions_obj.get("action_type", "no_action")
|
||||
@@ -116,14 +116,12 @@ class ChatterPlanFilter:
|
||||
|
||||
if action_type in reply_action_types:
|
||||
if not reply_action_added:
|
||||
final_actions.extend(
|
||||
await self._parse_single_action(item, used_message_id_list, plan)
|
||||
)
|
||||
final_actions.extend(await self._parse_single_action(item, used_message_id_list, plan))
|
||||
reply_action_added = True
|
||||
else:
|
||||
# 非回复类动作直接添加
|
||||
final_actions.extend(await self._parse_single_action(item, used_message_id_list, plan))
|
||||
|
||||
|
||||
if thinking and thinking != "未提供思考过程":
|
||||
logger.info(f"\n{SAKURA_PINK}思考: {thinking}{RESET_COLOR}\n")
|
||||
plan.decided_actions = self._filter_no_actions(final_actions)
|
||||
@@ -154,6 +152,7 @@ class ChatterPlanFilter:
|
||||
schedule_block = ""
|
||||
# 优先检查是否被吵醒
|
||||
from src.chat.message_manager.message_manager import message_manager
|
||||
|
||||
angry_prompt_addition = ""
|
||||
wakeup_mgr = message_manager.wakeup_manager
|
||||
|
||||
@@ -161,7 +160,7 @@ class ChatterPlanFilter:
|
||||
# 检查1: 直接从 wakeup_manager 获取
|
||||
if wakeup_mgr.is_in_angry_state():
|
||||
angry_prompt_addition = wakeup_mgr.get_angry_prompt_addition()
|
||||
|
||||
|
||||
# 检查2: 如果上面没获取到,再从 mood_manager 确认
|
||||
if not angry_prompt_addition:
|
||||
chat_mood_for_check = mood_manager.get_mood_by_chat_id(plan.chat_id)
|
||||
@@ -274,7 +273,9 @@ class ChatterPlanFilter:
|
||||
is_group_chat = plan.chat_type == ChatType.GROUP
|
||||
chat_context_description = "你现在正在一个群聊中"
|
||||
if not is_group_chat and plan.target_info:
|
||||
chat_target_name = plan.target_info.get("person_name") or plan.target_info.get("user_nickname") or "对方"
|
||||
chat_target_name = (
|
||||
plan.target_info.get("person_name") or plan.target_info.get("user_nickname") or "对方"
|
||||
)
|
||||
chat_context_description = f"你正在和 {chat_target_name} 私聊"
|
||||
|
||||
action_options_block = await self._build_action_options(plan.available_actions)
|
||||
@@ -315,12 +316,12 @@ class ChatterPlanFilter:
|
||||
"""构建已读/未读历史消息块"""
|
||||
try:
|
||||
# 从message_manager获取真实的已读/未读消息
|
||||
from src.chat.message_manager.message_manager import message_manager
|
||||
from src.chat.utils.utils import assign_message_ids
|
||||
from src.chat.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat
|
||||
|
||||
# 获取聊天流的上下文
|
||||
from src.plugin_system.apis.chat_api import get_chat_manager
|
||||
|
||||
chat_manager = get_chat_manager()
|
||||
chat_stream = chat_manager.get_stream(plan.chat_id)
|
||||
if not chat_stream:
|
||||
@@ -333,6 +334,7 @@ class ChatterPlanFilter:
|
||||
read_messages = stream_context.context.history_messages # 已读消息存储在history_messages中
|
||||
if not read_messages:
|
||||
from src.common.data_models.database_data_model import DatabaseMessages
|
||||
|
||||
# 如果内存中没有已读消息(比如刚启动),则从数据库加载最近的上下文
|
||||
fallback_messages_dicts = await get_raw_msg_before_timestamp_with_chat(
|
||||
chat_id=plan.chat_id,
|
||||
@@ -414,7 +416,7 @@ class ChatterPlanFilter:
|
||||
processed_plain_text=msg_dict.get("processed_plain_text", ""),
|
||||
key_words=msg_dict.get("key_words", "[]"),
|
||||
is_mentioned=msg_dict.get("is_mentioned", False),
|
||||
**{"user_info": user_info_dict} # 通过kwargs传入user_info
|
||||
**{"user_info": user_info_dict}, # 通过kwargs传入user_info
|
||||
)
|
||||
else:
|
||||
# 如果没有user_info字段,使用平铺的字段(flatten()方法返回的格式)
|
||||
@@ -425,13 +427,12 @@ class ChatterPlanFilter:
|
||||
user_platform=msg_dict.get("user_platform", ""),
|
||||
processed_plain_text=msg_dict.get("processed_plain_text", ""),
|
||||
key_words=msg_dict.get("key_words", "[]"),
|
||||
is_mentioned=msg_dict.get("is_mentioned", False)
|
||||
is_mentioned=msg_dict.get("is_mentioned", False),
|
||||
)
|
||||
|
||||
# 计算消息兴趣度
|
||||
interest_score_obj = await chatter_interest_scoring_system._calculate_single_message_score(
|
||||
message=db_message,
|
||||
bot_nickname=global_config.bot.nickname
|
||||
message=db_message, bot_nickname=global_config.bot.nickname
|
||||
)
|
||||
interest_score = interest_score_obj.total_score
|
||||
|
||||
@@ -454,7 +455,7 @@ class ChatterPlanFilter:
|
||||
try:
|
||||
# 从新的actions结构中获取动作信息
|
||||
actions_obj = action_json.get("actions", {})
|
||||
|
||||
|
||||
# 处理actions字段可能是字典或列表的情况
|
||||
actions_to_process = []
|
||||
if isinstance(actions_obj, dict):
|
||||
@@ -463,19 +464,23 @@ class ChatterPlanFilter:
|
||||
actions_to_process.extend(actions_obj)
|
||||
|
||||
if not actions_to_process:
|
||||
actions_to_process.append({"action_type": "no_action", "reason": "actions格式错误"})
|
||||
actions_to_process.append({"action_type": "no_action", "reason": "actions格式错误"})
|
||||
|
||||
for single_action_obj in actions_to_process:
|
||||
if not isinstance(single_action_obj, dict):
|
||||
continue
|
||||
|
||||
action = single_action_obj.get("action_type", "no_action")
|
||||
reasoning = single_action_obj.get("reasoning", "未提供原因") # 兼容旧的reason字段
|
||||
reasoning = single_action_obj.get("reasoning", "未提供原因") # 兼容旧的reason字段
|
||||
action_data = single_action_obj.get("action_data", {})
|
||||
|
||||
|
||||
# 为了向后兼容,如果action_data不存在,则从顶层字段获取
|
||||
if not action_data:
|
||||
action_data = {k: v for k, v in single_action_obj.items() if k not in ["action_type", "reason", "reasoning", "thinking"]}
|
||||
action_data = {
|
||||
k: v
|
||||
for k, v in single_action_obj.items()
|
||||
if k not in ["action_type", "reason", "reasoning", "thinking"]
|
||||
}
|
||||
|
||||
# 保留原始的thinking字段(如果有)
|
||||
thinking = action_json.get("thinking", "")
|
||||
@@ -501,7 +506,9 @@ class ChatterPlanFilter:
|
||||
# reply动作必须有目标消息,使用最新消息作为兜底
|
||||
target_message_dict = self._get_latest_message(message_id_list)
|
||||
if target_message_dict:
|
||||
logger.info(f"[{action}] 使用最新消息作为目标: {target_message_dict.get('message_id')}")
|
||||
logger.info(
|
||||
f"[{action}] 使用最新消息作为目标: {target_message_dict.get('message_id')}"
|
||||
)
|
||||
else:
|
||||
logger.error(f"[{action}] 无法找到任何目标消息,降级为no_action")
|
||||
action = "no_action"
|
||||
@@ -509,15 +516,21 @@ class ChatterPlanFilter:
|
||||
|
||||
elif action in ["poke_user", "set_emoji_like"]:
|
||||
# 这些动作可以尝试其他策略
|
||||
target_message_dict = self._find_poke_notice(message_id_list) or self._get_latest_message(message_id_list)
|
||||
target_message_dict = self._find_poke_notice(
|
||||
message_id_list
|
||||
) or self._get_latest_message(message_id_list)
|
||||
if target_message_dict:
|
||||
logger.info(f"[{action}] 使用替代消息作为目标: {target_message_dict.get('message_id')}")
|
||||
logger.info(
|
||||
f"[{action}] 使用替代消息作为目标: {target_message_dict.get('message_id')}"
|
||||
)
|
||||
|
||||
else:
|
||||
# 其他动作使用最新消息或跳过
|
||||
target_message_dict = self._get_latest_message(message_id_list)
|
||||
if target_message_dict:
|
||||
logger.info(f"[{action}] 使用最新消息作为目标: {target_message_dict.get('message_id')}")
|
||||
logger.info(
|
||||
f"[{action}] 使用最新消息作为目标: {target_message_dict.get('message_id')}"
|
||||
)
|
||||
else:
|
||||
# 如果LLM没有指定target_message_id,进行特殊处理
|
||||
if action == "poke_user":
|
||||
@@ -615,7 +628,7 @@ class ChatterPlanFilter:
|
||||
query_text=query,
|
||||
user_id="system", # 系统查询
|
||||
scope_id="system",
|
||||
limit=5
|
||||
limit=5,
|
||||
)
|
||||
|
||||
if not enhanced_memories:
|
||||
@@ -628,7 +641,9 @@ class ChatterPlanFilter:
|
||||
memory_type = memory_chunk.memory_type.value if memory_chunk.memory_type else "unknown"
|
||||
retrieved_memories.append((memory_type, content))
|
||||
|
||||
memory_statements = [f"关于'{topic}', 你记得'{memory_item}'。" for topic, memory_item in retrieved_memories]
|
||||
memory_statements = [
|
||||
f"关于'{topic}', 你记得'{memory_item}'。" for topic, memory_item in retrieved_memories
|
||||
]
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"增强记忆系统检索失败,使用默认回复: {e}")
|
||||
@@ -650,12 +665,17 @@ class ChatterPlanFilter:
|
||||
if action_name == "set_emoji_like" and p_name == "emoji":
|
||||
# 特殊处理set_emoji_like的emoji参数
|
||||
from src.plugins.built_in.social_toolkit_plugin.qq_emoji_list import qq_face
|
||||
emoji_options = [re.search(r"\[表情:(.+?)\]", name).group(1) for name in qq_face.values() if re.search(r"\[表情:(.+?)\]", name)]
|
||||
|
||||
emoji_options = [
|
||||
re.search(r"\[表情:(.+?)\]", name).group(1)
|
||||
for name in qq_face.values()
|
||||
if re.search(r"\[表情:(.+?)\]", name)
|
||||
]
|
||||
example_value = f"<从'{', '.join(emoji_options[:10])}...'中选择一个>"
|
||||
else:
|
||||
example_value = f"<{p_desc}>"
|
||||
params_json_list.append(f' "{p_name}": "{example_value}"')
|
||||
|
||||
|
||||
# 基础动作信息
|
||||
action_description = action_info.description
|
||||
action_require = "\n".join(f"- {req}" for req in action_info.action_require)
|
||||
@@ -668,11 +688,11 @@ class ChatterPlanFilter:
|
||||
# 将参数列表合并到JSON示例中
|
||||
if params_json_list:
|
||||
# 移除最后一行的逗号
|
||||
json_example_lines.extend([line.rstrip(',') for line in params_json_list])
|
||||
json_example_lines.extend([line.rstrip(",") for line in params_json_list])
|
||||
|
||||
json_example_lines.append(' "reason": "<执行该动作的详细原因>"')
|
||||
json_example_lines.append(" }")
|
||||
|
||||
|
||||
# 使用逗号连接内部元素,除了最后一个
|
||||
json_parts = []
|
||||
for i, line in enumerate(json_example_lines):
|
||||
@@ -680,14 +700,14 @@ class ChatterPlanFilter:
|
||||
if line.strip() in ["{", "}"]:
|
||||
json_parts.append(line)
|
||||
continue
|
||||
|
||||
|
||||
# 检查是否是最后一个需要逗号的元素
|
||||
is_last_item = True
|
||||
for next_line in json_example_lines[i+1:]:
|
||||
for next_line in json_example_lines[i + 1 :]:
|
||||
if next_line.strip() not in ["}"]:
|
||||
is_last_item = False
|
||||
break
|
||||
|
||||
|
||||
if not is_last_item:
|
||||
json_parts.append(f"{line},")
|
||||
else:
|
||||
@@ -715,7 +735,7 @@ class ChatterPlanFilter:
|
||||
|
||||
# 1. 标准化处理:去除可能的格式干扰
|
||||
original_id = str(message_id).strip()
|
||||
normalized_id = original_id.strip('<>"\'').strip()
|
||||
normalized_id = original_id.strip("<>\"'").strip()
|
||||
|
||||
if not normalized_id:
|
||||
return None
|
||||
@@ -733,12 +753,13 @@ class ChatterPlanFilter:
|
||||
|
||||
# 处理包含在文本中的ID格式 (如 "消息m123" -> 提取 m123)
|
||||
import re
|
||||
|
||||
# 尝试提取各种格式的ID
|
||||
id_patterns = [
|
||||
r'm\d+', # m123格式
|
||||
r'\d+', # 纯数字格式
|
||||
r'buffered-[a-f0-9-]+', # buffered-xxxx格式
|
||||
r'[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}', # UUID格式
|
||||
r"m\d+", # m123格式
|
||||
r"\d+", # 纯数字格式
|
||||
r"buffered-[a-f0-9-]+", # buffered-xxxx格式
|
||||
r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", # UUID格式
|
||||
]
|
||||
|
||||
for pattern in id_patterns:
|
||||
@@ -773,12 +794,12 @@ class ChatterPlanFilter:
|
||||
# 4. 尝试模糊匹配(数字部分匹配)
|
||||
for candidate in candidate_ids:
|
||||
# 提取数字部分进行模糊匹配
|
||||
number_part = re.sub(r'[^0-9]', '', candidate)
|
||||
number_part = re.sub(r"[^0-9]", "", candidate)
|
||||
if number_part:
|
||||
for item in message_id_list:
|
||||
if isinstance(item, dict):
|
||||
item_id = item.get("id", "")
|
||||
item_number = re.sub(r'[^0-9]', '', item_id)
|
||||
item_number = re.sub(r"[^0-9]", "", item_id)
|
||||
|
||||
# 数字部分匹配
|
||||
if item_number == number_part:
|
||||
@@ -789,7 +810,7 @@ class ChatterPlanFilter:
|
||||
message_obj = item.get("message")
|
||||
if isinstance(message_obj, dict):
|
||||
orig_mid = message_obj.get("message_id") or message_obj.get("id")
|
||||
orig_number = re.sub(r'[^0-9]', '', str(orig_mid)) if orig_mid else ""
|
||||
orig_number = re.sub(r"[^0-9]", "", str(orig_mid)) if orig_mid else ""
|
||||
if orig_number == number_part:
|
||||
logger.debug(f"模糊匹配成功(消息对象): {candidate} -> {orig_mid}")
|
||||
return message_obj
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
"""
|
||||
|
||||
from dataclasses import asdict
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
|
||||
|
||||
from src.plugins.built_in.affinity_flow_chatter.plan_executor import ChatterPlanExecutor
|
||||
@@ -90,15 +89,16 @@ class ChatterActionPlanner:
|
||||
try:
|
||||
# 在规划前,先进行动作修改
|
||||
from src.chat.planner_actions.action_modifier import ActionModifier
|
||||
|
||||
action_modifier = ActionModifier(self.action_manager, self.chat_id)
|
||||
await action_modifier.modify_actions()
|
||||
|
||||
|
||||
# 1. 生成初始 Plan
|
||||
initial_plan = await self.generator.generate(context.chat_mode)
|
||||
|
||||
# 确保Plan中包含所有当前可用的动作
|
||||
initial_plan.available_actions = self.action_manager.get_using_actions()
|
||||
|
||||
|
||||
unread_messages = context.get_unread_messages() if context else []
|
||||
# 2. 使用新的兴趣度管理系统进行评分
|
||||
score = 0.0
|
||||
@@ -117,7 +117,9 @@ class ChatterActionPlanner:
|
||||
message_interest = interest_score.total_score
|
||||
|
||||
message.interest_value = message_interest
|
||||
message.should_reply = message_interest > global_config.affinity_flow.non_reply_action_interest_threshold
|
||||
message.should_reply = (
|
||||
message_interest > global_config.affinity_flow.non_reply_action_interest_threshold
|
||||
)
|
||||
|
||||
interest_updates.append(
|
||||
{
|
||||
|
||||
@@ -596,7 +596,7 @@ class ChatterRelationshipTracker:
|
||||
quality = response_data.get("interaction_quality", "medium")
|
||||
|
||||
# 更新数据库
|
||||
await self._update_user_relationship_in_db(user_id, new_text, new_score)
|
||||
await self._update_user_relationship_in_db(user_id, new_text, new_score)
|
||||
|
||||
# 更新缓存
|
||||
self.user_relationship_cache[user_id] = {
|
||||
|
||||
@@ -268,7 +268,7 @@ class EmojiAction(BaseAction):
|
||||
if not success:
|
||||
logger.error(f"{self.log_prefix} 表情包发送失败")
|
||||
await self.store_action_info(
|
||||
action_build_into_prompt=True, action_prompt_display=f"发送了一个表情包,但失败了", action_done=False
|
||||
action_build_into_prompt=True, action_prompt_display="发送了一个表情包,但失败了", action_done=False
|
||||
)
|
||||
return False, "表情包发送失败"
|
||||
|
||||
@@ -279,7 +279,7 @@ class EmojiAction(BaseAction):
|
||||
logger.error(f"{self.log_prefix} 添加表情到历史记录时出错: {e}")
|
||||
|
||||
await self.store_action_info(
|
||||
action_build_into_prompt=True, action_prompt_display=f"发送了一个表情包", action_done=True
|
||||
action_build_into_prompt=True, action_prompt_display="发送了一个表情包", action_done=True
|
||||
)
|
||||
|
||||
return True, f"发送表情包: {emoji_description}"
|
||||
|
||||
@@ -47,9 +47,9 @@ class SearchKnowledgeFromLPMMTool(BaseTool):
|
||||
knowledge_parts = []
|
||||
for i, item in enumerate(knowledge_info["knowledge_items"]):
|
||||
knowledge_parts.append(f"- {item.get('content', 'N/A')}")
|
||||
|
||||
|
||||
knowledge_text = "\n".join(knowledge_parts)
|
||||
summary = knowledge_info.get('summary', '无总结')
|
||||
summary = knowledge_info.get("summary", "无总结")
|
||||
content = f"关于 '{query}', 你知道以下信息:\n{knowledge_text}\n\n总结: {summary}"
|
||||
else:
|
||||
content = f"关于 '{query}',你的知识库里好像没有相关的信息呢"
|
||||
|
||||
@@ -87,6 +87,7 @@ class MaiZoneRefactoredPlugin(BasePlugin):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
async def on_plugin_loaded(self):
|
||||
"""插件加载完成后的回调,初始化服务并启动后台任务"""
|
||||
# --- 注册权限节点 ---
|
||||
|
||||
@@ -140,5 +140,7 @@ class CookieService:
|
||||
self._save_cookies_to_file(qq_account, cookies)
|
||||
return cookies
|
||||
|
||||
logger.error(f"为 {qq_account} 获取Cookie的所有方法均失败。请确保Napcat HTTP服务或Adapter连接至少有一个正常工作,或存在有效的本地Cookie文件。")
|
||||
logger.error(
|
||||
f"为 {qq_account} 获取Cookie的所有方法均失败。请确保Napcat HTTP服务或Adapter连接至少有一个正常工作,或存在有效的本地Cookie文件。"
|
||||
)
|
||||
return None
|
||||
|
||||
@@ -290,9 +290,7 @@ class QZoneService:
|
||||
comment_content = comment.get("content", "")
|
||||
|
||||
try:
|
||||
reply_content = await self.content_service.generate_comment_reply(
|
||||
content, comment_content, nickname
|
||||
)
|
||||
reply_content = await self.content_service.generate_comment_reply(content, comment_content, nickname)
|
||||
if reply_content:
|
||||
success = await api_client["reply"](fid, qq_account, nickname, reply_content, comment_tid)
|
||||
if success:
|
||||
@@ -532,7 +530,9 @@ class QZoneService:
|
||||
async def _get_api_client(self, qq_account: str, stream_id: Optional[str]) -> Optional[Dict]:
|
||||
cookies = await self.cookie_service.get_cookies(qq_account, stream_id)
|
||||
if not cookies:
|
||||
logger.error("获取API客户端失败:未能获取到Cookie。请检查Napcat连接是否正常,或是否存在有效的本地Cookie文件。")
|
||||
logger.error(
|
||||
"获取API客户端失败:未能获取到Cookie。请检查Napcat连接是否正常,或是否存在有效的本地Cookie文件。"
|
||||
)
|
||||
return None
|
||||
|
||||
p_skey = cookies.get("p_skey") or cookies.get("p_skey".upper())
|
||||
@@ -726,7 +726,8 @@ class QZoneService:
|
||||
return {"pic_bo": picbo, "richval": richval}
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"从上传结果中提取图片参数失败: {e}, 上传结果: {upload_result}", exc_info=True
|
||||
f"从上传结果中提取图片参数失败: {e}, 上传结果: {upload_result}",
|
||||
exc_info=True,
|
||||
)
|
||||
return None
|
||||
else:
|
||||
@@ -764,7 +765,9 @@ class QZoneService:
|
||||
json_data = orjson.loads(res_text)
|
||||
|
||||
if json_data.get("code") != 0:
|
||||
logger.warning(f"获取说说列表API返回错误: code={json_data.get('code')}, message={json_data.get('message')}")
|
||||
logger.warning(
|
||||
f"获取说说列表API返回错误: code={json_data.get('code')}, message={json_data.get('message')}"
|
||||
)
|
||||
return []
|
||||
|
||||
feeds_list = []
|
||||
@@ -797,7 +800,7 @@ class QZoneService:
|
||||
for c in commentlist:
|
||||
if not isinstance(c, dict):
|
||||
continue
|
||||
|
||||
|
||||
# 添加主评论
|
||||
comments.append(
|
||||
{
|
||||
@@ -822,7 +825,7 @@ class QZoneService:
|
||||
"parent_tid": c.get("tid"), # 父ID是主评论的ID
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
feeds_list.append(
|
||||
{
|
||||
"tid": msg.get("tid", ""),
|
||||
|
||||
@@ -844,7 +844,7 @@ class MessageHandler:
|
||||
if music:
|
||||
tag = music.get("tag", "未知来源")
|
||||
logger.debug(f"检测到【{tag}】音乐分享消息 (music view),开始提取信息")
|
||||
|
||||
|
||||
title = music.get("title", "未知歌曲")
|
||||
desc = music.get("desc", "未知艺术家")
|
||||
jump_url = music.get("jumpUrl", "")
|
||||
@@ -862,7 +862,7 @@ class MessageHandler:
|
||||
artist = parts[1]
|
||||
else:
|
||||
artist = desc
|
||||
|
||||
|
||||
formatted_content = (
|
||||
f"这是一张来自【{tag}】的音乐分享卡片:\n"
|
||||
f"歌曲: {song_title}\n"
|
||||
@@ -879,12 +879,12 @@ class MessageHandler:
|
||||
if news and "网易云音乐" in news.get("tag", ""):
|
||||
tag = news.get("tag")
|
||||
logger.debug(f"检测到【{tag}】音乐分享消息 (news view),开始提取信息")
|
||||
|
||||
|
||||
title = news.get("title", "未知歌曲")
|
||||
desc = news.get("desc", "未知艺术家")
|
||||
jump_url = news.get("jumpUrl", "")
|
||||
preview_url = news.get("preview", "")
|
||||
|
||||
|
||||
formatted_content = (
|
||||
f"这是一张来自【{tag}】的音乐分享卡片:\n"
|
||||
f"标题: {title}\n"
|
||||
|
||||
@@ -3,7 +3,6 @@ import time
|
||||
import random
|
||||
import websockets as Server
|
||||
import uuid
|
||||
import asyncio
|
||||
from maim_message import (
|
||||
UserInfo,
|
||||
GroupInfo,
|
||||
@@ -96,7 +95,9 @@ class SendHandler:
|
||||
logger.error("无法识别的消息类型")
|
||||
return
|
||||
logger.info("尝试发送到napcat")
|
||||
logger.debug(f"准备发送到napcat的消息体: action='{action}', {id_name}='{target_id}', message='{processed_message}'")
|
||||
logger.debug(
|
||||
f"准备发送到napcat的消息体: action='{action}', {id_name}='{target_id}', message='{processed_message}'"
|
||||
)
|
||||
response = await self.send_message_to_napcat(
|
||||
action,
|
||||
{
|
||||
|
||||
@@ -6,7 +6,6 @@ import urllib3
|
||||
import ssl
|
||||
import io
|
||||
|
||||
import asyncio
|
||||
import time
|
||||
from asyncio import Lock
|
||||
|
||||
@@ -75,7 +74,7 @@ async def get_group_info(websocket: Server.ServerConnection, group_id: int) -> d
|
||||
except Exception as e:
|
||||
logger.error(f"获取群信息失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
data = socket_response.get("data")
|
||||
if data:
|
||||
await set_to_cache(cache_key, data)
|
||||
@@ -114,7 +113,7 @@ async def get_member_info(websocket: Server.ServerConnection, group_id: int, use
|
||||
cached_data = await get_from_cache(cache_key)
|
||||
if cached_data:
|
||||
return cached_data
|
||||
|
||||
|
||||
logger.debug(f"获取群成员信息中 (无缓存): group={group_id}, user={user_id}")
|
||||
request_uuid = str(uuid.uuid4())
|
||||
payload = json.dumps(
|
||||
@@ -133,7 +132,7 @@ async def get_member_info(websocket: Server.ServerConnection, group_id: int, use
|
||||
except Exception as e:
|
||||
logger.error(f"获取成员信息失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
data = socket_response.get("data")
|
||||
if data:
|
||||
await set_to_cache(cache_key, data)
|
||||
@@ -203,7 +202,7 @@ async def get_self_info(websocket: Server.ServerConnection) -> dict | None:
|
||||
except Exception as e:
|
||||
logger.error(f"获取自身信息失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
data = response.get("data")
|
||||
if data:
|
||||
await set_to_cache(cache_key, data)
|
||||
|
||||
@@ -260,7 +260,6 @@ class ManagementCommand(PlusCommand):
|
||||
except Exception as e:
|
||||
await self.send_text(f"❌ 强制重载过程中发生错误: {str(e)}")
|
||||
|
||||
|
||||
async def _add_dir(self, dir_path: str):
|
||||
"""添加插件目录"""
|
||||
await self.send_text(f"📁 正在添加插件目录: `{dir_path}`")
|
||||
@@ -501,13 +500,13 @@ class PluginManagementPlugin(BasePlugin):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# 注册权限节点
|
||||
|
||||
|
||||
async def on_plugin_loaded(self):
|
||||
await permission_api.register_permission_node(
|
||||
"plugin.management.admin",
|
||||
"插件管理:可以管理插件和组件的加载、卸载、启用、禁用等操作",
|
||||
"plugin_management",
|
||||
False,
|
||||
"plugin.management.admin",
|
||||
"插件管理:可以管理插件和组件的加载、卸载、启用、禁用等操作",
|
||||
"plugin_management",
|
||||
False,
|
||||
)
|
||||
|
||||
def get_plugin_components(self) -> List[Tuple[PlusCommandInfo, Type[PlusCommand]]]:
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
from typing import List, Tuple, Union, Type, Optional
|
||||
from typing import List, Tuple, Type
|
||||
|
||||
from src.common.logger import get_logger
|
||||
from src.config.official_configs import AffinityFlowConfig
|
||||
from src.plugin_system.base.base_plugin import BasePlugin
|
||||
from src.plugin_system import (
|
||||
BasePlugin,
|
||||
ConfigField,
|
||||
register_plugin,
|
||||
plugin_manage_api,
|
||||
component_manage_api,
|
||||
ComponentInfo,
|
||||
ComponentType,
|
||||
EventHandlerInfo,
|
||||
EventType,
|
||||
BaseEventHandler,
|
||||
)
|
||||
from .proacive_thinker_event import ProactiveThinkerEventHandler
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
@register_plugin
|
||||
class ProactiveThinkerPlugin(BasePlugin):
|
||||
"""一个主动思考的插件,但现在还只是个空壳子"""
|
||||
|
||||
plugin_name: str = "proactive_thinker"
|
||||
enable_plugin: bool = False
|
||||
dependencies: list[str] = []
|
||||
@@ -33,6 +29,7 @@ class ProactiveThinkerPlugin(BasePlugin):
|
||||
"config_version": ConfigField(type=str, default="1.1.0", description="配置文件版本"),
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -42,4 +39,3 @@ class ProactiveThinkerPlugin(BasePlugin):
|
||||
(ProactiveThinkerEventHandler.get_handler_info(), ProactiveThinkerEventHandler)
|
||||
]
|
||||
return components
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import asyncio
|
||||
import random
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import List, Union, Type, Optional
|
||||
from typing import List, Union
|
||||
|
||||
from maim_message import UserInfo
|
||||
|
||||
@@ -69,7 +69,7 @@ class ColdStartTask(AsyncTask):
|
||||
|
||||
# 创建 UserInfo 对象,这是创建聊天流的必要信息
|
||||
user_info = UserInfo(platform=platform, user_id=str(user_id), user_nickname=user_nickname)
|
||||
|
||||
|
||||
# 【关键步骤】主动创建聊天流。
|
||||
# 创建后,该用户就进入了机器人的“好友列表”,后续将由 ProactiveThinkingTask 接管
|
||||
stream = await self.chat_manager.get_or_create_stream(platform, user_info)
|
||||
@@ -175,10 +175,12 @@ class ProactiveThinkingTask(AsyncTask):
|
||||
# 2. 【核心逻辑】检查聊天冷却时间是否足够长
|
||||
time_since_last_active = time.time() - stream.last_active_time
|
||||
if time_since_last_active > next_interval:
|
||||
logger.info(f"【日常唤醒】聊天流 {stream.stream_id} 已冷却 {time_since_last_active:.2f} 秒,触发主动对话。")
|
||||
|
||||
logger.info(
|
||||
f"【日常唤醒】聊天流 {stream.stream_id} 已冷却 {time_since_last_active:.2f} 秒,触发主动对话。"
|
||||
)
|
||||
|
||||
await self.executor.execute(stream_id=stream.stream_id, start_mode="wake_up")
|
||||
|
||||
|
||||
# 【关键步骤】在触发后,立刻更新活跃时间并保存。
|
||||
# 这可以防止在同一个检查周期内,对同一个目标因为意外的延迟而发送多条消息。
|
||||
stream.update_active_time()
|
||||
|
||||
@@ -3,7 +3,16 @@ from typing import Optional, Dict, Any
|
||||
from datetime import datetime
|
||||
|
||||
from src.common.logger import get_logger
|
||||
from src.plugin_system.apis import chat_api, person_api, schedule_api, send_api, llm_api, message_api, generator_api, database_api
|
||||
from src.plugin_system.apis import (
|
||||
chat_api,
|
||||
person_api,
|
||||
schedule_api,
|
||||
send_api,
|
||||
llm_api,
|
||||
message_api,
|
||||
generator_api,
|
||||
database_api,
|
||||
)
|
||||
from src.config.config import global_config, model_config
|
||||
from src.person_info.person_info import get_person_info_manager
|
||||
|
||||
@@ -39,17 +48,16 @@ class ProactiveThinkerExecutor:
|
||||
# 2. 决策阶段
|
||||
decision_result = await self._make_decision(context, start_mode)
|
||||
|
||||
|
||||
if not decision_result or not decision_result.get("should_reply"):
|
||||
reason = decision_result.get("reason", "未提供") if decision_result else "决策过程返回None"
|
||||
logger.info(f"决策结果为:不回复。原因: {reason}")
|
||||
await database_api.store_action_info(
|
||||
chat_stream=self._get_stream_from_id(stream_id),
|
||||
action_name="proactive_decision",
|
||||
action_prompt_display=f"主动思考决定不回复,原因: {reason}",
|
||||
action_done = True,
|
||||
action_data=decision_result
|
||||
)
|
||||
chat_stream=self._get_stream_from_id(stream_id),
|
||||
action_name="proactive_decision",
|
||||
action_prompt_display=f"主动思考决定不回复,原因: {reason}",
|
||||
action_done=True,
|
||||
action_data=decision_result,
|
||||
)
|
||||
return
|
||||
|
||||
# 3. 规划与执行阶段
|
||||
@@ -59,15 +67,17 @@ class ProactiveThinkerExecutor:
|
||||
chat_stream=self._get_stream_from_id(stream_id),
|
||||
action_name="proactive_decision",
|
||||
action_prompt_display=f"主动思考决定回复,原因: {reason},话题:{topic}",
|
||||
action_done = True,
|
||||
action_data=decision_result
|
||||
action_done=True,
|
||||
action_data=decision_result,
|
||||
)
|
||||
logger.info(f"决策结果为:回复。话题: {topic}")
|
||||
|
||||
|
||||
plan_prompt = self._build_plan_prompt(context, start_mode, topic, reason)
|
||||
|
||||
is_success, response, _, _ = await llm_api.generate_with_model(prompt=plan_prompt, model_config=model_config.model_task_config.utils)
|
||||
|
||||
|
||||
is_success, response, _, _ = await llm_api.generate_with_model(
|
||||
prompt=plan_prompt, model_config=model_config.model_task_config.utils
|
||||
)
|
||||
|
||||
if is_success and response:
|
||||
stream = self._get_stream_from_id(stream_id)
|
||||
if stream:
|
||||
@@ -104,33 +114,41 @@ class ProactiveThinkerExecutor:
|
||||
if not user_info or not user_info.platform or not user_info.user_id:
|
||||
logger.warning(f"Stream {stream_id} 的 user_info 不完整")
|
||||
return None
|
||||
|
||||
|
||||
person_id = person_api.get_person_id(user_info.platform, int(user_info.user_id))
|
||||
person_info_manager = get_person_info_manager()
|
||||
|
||||
# 获取日程
|
||||
schedules = await schedule_api.ScheduleAPI.get_today_schedule()
|
||||
schedule_context = "\n".join([f"- {s['title']} ({s['start_time']}-{s['end_time']})" for s in schedules]) if schedules else "今天没有日程安排。"
|
||||
schedule_context = (
|
||||
"\n".join([f"- {s['title']} ({s['start_time']}-{s['end_time']})" for s in schedules])
|
||||
if schedules
|
||||
else "今天没有日程安排。"
|
||||
)
|
||||
|
||||
# 获取关系信息
|
||||
short_impression = await person_info_manager.get_value(person_id, "short_impression") or "无"
|
||||
impression = await person_info_manager.get_value(person_id, "impression") or "无"
|
||||
attitude = await person_info_manager.get_value(person_id, "attitude") or 50
|
||||
|
||||
|
||||
# 获取最近聊天记录
|
||||
recent_messages = await message_api.get_recent_messages(stream_id, limit=10)
|
||||
recent_chat_history = await message_api.build_readable_messages_to_str(recent_messages) if recent_messages else "无"
|
||||
|
||||
recent_chat_history = (
|
||||
await message_api.build_readable_messages_to_str(recent_messages) if recent_messages else "无"
|
||||
)
|
||||
|
||||
# 获取最近的动作历史
|
||||
action_history = await database_api.db_query(
|
||||
database_api.MODEL_MAPPING["ActionRecords"],
|
||||
filters={"chat_id": stream_id, "action_name": "proactive_decision"},
|
||||
limit=3,
|
||||
order_by=["-time"]
|
||||
order_by=["-time"],
|
||||
)
|
||||
action_history_context = "无"
|
||||
if isinstance(action_history, list):
|
||||
action_history_context = "\n".join([f"- {a['action_data']}" for a in action_history if isinstance(a, dict)]) or "无"
|
||||
action_history_context = (
|
||||
"\n".join([f"- {a['action_data']}" for a in action_history if isinstance(a, dict)]) or "无"
|
||||
)
|
||||
|
||||
return {
|
||||
"person_id": person_id,
|
||||
@@ -138,47 +156,43 @@ class ProactiveThinkerExecutor:
|
||||
"schedule_context": schedule_context,
|
||||
"recent_chat_history": recent_chat_history,
|
||||
"action_history_context": action_history_context,
|
||||
"relationship": {
|
||||
"short_impression": short_impression,
|
||||
"impression": impression,
|
||||
"attitude": attitude
|
||||
},
|
||||
"relationship": {"short_impression": short_impression, "impression": impression, "attitude": attitude},
|
||||
"persona": {
|
||||
"core": global_config.personality.personality_core,
|
||||
"side": global_config.personality.personality_side,
|
||||
"identity": global_config.personality.identity,
|
||||
},
|
||||
"current_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
"current_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
|
||||
async def _make_decision(self, context: Dict[str, Any], start_mode: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
决策模块:判断是否应该主动发起对话,以及聊什么话题
|
||||
"""
|
||||
persona = context['persona']
|
||||
user_info = context['user_info']
|
||||
relationship = context['relationship']
|
||||
persona = context["persona"]
|
||||
user_info = context["user_info"]
|
||||
relationship = context["relationship"]
|
||||
|
||||
prompt = f"""
|
||||
# 角色
|
||||
你的名字是{global_config.bot.nickname},你的人设如下:
|
||||
- 核心人设: {persona['core']}
|
||||
- 侧面人设: {persona['side']}
|
||||
- 身份: {persona['identity']}
|
||||
- 核心人设: {persona["core"]}
|
||||
- 侧面人设: {persona["side"]}
|
||||
- 身份: {persona["identity"]}
|
||||
|
||||
# 任务
|
||||
现在是 {context['current_time']},你需要根据当前的情境,决定是否要主动向用户 '{user_info.user_nickname}' 发起对话。
|
||||
现在是 {context["current_time"]},你需要根据当前的情境,决定是否要主动向用户 '{user_info.user_nickname}' 发起对话。
|
||||
|
||||
# 情境分析
|
||||
1. **启动模式**: {start_mode} ({'初次见面/很久未见' if start_mode == 'cold_start' else '日常唤醒'})
|
||||
1. **启动模式**: {start_mode} ({"初次见面/很久未见" if start_mode == "cold_start" else "日常唤醒"})
|
||||
2. **你的日程**:
|
||||
{context['schedule_context']}
|
||||
{context["schedule_context"]}
|
||||
3. **你和Ta的关系**:
|
||||
- 简短印象: {relationship['short_impression']}
|
||||
- 详细印象: {relationship['impression']}
|
||||
- 好感度: {relationship['attitude']}/100
|
||||
- 简短印象: {relationship["short_impression"]}
|
||||
- 详细印象: {relationship["impression"]}
|
||||
- 好感度: {relationship["attitude"]}/100
|
||||
4. **最近的聊天摘要**:
|
||||
{context['recent_chat_history']}
|
||||
{context["recent_chat_history"]}
|
||||
|
||||
# 决策指令
|
||||
请综合以上所有信息,做出决策。你的决策需要以JSON格式输出,包含以下字段:
|
||||
@@ -204,9 +218,11 @@ class ProactiveThinkerExecutor:
|
||||
|
||||
请输出你的决策:
|
||||
"""
|
||||
|
||||
is_success, response, _, _ = await llm_api.generate_with_model(prompt=prompt, model_config=model_config.model_task_config.utils)
|
||||
|
||||
|
||||
is_success, response, _, _ = await llm_api.generate_with_model(
|
||||
prompt=prompt, model_config=model_config.model_task_config.utils
|
||||
)
|
||||
|
||||
if not is_success:
|
||||
return {"should_reply": False, "reason": "决策模型生成失败"}
|
||||
|
||||
@@ -222,17 +238,17 @@ class ProactiveThinkerExecutor:
|
||||
"""
|
||||
根据启动模式和决策话题,构建最终的规划提示词
|
||||
"""
|
||||
persona = context['persona']
|
||||
user_info = context['user_info']
|
||||
relationship = context['relationship']
|
||||
persona = context["persona"]
|
||||
user_info = context["user_info"]
|
||||
relationship = context["relationship"]
|
||||
|
||||
if start_mode == "cold_start":
|
||||
prompt = f"""
|
||||
# 角色
|
||||
你的名字是{global_config.bot.nickname},你的人设如下:
|
||||
- 核心人设: {persona['core']}
|
||||
- 侧面人设: {persona['side']}
|
||||
- 身份: {persona['identity']}
|
||||
- 核心人设: {persona["core"]}
|
||||
- 侧面人设: {persona["side"]}
|
||||
- 身份: {persona["identity"]}
|
||||
|
||||
# 任务
|
||||
你需要主动向一个新朋友 '{user_info.user_nickname}' 发起对话。这是你们的第一次交流,或者很久没聊了。
|
||||
@@ -240,9 +256,9 @@ class ProactiveThinkerExecutor:
|
||||
# 决策上下文
|
||||
- **决策理由**: {reason}
|
||||
- **你和Ta的关系**:
|
||||
- 简短印象: {relationship['short_impression']}
|
||||
- 详细印象: {relationship['impression']}
|
||||
- 好感度: {relationship['attitude']}/100
|
||||
- 简短印象: {relationship["short_impression"]}
|
||||
- 详细印象: {relationship["impression"]}
|
||||
- 好感度: {relationship["attitude"]}/100
|
||||
|
||||
# 对话指引
|
||||
- 你的目标是“破冰”,让对话自然地开始。
|
||||
@@ -254,26 +270,26 @@ class ProactiveThinkerExecutor:
|
||||
prompt = f"""
|
||||
# 角色
|
||||
你的名字是{global_config.bot.nickname},你的人设如下:
|
||||
- 核心人设: {persona['core']}
|
||||
- 侧面人设: {persona['side']}
|
||||
- 身份: {persona['identity']}
|
||||
- 核心人设: {persona["core"]}
|
||||
- 侧面人设: {persona["side"]}
|
||||
- 身份: {persona["identity"]}
|
||||
|
||||
# 任务
|
||||
现在是 {context['current_time']},你需要主动向你的朋友 '{user_info.user_nickname}' 发起对话。
|
||||
现在是 {context["current_time"]},你需要主动向你的朋友 '{user_info.user_nickname}' 发起对话。
|
||||
|
||||
# 决策上下文
|
||||
- **决策理由**: {reason}
|
||||
|
||||
# 情境分析
|
||||
1. **你的日程**:
|
||||
{context['schedule_context']}
|
||||
{context["schedule_context"]}
|
||||
2. **你和Ta的关系**:
|
||||
- 详细印象: {relationship['impression']}
|
||||
- 好感度: {relationship['attitude']}/100
|
||||
- 详细印象: {relationship["impression"]}
|
||||
- 好感度: {relationship["attitude"]}/100
|
||||
3. **最近的聊天摘要**:
|
||||
{context['recent_chat_history']}
|
||||
{context["recent_chat_history"]}
|
||||
4. **你最近的相关动作**:
|
||||
{context['action_history_context']}
|
||||
{context["action_history_context"]}
|
||||
|
||||
# 对话指引
|
||||
- 你决定和Ta聊聊关于“{topic}”的话题。
|
||||
|
||||
@@ -16,8 +16,6 @@ from src.person_info.person_info import get_person_info_manager
|
||||
from dateutil.parser import parse as parse_datetime
|
||||
from src.manager.async_task_manager import AsyncTask, async_task_manager
|
||||
from src.plugin_system.apis import send_api, llm_api, generator_api
|
||||
from src.plugin_system.base.component_types import ComponentType
|
||||
from typing import Optional
|
||||
from src.chat.message_receive.chat_stream import ChatStream
|
||||
import asyncio
|
||||
import datetime
|
||||
|
||||
Reference in New Issue
Block a user