refactor: 统一类型注解风格并优化代码结构

- 将裸 except 改为显式 Exception 捕获
- 用列表推导式替换冗余 for 循环
- 为类属性添加 ClassVar 注解
- 统一 Union/Optional 写法为 |
- 移除未使用的导入
- 修复 SQLAlchemy 空值比较语法
- 优化字符串拼接与字典更新逻辑
- 补充缺失的 noqa 注释与异常链

BREAKING CHANGE: 所有插件基类的类级字段现要求显式 ClassVar 注解,自定义插件需同步更新
This commit is contained in:
明天好像没什么
2025-10-31 22:42:39 +08:00
parent 5080cfccfc
commit 0e129d385e
105 changed files with 592 additions and 561 deletions

View File

@@ -7,7 +7,7 @@ import asyncio
import time
import traceback
from datetime import datetime
from typing import Any
from typing import Any, ClassVar
from src.chat.express.expression_learner import expression_learner_manager
from src.chat.planner_actions.action_manager import ChatterActionManager
@@ -29,7 +29,7 @@ class AffinityChatter(BaseChatter):
chatter_name: str = "AffinityChatter"
chatter_description: str = "基于亲和力模型的智能聊天处理器,支持多种聊天类型"
chat_types: list[ChatType] = [ChatType.ALL] # 支持所有聊天类型
chat_types: ClassVar[list[ChatType]] = [ChatType.ALL] # 支持所有聊天类型
def __init__(self, stream_id: str, action_manager: ChatterActionManager):
"""
@@ -68,7 +68,7 @@ class AffinityChatter(BaseChatter):
try:
# 触发表达学习
learner = await expression_learner_manager.get_expression_learner(self.stream_id)
asyncio.create_task(learner.trigger_learning_for_chat())
asyncio.create_task(learner.trigger_learning_for_chat()) # noqa: RUF006
unread_messages = context.get_unread_messages()
@@ -87,7 +87,7 @@ class AffinityChatter(BaseChatter):
self.stats["successful_executions"] += 1
self.last_activity_time = time.time()
result = {
result: ClassVar = {
"success": True,
"stream_id": self.stream_id,
"plan_created": True,

View File

@@ -5,7 +5,7 @@
"""
import json
from typing import Any
from typing import Any, ClassVar
from sqlalchemy import select
@@ -29,7 +29,7 @@ class ChatStreamImpressionTool(BaseTool):
name = "update_chat_stream_impression"
description = "当你通过观察聊天记录对当前聊天环境(群聊或私聊)产生了整体印象或认识时使用此工具,更新对这个聊天流的看法。包括:环境氛围、聊天风格、常见话题、你的兴趣程度。调用时机:当你发现这个聊天环境有明显的氛围特点(如很活跃、很专业、很闲聊)、群成员经常讨论某类话题、或者你对这个环境的感受发生变化时。注意:这是对整个聊天环境的印象,而非对单个用户。"
parameters = [
parameters: ClassVar = [
(
"impression_description",
ToolParamType.STRING,
@@ -73,7 +73,7 @@ class ChatStreamImpressionTool(BaseTool):
)
except AttributeError:
# 降级处理
available_models = [
available_models: ClassVar = [
attr
for attr in dir(model_config.model_task_config)
if not attr.startswith("_") and attr != "model_dump"
@@ -153,7 +153,7 @@ class ChatStreamImpressionTool(BaseTool):
await self._update_stream_impression_in_db(stream_id, final_impression)
# 构建返回信息
updates = []
updates: ClassVar = []
if final_impression.get("stream_impression_text"):
updates.append(f"印象: {final_impression['stream_impression_text'][:50]}...")
if final_impression.get("stream_chat_style"):

View File

@@ -117,9 +117,11 @@ class ChatterPlanFilter:
elif isinstance(actions_obj, list):
actions_to_process_for_log.extend(actions_obj)
for single_action in actions_to_process_for_log:
if isinstance(single_action, dict):
action_types_to_log.append(single_action.get("action_type", "no_action"))
action_types_to_log = [
single_action.get("action_type", "no_action")
for single_action in actions_to_process_for_log
if isinstance(single_action, dict)
]
if thinking != "未提供思考过程" and action_types_to_log:
await self._add_decision_to_history(plan, thinking, ", ".join(action_types_to_log))

View File

@@ -118,7 +118,6 @@ class ChatterActionPlanner:
# 2. 使用新的兴趣度管理系统进行评分
max_message_interest = 0.0
reply_not_available = True
interest_updates: list[dict[str, Any]] = []
aggregate_should_act = False
if unread_messages:
@@ -247,7 +246,7 @@ class ChatterActionPlanner:
async def _normal_mode_flow(self, context: "StreamContext | None") -> tuple[list[dict[str, Any]], Any | None]:
"""Normal模式下的简化plan流程
只计算兴趣值并判断是否达到reply阈值不执行完整的plan流程。
根据focus_energy决定退出normal模式回到focus模式的概率。
"""
@@ -371,7 +370,7 @@ class ChatterActionPlanner:
async def _check_exit_normal_mode(self, context: "StreamContext | None") -> None:
"""检查并执行退出Normal模式的判定
Args:
context: 流上下文
"""

View File

@@ -2,6 +2,8 @@
亲和力聊天处理器插件(包含兴趣计算器功能)
"""
from typing import ClassVar
from src.common.logger import get_logger
from src.plugin_system.apis.plugin_register_api import register_plugin
from src.plugin_system.base.base_plugin import BasePlugin
@@ -21,12 +23,12 @@ class AffinityChatterPlugin(BasePlugin):
plugin_name: str = "affinity_chatter"
enable_plugin: bool = True
dependencies: list[str] = []
python_dependencies: list[str] = []
dependencies: ClassVar[list[str] ] = []
python_dependencies: ClassVar[list[str] ] = []
config_file_name: str = ""
# 简单的 config_schema 占位(如果将来需要配置可扩展)
config_schema = {}
config_schema: ClassVar = {}
def get_plugin_components(self) -> list[tuple[ComponentInfo, type]]:
"""返回插件包含的组件列表
@@ -34,7 +36,7 @@ class AffinityChatterPlugin(BasePlugin):
这里采用延迟导入以避免循环依赖和启动顺序问题。
如果导入失败则返回空列表以让注册过程继续而不崩溃。
"""
components = []
components: ClassVar = []
try:
# 延迟导入 AffinityChatter

View File

@@ -3,6 +3,9 @@
监听bot的reply事件在reply后重置对应聊天流的主动思考定时任务
"""
from typing import ClassVar
from src.common.logger import get_logger
from src.plugin_system import BaseEventHandler, EventType
from src.plugin_system.base.base_event import HandlerResult
@@ -23,7 +26,7 @@ class ProactiveThinkingReplyHandler(BaseEventHandler):
handler_name: str = "proactive_thinking_reply_handler"
handler_description: str = "监听reply事件重置主动思考定时任务"
init_subscribe: list[EventType | str] = [EventType.AFTER_SEND]
init_subscribe: ClassVar[list[EventType | str]] = [EventType.AFTER_SEND]
async def execute(self, kwargs: dict | None) -> HandlerResult:
"""处理reply事件
@@ -90,7 +93,7 @@ class ProactiveThinkingMessageHandler(BaseEventHandler):
handler_name: str = "proactive_thinking_message_handler"
handler_description: str = "监听消息事件,为新聊天流创建主动思考任务"
init_subscribe: list[EventType | str] = [EventType.ON_MESSAGE]
init_subscribe: ClassVar[list[EventType | str]] = [EventType.ON_MESSAGE]
async def execute(self, kwargs: dict | None) -> HandlerResult:
"""处理消息事件

View File

@@ -213,7 +213,7 @@ class ProactiveThinkingPlanner:
- 理由: {last_reasoning}"""
if last_topic:
last_decision_text += f"\n- 话题: {last_topic}"
return f"""你的人设是:
{context['bot_personality']}
@@ -238,7 +238,7 @@ class ProactiveThinkingPlanner:
- 适用场景:气氛不适合说话、最近对话很活跃、没什么特别想说的、或者此时说话会显得突兀。
- 心情影响:如果心情不好(如生气、难过),可能更倾向于保持沉默。
**选项2简单冒个泡 (simple_bubble)**
**选项2简单冒个泡 (simple_bubble)**
- 适用场景:对话有些冷清,你想缓和气氛或开启新的互动。
- 方式:说一句轻松随意的话,旨在建立或维持连接。
- 心情影响:心情会影响你冒泡的方式和内容。

View File

@@ -5,7 +5,7 @@
"""
import time
from typing import Any
from typing import Any, ClassVar
import orjson
from sqlalchemy import select
@@ -22,7 +22,7 @@ logger = get_logger("user_profile_tool")
class UserProfileTool(BaseTool):
"""用户画像更新工具
使用二步调用机制:
1. LLM决定是否调用工具并传入初步参数
2. 工具内部调用LLM结合现有数据和传入参数决定最终更新内容
@@ -30,7 +30,7 @@ class UserProfileTool(BaseTool):
name = "update_user_profile"
description = "当你通过聊天记录对某个用户产生了新的认识或印象时使用此工具更新该用户的画像信息。包括用户别名、你对TA的主观印象、TA的偏好兴趣、你对TA的好感程度。调用时机当你发现用户透露了新的个人信息、展现了性格特点、表达了兴趣偏好或者你们的互动让你对TA的看法发生变化时。"
parameters = [
parameters: ClassVar = [
("target_user_id", ToolParamType.STRING, "目标用户的ID必须", True, None),
("user_aliases", ToolParamType.STRING, "该用户的昵称或别名,如果发现用户自称或被他人称呼的其他名字时填写,多个别名用逗号分隔(可选)", False, None),
("impression_description", ToolParamType.STRING, "你对该用户的整体印象和性格感受,例如'这个用户很幽默开朗''TA对技术很有热情'等。当你通过对话了解到用户的性格、态度、行为特点时填写(可选)", False, None),
@@ -51,7 +51,7 @@ class UserProfileTool(BaseTool):
)
except AttributeError:
# 降级处理
available_models = [
available_models: ClassVar = [
attr for attr in dir(model_config.model_task_config)
if not attr.startswith("_") and attr != "model_dump"
]
@@ -68,10 +68,10 @@ class UserProfileTool(BaseTool):
async def execute(self, function_args: dict[str, Any]) -> dict[str, Any]:
"""执行用户画像更新
Args:
function_args: 工具参数
Returns:
dict: 执行结果
"""
@@ -131,7 +131,7 @@ class UserProfileTool(BaseTool):
await self._update_user_profile_in_db(target_user_id, final_profile)
# 构建返回信息
updates = []
updates: ClassVar = []
if final_profile.get("user_aliases"):
updates.append(f"别名: {final_profile['user_aliases']}")
if final_profile.get("relationship_text"):
@@ -160,10 +160,10 @@ class UserProfileTool(BaseTool):
async def _get_user_profile(self, user_id: str) -> dict[str, Any]:
"""从数据库获取用户现有画像
Args:
user_id: 用户ID
Returns:
dict: 用户画像数据
"""
@@ -210,7 +210,7 @@ class UserProfileTool(BaseTool):
new_score: float | None
) -> dict[str, Any] | None:
"""使用LLM决策最终的用户画像内容
Args:
target_user_id: 目标用户ID
existing_profile: 现有画像数据
@@ -218,7 +218,7 @@ class UserProfileTool(BaseTool):
new_impression: LLM传入的新印象
new_keywords: LLM传入的新关键词
new_score: LLM传入的新分数
Returns:
dict: 最终决定的画像数据如果失败返回None
"""
@@ -296,7 +296,7 @@ class UserProfileTool(BaseTool):
async def _update_user_profile_in_db(self, user_id: str, profile: dict[str, Any]):
"""更新数据库中的用户画像
Args:
user_id: 用户ID
profile: 画像数据
@@ -338,10 +338,10 @@ class UserProfileTool(BaseTool):
def _clean_llm_json_response(self, response: str) -> str:
"""清理LLM响应移除可能的JSON格式标记
Args:
response: LLM原始响应
Returns:
str: 清理后的JSON字符串
"""

View File

@@ -1,5 +1,6 @@
import random
import re
from typing import ClassVar
from src.chat.emoji_system.emoji_history import add_emoji_to_history, get_recent_emojis
from src.chat.emoji_system.emoji_manager import MaiEmoji, get_emoji_manager
@@ -20,14 +21,14 @@ logger = get_logger("emoji")
class EmojiAction(BaseAction):
"""表情动作 - 发送表情包
注意:此 Action 使用旧的激活类型配置方式(已废弃但仍然兼容)。
BaseAction.go_activate() 的默认实现会自动处理这些旧配置。
推荐的新写法(迁移示例):
----------------------------------------
# 移除下面的 activation_type 相关配置,改为重写 go_activate 方法:
async def go_activate(self, chat_content: str = "", llm_judge_model=None) -> bool:
# 根据配置选择激活方式
if global_config.emoji.emoji_activate_type == "llm":
@@ -75,17 +76,17 @@ class EmojiAction(BaseAction):
"""
# 动作参数定义
action_parameters = {}
action_parameters: ClassVar = {}
# 动作使用场景
action_require = [
action_require: ClassVar = [
"发送表情包辅助表达情绪",
"表达情绪时可以选择使用",
"不要连续发送,如果你已经发过[表情包],就不要选择此动作",
]
# 关联类型
associated_types = ["emoji"]
associated_types: ClassVar[list[str]] = ["emoji"]
async def execute(self) -> tuple[bool, str]:
"""执行表情动作"""
@@ -119,8 +120,8 @@ class EmojiAction(BaseAction):
logger.error(f"{self.log_prefix} 获取或处理表情发送历史时出错: {e}")
# 4. 准备情感数据和后备列表
emotion_map = {}
all_emojis_data = []
emotion_map: ClassVar = {}
all_emojis_data: ClassVar = []
for emoji in all_emojis_obj:
b64 = image_path_to_base64(emoji.full_path)

View File

@@ -6,6 +6,8 @@
"""
# 导入依赖的系统组件
from typing import ClassVar
from src.common.logger import get_logger
# 导入新插件系统
@@ -34,18 +36,18 @@ class CoreActionsPlugin(BasePlugin):
# 插件基本信息
plugin_name: str = "core_actions" # 内部标识符
enable_plugin: bool = True
dependencies: list[str] = [] # 插件依赖列表
python_dependencies: list[str] = [] # Python包依赖列表
dependencies: ClassVar[list[str]] = [] # 插件依赖列表
python_dependencies: ClassVar[list[str]] = [] # Python包依赖列表
config_file_name: str = "config.toml"
# 配置节描述
config_section_descriptions = {
config_section_descriptions: ClassVar = {
"plugin": "插件启用配置",
"components": "核心组件启用配置",
}
# 配置Schema定义
config_schema: dict = {
config_schema: ClassVar[dict] = {
"plugin": {
"enabled": ConfigField(type=bool, default=True, description="是否启用插件"),
"config_version": ConfigField(type=str, default="0.6.0", description="配置文件版本"),
@@ -63,7 +65,7 @@ class CoreActionsPlugin(BasePlugin):
"""返回插件包含的组件列表"""
# --- 根据配置注册组件 ---
components = []
components: ClassVar = []
if self.get_config("components.enable_emoji", True):
components.append((EmojiAction.get_action_info(), EmojiAction))
if self.get_config("components.enable_anti_injector_manager", True):

View File

@@ -1,4 +1,4 @@
from typing import Any
from typing import Any, ClassVar
from src.chat.knowledge.knowledge_lib import qa_manager
from src.common.logger import get_logger
@@ -13,7 +13,7 @@ class SearchKnowledgeFromLPMMTool(BaseTool):
name = "lpmm_search_knowledge"
description = "从知识库中搜索相关信息,如果你需要知识,就使用这个工具"
parameters = [
parameters: ClassVar = [
("query", ToolParamType.STRING, "搜索查询关键词", True, None),
("threshold", ToolParamType.FLOAT, "相似度阈值0.0到1.0之间", False, None),
]
@@ -44,7 +44,7 @@ class SearchKnowledgeFromLPMMTool(BaseTool):
logger.debug(f"知识库查询结果: {knowledge_info}")
if knowledge_info and knowledge_info.get("knowledge_items"):
knowledge_parts = []
knowledge_parts: ClassVar = []
for i, item in enumerate(knowledge_info["knowledge_items"]):
knowledge_parts.append(f"- {item.get('content', 'N/A')}")

View File

@@ -2,6 +2,8 @@
阅读说说动作组件
"""
from typing import ClassVar
from src.common.logger import get_logger
from src.plugin_system import ActionActivationType, BaseAction, ChatMode
from src.plugin_system.apis import generator_api
@@ -21,9 +23,9 @@ class ReadFeedAction(BaseAction):
action_description: str = "读取好友的最新动态并进行评论点赞"
activation_type: ActionActivationType = ActionActivationType.KEYWORD
mode_enable: ChatMode = ChatMode.ALL
activation_keywords: list = ["看说说", "看空间", "看动态", "刷空间"]
activation_keywords: ClassVar[list] = ["看说说", "看空间", "看动态", "刷空间"]
action_parameters = {
action_parameters: ClassVar[dict] = {
"target_name": "需要阅读动态的好友的昵称",
"user_name": "请求你阅读动态的好友的昵称",
}

View File

@@ -2,6 +2,8 @@
发送说说动作组件
"""
from typing import ClassVar
from src.common.logger import get_logger
from src.plugin_system import ActionActivationType, BaseAction, ChatMode
from src.plugin_system.apis import generator_api
@@ -21,9 +23,9 @@ class SendFeedAction(BaseAction):
action_description: str = "发送一条关于特定主题的说说"
activation_type: ActionActivationType = ActionActivationType.KEYWORD
mode_enable: ChatMode = ChatMode.ALL
activation_keywords: list = ["发说说", "发空间", "发动态"]
activation_keywords: ClassVar[list] = ["发说说", "发空间", "发动态"]
action_parameters = {
action_parameters: ClassVar[dict] = {
"topic": "用户想要发送的说说主题",
"user_name": "请求你发说说的好友的昵称",
}

View File

@@ -2,6 +2,9 @@
发送说说命令 await self.send_text(f"收到!正在为你生成关于"{topic or '随机'}"的说说,请稍候...【热重载测试成功】")件
"""
from typing import ClassVar
from src.common.logger import get_logger
from src.plugin_system.base.command_args import CommandArgs
from src.plugin_system.base.plus_command import PlusCommand
@@ -20,7 +23,7 @@ class SendFeedCommand(PlusCommand):
command_name: str = "send_feed"
command_description: str = "发一条QQ空间说说"
command_aliases = ["发空间"]
command_aliases: ClassVar[list[str]] = ["发空间"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

View File

@@ -4,6 +4,7 @@ MaiZone麦麦空间- 重构版
import asyncio
from pathlib import Path
from typing import ClassVar
from src.common.logger import get_logger
from src.plugin_system import BasePlugin, ComponentInfo, register_plugin
@@ -33,10 +34,10 @@ class MaiZoneRefactoredPlugin(BasePlugin):
plugin_description: str = "重构版的MaiZone插件"
config_file_name: str = "config.toml"
enable_plugin: bool = True
dependencies: list[str] = []
python_dependencies: list[str] = []
dependencies: ClassVar[list[str] ] = []
python_dependencies: ClassVar[list[str] ] = []
config_schema: dict = {
config_schema: ClassVar[dict] = {
"plugin": {"enable": ConfigField(type=bool, default=True, description="是否启用插件")},
"models": {
"text_model": ConfigField(type=str, default="maizone", description="生成文本的模型名称"),
@@ -83,7 +84,7 @@ class MaiZoneRefactoredPlugin(BasePlugin):
},
}
permission_nodes: list[PermissionNodeField] = [
permission_nodes: ClassVar[list[PermissionNodeField]] = [
PermissionNodeField(node_name="send_feed", description="是否可以使用机器人发送QQ空间说说"),
PermissionNodeField(node_name="read_feed", description="是否可以使用机器人读取QQ空间说说"),
]

View File

@@ -1,10 +1,11 @@
from typing import ClassVar
from src.common.logger import get_logger
from src.plugin_system import BaseEventHandler
from src.plugin_system.base.base_event import HandlerResult
from .src.send_handler import send_handler
from .event_types import NapcatEvent
from src.common.logger import get_logger
from .src.send_handler import send_handler
logger = get_logger("napcat_adapter")
@@ -14,7 +15,7 @@ class SetProfileHandler(BaseEventHandler):
handler_description: str = "设置账号信息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.SET_PROFILE]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.SET_PROFILE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -49,7 +50,7 @@ class GetOnlineClientsHandler(BaseEventHandler):
handler_description: str = "获取当前账号在线客户端列表"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.GET_ONLINE_CLIENTS]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.GET_ONLINE_CLIENTS]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -72,7 +73,7 @@ class SetOnlineStatusHandler(BaseEventHandler):
handler_description: str = "设置在线状态"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.SET_ONLINE_STATUS]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.SET_ONLINE_STATUS]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -103,7 +104,7 @@ class GetFriendsWithCategoryHandler(BaseEventHandler):
handler_description: str = "获取好友分组列表"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.GET_FRIENDS_WITH_CATEGORY]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.GET_FRIENDS_WITH_CATEGORY]
async def execute(self, params: dict):
payload = {}
@@ -120,7 +121,7 @@ class SetAvatarHandler(BaseEventHandler):
handler_description: str = "设置头像"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.SET_AVATAR]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.SET_AVATAR]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -147,7 +148,7 @@ class SendLikeHandler(BaseEventHandler):
handler_description: str = "点赞"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.SEND_LIKE]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.SEND_LIKE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -176,7 +177,7 @@ class SetFriendAddRequestHandler(BaseEventHandler):
handler_description: str = "处理好友请求"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.SET_FRIEND_ADD_REQUEST]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.SET_FRIEND_ADD_REQUEST]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -207,7 +208,7 @@ class SetSelfLongnickHandler(BaseEventHandler):
handler_description: str = "设置个性签名"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.SET_SELF_LONGNICK]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.SET_SELF_LONGNICK]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -240,7 +241,7 @@ class GetLoginInfoHandler(BaseEventHandler):
handler_description: str = "获取登录号信息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.GET_LOGIN_INFO]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.GET_LOGIN_INFO]
async def execute(self, params: dict):
payload = {}
@@ -257,7 +258,7 @@ class GetRecentContactHandler(BaseEventHandler):
handler_description: str = "最近消息列表"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.GET_RECENT_CONTACT]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.GET_RECENT_CONTACT]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -280,7 +281,7 @@ class GetStrangerInfoHandler(BaseEventHandler):
handler_description: str = "获取(指定)账号信息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.GET_STRANGER_INFO]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.GET_STRANGER_INFO]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -307,7 +308,7 @@ class GetFriendListHandler(BaseEventHandler):
handler_description: str = "获取好友列表"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.GET_FRIEND_LIST]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.GET_FRIEND_LIST]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -330,7 +331,7 @@ class GetProfileLikeHandler(BaseEventHandler):
handler_description: str = "获取点赞列表"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.GET_PROFILE_LIKE]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.GET_PROFILE_LIKE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -360,7 +361,7 @@ class DeleteFriendHandler(BaseEventHandler):
handler_description: str = "删除好友"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.DELETE_FRIEND]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.DELETE_FRIEND]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -395,7 +396,7 @@ class GetUserStatusHandler(BaseEventHandler):
handler_description: str = "获取(指定)用户状态"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.GET_USER_STATUS]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.GET_USER_STATUS]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -422,7 +423,7 @@ class GetStatusHandler(BaseEventHandler):
handler_description: str = "获取状态"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.GET_STATUS]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.GET_STATUS]
async def execute(self, params: dict):
payload = {}
@@ -439,7 +440,7 @@ class GetMiniAppArkHandler(BaseEventHandler):
handler_description: str = "获取小程序卡片"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.GET_MINI_APP_ARK]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.GET_MINI_APP_ARK]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -486,7 +487,7 @@ class SetDiyOnlineStatusHandler(BaseEventHandler):
handler_description: str = "设置自定义在线状态"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.ACCOUNT.SET_DIY_ONLINE_STATUS]
init_subscribe: ClassVar[list] = [NapcatEvent.ACCOUNT.SET_DIY_ONLINE_STATUS]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -518,7 +519,7 @@ class SendPrivateMsgHandler(BaseEventHandler):
handler_description: str = "发送私聊消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.SEND_PRIVATE_MSG]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.SEND_PRIVATE_MSG]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -547,7 +548,7 @@ class SendPokeHandler(BaseEventHandler):
handler_description: str = "发送戳一戳"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.SEND_POKE]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.SEND_POKE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -579,7 +580,7 @@ class DeleteMsgHandler(BaseEventHandler):
handler_description: str = "撤回消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.DELETE_MSG]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.DELETE_MSG]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -606,7 +607,7 @@ class GetGroupMsgHistoryHandler(BaseEventHandler):
handler_description: str = "获取群历史消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.GET_GROUP_MSG_HISTORY]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.GET_GROUP_MSG_HISTORY]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -644,7 +645,7 @@ class GetMsgHandler(BaseEventHandler):
handler_description: str = "获取消息详情"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.GET_MSG]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.GET_MSG]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -671,7 +672,7 @@ class GetForwardMsgHandler(BaseEventHandler):
handler_description: str = "获取合并转发消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.GET_FORWARD_MSG]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.GET_FORWARD_MSG]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -698,7 +699,7 @@ class SetMsgEmojiLikeHandler(BaseEventHandler):
handler_description: str = "贴表情"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.SET_MSG_EMOJI_LIKE]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.SET_MSG_EMOJI_LIKE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -729,7 +730,7 @@ class GetFriendMsgHistoryHandler(BaseEventHandler):
handler_description: str = "获取好友历史消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.GET_FRIEND_MSG_HISTORY]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.GET_FRIEND_MSG_HISTORY]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -767,7 +768,7 @@ class FetchEmojiLikeHandler(BaseEventHandler):
handler_description: str = "获取贴表情详情"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.FETCH_EMOJI_LIKE]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.FETCH_EMOJI_LIKE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -805,7 +806,7 @@ class SendForwardMsgHandler(BaseEventHandler):
handler_description: str = "发送合并转发消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.SEND_FORWARD_MSG]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.SEND_FORWARD_MSG]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -849,7 +850,7 @@ class SendGroupAiRecordHandler(BaseEventHandler):
handler_description: str = "发送群AI语音"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.MESSAGE.SEND_GROUP_AI_RECORD]
init_subscribe: ClassVar[list] = [NapcatEvent.MESSAGE.SEND_GROUP_AI_RECORD]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -881,7 +882,7 @@ class GetGroupInfoHandler(BaseEventHandler):
handler_description: str = "获取群信息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_INFO]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_INFO]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -908,7 +909,7 @@ class SetGroupAddOptionHandler(BaseEventHandler):
handler_description: str = "设置群添加选项"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_ADD_OPTION]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_ADD_OPTION]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -946,7 +947,7 @@ class SetGroupKickMembersHandler(BaseEventHandler):
handler_description: str = "批量踢出群成员"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_KICK_MEMBERS]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_KICK_MEMBERS]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -977,7 +978,7 @@ class SetGroupRemarkHandler(BaseEventHandler):
handler_description: str = "设置群备注"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_REMARK]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_REMARK]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1006,7 +1007,7 @@ class SetGroupKickHandler(BaseEventHandler):
handler_description: str = "群踢人"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_KICK]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_KICK]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1037,7 +1038,7 @@ class GetGroupSystemMsgHandler(BaseEventHandler):
handler_description: str = "获取群系统消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_SYSTEM_MSG]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_SYSTEM_MSG]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1064,7 +1065,7 @@ class SetGroupBanHandler(BaseEventHandler):
handler_description: str = "群禁言"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_BAN]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_BAN]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1095,7 +1096,7 @@ class GetEssenceMsgListHandler(BaseEventHandler):
handler_description: str = "获取群精华消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_ESSENCE_MSG_LIST]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_ESSENCE_MSG_LIST]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1122,7 +1123,7 @@ class SetGroupWholeBanHandler(BaseEventHandler):
handler_description: str = "全体禁言"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_WHOLE_BAN]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_WHOLE_BAN]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1151,7 +1152,7 @@ class SetGroupPortraitHandler(BaseEventHandler):
handler_description: str = "设置群头像"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_PORTRAINT]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_PORTRAINT]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1180,7 +1181,7 @@ class SetGroupAdminHandler(BaseEventHandler):
handler_description: str = "设置群管理"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_ADMIN]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_ADMIN]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1211,7 +1212,7 @@ class SetGroupCardHandler(BaseEventHandler):
handler_description: str = "设置群成员名片"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_CARD]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_CARD]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1245,7 +1246,7 @@ class SetEssenceMsgHandler(BaseEventHandler):
handler_description: str = "设置群精华消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_ESSENCE_MSG]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_ESSENCE_MSG]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1272,7 +1273,7 @@ class SetGroupNameHandler(BaseEventHandler):
handler_description: str = "设置群名"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_NAME]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_NAME]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1301,7 +1302,7 @@ class DeleteEssenceMsgHandler(BaseEventHandler):
handler_description: str = "删除群精华消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.DELETE_ESSENCE_MSG]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.DELETE_ESSENCE_MSG]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1328,7 +1329,7 @@ class SetGroupLeaveHandler(BaseEventHandler):
handler_description: str = "退群"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_LEAVE]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_LEAVE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1355,7 +1356,7 @@ class SendGroupNoticeHandler(BaseEventHandler):
handler_description: str = "发送群公告"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SEND_GROUP_NOTICE]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SEND_GROUP_NOTICE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1389,7 +1390,7 @@ class SetGroupSpecialTitleHandler(BaseEventHandler):
handler_description: str = "设置群头衔"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_SPECIAL_TITLE]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_SPECIAL_TITLE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1423,7 +1424,7 @@ class GetGroupNoticeHandler(BaseEventHandler):
handler_description: str = "获取群公告"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_NOTICE]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_NOTICE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1450,7 +1451,7 @@ class SetGroupAddRequestHandler(BaseEventHandler):
handler_description: str = "处理加群请求"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_ADD_REQUEST]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_ADD_REQUEST]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1484,7 +1485,7 @@ class GetGroupListHandler(BaseEventHandler):
handler_description: str = "获取群列表"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_LIST]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_LIST]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1507,7 +1508,7 @@ class DeleteGroupNoticeHandler(BaseEventHandler):
handler_description: str = "删除群公告"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.DELETE_GROUP_NOTICE]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.DELETE_GROUP_NOTICE]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1536,7 +1537,7 @@ class GetGroupMemberInfoHandler(BaseEventHandler):
handler_description: str = "获取群成员信息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_MEMBER_INFO]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_MEMBER_INFO]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1567,7 +1568,7 @@ class GetGroupMemberListHandler(BaseEventHandler):
handler_description: str = "获取群成员列表"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_MEMBER_LIST]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_MEMBER_LIST]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1596,7 +1597,7 @@ class GetGroupHonorInfoHandler(BaseEventHandler):
handler_description: str = "获取群荣誉"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_HONOR_INFO]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_HONOR_INFO]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1628,7 +1629,7 @@ class GetGroupInfoExHandler(BaseEventHandler):
handler_description: str = "获取群信息ex"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_INFO_EX]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_INFO_EX]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1655,7 +1656,7 @@ class GetGroupAtAllRemainHandler(BaseEventHandler):
handler_description: str = "获取群 @全体成员 剩余次数"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_AT_ALL_REMAIN]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_AT_ALL_REMAIN]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1682,7 +1683,7 @@ class GetGroupShutListHandler(BaseEventHandler):
handler_description: str = "获取群禁言列表"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_SHUT_LIST]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_SHUT_LIST]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1709,7 +1710,7 @@ class GetGroupIgnoredNotifiesHandler(BaseEventHandler):
handler_description: str = "获取群过滤系统消息"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.GET_GROUP_IGNORED_NOTIFIES]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.GET_GROUP_IGNORED_NOTIFIES]
async def execute(self, params: dict):
payload = {}
@@ -1726,7 +1727,7 @@ class SetGroupSignHandler(BaseEventHandler):
handler_description: str = "群打卡"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.GROUP.SET_GROUP_SIGN]
init_subscribe: ClassVar[list] = [NapcatEvent.GROUP.SET_GROUP_SIGN]
async def execute(self, params: dict):
raw = params.get("raw", {})
@@ -1754,7 +1755,7 @@ class SetInputStatusHandler(BaseEventHandler):
handler_description: str = "设置输入状态"
weight: int = 100
intercept_message: bool = False
init_subscribe = [NapcatEvent.PERSONAL.SET_INPUT_STATUS]
init_subscribe: ClassVar[list] = [NapcatEvent.PERSONAL.SET_INPUT_STATUS]
async def execute(self, params: dict):
raw = params.get("raw", {})

View File

@@ -1,25 +1,24 @@
import asyncio
import json
import inspect
import json
from typing import ClassVar, List
import websockets as Server
from . import event_types, CONSTS, event_handlers
from typing import List
from src.plugin_system import BasePlugin, BaseEventHandler, register_plugin, EventType, ConfigField
from src.plugin_system.core.event_manager import event_manager
from src.plugin_system.apis import config_api
from src.common.logger import get_logger
from src.plugin_system import BaseEventHandler, BasePlugin, ConfigField, EventType, register_plugin
from src.plugin_system.apis import config_api
from src.plugin_system.core.event_manager import event_manager
from . import CONSTS, event_handlers, event_types
from .src.message_chunker import chunker, reassembler
from .src.mmc_com_layer import mmc_start_com, mmc_stop_com, router
from .src.recv_handler.message_handler import message_handler
from .src.recv_handler.message_sending import message_send_instance
from .src.recv_handler.meta_event_handler import meta_event_handler
from .src.recv_handler.notice_handler import notice_handler
from .src.recv_handler.message_sending import message_send_instance
from .src.response_pool import check_timeout_response, put_response
from .src.send_handler import send_handler
from .src.mmc_com_layer import mmc_start_com, router, mmc_stop_com
from .src.response_pool import put_response, check_timeout_response
from .src.websocket_manager import websocket_manager
logger = get_logger("napcat_adapter")
@@ -219,7 +218,7 @@ class LauchNapcatAdapterHandler(BaseEventHandler):
handler_description: str = "自动启动napcat adapter"
weight: int = 100
intercept_message: bool = False
init_subscribe = [EventType.ON_START]
init_subscribe: ClassVar[list] = [EventType.ON_START]
async def execute(self, kwargs):
# 启动消息重组器的清理任务
@@ -267,7 +266,7 @@ class StopNapcatAdapterHandler(BaseEventHandler):
handler_description: str = "关闭napcat adapter"
weight: int = 100
intercept_message: bool = False
init_subscribe = [EventType.ON_STOP]
init_subscribe: ClassVar[list] = [EventType.ON_STOP]
async def execute(self, kwargs):
await graceful_shutdown()
@@ -277,8 +276,8 @@ class StopNapcatAdapterHandler(BaseEventHandler):
@register_plugin
class NapcatAdapterPlugin(BasePlugin):
plugin_name = CONSTS.PLUGIN_NAME
dependencies: List[str] = [] # 插件依赖列表
python_dependencies: List[str] = [] # Python包依赖列表
dependencies: ClassVar[List[str]] = [] # 插件依赖列表
python_dependencies: ClassVar[List[str]] = [] # Python包依赖列表
config_file_name: str = "config.toml" # 配置文件名
@property
@@ -291,10 +290,10 @@ class NapcatAdapterPlugin(BasePlugin):
return False
# 配置节描述
config_section_descriptions = {"plugin": "插件基本信息"}
config_section_descriptions: ClassVar[dict] = {"plugin": "插件基本信息"}
# 配置Schema定义
config_schema: dict = {
config_schema: ClassVar[dict] = {
"plugin": {
"name": ConfigField(type=str, default="napcat_adapter_plugin", description="插件名称"),
"version": ConfigField(type=str, default="1.1.0", description="插件版本"),
@@ -389,7 +388,7 @@ class NapcatAdapterPlugin(BasePlugin):
}
# 配置节描述
config_section_descriptions = {
config_section_descriptions: ClassVar[dict] = {
"plugin": "插件基本信息",
"inner": "内部配置信息(请勿修改)",
"nickname": "昵称配置(目前未使用)",
@@ -421,9 +420,11 @@ class NapcatAdapterPlugin(BasePlugin):
components = []
components.append((LauchNapcatAdapterHandler.get_handler_info(), LauchNapcatAdapterHandler))
components.append((StopNapcatAdapterHandler.get_handler_info(), StopNapcatAdapterHandler))
for handler in get_classes_in_module(event_handlers):
if issubclass(handler, BaseEventHandler):
components.append((handler.get_handler_info(), handler))
components.extend(
(handler.get_handler_info(), handler)
for handler in get_classes_in_module(event_handlers)
if issubclass(handler, BaseEventHandler)
)
return components
async def on_plugin_loaded(self):

View File

@@ -1,6 +1,8 @@
from enum import Enum
import tomlkit
import os
from enum import Enum
import tomlkit
from src.common.logger import get_logger
logger = get_logger("napcat_adapter")

View File

@@ -13,9 +13,9 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Optional, List, Sequence
from typing import List, Optional, Sequence
from sqlalchemy import Column, Integer, BigInteger, UniqueConstraint, select, Index
from sqlalchemy import BigInteger, Column, Index, Integer, UniqueConstraint, select
from sqlalchemy.ext.asyncio import AsyncSession
from src.common.database.sqlalchemy_models import Base, get_db_session

View File

@@ -4,14 +4,14 @@
仅在 Ada -> MMC 方向进行切片其他方向MMC -> AdaAda <-> Napcat不切片
"""
import json
import uuid
import asyncio
import json
import time
from typing import List, Dict, Any, Optional, Union
from src.plugin_system.apis import config_api
import uuid
from typing import Any, Dict, List, Optional, Union
from src.common.logger import get_logger
from src.plugin_system.apis import config_api
logger = get_logger("napcat_adapter")

View File

@@ -1,4 +1,4 @@
from maim_message import Router, RouteConfig, TargetConfig
from maim_message import RouteConfig, Router, TargetConfig
from src.common.logger import get_logger
from src.common.server import get_global_server

View File

@@ -1,45 +1,43 @@
from ...event_types import NapcatEvent
from src.plugin_system.core.event_manager import event_manager
import base64
import json
import time
import uuid
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
import websockets as Server
from maim_message import (
BaseMessageInfo,
FormatInfo,
GroupInfo,
MessageBase,
Seg,
TemplateInfo,
UserInfo,
)
from src.common.logger import get_logger
from ...CONSTS import PLUGIN_NAME
logger = get_logger("napcat_adapter")
from src.plugin_system.apis import config_api
from src.plugin_system.core.event_manager import event_manager
from ...CONSTS import PLUGIN_NAME
from ...event_types import NapcatEvent
from ..response_pool import get_response
from ..utils import (
get_group_info,
get_member_info,
get_image_base64,
get_member_info,
get_message_detail,
get_record_detail,
get_self_info,
get_message_detail,
)
from .qq_emoji_list import qq_face
from .message_sending import message_send_instance
from . import RealMessageType, MessageType, ACCEPT_FORMAT
from ..video_handler import get_video_downloader
from ..websocket_manager import websocket_manager
from . import ACCEPT_FORMAT, MessageType, RealMessageType
from .message_sending import message_send_instance
from .qq_emoji_list import qq_face
import time
import json
import websockets as Server
import base64
from pathlib import Path
from typing import List, Tuple, Optional, Dict, Any
import uuid
from maim_message import (
UserInfo,
GroupInfo,
Seg,
BaseMessageInfo,
MessageBase,
TemplateInfo,
FormatInfo,
)
from ..response_pool import get_response
logger = get_logger("napcat_adapter")
class MessageHandler:

View File

@@ -1,11 +1,13 @@
import asyncio
from maim_message import MessageBase, Router
from src.common.logger import get_logger
from ..message_chunker import chunker
from src.plugin_system.apis import config_api
from ..message_chunker import chunker
logger = get_logger("napcat_adapter")
from maim_message import MessageBase, Router
class MessageSending:

View File

@@ -1,12 +1,13 @@
from src.common.logger import get_logger
logger = get_logger("napcat_adapter")
from src.plugin_system.apis import config_api
import time
import asyncio
import time
from src.common.logger import get_logger
from src.plugin_system.apis import config_api
from . import MetaEventType
logger = get_logger("napcat_adapter")
class MetaEventHandler:
"""

View File

@@ -1,21 +1,16 @@
import time
import json
import asyncio
import json
import time
from typing import ClassVar, Optional, Tuple
import websockets as Server
from typing import Tuple, Optional
from maim_message import BaseMessageInfo, FormatInfo, GroupInfo, MessageBase, Seg, UserInfo
from src.common.logger import get_logger
logger = get_logger("napcat_adapter")
from src.plugin_system.apis import config_api
from ..database import BanUser, napcat_db, is_identical
from . import NoticeType, ACCEPT_FORMAT
from .message_sending import message_send_instance
from .message_handler import message_handler
from maim_message import FormatInfo, UserInfo, GroupInfo, Seg, BaseMessageInfo, MessageBase
from ..websocket_manager import websocket_manager
from ...CONSTS import PLUGIN_NAME, QQ_FACE
from ..database import BanUser, is_identical, napcat_db
from ..utils import (
get_group_info,
get_member_info,
@@ -23,16 +18,20 @@ from ..utils import (
get_stranger_info,
read_ban_list,
)
from ..websocket_manager import websocket_manager
from . import ACCEPT_FORMAT, NoticeType
from .message_handler import message_handler
from .message_sending import message_send_instance
from ...CONSTS import PLUGIN_NAME, QQ_FACE
logger = get_logger("napcat_adapter")
notice_queue: asyncio.Queue[MessageBase] = asyncio.Queue(maxsize=100)
unsuccessful_notice_queue: asyncio.Queue[MessageBase] = asyncio.Queue(maxsize=3)
class NoticeHandler:
banned_list: list[BanUser] = [] # 当前仍在禁言中的用户列表
lifted_list: list[BanUser] = [] # 已经自然解除禁言
banned_list: ClassVar[list[BanUser]] = [] # 当前仍在禁言中的用户列表
lifted_list: ClassVar[list[BanUser]] = [] # 已经自然解除禁言
def __init__(self):
self.server_connection: Server.ServerConnection | None = None
@@ -131,6 +130,7 @@ class NoticeHandler:
logger.warning("戳一戳消息被禁用,取消戳一戳处理")
case NoticeType.Notify.input_status:
from src.plugin_system.core.event_manager import event_manager
from ...event_types import NapcatEvent
await event_manager.trigger_event(NapcatEvent.ON_RECEIVED.FRIEND_INPUT, permission_group=PLUGIN_NAME)
@@ -357,6 +357,7 @@ class NoticeHandler:
logger.debug("无法获取表情回复对方的用户昵称")
from src.plugin_system.core.event_manager import event_manager
from ...event_types import NapcatEvent
target_message = await event_manager.trigger_event(NapcatEvent.MESSAGE.GET_MSG,message_id=raw_message.get("message_id",""))

View File

@@ -1,6 +1,7 @@
import asyncio
import time
from typing import Dict
from src.common.logger import get_logger
from src.plugin_system.apis import config_api

View File

@@ -1,26 +1,28 @@
import json
import time
import random
import websockets as Server
import time
import uuid
from typing import Any, Dict, Optional, Tuple
import websockets as Server
from maim_message import (
UserInfo,
GroupInfo,
Seg,
BaseMessageInfo,
GroupInfo,
MessageBase,
Seg,
UserInfo,
)
from typing import Dict, Any, Tuple, Optional
from src.common.logger import get_logger
from src.plugin_system.apis import config_api
from . import CommandType
from .recv_handler.message_sending import message_send_instance
from .response_pool import get_response
from src.common.logger import get_logger
from .utils import convert_image_to_gif, get_image_format
from .websocket_manager import websocket_manager
logger = get_logger("napcat_adapter")
from .utils import get_image_format, convert_image_to_gif
from .recv_handler.message_sending import message_send_instance
from .websocket_manager import websocket_manager
class SendHandler:
@@ -547,7 +549,7 @@ class SendHandler:
set_like = bool(args["set"])
except (KeyError, ValueError) as e:
logger.error(f"处理表情回应命令时发生错误: {e}, 原始参数: {args}")
raise ValueError(f"缺少必需参数或参数类型错误: {e}")
raise ValueError(f"缺少必需参数或参数类型错误: {e}") from e
return (
CommandType.SET_EMOJI_LIKE.value,
@@ -567,8 +569,8 @@ class SendHandler:
try:
user_id: int = int(args["qq_id"])
times: int = int(args["times"])
except (KeyError, ValueError):
raise ValueError("缺少必需参数: qq_id 或 times")
except (KeyError, ValueError) as e:
raise ValueError("缺少必需参数: qq_id 或 times") from e
return (
CommandType.SEND_LIKE.value,

View File

@@ -1,19 +1,20 @@
import websockets as Server
import json
import base64
import uuid
import urllib3
import ssl
import io
import json
import ssl
import uuid
from typing import List, Optional, Tuple, Union
import urllib3
import websockets as Server
from PIL import Image
from .database import BanUser, napcat_db
from src.common.logger import get_logger
logger = get_logger("napcat_adapter")
from .database import BanUser, napcat_db
from .response_pool import get_response
from PIL import Image
from typing import Union, List, Tuple, Optional
logger = get_logger("napcat_adapter")
class SSLAdapter(urllib3.PoolManager):

View File

@@ -5,10 +5,12 @@
用于从QQ消息中下载视频并转发给Bot进行分析
"""
import aiohttp
import asyncio
from pathlib import Path
from typing import Optional, Dict, Any
from typing import Any, Dict, Optional
import aiohttp
from src.common.logger import get_logger
logger = get_logger("video_handler")
@@ -34,20 +36,20 @@ class VideoDownloader:
if any(keyword in url_lower for keyword in video_keywords):
return True
# 检查文件扩展名传统方法
# 检查文件扩展名(传统方法)
path = Path(url.split("?")[0]) # 移除查询参数
if path.suffix.lower() in self.supported_formats:
return True
# 对于QQ等特殊平台URL可能没有扩展名
# 我们允许这些URL通过稍后通过HTTP头Content-Type验证
# 对于QQ等特殊平台,URL可能没有扩展名
# 我们允许这些URL通过,稍后通过HTTP头Content-Type验证
qq_domains = ["qpic.cn", "gtimg.cn", "qq.com", "tencent.com"]
if any(domain in url_lower for domain in qq_domains):
return True
return False
except:
# 如果解析失败默认允许尝试下载稍后验证
except Exception:
# 如果解析失败,默认允许尝试下载(稍后验证)
return True
def check_file_size(self, content_length: Optional[str]) -> bool:
@@ -59,7 +61,7 @@ class VideoDownloader:
size_bytes = int(content_length)
size_mb = size_bytes / (1024 * 1024)
return size_mb <= self.max_size_mb
except:
except Exception:
return True
async def download_video(self, url: str, filename: Optional[str] = None) -> Dict[str, Any]:

View File

@@ -1,6 +1,8 @@
import asyncio
from typing import Any, Callable, Optional
import websockets as Server
from typing import Optional, Callable, Any
from src.common.logger import get_logger
from src.plugin_system.apis import config_api

View File

@@ -6,6 +6,7 @@
"""
import re
from typing import ClassVar
from src.plugin_system.apis.logging_api import get_logger
from src.plugin_system.apis.permission_api import permission_api
@@ -29,7 +30,7 @@ class PermissionCommand(PlusCommand):
command_name = "permission"
command_description = "权限管理命令,支持授权、撤销、查询等功能"
command_aliases = ["perm", "权限"]
command_aliases: ClassVar[list[str]] = ["perm", "权限"]
priority = 10
chat_type_allow = ChatType.ALL
intercept_message = True
@@ -37,7 +38,7 @@ class PermissionCommand(PlusCommand):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
permission_nodes: list[PermissionNodeField] = [
permission_nodes: ClassVar[list[PermissionNodeField]] = [
PermissionNodeField(
node_name="manage",
description="权限管理:可以授权和撤销其他用户的权限",
@@ -382,10 +383,10 @@ class PermissionCommand(PlusCommand):
class PermissionManagerPlugin(BasePlugin):
plugin_name: str = "permission_manager_plugin"
enable_plugin: bool = True
dependencies: list[str] = []
python_dependencies: list[str] = []
dependencies: ClassVar[list[str]] = []
python_dependencies: ClassVar[list[str]] = []
config_file_name: str = "config.toml"
config_schema: dict = {
config_schema: ClassVar[dict] = {
"plugin": {
"enabled": ConfigField(bool, default=True, description="是否启用插件"),
"config_version": ConfigField(type=str, default="1.1.0", description="配置文件版本"),

View File

@@ -1,4 +1,5 @@
import asyncio
from typing import ClassVar
from src.plugin_system import (
BasePlugin,
@@ -21,7 +22,7 @@ class ManagementCommand(PlusCommand):
command_name = "pm"
command_description = "插件管理命令,支持插件和组件的管理操作"
command_aliases = ["pluginmanage", "插件管理"]
command_aliases: ClassVar[list[str]] = ["pluginmanage", "插件管理"]
priority = 10
chat_type_allow = ChatType.ALL
intercept_message = True
@@ -273,6 +274,7 @@ class ManagementCommand(PlusCommand):
def _fetch_all_registered_components() -> list[ComponentInfo]:
all_plugin_info = component_manage_api.get_all_plugin_info()
if not all_plugin_info:
return []
components_info: list[ComponentInfo] = []
@@ -486,10 +488,10 @@ class ManagementCommand(PlusCommand):
class PluginManagementPlugin(BasePlugin):
plugin_name: str = "plugin_management_plugin"
enable_plugin: bool = True
dependencies: list[str] = []
python_dependencies: list[str] = []
dependencies: ClassVar[list[str]] = []
python_dependencies: ClassVar[list[str]] = []
config_file_name: str = "config.toml"
config_schema: dict = {
config_schema: ClassVar[dict] = {
"plugin": {
"enabled": ConfigField(bool, default=False, description="是否启用插件"),
"config_version": ConfigField(type=str, default="1.1.0", description="配置文件版本"),

View File

@@ -152,12 +152,12 @@ class PokeAction(BaseAction):
parallel_action = True
# === 功能描述(必须填写)===
action_parameters = {
action_parameters: ClassVar[dict] = {
"user_name": "需要戳一戳的用户的名字 (可选)",
"user_id": "需要戳一戳的用户的ID (可选,优先级更高)",
"times": "需要戳一戳的次数 (默认为 1)",
}
action_require = ["当需要戳某个用户时使用", "当你想提醒特定用户时使用"]
action_require: ClassVar[list] = ["当需要戳某个用户时使用", "当你想提醒特定用户时使用"]
llm_judge_prompt = """
判定是否需要使用戳一戳动作的条件:
1. **互动时机**: 这是一个有趣的互动方式,可以在想提醒某人,或者单纯想开个玩笑时使用。
@@ -167,7 +167,7 @@ class PokeAction(BaseAction):
请根据上述规则,回答“是”或“否”。
"""
associated_types = ["text"]
associated_types: ClassVar[list[str]] = ["text"]
async def execute(self) -> tuple[bool, str]:
"""执行戳一戳的动作"""
@@ -225,10 +225,10 @@ class SetEmojiLikeAction(BaseAction):
parallel_action = True
# === 功能描述(必须填写)===
action_parameters = {
action_parameters: ClassVar[dict] = {
"set": "是否设置回应 (True/False)",
}
action_require = [
action_require: ClassVar[list] = [
"当需要对一个已存在消息进行‘贴表情’回应时使用",
"这是一个对旧消息的操作,而不是发送新消息",
]
@@ -240,10 +240,10 @@ class SetEmojiLikeAction(BaseAction):
请回答""""
"""
associated_types = ["text"]
associated_types: ClassVar[list[str]] = ["text"]
# 重新启用完整的表情库
emoji_options = []
emoji_options: ClassVar[list] = []
for name in qq_face.values():
match = re.search(r"\[表情:(.+?)\]", name)
if match:
@@ -359,14 +359,14 @@ class RemindAction(BaseAction):
action_name = "set_reminder"
action_description = "根据用户的对话内容,智能地设置一个未来的提醒事项。"
activation_type = ActionActivationType.KEYWORD
activation_keywords = ["提醒", "叫我", "记得", "别忘了"]
activation_keywords: ClassVar[list[str]] = ["提醒", "叫我", "记得", "别忘了"]
chat_type_allow = ChatType.ALL
parallel_action = True
# === LLM 判断与参数提取 ===
llm_judge_prompt = ""
action_parameters = {}
action_require = [
action_parameters: ClassVar[dict] = {}
action_require: ClassVar[list] = [
"当用户请求在未来的某个时间点提醒他/她或别人某件事时使用",
"适用于包含明确时间信息和事件描述的对话",
"例如:'10分钟后提醒我收快递''明天早上九点喊一下李四参加晨会'",
@@ -545,12 +545,12 @@ class SetEmojiLikePlugin(BasePlugin):
# 插件基本信息
plugin_name: str = "social_toolkit_plugin" # 内部标识符
enable_plugin: bool = True
dependencies: list[str] = [] # 插件依赖列表
python_dependencies: list[str] = [] # Python包依赖列表现在使用内置API
dependencies: ClassVar[list[str]] = [] # 插件依赖列表
python_dependencies: ClassVar[list[str]] = [] # Python包依赖列表现在使用内置API
config_file_name: str = "config.toml" # 配置文件名
# 配置节描述
config_section_descriptions = {"plugin": "插件基本信息", "components": "插件组件"}
config_section_descriptions: ClassVar[dict] = {"plugin": "插件基本信息", "components": "插件组件"}
# 配置Schema定义
config_schema: ClassVar[dict] = {

View File

@@ -1,4 +1,5 @@
import asyncio
from typing import ClassVar
import whisper
@@ -19,7 +20,7 @@ class LocalASRTool(BaseTool):
"""
tool_name = "local_asr"
tool_description = "将本地音频文件路径转换为文字。"
tool_parameters = [
tool_parameters: ClassVar[list] = [
{"name": "audio_path", "type": "string", "description": "需要识别的音频文件路径", "required": True}
]
@@ -50,6 +51,7 @@ class LocalASRTool(BaseTool):
async def execute(self, function_args: dict) -> str:
audio_path = function_args.get("audio_path")
if not audio_path:
return "错误:缺少 audio_path 参数。"
global _whisper_model
@@ -78,7 +80,7 @@ class LocalASRTool(BaseTool):
class STTWhisperPlugin(BasePlugin):
plugin_name = "stt_whisper_plugin"
config_file_name = "config.toml"
python_dependencies = ["openai-whisper"]
python_dependencies: ClassVar[list[str]] = ["openai-whisper"]
async def on_plugin_loaded(self):
"""

View File

@@ -1,3 +1,5 @@
from typing import ClassVar
from src.common.logger import get_logger
from src.plugin_system.apis.plugin_register_api import register_plugin
from src.plugin_system.base.base_action import ActionActivationType, BaseAction, ChatMode
@@ -22,16 +24,16 @@ class TTSAction(BaseAction):
action_description = "将文本转换为语音进行播放,适用于需要语音输出的场景"
# 关键词配置 - Normal模式下使用关键词触发
activation_keywords = ["语音", "tts", "播报", "读出来", "语音播放", "", "朗读"]
activation_keywords: ClassVar[list[str]] = ["语音", "tts", "播报", "读出来", "语音播放", "", "朗读"]
keyword_case_sensitive = False
# 动作参数定义
action_parameters = {
action_parameters: ClassVar[dict] = {
"text": "需要转换为语音的文本内容,必填,内容应当适合语音播报,语句流畅、清晰",
}
# 动作使用场景
action_require = [
action_require: ClassVar[list] = [
"当需要发送语音信息时使用",
"当用户要求你说话时使用",
"当用户要求听你声音时使用",
@@ -41,7 +43,7 @@ class TTSAction(BaseAction):
]
# 关联类型
associated_types = ["tts_text"]
associated_types: ClassVar[list[str]] = ["tts_text"]
async def execute(self) -> tuple[bool, str]:
"""处理TTS文本转语音动作"""
@@ -111,19 +113,19 @@ class TTSPlugin(BasePlugin):
# 插件基本信息
plugin_name: str = "tts_plugin" # 内部标识符
enable_plugin: bool = True
dependencies: list[str] = [] # 插件依赖列表
python_dependencies: list[str] = [] # Python包依赖列表
dependencies: ClassVar[list[str]] = [] # 插件依赖列表
python_dependencies: ClassVar[list[str]] = [] # Python包依赖列表
config_file_name: str = "config.toml"
# 配置节描述
config_section_descriptions = {
config_section_descriptions: ClassVar[dict] = {
"plugin": "插件基本信息配置",
"components": "组件启用控制",
"logging": "日志记录相关配置",
}
# 配置Schema定义
config_schema: dict = {
config_schema: ClassVar[dict] = {
"plugin": {
"name": ConfigField(type=str, default="tts_plugin", description="插件名称", required=True),
"version": ConfigField(type=str, default="0.1.0", description="插件版本号"),

View File

@@ -3,6 +3,7 @@ TTS 语音合成 Action
"""
from pathlib import Path
from typing import ClassVar
import toml
@@ -32,6 +33,7 @@ def _get_available_styles() -> list[str]:
styles_config = config.get("tts_styles", [])
if not isinstance(styles_config, list):
return ["default"]
# 使用显式循环和类型检查来提取 style_name以确保 Pylance 类型检查通过
@@ -65,7 +67,7 @@ class TTSVoiceAction(BaseAction):
mode_enable = ChatMode.ALL
parallel_action = False
action_parameters = {
action_parameters: ClassVar[dict] = {
"text": {
"type": "string",
"description": "需要转换为语音并发送的完整、自然、适合口语的文本内容。",
@@ -97,7 +99,7 @@ class TTSVoiceAction(BaseAction):
}
}
action_require = [
action_require: ClassVar[list] = [
"在调用此动作时,你必须在 'text' 参数中提供要合成语音的完整回复内容。这是强制性的。",
"当用户明确请求使用语音进行回复时,例如‘发个语音听听’、‘用语音说’等。",
"当对话内容适合用语音表达,例如讲故事、念诗、撒嬌或进行角色扮演时。",

View File

@@ -1,6 +1,8 @@
"""
TTS 语音合成命令
"""
from typing import ClassVar
from src.common.logger import get_logger
from src.plugin_system.base.command_args import CommandArgs
from src.plugin_system.base.plus_command import PlusCommand
@@ -18,7 +20,7 @@ class TTSVoiceCommand(PlusCommand):
command_name: str = "tts"
command_description: str = "使用GPT-SoVITS将文本转换为语音并发送"
command_aliases = ["语音合成", ""]
command_aliases: ClassVar[list[str]] = ["语音合成", ""]
command_usage = "/tts <要说的文本> [风格]"
def __init__(self, *args, **kwargs):

View File

@@ -2,7 +2,7 @@
TTS Voice 插件 - 重构版
"""
from pathlib import Path
from typing import Any
from typing import Any, ClassVar
import toml
@@ -29,15 +29,15 @@ class TTSVoicePlugin(BasePlugin):
plugin_version = "3.1.2"
plugin_author = "Kilo Code & 靚仔"
config_file_name = "config.toml"
dependencies = []
dependencies: ClassVar[list[str]] = []
permission_nodes: list[PermissionNodeField] = [
permission_nodes: ClassVar[list[PermissionNodeField]] = [
PermissionNodeField(node_name="command.use", description="是否可以使用 /tts 命令"),
]
config_schema = {}
config_schema: ClassVar[dict] = {}
config_section_descriptions = {
config_section_descriptions: ClassVar[dict] = {
"plugin": "插件基本配置",
"components": "组件启用控制",
"tts": "TTS语音合成基础配置",

View File

@@ -67,10 +67,14 @@ class TTSService:
logger.warning("TTS 'default' style is missing 'refer_wav_path'.")
for style_cfg in tts_styles_config:
if not isinstance(style_cfg, dict): continue
if not isinstance(style_cfg, dict):
continue
style_name = style_cfg.get("style_name")
if not style_name: continue
if not style_name:
continue
styles[style_name] = {
"url": global_server,
@@ -158,7 +162,9 @@ class TTSService:
# --- 步骤一:像稳定版一样,先切换模型 ---
async def switch_model_weights(weights_path: str | None, weight_type: str):
if not weights_path: return
if not weights_path:
return
api_endpoint = f"/set_{weight_type}_weights"
switch_url = f"{base_url}{api_endpoint}"
try:
@@ -220,6 +226,7 @@ class TTSService:
try:
effects_config = self.get_config("spatial_effects", {})
if not effects_config.get("enabled", False):
return audio_data
# 获取插件目录和IR文件路径
@@ -251,6 +258,8 @@ class TTSService:
logger.warning(f"卷积混响已启用但IR文件不存在 ({ir_path}),跳过该效果。")
if not effects:
return audio_data
# 将原始音频数据加载到内存中的 AudioFile 对象
@@ -293,7 +302,9 @@ class TTSService:
server_config = self.tts_styles[style]
clean_text = self._clean_text_for_tts(text)
if not clean_text: return None
if not clean_text:
return None
# 语言决策流程:
# 1. 优先使用决策模型直接指定的 language_hint (最高优先级)

View File

@@ -42,6 +42,7 @@ class TavilySearchEngine(BaseSearchEngine):
async def search(self, args: dict[str, Any]) -> list[dict[str, Any]]:
"""执行Tavily搜索"""
if not self.is_available():
return []
query = args["query"]
@@ -76,15 +77,15 @@ class TavilySearchEngine(BaseSearchEngine):
results = []
if search_response and "results" in search_response:
for res in search_response["results"]:
results.append(
{
"title": res.get("title", "无标题"),
"url": res.get("url", ""),
"snippet": res.get("content", "")[:300] + "..." if res.get("content") else "无摘要",
"provider": "Tavily",
}
)
results.extend(
{
"title": res.get("title", "无标题"),
"url": res.get("url", ""),
"snippet": res.get("content", "")[:300] + "..." if res.get("content") else "无摘要",
"provider": "Tavily",
}
for res in search_response["results"]
)
return results

View File

@@ -4,6 +4,8 @@ Web Search Tool Plugin
一个功能强大的网络搜索和URL解析插件支持多种搜索引擎和解析策略。
"""
from typing import ClassVar
from src.common.logger import get_logger
from src.plugin_system import BasePlugin, ComponentInfo, ConfigField, register_plugin
from src.plugin_system.apis import config_api
@@ -30,7 +32,7 @@ class WEBSEARCHPLUGIN(BasePlugin):
# 插件基本信息
plugin_name: str = "web_search_tool" # 内部标识符
enable_plugin: bool = True
dependencies: list[str] = [] # 插件依赖列表
dependencies: ClassVar[list[str]] = [] # 插件依赖列表
def __init__(self, *args, **kwargs):
"""初始化插件,立即加载所有搜索引擎"""
@@ -77,11 +79,11 @@ class WEBSEARCHPLUGIN(BasePlugin):
config_file_name: str = "config.toml" # 配置文件名
# 配置节描述
config_section_descriptions = {"plugin": "插件基本信息", "proxy": "链接本地解析代理配置"}
config_section_descriptions: ClassVar[dict] = {"plugin": "插件基本信息", "proxy": "链接本地解析代理配置"}
# 配置Schema定义
# 注意EXA配置和组件设置已迁移到主配置文件(bot_config.toml)的[exa]和[web_search]部分
config_schema: dict = {
config_schema: ClassVar[dict] = {
"plugin": {
"name": ConfigField(type=str, default="WEB_SEARCH_PLUGIN", description="插件名称"),
"version": ConfigField(type=str, default="1.0.0", description="插件版本"),

View File

@@ -4,7 +4,7 @@ URL parser tool implementation
import asyncio
import functools
from typing import Any
from typing import Any, ClassVar
import httpx
from bs4 import BeautifulSoup
@@ -30,7 +30,7 @@ class URLParserTool(BaseTool):
name: str = "parse_url"
description: str = "当需要理解一个或多个特定网页链接的内容时,使用此工具。例如:'这些网页讲了什么?[https://example.com, https://example2.com]''帮我总结一下这些文章'"
available_for_llm: bool = True
parameters = [
parameters: ClassVar[list] = [
("urls", ToolParamType.STRING, "要理解的网站", True, None),
]
@@ -93,6 +93,8 @@ class URLParserTool(BaseTool):
text = soup.get_text(strip=True)
if not text:
return {"error": "无法从页面提取有效文本内容。"}
summary_prompt = f"请根据以下网页内容生成一段不超过300字的中文摘要保留核心信息和关键点:\n\n---\n\n标题: {title}\n\n内容:\n{text[:4000]}\n\n---\n\n摘要:"
@@ -144,16 +146,19 @@ class URLParserTool(BaseTool):
urls_input = function_args.get("urls")
if not urls_input:
return {"error": "URL列表不能为空。"}
# 处理URL输入确保是列表格式
urls = parse_urls_from_input(urls_input)
if not urls:
return {"error": "提供的字符串中未找到有效的URL。"}
# 验证URL格式
valid_urls = validate_urls(urls)
if not valid_urls:
return {"error": "未找到有效的URL。"}
urls = valid_urls
@@ -226,6 +231,8 @@ class URLParserTool(BaseTool):
successful_results.append(res)
if not successful_results:
return {"error": "无法从所有给定的URL获取内容。", "details": error_messages}
formatted_content = format_url_parse_results(successful_results)

View File

@@ -3,7 +3,7 @@ Web search tool implementation
"""
import asyncio
from typing import Any
from typing import Any, ClassVar
from src.common.cache_manager import tool_cache
from src.common.logger import get_logger
@@ -31,7 +31,7 @@ class WebSurfingTool(BaseTool):
"用于执行网络搜索。当用户明确要求搜索,或者需要获取关于公司、产品、事件的最新信息、新闻或动态时,必须使用此工具"
)
available_for_llm: bool = True
parameters = [
parameters: ClassVar[list] = [
("query", ToolParamType.STRING, "要搜索的关键词或问题。", True, None),
("num_results", ToolParamType.INTEGER, "期望每个搜索引擎返回的搜索结果数量默认为5。", False, None),
(
@@ -58,6 +58,7 @@ class WebSurfingTool(BaseTool):
async def execute(self, function_args: dict[str, Any]) -> dict[str, Any]:
query = function_args.get("query")
if not query:
return {"error": "搜索查询不能为空。"}
# 获取当前文件路径用于缓存键
@@ -105,6 +106,8 @@ class WebSurfingTool(BaseTool):
search_tasks.append(engine.search(custom_args))
if not search_tasks:
return {"error": "没有可用的搜索引擎。"}
try:
@@ -137,6 +140,7 @@ class WebSurfingTool(BaseTool):
for engine_name in enabled_engines:
engine = self.engines.get(engine_name)
if not engine or not engine.is_available():
continue
try:
@@ -163,6 +167,7 @@ class WebSurfingTool(BaseTool):
for engine_name in enabled_engines:
engine = self.engines.get(engine_name)
if not engine or not engine.is_available():
continue
try:

View File

@@ -33,10 +33,10 @@ class APIKeyManager(Generic[T]):
if api_keys:
# 过滤有效的API密钥排除None、空字符串、"None"字符串等
valid_keys = []
for key in api_keys:
if isinstance(key, str) and key.strip() and key.strip().lower() not in ("none", "null", ""):
valid_keys.append(key.strip())
valid_keys = [
key.strip() for key in api_keys
if isinstance(key, str) and key.strip() and key.strip().lower() not in ("none", "null", "")
]
if valid_keys:
try:
@@ -59,6 +59,7 @@ class APIKeyManager(Generic[T]):
def get_next_client(self) -> T | None:
"""获取下一个客户端(轮询)"""
if not self.is_available():
return None
return next(self.client_cycle)

View File

@@ -32,8 +32,4 @@ def validate_urls(urls: list[str]) -> list[str]:
"""
验证URL格式返回有效的URL列表
"""
valid_urls = []
for url in urls:
if url.startswith(("http://", "https://")):
valid_urls.append(url)
return valid_urls
return [url for url in urls if url.startswith(("http://", "https://"))]