""" Bot 抽象模块 定义了 Bot 类,封装了 OneBot API 的调用逻辑,提供了便捷的消息发送方法。 """ from typing import TYPE_CHECKING, Union, List if TYPE_CHECKING: from .ws import WS from models import OneBotEvent, MessageSegment class Bot: """ Bot 抽象类,封装 API 调用和常用操作 """ def __init__(self, ws_client: "WS"): """ 初始化 Bot 实例 :param ws_client: WebSocket 客户端实例,用于底层通信 """ self.ws = ws_client async def call_api(self, action: str, params: dict = None) -> dict: """ 调用 OneBot API :param action: API 动作名称 :param params: API 参数 :return: API 响应结果 """ return await self.ws.call_api(action, params) async def send_group_msg(self, group_id: int, message: Union[str, "MessageSegment", List["MessageSegment"]], auto_escape: bool = False) -> dict: """ 发送群消息 :param group_id: 群号 :param message: 消息内容,可以是字符串、MessageSegment 对象或 MessageSegment 列表 :param auto_escape: 是否自动转义(仅当 message 为字符串时有效) :return: API 响应结果 """ return await self.call_api( "send_group_msg", {"group_id": group_id, "message": self._process_message(message), "auto_escape": auto_escape} ) async def send_private_msg(self, user_id: int, message: Union[str, "MessageSegment", List["MessageSegment"]], auto_escape: bool = False) -> dict: """ 发送私聊消息 :param user_id: 用户 QQ 号 :param message: 消息内容,可以是字符串、MessageSegment 对象或 MessageSegment 列表 :param auto_escape: 是否自动转义(仅当 message 为字符串时有效) :return: API 响应结果 """ return await self.call_api( "send_private_msg", {"user_id": user_id, "message": self._process_message(message), "auto_escape": auto_escape} ) async def send(self, event: "OneBotEvent", message: Union[str, "MessageSegment", List["MessageSegment"]], auto_escape: bool = False) -> dict: """ 智能发送消息,根据事件类型自动选择发送方式 :param event: 触发事件对象 :param message: 消息内容 :param auto_escape: 是否自动转义 :return: API 响应结果 """ # 如果是消息事件,直接调用 reply if hasattr(event, "reply"): await event.reply(message, auto_escape) return {"status": "ok", "msg": "Replied via event.reply()"} # 尝试从事件中获取 user_id 或 group_id user_id = getattr(event, "user_id", None) group_id = getattr(event, "group_id", None) if group_id: return await self.send_group_msg(group_id, message, auto_escape) elif user_id: return await self.send_private_msg(user_id, message, auto_escape) return {"status": "failed", "msg": "Unknown message target"} async def delete_msg(self, message_id: int) -> dict: """ 撤回消息 :param message_id: 消息 ID :return: API 响应结果 """ return await self.call_api("delete_msg", {"message_id": message_id}) async def get_msg(self, message_id: int) -> dict: """ 获取消息 :param message_id: 消息 ID :return: API 响应结果 """ return await self.call_api("get_msg", {"message_id": message_id}) async def get_forward_msg(self, id: str) -> dict: """ 获取合并转发消息 :param id: 合并转发 ID :return: API 响应结果 """ return await self.call_api("get_forward_msg", {"id": id}) async def send_like(self, user_id: int, times: int = 1) -> dict: """ 发送点赞 :param user_id: 对方 QQ 号 :param times: 点赞次数 :return: API 响应结果 """ return await self.call_api("send_like", {"user_id": user_id, "times": times}) async def set_group_kick(self, group_id: int, user_id: int, reject_add_request: bool = False) -> dict: """ 群组踢人 :param group_id: 群号 :param user_id: 要踢的 QQ 号 :param reject_add_request: 拒绝此人的加群请求 :return: API 响应结果 """ return await self.call_api("set_group_kick", {"group_id": group_id, "user_id": user_id, "reject_add_request": reject_add_request}) async def set_group_ban(self, group_id: int, user_id: int, duration: int = 30 * 60) -> dict: """ 群组单人禁言 :param group_id: 群号 :param user_id: 要禁言的 QQ 号 :param duration: 禁言时长(秒),0 表示解除禁言 :return: API 响应结果 """ return await self.call_api("set_group_ban", {"group_id": group_id, "user_id": user_id, "duration": duration}) async def set_group_anonymous_ban(self, group_id: int, anonymous: dict = None, duration: int = 30 * 60, flag: str = None) -> dict: """ 群组匿名禁言 :param group_id: 群号 :param anonymous: 可选,要禁言的匿名用户对象(群消息事件的 anonymous 字段) :param duration: 禁言时长(秒) :param flag: 可选,要禁言的匿名用户的 flag(需从群消息事件的 anonymous 字段中获取) :return: API 响应结果 """ params = {"group_id": group_id, "duration": duration} if anonymous: params["anonymous"] = anonymous if flag: params["flag"] = flag return await self.call_api("set_group_anonymous_ban", params) async def set_group_whole_ban(self, group_id: int, enable: bool = True) -> dict: """ 群组全员禁言 :param group_id: 群号 :param enable: 是否开启 :return: API 响应结果 """ return await self.call_api("set_group_whole_ban", {"group_id": group_id, "enable": enable}) async def set_group_admin(self, group_id: int, user_id: int, enable: bool = True) -> dict: """ 群组设置管理员 :param group_id: 群号 :param user_id: 要设置的 QQ 号 :param enable: True 为设置,False 为取消 :return: API 响应结果 """ return await self.call_api("set_group_admin", {"group_id": group_id, "user_id": user_id, "enable": enable}) async def set_group_anonymous(self, group_id: int, enable: bool = True) -> dict: """ 群组匿名 :param group_id: 群号 :param enable: 是否开启 :return: API 响应结果 """ return await self.call_api("set_group_anonymous", {"group_id": group_id, "enable": enable}) async def set_group_card(self, group_id: int, user_id: int, card: str = "") -> dict: """ 设置群名片(群备注) :param group_id: 群号 :param user_id: 要设置的 QQ 号 :param card: 群名片内容,不填或空字符串表示删除群名片 :return: API 响应结果 """ return await self.call_api("set_group_card", {"group_id": group_id, "user_id": user_id, "card": card}) async def set_group_name(self, group_id: int, group_name: str) -> dict: """ 设置群名 :param group_id: 群号 :param group_name: 新群名 :return: API 响应结果 """ return await self.call_api("set_group_name", {"group_id": group_id, "group_name": group_name}) async def set_group_leave(self, group_id: int, is_dismiss: bool = False) -> dict: """ 退出群组 :param group_id: 群号 :param is_dismiss: 是否解散,如果登录号是群主,则仅在此项为 True 时能够解散 :return: API 响应结果 """ return await self.call_api("set_group_leave", {"group_id": group_id, "is_dismiss": is_dismiss}) async def set_group_special_title(self, group_id: int, user_id: int, special_title: str = "", duration: int = -1) -> dict: """ 设置群组专属头衔 :param group_id: 群号 :param user_id: 要设置的 QQ 号 :param special_title: 专属头衔,不填或空字符串表示删除 :param duration: 有效期(秒),-1 表示永久 :return: API 响应结果 """ return await self.call_api("set_group_special_title", {"group_id": group_id, "user_id": user_id, "special_title": special_title, "duration": duration}) async def get_group_info(self, group_id: int, no_cache: bool = False) -> dict: """ 获取群信息 :param group_id: 群号 :param no_cache: 是否不使用缓存 :return: API 响应结果 """ return await self.call_api("get_group_info", {"group_id": group_id, "no_cache": no_cache}) async def get_group_list(self) -> dict: """ 获取群列表 :return: API 响应结果 """ return await self.call_api("get_group_list") async def get_group_member_info(self, group_id: int, user_id: int, no_cache: bool = False) -> dict: """ 获取群成员信息 :param group_id: 群号 :param user_id: QQ 号 :param no_cache: 是否不使用缓存 :return: API 响应结果 """ return await self.call_api("get_group_member_info", {"group_id": group_id, "user_id": user_id, "no_cache": no_cache}) async def get_group_member_list(self, group_id: int) -> dict: """ 获取群成员列表 :param group_id: 群号 :return: API 响应结果 """ return await self.call_api("get_group_member_list", {"group_id": group_id}) async def get_group_honor_info(self, group_id: int, type: str) -> dict: """ 获取群荣誉信息 :param group_id: 群号 :param type: 要获取的群荣誉类型,可传入 talkative, performer, legend, strong_newbie, emotion 等 :return: API 响应结果 """ return await self.call_api("get_group_honor_info", {"group_id": group_id, "type": type}) async def get_login_info(self) -> dict: """ 获取登录号信息 :return: API 响应结果 """ return await self.call_api("get_login_info") async def get_stranger_info(self, user_id: int, no_cache: bool = False) -> dict: """ 获取陌生人信息 :param user_id: QQ 号 :param no_cache: 是否不使用缓存 :return: API 响应结果 """ return await self.call_api("get_stranger_info", {"user_id": user_id, "no_cache": no_cache}) async def get_friend_list(self) -> dict: """ 获取好友列表 :return: API 响应结果 """ return await self.call_api("get_friend_list") async def set_friend_add_request(self, flag: str, approve: bool = True, remark: str = "") -> dict: """ 处理加好友请求 :param flag: 加好友请求的 flag(需从上报的数据中获取) :param approve: 是否同意请求 :param remark: 添加后的好友备注(仅在同意时有效) :return: API 响应结果 """ return await self.call_api("set_friend_add_request", {"flag": flag, "approve": approve, "remark": remark}) async def set_group_add_request(self, flag: str, sub_type: str, approve: bool = True, reason: str = "") -> dict: """ 处理加群请求/邀请 :param flag: 加群请求的 flag(需从上报的数据中获取) :param sub_type: add 或 invite,请求类型(需要与上报消息中的 sub_type 字段相符) :param approve: 是否同意请求/邀请 :param reason: 拒绝理由(仅在拒绝时有效) :return: API 响应结果 """ return await self.call_api("set_group_add_request", {"flag": flag, "sub_type": sub_type, "approve": approve, "reason": reason}) async def get_version_info(self) -> dict: """ 获取版本信息 :return: API 响应结果 """ return await self.call_api("get_version_info") async def get_status(self) -> dict: """ 获取状态 :return: API 响应结果 """ return await self.call_api("get_status") async def can_send_image(self) -> dict: """ 检查是否可以发送图片 :return: API 响应结果 """ return await self.call_api("can_send_image") async def can_send_record(self) -> dict: """ 检查是否可以发送语音 :return: API 响应结果 """ return await self.call_api("can_send_record") async def clean_cache(self) -> dict: """ 清理缓存 :return: API 响应结果 """ return await self.call_api("clean_cache") def _process_message(self, message: Union[str, "MessageSegment", List["MessageSegment"]]) -> Union[str, List[dict]]: """ 处理消息内容,将其转换为 API 可接受的格式 :param message: 原始消息内容 :return: 处理后的消息内容 """ if isinstance(message, str): return message # 避免循环导入,在运行时导入 from models import MessageSegment if isinstance(message, MessageSegment): return [self._segment_to_dict(message)] if isinstance(message, list): return [self._segment_to_dict(m) for m in message if isinstance(m, MessageSegment)] return str(message) def _segment_to_dict(self, segment: "MessageSegment") -> dict: """ 将 MessageSegment 对象转换为字典 :param segment: MessageSegment 对象 :return: 字典格式的消息段 """ return { "type": segment.type, "data": segment.data }