Merge branch 'MoFox-Studio:dev' into dev
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "MoFox-Bot"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
description = "MoFox-Bot 是一个基于大语言模型的可交互智能体"
|
||||
requires-python = ">=3.11,<=3.13"
|
||||
dependencies = [
|
||||
|
||||
@@ -93,29 +93,18 @@ class MessageManager:
|
||||
logger.info("消息管理器已停止")
|
||||
|
||||
async def add_message(self, stream_id: str, message: DatabaseMessages):
|
||||
"""添加消息到指定聊天流"""
|
||||
"""添加消息到指定聊天流
|
||||
|
||||
注意:Notice 消息已在 MessageHandler._handle_notice_message 中单独处理,
|
||||
不再经过此方法。此方法仅处理普通消息。
|
||||
"""
|
||||
try:
|
||||
# 检查是否为notice消息
|
||||
if self._is_notice_message(message):
|
||||
# Notice消息处理 - 添加到全局管理器
|
||||
logger.debug(f"检测到notice消息: notice_type={getattr(message, 'notice_type', None)}")
|
||||
await self._handle_notice_message(stream_id, message)
|
||||
|
||||
# 根据配置决定是否继续处理(触发聊天流程)
|
||||
if not global_config.notice.enable_notice_trigger_chat:
|
||||
logger.debug(f"Notice消息将被忽略,不触发聊天流程: {stream_id}")
|
||||
return # 停止处理,不进入未读消息队列
|
||||
else:
|
||||
logger.debug(f"Notice消息将触发聊天流程: {stream_id}")
|
||||
# 继续执行,将消息添加到未读队列
|
||||
|
||||
# 普通消息处理
|
||||
chat_manager = get_chat_manager()
|
||||
chat_stream = await chat_manager.get_stream(stream_id)
|
||||
if not chat_stream:
|
||||
logger.warning(f"MessageManager.add_message: 聊天流 {stream_id} 不存在")
|
||||
return
|
||||
# 启动steam loop任务(如果尚未启动)
|
||||
# 启动 stream loop 任务(如果尚未启动)
|
||||
await stream_loop_manager.start_stream_loop(stream_id)
|
||||
await self._check_and_handle_interruption(chat_stream, message)
|
||||
await chat_stream.context.add_message(message)
|
||||
|
||||
@@ -120,9 +120,6 @@ class MessageHandler:
|
||||
# 注册前置钩子:消息预处理和过滤
|
||||
runtime.register_before_hook(self._before_hook)
|
||||
|
||||
# 注册后置钩子:存储、情绪更新等
|
||||
runtime.register_after_hook(self._after_hook)
|
||||
|
||||
# 注册错误钩子:统一异常处理
|
||||
runtime.register_error_hook(self._error_hook)
|
||||
|
||||
@@ -140,6 +137,24 @@ class MessageHandler:
|
||||
message_type="adapter_response",
|
||||
)
|
||||
|
||||
# 注册 notice 消息处理器(处理通知消息,如戳一戳、禁言等)
|
||||
def _is_notice_message(env: MessageEnvelope) -> bool:
|
||||
"""检查是否为 notice 消息"""
|
||||
message_info = env.get("message_info")
|
||||
if not isinstance(message_info, dict):
|
||||
return False
|
||||
additional_config = message_info.get("additional_config")
|
||||
if isinstance(additional_config, dict):
|
||||
return additional_config.get("is_notice", False)
|
||||
return False
|
||||
|
||||
runtime.add_route(
|
||||
predicate=_is_notice_message,
|
||||
handler=self._handle_notice_message,
|
||||
name="notice_message_handler",
|
||||
message_type="notice",
|
||||
)
|
||||
|
||||
# 注册默认消息处理器(处理所有其他消息)
|
||||
runtime.add_route(
|
||||
predicate=lambda _: True, # 匹配所有消息
|
||||
@@ -204,14 +219,6 @@ class MessageHandler:
|
||||
await MessageStorage.update_message(dict(envelope))
|
||||
raise UserWarning("Echo 消息已处理")
|
||||
|
||||
async def _after_hook(self, envelope: MessageEnvelope) -> None:
|
||||
"""
|
||||
后置钩子:消息后处理
|
||||
|
||||
在消息处理完成后执行的清理工作
|
||||
"""
|
||||
# 后置处理逻辑(如有需要)
|
||||
pass
|
||||
|
||||
async def _error_hook(self, envelope: MessageEnvelope, exc: BaseException) -> None:
|
||||
"""
|
||||
@@ -235,6 +242,165 @@ class MessageHandler:
|
||||
await self._handle_adapter_response(seg_data)
|
||||
return None
|
||||
|
||||
async def _handle_notice_message(self, envelope: MessageEnvelope) -> MessageEnvelope | None:
|
||||
"""
|
||||
Notice 消息专属处理器:处理通知消息(戳一戳、禁言、表情回复等)
|
||||
|
||||
Notice 消息与普通消息不同,它们不需要完整的消息处理链:
|
||||
1. 不触发命令处理
|
||||
2. 存储到数据库
|
||||
3. 添加到全局 Notice 管理器
|
||||
4. 触发 ON_NOTICE_RECEIVED 事件供插件监听
|
||||
"""
|
||||
try:
|
||||
message_info = envelope.get("message_info")
|
||||
if not isinstance(message_info, dict):
|
||||
logger.debug("Notice 消息缺少 message_info,已跳过")
|
||||
return None
|
||||
|
||||
# 获取 notice 配置
|
||||
additional_config = message_info.get("additional_config", {})
|
||||
if not isinstance(additional_config, dict):
|
||||
additional_config = {}
|
||||
|
||||
notice_type = additional_config.get("notice_type", "unknown")
|
||||
is_public_notice = additional_config.get("is_public_notice", False)
|
||||
|
||||
# 获取用户和群组信息
|
||||
group_info = message_info.get("group_info")
|
||||
user_info = message_info.get("user_info")
|
||||
|
||||
if not user_info:
|
||||
logger.debug("Notice 消息缺少用户信息,已跳过")
|
||||
return None
|
||||
|
||||
# 获取或创建聊天流
|
||||
platform = message_info.get("platform", "unknown")
|
||||
|
||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||
chat = await get_chat_manager().get_or_create_stream(
|
||||
platform=platform,
|
||||
user_info=DatabaseUserInfo.from_dict(user_info) if user_info else None, # type: ignore
|
||||
group_info=DatabaseGroupInfo.from_dict(group_info) if group_info else None,
|
||||
)
|
||||
|
||||
# 将消息信封转换为 DatabaseMessages
|
||||
from src.chat.message_receive.message_processor import process_message_from_dict
|
||||
message = await process_message_from_dict(
|
||||
message_dict=envelope,
|
||||
stream_id=chat.stream_id,
|
||||
platform=chat.platform
|
||||
)
|
||||
|
||||
# 填充聊天流时间信息
|
||||
message.chat_info.create_time = chat.create_time
|
||||
message.chat_info.last_active_time = chat.last_active_time
|
||||
|
||||
# 标记为 notice 消息
|
||||
message.is_notify = True
|
||||
message.notice_type = notice_type
|
||||
|
||||
# 打印接收日志
|
||||
chat_name = chat.group_info.group_name if chat.group_info else "私聊"
|
||||
user_nickname = message.user_info.user_nickname if message.user_info else "未知用户"
|
||||
logger.info(f"[Notice][{chat_name}][{notice_type}] {user_nickname}: {message.processed_plain_text}\u001b[0m")
|
||||
|
||||
# 存储消息到数据库
|
||||
await MessageStorage.store_message(message, chat)
|
||||
|
||||
# 添加到全局 Notice 管理器
|
||||
await self._add_notice_to_manager(message, chat.stream_id, is_public_notice, notice_type)
|
||||
|
||||
# 触发 notice 事件(可供插件监听)
|
||||
await event_manager.trigger_event(
|
||||
EventType.ON_NOTICE_RECEIVED,
|
||||
permission_group="USER",
|
||||
message=message,
|
||||
notice_type=notice_type,
|
||||
chat_stream=chat,
|
||||
)
|
||||
|
||||
# 根据配置决定是否触发聊天流程
|
||||
if global_config and global_config.notice and global_config.notice.enable_notice_trigger_chat:
|
||||
logger.debug(f"Notice 消息将触发聊天流程: {chat.stream_id}")
|
||||
# 添加到聊天流上下文,触发正常的消息处理流程
|
||||
from src.chat.message_manager.distribution_manager import stream_loop_manager
|
||||
await stream_loop_manager.start_stream_loop(chat.stream_id)
|
||||
await chat.context.add_message(message)
|
||||
else:
|
||||
logger.debug(f"Notice 消息不触发聊天流程: {chat.stream_id}")
|
||||
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理 Notice 消息时出错: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
async def _add_notice_to_manager(
|
||||
self,
|
||||
message: DatabaseMessages,
|
||||
stream_id: str,
|
||||
is_public_notice: bool,
|
||||
notice_type: str
|
||||
) -> None:
|
||||
"""将 notice 消息添加到全局 Notice 管理器
|
||||
|
||||
Args:
|
||||
message: 数据库消息对象
|
||||
stream_id: 聊天流ID
|
||||
is_public_notice: 是否为公共 notice
|
||||
notice_type: notice 类型
|
||||
"""
|
||||
try:
|
||||
from src.chat.message_manager.global_notice_manager import NoticeScope
|
||||
|
||||
# 确定作用域
|
||||
scope = NoticeScope.PUBLIC if is_public_notice else NoticeScope.STREAM
|
||||
|
||||
# 获取 TTL
|
||||
ttl = self._get_notice_ttl(notice_type)
|
||||
|
||||
# 添加到全局 notice 管理器
|
||||
success = message_manager.notice_manager.add_notice(
|
||||
message=message,
|
||||
scope=scope,
|
||||
target_stream_id=stream_id if scope == NoticeScope.STREAM else None,
|
||||
ttl=ttl
|
||||
)
|
||||
|
||||
if success:
|
||||
logger.debug(
|
||||
f"Notice 消息已添加到全局管理器: message_id={message.message_id}, "
|
||||
f"scope={scope.value}, stream={stream_id}, ttl={ttl}s"
|
||||
)
|
||||
else:
|
||||
logger.warning(f"Notice 消息添加失败: message_id={message.message_id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"添加 notice 到管理器失败: {e}")
|
||||
|
||||
def _get_notice_ttl(self, notice_type: str) -> int:
|
||||
"""根据 notice 类型获取生存时间(秒)
|
||||
|
||||
Args:
|
||||
notice_type: notice 类型
|
||||
|
||||
Returns:
|
||||
int: TTL 秒数
|
||||
"""
|
||||
ttl_mapping = {
|
||||
"poke": 1800, # 戳一戳 30 分钟
|
||||
"emoji_like": 3600, # 表情回复 1 小时
|
||||
"group_ban": 7200, # 禁言 2 小时
|
||||
"group_lift_ban": 7200, # 解禁 2 小时
|
||||
"group_whole_ban": 3600, # 全体禁言 1 小时
|
||||
"group_whole_lift_ban": 3600, # 解除全体禁言 1 小时
|
||||
"group_upload": 3600, # 群文件上传 1 小时
|
||||
}
|
||||
return ttl_mapping.get(notice_type, 3600) # 默认 1 小时
|
||||
|
||||
async def _handle_normal_message(self, envelope: MessageEnvelope) -> MessageEnvelope | None:
|
||||
"""
|
||||
默认消息处理器:处理普通消息
|
||||
@@ -309,6 +475,21 @@ class MessageHandler:
|
||||
# 处理命令和后续流程
|
||||
await self._process_commands(message, chat)
|
||||
|
||||
# 触发消息事件
|
||||
result = await event_manager.trigger_event(
|
||||
EventType.ON_MESSAGE,
|
||||
permission_group="SYSTEM",
|
||||
message=message
|
||||
)
|
||||
if result and not result.all_continue_process():
|
||||
raise UserWarning(
|
||||
f"插件{result.get_summary().get('stopped_handlers', '')}于消息到达时取消了消息处理"
|
||||
)
|
||||
|
||||
# 预处理消息
|
||||
await self._preprocess_message(message, chat)
|
||||
|
||||
|
||||
except UserWarning as uw:
|
||||
logger.info(str(uw))
|
||||
except Exception as e:
|
||||
@@ -317,22 +498,6 @@ class MessageHandler:
|
||||
|
||||
return None
|
||||
|
||||
# 保留旧的 process_message 方法用于向后兼容
|
||||
async def process_message(self, envelope: MessageEnvelope) -> None:
|
||||
"""
|
||||
处理接收到的消息信封(向后兼容)
|
||||
|
||||
注意:此方法已被 MessageRuntime 路由取代。
|
||||
如果直接调用此方法,它会委托给 runtime.handle_message()。
|
||||
|
||||
Args:
|
||||
envelope: 消息信封(来自适配器)
|
||||
"""
|
||||
if self._runtime:
|
||||
await self._runtime.handle_message(envelope)
|
||||
else:
|
||||
# 如果 runtime 未设置,使用旧的处理流程
|
||||
await self._handle_normal_message(envelope)
|
||||
|
||||
async def _process_commands(self, message: DatabaseMessages, chat: "ChatStream") -> None:
|
||||
"""处理命令和继续消息流程"""
|
||||
@@ -354,20 +519,6 @@ class MessageHandler:
|
||||
logger.info(f"命令处理完成,跳过后续消息处理: {cmd_result}")
|
||||
return
|
||||
|
||||
# 触发消息事件
|
||||
result = await event_manager.trigger_event(
|
||||
EventType.ON_MESSAGE,
|
||||
permission_group="SYSTEM",
|
||||
message=message
|
||||
)
|
||||
if result and not result.all_continue_process():
|
||||
raise UserWarning(
|
||||
f"插件{result.get_summary().get('stopped_handlers', '')}于消息到达时取消了消息处理"
|
||||
)
|
||||
|
||||
# 预处理消息
|
||||
await self._preprocess_message(message, chat)
|
||||
|
||||
except UserWarning as uw:
|
||||
logger.info(str(uw))
|
||||
except Exception as e:
|
||||
|
||||
@@ -84,11 +84,12 @@ async def check_and_migrate_database(existing_engine=None):
|
||||
|
||||
try:
|
||||
# 检查并添加缺失的列
|
||||
db_columns = await connection.run_sync(
|
||||
db_columns_info = await connection.run_sync(
|
||||
lambda conn: {
|
||||
col["name"] for col in inspector.get_columns(table_name)
|
||||
col["name"]: col for col in inspector.get_columns(table_name)
|
||||
}
|
||||
)
|
||||
db_columns = set(db_columns_info.keys())
|
||||
model_columns = {col.name for col in table.c}
|
||||
missing_columns = model_columns - db_columns
|
||||
|
||||
@@ -144,7 +145,12 @@ async def check_and_migrate_database(existing_engine=None):
|
||||
# 提交列添加事务
|
||||
await connection.commit()
|
||||
else:
|
||||
logger.info(f"表 '{table_name}' 的列结构一致。")
|
||||
logger.debug(f"表 '{table_name}' 的列结构一致。")
|
||||
|
||||
# 3. 检查并修复列类型不匹配(仅 PostgreSQL)
|
||||
await _check_and_fix_column_types(
|
||||
connection, inspector, table_name, table, db_columns_info
|
||||
)
|
||||
|
||||
# 检查并创建缺失的索引
|
||||
db_indexes = await connection.run_sync(
|
||||
@@ -225,3 +231,126 @@ async def drop_all_tables(existing_engine=None):
|
||||
await connection.run_sync(Base.metadata.drop_all)
|
||||
|
||||
logger.warning("所有数据库表已删除。")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 列类型修复辅助函数
|
||||
# =============================================================================
|
||||
|
||||
# 已知需要修复的列类型映射
|
||||
# 格式: {(表名, 列名): (期望的Python类型类别, PostgreSQL USING 子句)}
|
||||
# Python类型类别: "boolean", "integer", "float", "string"
|
||||
_BOOLEAN_USING_CLAUSE = (
|
||||
"boolean",
|
||||
"USING CASE WHEN {column} IS NULL THEN FALSE "
|
||||
"WHEN {column} = 0 THEN FALSE ELSE TRUE END"
|
||||
)
|
||||
|
||||
_COLUMN_TYPE_FIXES = {
|
||||
# messages 表的布尔列
|
||||
("messages", "is_public_notice"): _BOOLEAN_USING_CLAUSE,
|
||||
("messages", "should_reply"): _BOOLEAN_USING_CLAUSE,
|
||||
("messages", "should_act"): _BOOLEAN_USING_CLAUSE,
|
||||
("messages", "is_mentioned"): _BOOLEAN_USING_CLAUSE,
|
||||
("messages", "is_emoji"): _BOOLEAN_USING_CLAUSE,
|
||||
("messages", "is_picid"): _BOOLEAN_USING_CLAUSE,
|
||||
("messages", "is_command"): _BOOLEAN_USING_CLAUSE,
|
||||
("messages", "is_notify"): _BOOLEAN_USING_CLAUSE,
|
||||
}
|
||||
|
||||
|
||||
def _get_expected_pg_type(python_type_category: str) -> str:
|
||||
"""获取期望的 PostgreSQL 类型名称"""
|
||||
mapping = {
|
||||
"boolean": "boolean",
|
||||
"integer": "integer",
|
||||
"float": "double precision",
|
||||
"string": "text",
|
||||
}
|
||||
return mapping.get(python_type_category, "text")
|
||||
|
||||
|
||||
def _normalize_pg_type(type_name: str) -> str:
|
||||
"""标准化 PostgreSQL 类型名称用于比较"""
|
||||
type_name = type_name.lower().strip()
|
||||
# 处理常见的别名
|
||||
aliases = {
|
||||
"bool": "boolean",
|
||||
"int": "integer",
|
||||
"int4": "integer",
|
||||
"int8": "bigint",
|
||||
"float8": "double precision",
|
||||
"float4": "real",
|
||||
"numeric": "numeric",
|
||||
"decimal": "numeric",
|
||||
}
|
||||
return aliases.get(type_name, type_name)
|
||||
|
||||
|
||||
async def _check_and_fix_column_types(connection, inspector, table_name, table, db_columns_info):
|
||||
"""检查并修复列类型不匹配的问题(仅 PostgreSQL)
|
||||
|
||||
Args:
|
||||
connection: 数据库连接
|
||||
inspector: SQLAlchemy inspector
|
||||
table_name: 表名
|
||||
table: SQLAlchemy Table 对象
|
||||
db_columns_info: 数据库中列的信息字典
|
||||
"""
|
||||
# 获取数据库方言
|
||||
def get_dialect_name(conn):
|
||||
return conn.dialect.name
|
||||
|
||||
dialect_name = await connection.run_sync(get_dialect_name)
|
||||
|
||||
# 目前只处理 PostgreSQL
|
||||
if dialect_name != "postgresql":
|
||||
return
|
||||
|
||||
for (fix_table, fix_column), (expected_type_category, using_clause) in _COLUMN_TYPE_FIXES.items():
|
||||
if fix_table != table_name:
|
||||
continue
|
||||
|
||||
if fix_column not in db_columns_info:
|
||||
continue
|
||||
|
||||
col_info = db_columns_info[fix_column]
|
||||
current_type = _normalize_pg_type(str(col_info.get("type", "")))
|
||||
expected_type = _get_expected_pg_type(expected_type_category)
|
||||
|
||||
# 如果类型已经正确,跳过
|
||||
if current_type == expected_type:
|
||||
continue
|
||||
|
||||
# 检查是否需要修复:如果当前是 numeric 但期望是 boolean
|
||||
if current_type == "numeric" and expected_type == "boolean":
|
||||
logger.warning(
|
||||
f"发现列类型不匹配: {table_name}.{fix_column} "
|
||||
f"(当前: {current_type}, 期望: {expected_type})"
|
||||
)
|
||||
|
||||
# PostgreSQL 需要先删除默认值,再修改类型,最后重新设置默认值
|
||||
using_sql = using_clause.format(column=fix_column)
|
||||
drop_default_sql = f"ALTER TABLE {table_name} ALTER COLUMN {fix_column} DROP DEFAULT"
|
||||
alter_type_sql = f"ALTER TABLE {table_name} ALTER COLUMN {fix_column} TYPE BOOLEAN {using_sql}"
|
||||
set_default_sql = f"ALTER TABLE {table_name} ALTER COLUMN {fix_column} SET DEFAULT FALSE"
|
||||
|
||||
try:
|
||||
def execute_alter(conn):
|
||||
# 步骤 1: 删除默认值
|
||||
try:
|
||||
conn.execute(text(drop_default_sql))
|
||||
except Exception:
|
||||
pass # 如果没有默认值,忽略错误
|
||||
# 步骤 2: 修改类型
|
||||
conn.execute(text(alter_type_sql))
|
||||
# 步骤 3: 重新设置默认值
|
||||
conn.execute(text(set_default_sql))
|
||||
|
||||
await connection.run_sync(execute_alter)
|
||||
await connection.commit()
|
||||
logger.info(f"成功修复列类型: {table_name}.{fix_column} -> BOOLEAN")
|
||||
except Exception as e:
|
||||
logger.error(f"修复列类型失败 {table_name}.{fix_column}: {e}")
|
||||
await connection.rollback()
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ class EventType(Enum):
|
||||
ON_START = "on_start" # 启动事件,用于调用按时任务
|
||||
ON_STOP = "on_stop"
|
||||
ON_MESSAGE = "on_message"
|
||||
ON_NOTICE_RECEIVED = "on_notice_received" # Notice 消息事件(戳一戳、禁言等)
|
||||
ON_PLAN = "on_plan"
|
||||
POST_LLM = "post_llm"
|
||||
AFTER_LLM = "after_llm"
|
||||
|
||||
@@ -99,8 +99,47 @@ class NapcatAdapter(BaseAdapter):
|
||||
self.meta_event_handler.set_plugin_config(self.plugin.config)
|
||||
self.send_handler.set_plugin_config(self.plugin.config)
|
||||
|
||||
# 注册 notice 事件到 event manager
|
||||
await self._register_notice_events()
|
||||
|
||||
logger.info("Napcat 适配器已加载")
|
||||
|
||||
async def _register_notice_events(self) -> None:
|
||||
"""注册 notice 相关事件到 event manager"""
|
||||
from src.plugin_system.core.event_manager import event_manager
|
||||
from .src.event_types import NapcatEvent
|
||||
|
||||
# 定义所有 notice 事件类型
|
||||
notice_events = [
|
||||
NapcatEvent.ON_RECEIVED.POKE,
|
||||
NapcatEvent.ON_RECEIVED.EMOJI_LIEK,
|
||||
NapcatEvent.ON_RECEIVED.GROUP_UPLOAD,
|
||||
NapcatEvent.ON_RECEIVED.GROUP_BAN,
|
||||
NapcatEvent.ON_RECEIVED.GROUP_LIFT_BAN,
|
||||
NapcatEvent.ON_RECEIVED.FRIEND_RECALL,
|
||||
NapcatEvent.ON_RECEIVED.GROUP_RECALL,
|
||||
NapcatEvent.ON_RECEIVED.FRIEND_INPUT,
|
||||
]
|
||||
|
||||
# 注册所有事件
|
||||
registered_count = 0
|
||||
for event_type in notice_events:
|
||||
try:
|
||||
# 使用同步的 register_event 方法注册事件
|
||||
success = event_manager.register_event(
|
||||
event_name=event_type,
|
||||
allowed_triggers=["napcat_adapter_plugin"], # 只允许此插件触发
|
||||
)
|
||||
if success:
|
||||
registered_count += 1
|
||||
logger.debug(f"已注册 notice 事件: {event_type}")
|
||||
else:
|
||||
logger.debug(f"notice 事件已存在: {event_type}")
|
||||
except Exception as e:
|
||||
logger.warning(f"注册 notice 事件失败: {event_type}, 错误: {e}")
|
||||
|
||||
logger.info(f"已注册 {registered_count} 个新 notice 事件类型(共 {len(notice_events)} 个)")
|
||||
|
||||
async def on_adapter_unloaded(self) -> None:
|
||||
"""适配器卸载时的清理"""
|
||||
logger.info("Napcat 适配器正在关闭...")
|
||||
@@ -133,22 +172,28 @@ class NapcatAdapter(BaseAdapter):
|
||||
if not future.done():
|
||||
future.set_result(raw)
|
||||
|
||||
# 消息事件
|
||||
if post_type == "message":
|
||||
return await self.message_handler.handle_raw_message(raw) # type: ignore[return-value]
|
||||
try:
|
||||
# 消息事件
|
||||
if post_type == "message":
|
||||
return await self.message_handler.handle_raw_message(raw) # type: ignore[return-value]
|
||||
# 通知事件
|
||||
elif post_type == "notice":
|
||||
return await self.notice_handler.handle_notice(raw) # type: ignore[return-value]
|
||||
|
||||
# 通知事件
|
||||
elif post_type == "notice":
|
||||
return await self.notice_handler.handle_notice(raw) # type: ignore[return-value]
|
||||
|
||||
# 元事件
|
||||
elif post_type == "meta_event":
|
||||
return await self.meta_event_handler.handle_meta_event(raw) # type: ignore[return-value]
|
||||
|
||||
# 未知事件类型
|
||||
else:
|
||||
return
|
||||
# 元事件
|
||||
elif post_type == "meta_event":
|
||||
return await self.meta_event_handler.handle_meta_event(raw) # type: ignore[return-value]
|
||||
|
||||
# 未知事件类型
|
||||
else:
|
||||
return None
|
||||
except ValueError as ve:
|
||||
logger.warning(f"处理 Napcat 事件时数据无效: {ve}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"处理 Napcat 事件失败: {e}, 原始数据: {raw}")
|
||||
return None
|
||||
|
||||
async def _send_platform_message(self, envelope: MessageEnvelope) -> None: # type: ignore[override]
|
||||
"""
|
||||
将 MessageEnvelope 转换并发送到 Napcat
|
||||
@@ -156,7 +201,10 @@ class NapcatAdapter(BaseAdapter):
|
||||
这里不直接通过 WebSocket 发送 envelope,
|
||||
而是调用 Napcat API(send_group_msg, send_private_msg 等)
|
||||
"""
|
||||
await self.send_handler.handle_message(envelope)
|
||||
try:
|
||||
await self.send_handler.handle_message(envelope)
|
||||
except Exception as e:
|
||||
logger.error(f"发送 Napcat 消息失败: {e}")
|
||||
|
||||
async def send_napcat_api(self, action: str, params: Dict[str, Any], timeout: float = 30.0) -> Dict[str, Any]:
|
||||
"""
|
||||
@@ -265,6 +313,10 @@ class NapcatAdapterPlugin(BasePlugin):
|
||||
"private_list": ConfigField(type=list, default=[], description="私聊名单;根据名单模式过滤"),
|
||||
"ban_user_id": ConfigField(type=list, default=[], description="全局封禁的用户 ID 列表"),
|
||||
"ban_qq_bot": ConfigField(type=bool, default=False, description="是否屏蔽其他 QQ 机器人消息"),
|
||||
"enable_poke": ConfigField(type=bool, default=True, description="是否启用戳一戳消息处理"),
|
||||
"ignore_non_self_poke": ConfigField(type=bool, default=False, description="是否忽略不是针对自己的戳一戳消息"),
|
||||
"poke_debounce_seconds": ConfigField(type=float, default=2.0, description="戳一戳防抖时间(秒)"),
|
||||
"enable_emoji_like": ConfigField(type=bool, default=True, description="是否启用群聊表情回复处理"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ ACCEPT_FORMAT = [
|
||||
]
|
||||
|
||||
# 插件名称
|
||||
PLUGIN_NAME = "NEW_napcat_adapter"
|
||||
PLUGIN_NAME = "napcat_adapter_plugin"
|
||||
|
||||
# QQ表情映射表
|
||||
QQ_FACE = {
|
||||
|
||||
@@ -210,8 +210,9 @@ class NoticeHandler:
|
||||
msg_builder.seg_list([handled_segment])
|
||||
|
||||
# 设置 additional_config(包含 notice 相关配置)
|
||||
res = msg_builder.build()["message_info"]["additional_config"] = notice_config
|
||||
return res
|
||||
envelope = msg_builder.build()
|
||||
envelope["message_info"]["additional_config"] = notice_config
|
||||
return envelope
|
||||
|
||||
async def _handle_poke_notify(
|
||||
self, raw: Dict[str, Any], group_id: Any, user_id: Any
|
||||
|
||||
Reference in New Issue
Block a user