重构服务模块,优化消息处理逻辑,移除冗余功能,更新数据模型适配
This commit is contained in:
@@ -13,9 +13,9 @@ from src.config.config import global_config, model_config
|
|||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.chat.logger.plan_reply_logger import PlanReplyLogger
|
from src.chat.logger.plan_reply_logger import PlanReplyLogger
|
||||||
from src.common.data_models.info_data_model import ActionPlannerInfo
|
from src.common.data_models.info_data_model import ActionPlannerInfo
|
||||||
|
from src.common.utils.utils_action import ActionUtils
|
||||||
from src.prompt.prompt_manager import prompt_manager
|
from src.prompt.prompt_manager import prompt_manager
|
||||||
from src.services.message_service import (
|
from src.services.message_service import (
|
||||||
build_readable_actions,
|
|
||||||
build_readable_messages_with_id,
|
build_readable_messages_with_id,
|
||||||
get_actions_by_timestamp_with_chat,
|
get_actions_by_timestamp_with_chat,
|
||||||
get_messages_before_time_in_chat,
|
get_messages_before_time_in_chat,
|
||||||
@@ -28,7 +28,7 @@ from src.core.component_registry import component_registry
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from src.common.data_models.info_data_model import TargetPersonInfo
|
from src.common.data_models.info_data_model import TargetPersonInfo
|
||||||
from src.common.data_models.database_data_model import DatabaseMessages
|
from src.chat.message_receive.message import SessionMessage
|
||||||
|
|
||||||
logger = get_logger("planner")
|
logger = get_logger("planner")
|
||||||
|
|
||||||
@@ -51,8 +51,8 @@ class BrainPlanner:
|
|||||||
self.plan_log: List[Tuple[str, float, List[ActionPlannerInfo]]] = []
|
self.plan_log: List[Tuple[str, float, List[ActionPlannerInfo]]] = []
|
||||||
|
|
||||||
def find_message_by_id(
|
def find_message_by_id(
|
||||||
self, message_id: str, message_id_list: List[Tuple[str, "DatabaseMessages"]]
|
self, message_id: str, message_id_list: List[Tuple[str, "SessionMessage"]]
|
||||||
) -> Optional["DatabaseMessages"]:
|
) -> Optional["SessionMessage"]:
|
||||||
# sourcery skip: use-next
|
# sourcery skip: use-next
|
||||||
"""
|
"""
|
||||||
根据message_id从message_id_list中查找对应的原始消息
|
根据message_id从message_id_list中查找对应的原始消息
|
||||||
@@ -72,7 +72,7 @@ class BrainPlanner:
|
|||||||
def _parse_single_action(
|
def _parse_single_action(
|
||||||
self,
|
self,
|
||||||
action_json: dict,
|
action_json: dict,
|
||||||
message_id_list: List[Tuple[str, "DatabaseMessages"]],
|
message_id_list: List[Tuple[str, "SessionMessage"]],
|
||||||
current_available_actions: List[Tuple[str, ActionInfo]],
|
current_available_actions: List[Tuple[str, ActionInfo]],
|
||||||
) -> List[ActionPlannerInfo]:
|
) -> List[ActionPlannerInfo]:
|
||||||
"""解析单个action JSON并返回ActionPlannerInfo列表"""
|
"""解析单个action JSON并返回ActionPlannerInfo列表"""
|
||||||
@@ -169,7 +169,7 @@ class BrainPlanner:
|
|||||||
limit=int(global_config.chat.max_context_size * 0.6),
|
limit=int(global_config.chat.max_context_size * 0.6),
|
||||||
filter_intercept_message_level=1,
|
filter_intercept_message_level=1,
|
||||||
)
|
)
|
||||||
message_id_list: list[Tuple[str, "DatabaseMessages"]] = []
|
message_id_list: list[Tuple[str, "SessionMessage"]] = []
|
||||||
chat_content_block, message_id_list = build_readable_messages_with_id(
|
chat_content_block, message_id_list = build_readable_messages_with_id(
|
||||||
messages=message_list_before_now,
|
messages=message_list_before_now,
|
||||||
timestamp_mode="normal_no_YMD",
|
timestamp_mode="normal_no_YMD",
|
||||||
@@ -251,11 +251,11 @@ class BrainPlanner:
|
|||||||
self,
|
self,
|
||||||
chat_target_info: Optional["TargetPersonInfo"],
|
chat_target_info: Optional["TargetPersonInfo"],
|
||||||
current_available_actions: Dict[str, ActionInfo],
|
current_available_actions: Dict[str, ActionInfo],
|
||||||
message_id_list: List[Tuple[str, "DatabaseMessages"]],
|
message_id_list: List[Tuple[str, "SessionMessage"]],
|
||||||
chat_content_block: str = "",
|
chat_content_block: str = "",
|
||||||
interest: str = "",
|
interest: str = "",
|
||||||
prompt_key: str = "brain_planner",
|
prompt_key: str = "brain_planner",
|
||||||
) -> tuple[str, List[Tuple[str, "DatabaseMessages"]]]:
|
) -> tuple[str, List[Tuple[str, "SessionMessage"]]]:
|
||||||
"""构建 Planner LLM 的提示词 (获取模板并填充数据)"""
|
"""构建 Planner LLM 的提示词 (获取模板并填充数据)"""
|
||||||
try:
|
try:
|
||||||
# 获取最近执行过的动作
|
# 获取最近执行过的动作
|
||||||
@@ -265,7 +265,7 @@ class BrainPlanner:
|
|||||||
timestamp_end=time.time(),
|
timestamp_end=time.time(),
|
||||||
limit=6,
|
limit=6,
|
||||||
)
|
)
|
||||||
actions_before_now_block = build_readable_actions(actions=actions_before_now)
|
actions_before_now_block = ActionUtils.build_readable_action_records(actions_before_now)
|
||||||
if actions_before_now_block:
|
if actions_before_now_block:
|
||||||
actions_before_now_block = f"你刚刚选择并执行过的action是:\n{actions_before_now_block}"
|
actions_before_now_block = f"你刚刚选择并执行过的action是:\n{actions_before_now_block}"
|
||||||
else:
|
else:
|
||||||
@@ -395,7 +395,7 @@ class BrainPlanner:
|
|||||||
async def _execute_main_planner(
|
async def _execute_main_planner(
|
||||||
self,
|
self,
|
||||||
prompt: str,
|
prompt: str,
|
||||||
message_id_list: List[Tuple[str, "DatabaseMessages"]],
|
message_id_list: List[Tuple[str, "SessionMessage"]],
|
||||||
filtered_actions: Dict[str, ActionInfo],
|
filtered_actions: Dict[str, ActionInfo],
|
||||||
available_actions: Dict[str, ActionInfo],
|
available_actions: Dict[str, ActionInfo],
|
||||||
loop_start_time: float,
|
loop_start_time: float,
|
||||||
|
|||||||
@@ -1,10 +1,26 @@
|
|||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from src.config.config import global_config
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
|
|
||||||
logger = get_logger("plugin_runtime.integration")
|
logger = get_logger("plugin_runtime.integration")
|
||||||
|
|
||||||
|
|
||||||
|
def _get_nested_config_value(source: Any, key: str, default: Any = None) -> Any:
|
||||||
|
current = source
|
||||||
|
try:
|
||||||
|
for part in key.split("."):
|
||||||
|
if isinstance(current, dict) and part in current:
|
||||||
|
current = current[part]
|
||||||
|
elif hasattr(current, part):
|
||||||
|
current = getattr(current, part)
|
||||||
|
else:
|
||||||
|
raise KeyError(part)
|
||||||
|
return current
|
||||||
|
except Exception:
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
class RuntimeCoreCapabilityMixin:
|
class RuntimeCoreCapabilityMixin:
|
||||||
async def _cap_send_text(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_send_text(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import send_service as send_api
|
from src.services import send_service as send_api
|
||||||
@@ -74,8 +90,9 @@ class RuntimeCoreCapabilityMixin:
|
|||||||
return {"success": False, "error": "缺少必要参数 command 或 stream_id"}
|
return {"success": False, "error": "缺少必要参数 command 或 stream_id"}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = await send_api.command_to_stream(
|
result = await send_api.custom_to_stream(
|
||||||
command=command,
|
message_type="command",
|
||||||
|
content=command,
|
||||||
stream_id=stream_id,
|
stream_id=stream_id,
|
||||||
storage_message=args.get("storage_message", True),
|
storage_message=args.get("storage_message", True),
|
||||||
display_message=args.get("display_message", ""),
|
display_message=args.get("display_message", ""),
|
||||||
@@ -110,36 +127,6 @@ class RuntimeCoreCapabilityMixin:
|
|||||||
logger.error(f"[cap.send.custom] 执行失败: {e}", exc_info=True)
|
logger.error(f"[cap.send.custom] 执行失败: {e}", exc_info=True)
|
||||||
return {"success": False, "error": str(e)}
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
async def _cap_send_forward(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
|
||||||
from src.services import send_service as send_api
|
|
||||||
|
|
||||||
messages = args.get("messages", [])
|
|
||||||
stream_id: str = args.get("stream_id", "")
|
|
||||||
if not messages or not stream_id:
|
|
||||||
return {"success": False, "error": "缺少必要参数 messages 或 stream_id"}
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = await send_api.forward_to_stream(messages=messages, stream_id=stream_id)
|
|
||||||
return {"success": result}
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"[cap.send.forward] 执行失败: {e}", exc_info=True)
|
|
||||||
return {"success": False, "error": str(e)}
|
|
||||||
|
|
||||||
async def _cap_send_hybrid(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
|
||||||
from src.services import send_service as send_api
|
|
||||||
|
|
||||||
segments = args.get("segments", [])
|
|
||||||
stream_id: str = args.get("stream_id", "")
|
|
||||||
if not segments or not stream_id:
|
|
||||||
return {"success": False, "error": "缺少必要参数 segments 或 stream_id"}
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = await send_api.hybrid_to_stream(segments=segments, stream_id=stream_id)
|
|
||||||
return {"success": result}
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"[cap.send.hybrid] 执行失败: {e}", exc_info=True)
|
|
||||||
return {"success": False, "error": str(e)}
|
|
||||||
|
|
||||||
async def _cap_llm_generate(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_llm_generate(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import llm_service as llm_api
|
from src.services import llm_service as llm_api
|
||||||
|
|
||||||
@@ -235,15 +222,13 @@ class RuntimeCoreCapabilityMixin:
|
|||||||
return {"success": False, "error": str(e)}
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
async def _cap_config_get(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_config_get(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import config_service as config_api
|
|
||||||
|
|
||||||
key: str = args.get("key", "")
|
key: str = args.get("key", "")
|
||||||
default = args.get("default")
|
default = args.get("default")
|
||||||
if not key:
|
if not key:
|
||||||
return {"success": False, "value": None, "error": "缺少必要参数 key"}
|
return {"success": False, "value": None, "error": "缺少必要参数 key"}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
value = config_api.get_global_config(key, default)
|
value = _get_nested_config_value(global_config, key, default)
|
||||||
return {"success": True, "value": value}
|
return {"success": True, "value": value}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {"success": False, "value": None, "error": str(e)}
|
return {"success": False, "value": None, "error": str(e)}
|
||||||
@@ -261,9 +246,7 @@ class RuntimeCoreCapabilityMixin:
|
|||||||
return {"success": False, "value": default, "error": f"未找到插件 {plugin_name} 的配置"}
|
return {"success": False, "value": default, "error": f"未找到插件 {plugin_name} 的配置"}
|
||||||
|
|
||||||
if key:
|
if key:
|
||||||
from src.services import config_service as config_api
|
value = _get_nested_config_value(config, key, default)
|
||||||
|
|
||||||
value = config_api.get_plugin_config(config, key, default)
|
|
||||||
return {"success": True, "value": value}
|
return {"success": True, "value": value}
|
||||||
|
|
||||||
return {"success": True, "value": config}
|
return {"success": True, "value": config}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class RuntimeDataCapabilityMixin:
|
|||||||
return EMOJI_DIR / f"emoji_cap_{int(time.time() * 1000000)}.png"
|
return EMOJI_DIR / f"emoji_cap_{int(time.time() * 1000000)}.png"
|
||||||
|
|
||||||
async def _cap_database_query(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_database_query(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import database_service as database_api
|
from src.services import database_service
|
||||||
|
|
||||||
model_name: str = args.get("model_name", "")
|
model_name: str = args.get("model_name", "")
|
||||||
if not model_name:
|
if not model_name:
|
||||||
@@ -49,7 +49,7 @@ class RuntimeDataCapabilityMixin:
|
|||||||
|
|
||||||
query_type = args.get("query_type", "get")
|
query_type = args.get("query_type", "get")
|
||||||
if query_type == "get":
|
if query_type == "get":
|
||||||
result = await database_api.db_get(
|
result = await database_service.db_get(
|
||||||
model_class=model_class,
|
model_class=model_class,
|
||||||
filters=args.get("filters"),
|
filters=args.get("filters"),
|
||||||
limit=args.get("limit"),
|
limit=args.get("limit"),
|
||||||
@@ -59,19 +59,19 @@ class RuntimeDataCapabilityMixin:
|
|||||||
elif query_type == "create":
|
elif query_type == "create":
|
||||||
if not (data := args.get("data")):
|
if not (data := args.get("data")):
|
||||||
return {"success": False, "error": "create 需要 data"}
|
return {"success": False, "error": "create 需要 data"}
|
||||||
result = await database_api.db_save(model_class=model_class, data=data)
|
result = await database_service.db_save(model_class=model_class, data=data)
|
||||||
elif query_type == "update":
|
elif query_type == "update":
|
||||||
if not (data := args.get("data")):
|
if not (data := args.get("data")):
|
||||||
return {"success": False, "error": "update 需要 data"}
|
return {"success": False, "error": "update 需要 data"}
|
||||||
result = await database_api.db_update(
|
result = await database_service.db_update(
|
||||||
model_class=model_class,
|
model_class=model_class,
|
||||||
data=data,
|
data=data,
|
||||||
filters=args.get("filters"),
|
filters=args.get("filters"),
|
||||||
)
|
)
|
||||||
elif query_type == "delete":
|
elif query_type == "delete":
|
||||||
result = await database_api.db_delete(model_class=model_class, filters=args.get("filters"))
|
result = await database_service.db_delete(model_class=model_class, filters=args.get("filters"))
|
||||||
elif query_type == "count":
|
elif query_type == "count":
|
||||||
result = await database_api.db_count(model_class=model_class, filters=args.get("filters"))
|
result = await database_service.db_count(model_class=model_class, filters=args.get("filters"))
|
||||||
else:
|
else:
|
||||||
return {"success": False, "error": f"不支持的 query_type: {query_type}"}
|
return {"success": False, "error": f"不支持的 query_type: {query_type}"}
|
||||||
return {"success": True, "result": result}
|
return {"success": True, "result": result}
|
||||||
@@ -80,7 +80,7 @@ class RuntimeDataCapabilityMixin:
|
|||||||
return {"success": False, "error": str(e)}
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
async def _cap_database_save(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_database_save(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import database_service as database_api
|
from src.services import database_service
|
||||||
|
|
||||||
model_name: str = args.get("model_name", "")
|
model_name: str = args.get("model_name", "")
|
||||||
data: Optional[Dict[str, Any]] = args.get("data")
|
data: Optional[Dict[str, Any]] = args.get("data")
|
||||||
@@ -94,7 +94,7 @@ class RuntimeDataCapabilityMixin:
|
|||||||
if model_class is None:
|
if model_class is None:
|
||||||
return {"success": False, "error": f"未找到数据模型: {model_name}"}
|
return {"success": False, "error": f"未找到数据模型: {model_name}"}
|
||||||
|
|
||||||
result = await database_api.db_save(
|
result = await database_service.db_save(
|
||||||
model_class=model_class,
|
model_class=model_class,
|
||||||
data=data,
|
data=data,
|
||||||
key_field=args.get("key_field"),
|
key_field=args.get("key_field"),
|
||||||
@@ -106,7 +106,7 @@ class RuntimeDataCapabilityMixin:
|
|||||||
return {"success": False, "error": str(e)}
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
async def _cap_database_get(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_database_get(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import database_service as database_api
|
from src.services import database_service
|
||||||
|
|
||||||
model_name: str = args.get("model_name", "")
|
model_name: str = args.get("model_name", "")
|
||||||
if not model_name:
|
if not model_name:
|
||||||
@@ -119,7 +119,7 @@ class RuntimeDataCapabilityMixin:
|
|||||||
if model_class is None:
|
if model_class is None:
|
||||||
return {"success": False, "error": f"未找到数据模型: {model_name}"}
|
return {"success": False, "error": f"未找到数据模型: {model_name}"}
|
||||||
|
|
||||||
result = await database_api.db_get(
|
result = await database_service.db_get(
|
||||||
model_class=model_class,
|
model_class=model_class,
|
||||||
filters=args.get("filters"),
|
filters=args.get("filters"),
|
||||||
limit=args.get("limit"),
|
limit=args.get("limit"),
|
||||||
@@ -132,7 +132,7 @@ class RuntimeDataCapabilityMixin:
|
|||||||
return {"success": False, "error": str(e)}
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
async def _cap_database_delete(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_database_delete(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import database_service as database_api
|
from src.services import database_service
|
||||||
|
|
||||||
model_name: str = args.get("model_name", "")
|
model_name: str = args.get("model_name", "")
|
||||||
filters = args.get("filters", {})
|
filters = args.get("filters", {})
|
||||||
@@ -148,14 +148,14 @@ class RuntimeDataCapabilityMixin:
|
|||||||
if model_class is None:
|
if model_class is None:
|
||||||
return {"success": False, "error": f"未找到数据模型: {model_name}"}
|
return {"success": False, "error": f"未找到数据模型: {model_name}"}
|
||||||
|
|
||||||
result = await database_api.db_delete(model_class=model_class, filters=filters)
|
result = await database_service.db_delete(model_class=model_class, filters=filters)
|
||||||
return {"success": True, "result": result}
|
return {"success": True, "result": result}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[cap.database.delete] 执行失败: {e}", exc_info=True)
|
logger.error(f"[cap.database.delete] 执行失败: {e}", exc_info=True)
|
||||||
return {"success": False, "error": str(e)}
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
async def _cap_database_count(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_database_count(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import database_service as database_api
|
from src.services import database_service
|
||||||
|
|
||||||
model_name: str = args.get("model_name", "")
|
model_name: str = args.get("model_name", "")
|
||||||
if not model_name:
|
if not model_name:
|
||||||
@@ -168,7 +168,7 @@ class RuntimeDataCapabilityMixin:
|
|||||||
if model_class is None:
|
if model_class is None:
|
||||||
return {"success": False, "error": f"未找到数据模型: {model_name}"}
|
return {"success": False, "error": f"未找到数据模型: {model_name}"}
|
||||||
|
|
||||||
result = await database_api.db_count(model_class=model_class, filters=args.get("filters"))
|
result = await database_service.db_count(model_class=model_class, filters=args.get("filters"))
|
||||||
return {"success": True, "count": result}
|
return {"success": True, "count": result}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[cap.database.count] 执行失败: {e}", exc_info=True)
|
logger.error(f"[cap.database.count] 执行失败: {e}", exc_info=True)
|
||||||
@@ -272,10 +272,10 @@ class RuntimeDataCapabilityMixin:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
async def _cap_message_get_by_time(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_message_get_by_time(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import message_service as message_api
|
from src.services import message_service
|
||||||
|
|
||||||
try:
|
try:
|
||||||
messages = message_api.get_messages_by_time(
|
messages = message_service.get_messages_by_time(
|
||||||
start_time=float(args.get("start_time", 0.0)),
|
start_time=float(args.get("start_time", 0.0)),
|
||||||
end_time=float(args.get("end_time", 0.0)),
|
end_time=float(args.get("end_time", 0.0)),
|
||||||
limit=args.get("limit", 0),
|
limit=args.get("limit", 0),
|
||||||
@@ -288,14 +288,14 @@ class RuntimeDataCapabilityMixin:
|
|||||||
return {"success": False, "error": str(e)}
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
async def _cap_message_get_by_time_in_chat(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_message_get_by_time_in_chat(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import message_service as message_api
|
from src.services import message_service
|
||||||
|
|
||||||
chat_id: str = args.get("chat_id", "")
|
chat_id: str = args.get("chat_id", "")
|
||||||
if not chat_id:
|
if not chat_id:
|
||||||
return {"success": False, "error": "缺少必要参数 chat_id"}
|
return {"success": False, "error": "缺少必要参数 chat_id"}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
messages = message_api.get_messages_by_time_in_chat(
|
messages = message_service.get_messages_by_time_in_chat(
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
start_time=float(args.get("start_time", 0.0)),
|
start_time=float(args.get("start_time", 0.0)),
|
||||||
end_time=float(args.get("end_time", 0.0)),
|
end_time=float(args.get("end_time", 0.0)),
|
||||||
@@ -310,16 +310,21 @@ class RuntimeDataCapabilityMixin:
|
|||||||
return {"success": False, "error": str(e)}
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
async def _cap_message_get_recent(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_message_get_recent(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import message_service as message_api
|
from src.services import message_service
|
||||||
|
|
||||||
chat_id: str = args.get("chat_id", "")
|
chat_id: str = args.get("chat_id", "")
|
||||||
if not chat_id:
|
if not chat_id:
|
||||||
return {"success": False, "error": "缺少必要参数 chat_id"}
|
return {"success": False, "error": "缺少必要参数 chat_id"}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
messages = message_api.get_recent_messages(
|
hours = float(args.get("hours", 24.0))
|
||||||
|
if hours < 0:
|
||||||
|
return {"success": False, "error": "hours 不能是负数"}
|
||||||
|
current_time = time.time()
|
||||||
|
messages = message_service.get_messages_by_time_in_chat(
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
hours=float(args.get("hours", 24.0)),
|
start_time=current_time - hours * 3600,
|
||||||
|
end_time=current_time,
|
||||||
limit=args.get("limit", 100),
|
limit=args.get("limit", 100),
|
||||||
limit_mode=args.get("limit_mode", "latest"),
|
limit_mode=args.get("limit_mode", "latest"),
|
||||||
filter_mai=args.get("filter_mai", False),
|
filter_mai=args.get("filter_mai", False),
|
||||||
@@ -330,7 +335,7 @@ class RuntimeDataCapabilityMixin:
|
|||||||
return {"success": False, "error": str(e)}
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
async def _cap_message_count_new(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_message_count_new(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import message_service as message_api
|
from src.services import message_service
|
||||||
|
|
||||||
chat_id: str = args.get("chat_id", "")
|
chat_id: str = args.get("chat_id", "")
|
||||||
if not chat_id:
|
if not chat_id:
|
||||||
@@ -339,7 +344,7 @@ class RuntimeDataCapabilityMixin:
|
|||||||
try:
|
try:
|
||||||
since = args.get("since")
|
since = args.get("since")
|
||||||
start_time = float(since) if since is not None else float(args.get("start_time", 0.0))
|
start_time = float(since) if since is not None else float(args.get("start_time", 0.0))
|
||||||
count = message_api.count_new_messages(
|
count = message_service.count_new_messages(
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
start_time=start_time,
|
start_time=start_time,
|
||||||
end_time=args.get("end_time"),
|
end_time=args.get("end_time"),
|
||||||
@@ -350,21 +355,21 @@ class RuntimeDataCapabilityMixin:
|
|||||||
return {"success": False, "error": str(e)}
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
async def _cap_message_build_readable(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
async def _cap_message_build_readable(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
|
||||||
from src.services import message_service as message_api
|
from src.services import message_service
|
||||||
|
|
||||||
try:
|
try:
|
||||||
messages = args.get("messages")
|
messages = args.get("messages")
|
||||||
if messages is None:
|
if messages is None:
|
||||||
if not (chat_id := args.get("chat_id", "")):
|
if not (chat_id := args.get("chat_id", "")):
|
||||||
return {"success": False, "error": "缺少必要参数: messages 或 chat_id"}
|
return {"success": False, "error": "缺少必要参数: messages 或 chat_id"}
|
||||||
messages = message_api.get_messages_by_time_in_chat(
|
messages = message_service.get_messages_by_time_in_chat(
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
start_time=float(args.get("start_time", 0.0)),
|
start_time=float(args.get("start_time", 0.0)),
|
||||||
end_time=float(args.get("end_time", 0.0)),
|
end_time=float(args.get("end_time", 0.0)),
|
||||||
limit=args.get("limit", 0),
|
limit=args.get("limit", 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
readable = message_api.build_readable_messages(
|
readable = message_service.build_readable_messages(
|
||||||
messages=messages,
|
messages=messages,
|
||||||
replace_bot_name=args.get("replace_bot_name", True),
|
replace_bot_name=args.get("replace_bot_name", True),
|
||||||
timestamp_mode=args.get("timestamp_mode", "relative"),
|
timestamp_mode=args.get("timestamp_mode", "relative"),
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ def register_capability_impls(manager: "PluginRuntimeManager", supervisor: Plugi
|
|||||||
cap_service.register_capability("send.image", manager._cap_send_image)
|
cap_service.register_capability("send.image", manager._cap_send_image)
|
||||||
cap_service.register_capability("send.command", manager._cap_send_command)
|
cap_service.register_capability("send.command", manager._cap_send_command)
|
||||||
cap_service.register_capability("send.custom", manager._cap_send_custom)
|
cap_service.register_capability("send.custom", manager._cap_send_custom)
|
||||||
cap_service.register_capability("send.forward", manager._cap_send_forward)
|
|
||||||
cap_service.register_capability("send.hybrid", manager._cap_send_hybrid)
|
|
||||||
|
|
||||||
cap_service.register_capability("llm.generate", manager._cap_llm_generate)
|
cap_service.register_capability("llm.generate", manager._cap_llm_generate)
|
||||||
cap_service.register_capability("llm.generate_with_tools", manager._cap_llm_generate_with_tools)
|
cap_service.register_capability("llm.generate_with_tools", manager._cap_llm_generate_with_tools)
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
"""配置服务模块
|
|
||||||
|
|
||||||
提供配置读取的核心功能。
|
|
||||||
"""
|
|
||||||
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
|
||||||
from src.config.config import global_config
|
|
||||||
|
|
||||||
logger = get_logger("config_service")
|
|
||||||
|
|
||||||
|
|
||||||
def get_global_config(key: str, default: Any = None) -> Any:
|
|
||||||
"""
|
|
||||||
安全地从全局配置中获取一个值。
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key: 命名空间式配置键名,使用嵌套访问,如 "section.subsection.key",大小写敏感
|
|
||||||
default: 如果配置不存在时返回的默认值
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Any: 配置值或默认值
|
|
||||||
"""
|
|
||||||
keys = key.split(".")
|
|
||||||
current = global_config
|
|
||||||
|
|
||||||
try:
|
|
||||||
for k in keys:
|
|
||||||
if hasattr(current, k):
|
|
||||||
current = getattr(current, k)
|
|
||||||
else:
|
|
||||||
raise KeyError(f"配置中不存在子空间或键 '{k}'")
|
|
||||||
return current
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"[ConfigService] 获取全局配置 {key} 失败: {e}")
|
|
||||||
return default
|
|
||||||
|
|
||||||
|
|
||||||
def get_plugin_config(plugin_config: dict, key: str, default: Any = None) -> Any:
|
|
||||||
"""
|
|
||||||
从插件配置中获取值,支持嵌套键访问
|
|
||||||
|
|
||||||
Args:
|
|
||||||
plugin_config: 插件配置字典
|
|
||||||
key: 配置键名,支持嵌套访问如 "section.subsection.key",大小写敏感
|
|
||||||
default: 如果配置不存在时返回的默认值
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Any: 配置值或默认值
|
|
||||||
"""
|
|
||||||
keys = key.split(".")
|
|
||||||
current = plugin_config
|
|
||||||
|
|
||||||
try:
|
|
||||||
for k in keys:
|
|
||||||
if isinstance(current, dict) and k in current:
|
|
||||||
current = current[k]
|
|
||||||
elif hasattr(current, k):
|
|
||||||
current = getattr(current, k)
|
|
||||||
else:
|
|
||||||
raise KeyError(f"配置中不存在子空间或键 '{k}'")
|
|
||||||
return current
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"[ConfigService] 获取插件配置 {key} 失败: {e}")
|
|
||||||
return default
|
|
||||||
@@ -154,22 +154,6 @@ def get_messages_before_time_in_chat(
|
|||||||
return _normalize_messages(messages)
|
return _normalize_messages(messages)
|
||||||
|
|
||||||
|
|
||||||
def get_recent_messages(
|
|
||||||
chat_id: str, hours: float = 24.0, limit: int = 100, limit_mode: str = "latest", filter_mai: bool = False
|
|
||||||
) -> List[SessionMessage]:
|
|
||||||
if not isinstance(hours, (int, float)) or hours < 0:
|
|
||||||
raise ValueError("hours 不能是负数")
|
|
||||||
if not isinstance(limit, int) or limit < 0:
|
|
||||||
raise ValueError("limit 必须是非负整数")
|
|
||||||
if not chat_id:
|
|
||||||
raise ValueError("chat_id 不能为空")
|
|
||||||
if not isinstance(chat_id, str):
|
|
||||||
raise ValueError("chat_id 必须是字符串类型")
|
|
||||||
now = time.time()
|
|
||||||
start_time = now - hours * 3600
|
|
||||||
return get_messages_by_time_in_chat(chat_id, start_time, now, limit, limit_mode, filter_mai)
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 消息计数函数
|
# 消息计数函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -221,14 +205,14 @@ def build_readable_messages(
|
|||||||
line = f"{line[:200]}......(内容太长了)"
|
line = f"{line[:200]}......(内容太长了)"
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
if show_actions and normalized_messages:
|
if show_actions and normalized_messages:
|
||||||
action_lines = build_readable_actions(
|
if action_lines := ActionUtils.build_readable_action_records(
|
||||||
get_actions_by_timestamp_with_chat(
|
get_actions_by_timestamp_with_chat(
|
||||||
normalized_messages[0].session_id,
|
normalized_messages[0].session_id,
|
||||||
normalized_messages[0].timestamp.timestamp(),
|
normalized_messages[0].timestamp.timestamp(),
|
||||||
normalized_messages[-1].timestamp.timestamp(),
|
normalized_messages[-1].timestamp.timestamp(),
|
||||||
)
|
),
|
||||||
)
|
"relative",
|
||||||
if action_lines:
|
):
|
||||||
lines.append(action_lines)
|
lines.append(action_lines)
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
@@ -260,19 +244,24 @@ def build_readable_messages_with_id(
|
|||||||
lines.append(line)
|
lines.append(line)
|
||||||
message_id_list.append((message.message_id, message))
|
message_id_list.append((message.message_id, message))
|
||||||
if show_actions and normalized_messages:
|
if show_actions and normalized_messages:
|
||||||
action_lines = build_readable_actions(
|
if action_lines := ActionUtils.build_readable_action_records(
|
||||||
get_actions_by_timestamp_with_chat(
|
get_actions_by_timestamp_with_chat(
|
||||||
normalized_messages[0].session_id,
|
normalized_messages[0].session_id,
|
||||||
normalized_messages[0].timestamp.timestamp(),
|
normalized_messages[0].timestamp.timestamp(),
|
||||||
normalized_messages[-1].timestamp.timestamp(),
|
normalized_messages[-1].timestamp.timestamp(),
|
||||||
)
|
),
|
||||||
)
|
"relative",
|
||||||
if action_lines:
|
):
|
||||||
lines.append(action_lines)
|
lines.append(action_lines)
|
||||||
return "\n".join(lines), message_id_list
|
return "\n".join(lines), message_id_list
|
||||||
|
|
||||||
|
|
||||||
def get_actions_by_timestamp_with_chat(chat_id: str, timestamp_start: float, timestamp_end: float) -> List[MaiActionRecord]:
|
def get_actions_by_timestamp_with_chat(
|
||||||
|
chat_id: str,
|
||||||
|
timestamp_start: float,
|
||||||
|
timestamp_end: float,
|
||||||
|
limit: Optional[int] = None,
|
||||||
|
) -> List[MaiActionRecord]:
|
||||||
with get_db_session() as session:
|
with get_db_session() as session:
|
||||||
statement = (
|
statement = (
|
||||||
select(ActionRecord)
|
select(ActionRecord)
|
||||||
@@ -281,13 +270,11 @@ def get_actions_by_timestamp_with_chat(chat_id: str, timestamp_start: float, tim
|
|||||||
.where(col(ActionRecord.timestamp) <= datetime.fromtimestamp(timestamp_end))
|
.where(col(ActionRecord.timestamp) <= datetime.fromtimestamp(timestamp_end))
|
||||||
.order_by(col(ActionRecord.timestamp))
|
.order_by(col(ActionRecord.timestamp))
|
||||||
)
|
)
|
||||||
|
if limit is not None:
|
||||||
|
statement = statement.limit(limit)
|
||||||
return [MaiActionRecord.from_db_instance(item) for item in session.exec(statement).all()]
|
return [MaiActionRecord.from_db_instance(item) for item in session.exec(statement).all()]
|
||||||
|
|
||||||
|
|
||||||
def build_readable_actions(actions: List[MaiActionRecord], timestamp_mode: str = "relative") -> str:
|
|
||||||
return ActionUtils.build_readable_action_records(actions, timestamp_mode)
|
|
||||||
|
|
||||||
|
|
||||||
def replace_user_references(text: str, platform: str, replace_bot_name: bool = False) -> str:
|
def replace_user_references(text: str, platform: str, replace_bot_name: bool = False) -> str:
|
||||||
del platform
|
del platform
|
||||||
if not text:
|
if not text:
|
||||||
@@ -312,9 +299,4 @@ def translate_pid_to_description(pid: str) -> str:
|
|||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
image = session.exec(statement).first() if statement is not None else None
|
image = session.exec(statement).first() if statement is not None else None
|
||||||
description = ""
|
return image.description.strip() if image and image.description and image.description.strip() else "[图片]"
|
||||||
if image and image.description and image.description.strip():
|
|
||||||
description = image.description.strip()
|
|
||||||
else:
|
|
||||||
description = "[图片]"
|
|
||||||
return description
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
提供发送各种类型消息的核心功能。
|
提供发送各种类型消息的核心功能。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import traceback
|
|
||||||
import time
|
import time
|
||||||
from typing import Optional, Union, Dict, List, TYPE_CHECKING
|
import traceback
|
||||||
|
from typing import Dict, List, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
from maim_message import BaseMessageInfo, GroupInfo as MaimGroupInfo, MessageBase, Seg, UserInfo as MaimUserInfo
|
from maim_message import BaseMessageInfo, GroupInfo as MaimGroupInfo, MessageBase, Seg, UserInfo as MaimUserInfo
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ async def _send_to_target(
|
|||||||
|
|
||||||
anchor_message: Optional[MaiMessage] = None
|
anchor_message: Optional[MaiMessage] = None
|
||||||
if reply_message:
|
if reply_message:
|
||||||
anchor_message = db_message_to_mai_message(reply_message)
|
anchor_message = reply_message.deepcopy()
|
||||||
if anchor_message:
|
if anchor_message:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"[SendService] 找到匹配的回复消息,发送者: {anchor_message.message_info.user_info.user_id}"
|
f"[SendService] 找到匹配的回复消息,发送者: {anchor_message.message_info.user_info.user_id}"
|
||||||
@@ -127,11 +127,6 @@ async def _send_to_target(
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def db_message_to_mai_message(message_obj: "SessionMessage") -> Optional[MaiMessage]:
|
|
||||||
"""将数据库消息重建为 MaiMessage 对象,用于回复引用。"""
|
|
||||||
return message_obj.deepcopy()
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 公共函数 - 预定义类型的发送函数
|
# 公共函数 - 预定义类型的发送函数
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -197,23 +192,6 @@ async def image_to_stream(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def command_to_stream(
|
|
||||||
command: Union[str, dict],
|
|
||||||
stream_id: str,
|
|
||||||
storage_message: bool = True,
|
|
||||||
display_message: str = "",
|
|
||||||
) -> bool:
|
|
||||||
"""向指定流发送命令"""
|
|
||||||
return await _send_to_target(
|
|
||||||
message_segment=Seg(type="command", data=command), # type: ignore
|
|
||||||
stream_id=stream_id,
|
|
||||||
display_message=display_message,
|
|
||||||
typing=False,
|
|
||||||
storage_message=storage_message,
|
|
||||||
set_reply=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def custom_to_stream(
|
async def custom_to_stream(
|
||||||
message_type: str,
|
message_type: str,
|
||||||
content: str | Dict,
|
content: str | Dict,
|
||||||
|
|||||||
Reference in New Issue
Block a user