Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 344f92e0e7 | |||
| fdabfef6a7 | |||
| 6c5718f134 |
+1
-1
@@ -8,5 +8,5 @@ configs/config.yaml
|
||||
temp
|
||||
cmd_config.json
|
||||
addons/plugins/
|
||||
data/
|
||||
data/*
|
||||
cookies.json
|
||||
|
||||
+3
-4
@@ -22,7 +22,6 @@ from nakuru import (
|
||||
from nakuru.entities.components import Plain, At, Image
|
||||
|
||||
from addons.baidu_aip_judge import BaiduJudge
|
||||
from model.platform._nakuru_translation_layer import NakuruGuildMessage
|
||||
from model.provider.provider import Provider
|
||||
from model.command.command import Command
|
||||
from util import general_utils as gu
|
||||
@@ -44,7 +43,7 @@ frequency_time = 60
|
||||
frequency_count = 10
|
||||
|
||||
# 版本
|
||||
version = '3.1.8'
|
||||
version = '3.1.10'
|
||||
|
||||
# 语言模型
|
||||
REV_CHATGPT = 'rev_chatgpt'
|
||||
@@ -307,7 +306,7 @@ async def record_message(platform: str, session_id: str):
|
||||
db_inst.increment_stat_platform(curr_ts, platform, 1)
|
||||
_global_object.cnt_total += 1
|
||||
|
||||
async def oper_msg(message: Union[GroupMessage, FriendMessage, GuildMessage, NakuruGuildMessage],
|
||||
async def oper_msg(message: AstrBotMessage,
|
||||
session_id: str,
|
||||
role: str = 'member',
|
||||
platform: str = None,
|
||||
@@ -346,7 +345,7 @@ async def oper_msg(message: Union[GroupMessage, FriendMessage, GuildMessage, Nak
|
||||
return MessageResult("Hi~")
|
||||
|
||||
# 检查发言频率
|
||||
if not check_frequency(message.user_id):
|
||||
if not check_frequency(message.sender.user_id):
|
||||
return MessageResult(f'你的发言超过频率限制(╯▔皿▔)╯。\n管理员设置{frequency_time}秒内只能提问{frequency_count}次。')
|
||||
|
||||
# 检查是否是更换语言模型的请求
|
||||
|
||||
+31
-3
@@ -1,4 +1,3 @@
|
||||
from model.platform.qq_official import NakuruGuildMessage
|
||||
from model.provider.provider import Provider as LLMProvider
|
||||
from model.platform._platfrom import Platform
|
||||
from nakuru import (
|
||||
@@ -6,11 +5,40 @@ from nakuru import (
|
||||
FriendMessage,
|
||||
GuildMessage,
|
||||
)
|
||||
from nakuru.entities.components import BaseMessageComponent
|
||||
from typing import Union, List, ClassVar
|
||||
from types import ModuleType
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
|
||||
class MessageType(Enum):
|
||||
GROUP_MESSAGE = 'GroupMessage' # 群组形式的消息
|
||||
FRIEND_MESSAGE = 'FriendMessage' # 私聊、好友等单聊消息
|
||||
GUILD_MESSAGE = 'GuildMessage' # 频道消息
|
||||
|
||||
@dataclass
|
||||
class MessageMember():
|
||||
user_id: str # 发送者id
|
||||
nickname: str = None
|
||||
|
||||
class AstrBotMessage():
|
||||
'''
|
||||
AstrBot 的消息对象
|
||||
'''
|
||||
tag: str # 消息来源标签
|
||||
type: MessageType # 消息类型
|
||||
self_id: str # 机器人的识别id
|
||||
session_id: str # 会话id
|
||||
message_id: str # 消息id
|
||||
sender: MessageMember # 发送者
|
||||
message: List[BaseMessageComponent] # 消息链使用 Nakuru 的消息链格式
|
||||
message_str: str # 最直观的纯文本消息字符串
|
||||
raw_message: object
|
||||
timestamp: int # 消息时间戳
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.__dict__)
|
||||
|
||||
class PluginType(Enum):
|
||||
PLATFORM = 'platfrom' # 平台类插件。
|
||||
LLM = 'llm' # 大语言模型类插件
|
||||
@@ -107,14 +135,14 @@ class AstrMessageEvent():
|
||||
'''
|
||||
context: GlobalObject # 一些公用数据
|
||||
message_str: str # 纯消息字符串
|
||||
message_obj: Union[GroupMessage, FriendMessage, GuildMessage, NakuruGuildMessage] # 消息对象
|
||||
message_obj: AstrBotMessage # 消息对象
|
||||
platform: RegisteredPlatform # 来源平台
|
||||
role: str # 基本身份。`admin` 或 `member`
|
||||
session_id: int # 会话 id
|
||||
|
||||
def __init__(self,
|
||||
message_str: str,
|
||||
message_obj: Union[GroupMessage, FriendMessage, GuildMessage, NakuruGuildMessage],
|
||||
message_obj: AstrBotMessage,
|
||||
platform: RegisteredPlatform,
|
||||
role: str,
|
||||
context: GlobalObject,
|
||||
|
||||
@@ -49,7 +49,7 @@ class CommandOpenAIOfficial(Command):
|
||||
elif self.command_start_with(message, "update"):
|
||||
return True, self.update(message, role)
|
||||
elif self.command_start_with(message, "画", "draw"):
|
||||
return True, self.draw(message)
|
||||
return True, await self.draw(message)
|
||||
elif self.command_start_with(message, "key"):
|
||||
return True, self.key(message)
|
||||
elif self.command_start_with(message, "switch"):
|
||||
@@ -256,7 +256,7 @@ class CommandOpenAIOfficial(Command):
|
||||
self.personality_str = message
|
||||
return True, f"自定义人格已设置。 \n人格信息: {ps}", "set"
|
||||
|
||||
def draw(self, message):
|
||||
async def draw(self, message):
|
||||
if self.provider is None:
|
||||
return False, "未启用 OpenAI 官方 API", "draw"
|
||||
if message.startswith("/画"):
|
||||
@@ -265,7 +265,7 @@ class CommandOpenAIOfficial(Command):
|
||||
message = message[1:]
|
||||
try:
|
||||
# 画图模式传回3个参数
|
||||
img_url = self.provider.image_chat(message)
|
||||
img_url = await self.provider.image_chat(message)
|
||||
return True, img_url, "draw"
|
||||
except Exception as e:
|
||||
if 'exceeded' in str(e):
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
from nakuru.entities.components import Plain, At, Image, BaseMessageComponent
|
||||
from nakuru import (
|
||||
GuildMessage,
|
||||
GroupMessage,
|
||||
FriendMessage
|
||||
)
|
||||
import botpy.message
|
||||
from cores.qqbot.types import MessageType, AstrBotMessage, MessageMember
|
||||
from typing import List, Union
|
||||
import time
|
||||
|
||||
# QQ官方消息类型转换
|
||||
def qq_official_message_parse(message: List[BaseMessageComponent]):
|
||||
plain_text = ""
|
||||
image_path = None # only one img supported
|
||||
for i in message:
|
||||
if isinstance(i, Plain):
|
||||
plain_text += i.text
|
||||
elif isinstance(i, Image) and image_path == None:
|
||||
if i.path is not None:
|
||||
image_path = i.path
|
||||
else:
|
||||
image_path = i.file
|
||||
return plain_text, image_path
|
||||
|
||||
# QQ官方消息类型 2 AstrBotMessage
|
||||
def qq_official_message_parse_rev(message: Union[botpy.message.Message, botpy.message.GroupMessage],
|
||||
message_type: MessageType) -> AstrBotMessage:
|
||||
abm = AstrBotMessage()
|
||||
abm.type = message_type
|
||||
abm.timestamp = int(time.time())
|
||||
abm.raw_message = message
|
||||
abm.message_id = message.id
|
||||
abm.tag = "qqchan"
|
||||
msg: List[BaseMessageComponent] = []
|
||||
|
||||
if message_type == MessageType.GROUP_MESSAGE:
|
||||
abm.sender = MessageMember(
|
||||
message.author.member_openid,
|
||||
""
|
||||
)
|
||||
abm.message_str = message.content.strip()
|
||||
abm.self_id = "unknown_selfid"
|
||||
|
||||
msg.append(Plain(abm.message_str))
|
||||
if message.attachments:
|
||||
for i in message.attachments:
|
||||
if i.content_type.startswith("image"):
|
||||
url = i.url
|
||||
if not url.startswith("http"):
|
||||
url = "https://"+url
|
||||
img = Image.fromURL(url)
|
||||
msg.append(img)
|
||||
abm.message = msg
|
||||
|
||||
elif message_type == MessageType.GUILD_MESSAGE or message_type == MessageType.FRIEND_MESSAGE:
|
||||
# 目前对于 FRIEND_MESSAGE 只处理频道私聊
|
||||
try:
|
||||
abm.self_id = str(message.mentions[0].id)
|
||||
except:
|
||||
abm.self_id = ""
|
||||
|
||||
plain_content = message.content.replace("<@!"+str(abm.self_id)+">", "").strip()
|
||||
msg.append(Plain(plain_content))
|
||||
if message.attachments:
|
||||
for i in message.attachments:
|
||||
if i.content_type.startswith("image"):
|
||||
url = i.url
|
||||
if not url.startswith("http"):
|
||||
url = "https://"+url
|
||||
img = Image.fromURL(url)
|
||||
msg.append(img)
|
||||
abm.message = msg
|
||||
abm.message_str = plain_content
|
||||
abm.sender = MessageMember(
|
||||
str(message.author.id),
|
||||
str(message.author.username)
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"Unknown message type: {message_type}")
|
||||
return abm
|
||||
|
||||
def nakuru_message_parse_rev(message: Union[GuildMessage, GroupMessage, FriendMessage]) -> AstrBotMessage:
|
||||
abm = AstrBotMessage()
|
||||
abm.type = MessageType(message.type)
|
||||
abm.timestamp = int(time.time())
|
||||
abm.raw_message = message
|
||||
abm.message_id = message.message_id
|
||||
|
||||
plain_content = ""
|
||||
for i in message.message:
|
||||
if isinstance(i, Plain):
|
||||
plain_content += i.text
|
||||
abm.message_str = plain_content
|
||||
|
||||
abm.self_id = str(message.self_id)
|
||||
abm.sender = MessageMember(
|
||||
str(message.sender.user_id),
|
||||
str(message.sender.nickname)
|
||||
)
|
||||
abm.tag = "gocq"
|
||||
abm.message = message.message
|
||||
|
||||
return abm
|
||||
@@ -1,77 +0,0 @@
|
||||
from nakuru.entities.components import Plain, At, Image
|
||||
from botpy.message import Message, DirectMessage
|
||||
|
||||
class NakuruGuildMember():
|
||||
tiny_id: int # 发送者识别号
|
||||
user_id: int # 发送者识别号
|
||||
title: str
|
||||
nickname: str # 昵称
|
||||
role: int # 角色
|
||||
icon_url: str # 头像url
|
||||
|
||||
class NakuruGuildMessage():
|
||||
type: str = "GuildMessage"
|
||||
self_id: int # bot的qq号
|
||||
self_tiny_id: int # bot的qq号
|
||||
sub_type: str # 消息类型
|
||||
message_id: str # 消息id
|
||||
guild_id: int # 频道号
|
||||
channel_id: int # 子频道号
|
||||
user_id: int # 发送者qq号
|
||||
message: list # 消息内容
|
||||
sender: NakuruGuildMember # 发送者信息
|
||||
raw_message: Message
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.__dict__)
|
||||
|
||||
# gocq-频道SDK兼容层(发)
|
||||
def gocq_compatible_send(gocq_message_chain: list):
|
||||
plain_text = ""
|
||||
image_path = None # only one img supported
|
||||
for i in gocq_message_chain:
|
||||
if isinstance(i, Plain):
|
||||
plain_text += i.text
|
||||
elif isinstance(i, Image) and image_path == None:
|
||||
if i.path is not None:
|
||||
image_path = i.path
|
||||
else:
|
||||
image_path = i.file
|
||||
return plain_text, image_path
|
||||
|
||||
# gocq-频道SDK兼容层(收)
|
||||
def gocq_compatible_receive(message: Message) -> NakuruGuildMessage:
|
||||
ngm = NakuruGuildMessage()
|
||||
try:
|
||||
ngm.self_id = message.mentions[0].id
|
||||
ngm.self_tiny_id = message.mentions[0].id
|
||||
except:
|
||||
ngm.self_id = 0
|
||||
ngm.self_tiny_id = 0
|
||||
|
||||
ngm.sub_type = "normal"
|
||||
ngm.message_id = message.id
|
||||
ngm.guild_id = int(message.guild_id)
|
||||
ngm.channel_id = int(message.channel_id)
|
||||
ngm.user_id = int(message.author.id)
|
||||
msg = []
|
||||
plain_content = message.content.replace("<@!"+str(ngm.self_id)+">", "").strip()
|
||||
msg.append(Plain(plain_content))
|
||||
if message.attachments:
|
||||
for i in message.attachments:
|
||||
if i.content_type.startswith("image"):
|
||||
url = i.url
|
||||
if not url.startswith("http"):
|
||||
url = "https://"+url
|
||||
img = Image.fromURL(url)
|
||||
msg.append(img)
|
||||
ngm.message = msg
|
||||
ngm.sender = NakuruGuildMember()
|
||||
ngm.sender.tiny_id = int(message.author.id)
|
||||
ngm.sender.user_id = int(message.author.id)
|
||||
ngm.sender.title = ""
|
||||
ngm.sender.nickname = message.author.username
|
||||
ngm.sender.role = 0
|
||||
ngm.sender.icon_url = message.author.avatar
|
||||
ngm.raw_message = message
|
||||
return ngm
|
||||
@@ -5,9 +5,6 @@ from nakuru import (
|
||||
GroupMessage,
|
||||
FriendMessage,
|
||||
)
|
||||
from ._nakuru_translation_layer import (
|
||||
NakuruGuildMessage,
|
||||
)
|
||||
from nakuru.entities.components import Plain, At, Image
|
||||
|
||||
|
||||
|
||||
+38
-24
@@ -14,6 +14,8 @@ from typing import Union
|
||||
import time
|
||||
|
||||
from ._platfrom import Platform
|
||||
from ._message_parse import nakuru_message_parse_rev
|
||||
from cores.qqbot.types import MessageType, AstrBotMessage, MessageMember
|
||||
|
||||
|
||||
class FakeSource:
|
||||
@@ -57,52 +59,58 @@ class QQGOCQ(Platform):
|
||||
@gocq_app.receiver("GroupMessage")
|
||||
async def _(app: CQHTTP, source: GroupMessage):
|
||||
if self.cc.get("gocq_react_group", True):
|
||||
abm = nakuru_message_parse_rev(source)
|
||||
if isinstance(source.message[0], Plain):
|
||||
await self.handle_msg(source, True)
|
||||
await self.handle_msg(abm)
|
||||
elif isinstance(source.message[0], At):
|
||||
if source.message[0].qq == source.self_id:
|
||||
await self.handle_msg(source, True)
|
||||
await self.handle_msg(abm)
|
||||
else:
|
||||
return
|
||||
|
||||
@gocq_app.receiver("FriendMessage")
|
||||
async def _(app: CQHTTP, source: FriendMessage):
|
||||
if self.cc.get("gocq_react_friend", True):
|
||||
abm = nakuru_message_parse_rev(source)
|
||||
if isinstance(source.message[0], Plain):
|
||||
await self.handle_msg(source, False)
|
||||
await self.handle_msg(abm)
|
||||
else:
|
||||
return
|
||||
|
||||
@gocq_app.receiver("GroupMemberIncrease")
|
||||
async def _(app: CQHTTP, source: GroupMemberIncrease):
|
||||
if self.cc.get("gocq_react_group_increase", True):
|
||||
|
||||
await app.sendGroupMessage(source.group_id, [
|
||||
Plain(text = self.announcement)
|
||||
])
|
||||
|
||||
@gocq_app.receiver("Notify")
|
||||
async def _(app: CQHTTP, source: Notify):
|
||||
print(source)
|
||||
if source.sub_type == "poke" and source.target_id == source.self_id:
|
||||
await self.handle_msg(source, False)
|
||||
# @gocq_app.receiver("Notify")
|
||||
# async def _(app: CQHTTP, source: Notify):
|
||||
# print(source)
|
||||
# if source.sub_type == "poke" and source.target_id == source.self_id:
|
||||
# await self.handle_msg(source)
|
||||
|
||||
@gocq_app.receiver("GuildMessage")
|
||||
async def _(app: CQHTTP, source: GuildMessage):
|
||||
if self.cc.get("gocq_react_guild", True):
|
||||
abm = nakuru_message_parse_rev(source)
|
||||
if isinstance(source.message[0], Plain):
|
||||
await self.handle_msg(source, True)
|
||||
await self.handle_msg(abm)
|
||||
elif isinstance(source.message[0], At):
|
||||
if source.message[0].qq == source.self_tiny_id:
|
||||
await self.handle_msg(source, True)
|
||||
await self.handle_msg(abm)
|
||||
else:
|
||||
return
|
||||
|
||||
def run(self):
|
||||
self.client.run()
|
||||
|
||||
async def handle_msg(self, message: Union[GroupMessage, FriendMessage, GuildMessage, Notify], is_group: bool):
|
||||
self.logger.log(f"{message.user_id} -> {self.parse_message_outline(message)}", tag="QQ_GOCQ")
|
||||
async def handle_msg(self, message: AstrBotMessage):
|
||||
self.logger.log(f"{message.sender.nickname}/{message.sender.user_id} -> {self.parse_message_outline(message)}", tag="QQ_GOCQ")
|
||||
|
||||
assert isinstance(message.raw_message, (GroupMessage, FriendMessage, GuildMessage))
|
||||
is_group = message.type != MessageType.FRIEND_MESSAGE
|
||||
|
||||
# 判断是否响应消息
|
||||
resp = False
|
||||
if not is_group:
|
||||
@@ -111,7 +119,7 @@ class QQGOCQ(Platform):
|
||||
for i in message.message:
|
||||
if isinstance(i, At):
|
||||
if message.type == "GuildMessage":
|
||||
if i.qq == message.user_id or i.qq == message.self_tiny_id:
|
||||
if i.qq == message.raw_message.user_id or i.qq == message.raw_message.self_tiny_id:
|
||||
resp = True
|
||||
if message.type == "FriendMessage":
|
||||
if i.qq == message.self_id:
|
||||
@@ -129,16 +137,18 @@ class QQGOCQ(Platform):
|
||||
|
||||
# 解析 session_id
|
||||
if self.unique_session or not is_group:
|
||||
session_id = message.user_id
|
||||
elif message.type == "GroupMessage":
|
||||
session_id = message.group_id
|
||||
elif message.type == "GuildMessage":
|
||||
session_id = message.channel_id
|
||||
session_id = message.raw_message.user_id
|
||||
elif message.type == MessageType.GROUP_MESSAGE:
|
||||
session_id = message.raw_message.group_id
|
||||
elif message.type == MessageType.GUILD_MESSAGE:
|
||||
session_id = message.raw_message.channel_id
|
||||
else:
|
||||
session_id = message.user_id
|
||||
session_id = message.raw_message.user_id
|
||||
|
||||
message.session_id = session_id
|
||||
|
||||
# 解析 role
|
||||
sender_id = str(message.user_id)
|
||||
sender_id = str(message.raw_message.user_id)
|
||||
if sender_id == self.cc.get('admin_qq', '') or \
|
||||
sender_id in self.cc.get('other_admins', []):
|
||||
role = 'admin'
|
||||
@@ -163,12 +173,16 @@ class QQGOCQ(Platform):
|
||||
self.waiting[session_id] = message
|
||||
|
||||
async def reply_msg(self,
|
||||
message: Union[GroupMessage, FriendMessage, GuildMessage, Notify],
|
||||
message: Union[AstrBotMessage, GuildMessage, GroupMessage, FriendMessage],
|
||||
result_message: list):
|
||||
"""
|
||||
插件开发者请使用send方法, 可以不用直接调用这个方法。
|
||||
"""
|
||||
source = message
|
||||
if isinstance(message, AstrBotMessage):
|
||||
source = message.raw_message
|
||||
else:
|
||||
source = message
|
||||
|
||||
res = result_message
|
||||
|
||||
self.logger.log(f"{source.user_id} <- {self.parse_message_outline(res)}", tag="QQ_GOCQ")
|
||||
@@ -233,7 +247,7 @@ class QQGOCQ(Platform):
|
||||
await self.client.sendGroupMessage(source.group_id, res)
|
||||
return
|
||||
|
||||
async def send_msg(self, message: Union[GroupMessage, FriendMessage, GuildMessage, Notify], result_message: list):
|
||||
async def send_msg(self, message: Union[GroupMessage, FriendMessage, GuildMessage, AstrBotMessage], result_message: list):
|
||||
'''
|
||||
提供给插件的发送QQ消息接口。
|
||||
参数说明:第一个参数可以是消息对象,也可以是QQ群号。第二个参数是消息内容(消息内容可以是消息链列表,也可以是纯文字信息)。
|
||||
|
||||
+105
-49
@@ -1,7 +1,7 @@
|
||||
import io
|
||||
import botpy
|
||||
from PIL import Image as PILImage
|
||||
from botpy.message import Message, DirectMessage
|
||||
import botpy.message
|
||||
import re
|
||||
import asyncio
|
||||
import aiohttp
|
||||
@@ -11,29 +11,34 @@ from botpy.types.message import Reference
|
||||
from botpy import Client
|
||||
import time
|
||||
from ._platfrom import Platform
|
||||
from ._nakuru_translation_layer import(
|
||||
NakuruGuildMessage,
|
||||
gocq_compatible_receive,
|
||||
gocq_compatible_send
|
||||
from ._message_parse import(
|
||||
qq_official_message_parse_rev,
|
||||
qq_official_message_parse
|
||||
)
|
||||
from typing import Union
|
||||
from cores.qqbot.types import MessageType, AstrBotMessage, MessageMember
|
||||
from typing import Union, List
|
||||
from nakuru.entities.components import BaseMessageComponent
|
||||
|
||||
# QQ 机器人官方框架
|
||||
class botClient(Client):
|
||||
def set_platform(self, platform: 'QQOfficial'):
|
||||
self.platform = platform
|
||||
|
||||
async def on_group_at_message_create(self, message: botpy.message.GroupMessage):
|
||||
abm = qq_official_message_parse_rev(message, MessageType.GROUP_MESSAGE)
|
||||
await self.platform.handle_msg(abm)
|
||||
|
||||
# 收到频道消息
|
||||
async def on_at_message_create(self, message: Message):
|
||||
async def on_at_message_create(self, message: botpy.message.Message):
|
||||
# 转换层
|
||||
nakuru_guild_message = gocq_compatible_receive(message)
|
||||
await self.platform.handle_msg(nakuru_guild_message, True)
|
||||
abm = qq_official_message_parse_rev(message, MessageType.GUILD_MESSAGE)
|
||||
await self.platform.handle_msg(abm)
|
||||
|
||||
# 收到私聊消息
|
||||
async def on_direct_message_create(self, message: DirectMessage):
|
||||
async def on_direct_message_create(self, message: botpy.message.DirectMessage):
|
||||
# 转换层
|
||||
nakuru_guild_message = gocq_compatible_receive(message)
|
||||
await self.platform.handle_msg(nakuru_guild_message, False)
|
||||
abm = qq_official_message_parse_rev(message, MessageType.FRIEND_MESSAGE)
|
||||
await self.platform.handle_msg(abm)
|
||||
|
||||
class QQOfficial(Platform):
|
||||
|
||||
@@ -51,15 +56,26 @@ class QQOfficial(Platform):
|
||||
self.secret = cfg['qqbot_secret']
|
||||
self.unique_session = cfg['uniqueSessionMode']
|
||||
self.logger: gu.Logger = global_object.logger
|
||||
|
||||
self.intents = botpy.Intents(
|
||||
public_guild_messages=True,
|
||||
direct_message=cfg['direct_message_mode']
|
||||
)
|
||||
self.client = botClient(
|
||||
intents=self.intents,
|
||||
bot_log=False
|
||||
)
|
||||
|
||||
try:
|
||||
self.intents = botpy.Intents(
|
||||
public_messages=True,
|
||||
public_guild_messages=True,
|
||||
direct_message=cfg['direct_message_mode']
|
||||
)
|
||||
self.client = botClient(
|
||||
intents=self.intents,
|
||||
bot_log=False
|
||||
)
|
||||
except BaseException:
|
||||
self.intents = botpy.Intents(
|
||||
public_guild_messages=True,
|
||||
direct_message=cfg['direct_message_mode']
|
||||
)
|
||||
self.client = botClient(
|
||||
intents=self.intents,
|
||||
bot_log=False
|
||||
)
|
||||
self.client.set_platform(self)
|
||||
|
||||
def run(self):
|
||||
@@ -80,17 +96,27 @@ class QQOfficial(Platform):
|
||||
token=self.token
|
||||
)
|
||||
|
||||
async def handle_msg(self, message: NakuruGuildMessage, is_group: bool):
|
||||
async def handle_msg(self, message: AstrBotMessage):
|
||||
assert isinstance(message.raw_message, (botpy.message.Message, botpy.message.GroupMessage, botpy.message.DirectMessage))
|
||||
is_group = message.type != MessageType.FRIEND_MESSAGE
|
||||
|
||||
_t = "/私聊" if not is_group else ""
|
||||
self.logger.log(f"{message.sender.nickname}({message.sender.tiny_id}{_t}) -> {self.parse_message_outline(message)}", tag="QQ_OFFICIAL")
|
||||
self.logger.log(f"{message.sender.nickname}({message.sender.user_id}{_t}) -> {self.parse_message_outline(message)}", tag="QQ_OFFICIAL")
|
||||
|
||||
# 解析出 session_id
|
||||
if self.unique_session or not is_group:
|
||||
session_id = message.sender.user_id
|
||||
else:
|
||||
session_id = message.channel_id
|
||||
if message.type == MessageType.GUILD_MESSAGE:
|
||||
session_id = message.raw_message.channel_id
|
||||
elif message.type == MessageType.GROUP_MESSAGE:
|
||||
session_id = str(message.raw_message.group_openid)
|
||||
else:
|
||||
session_id = str(message.raw_message.author.id)
|
||||
message.session_id = session_id
|
||||
|
||||
# 解析出 role
|
||||
sender_id = str(message.sender.tiny_id)
|
||||
sender_id = message.sender.user_id
|
||||
if sender_id == self.cfg['admin_qqchan'] or \
|
||||
sender_id in self.cfg['other_admins']:
|
||||
role = 'admin'
|
||||
@@ -107,7 +133,7 @@ class QQOfficial(Platform):
|
||||
if message_result is None:
|
||||
return
|
||||
|
||||
await self.reply_msg(is_group, message, message_result.result_message)
|
||||
await self.reply_msg(message, message_result.result_message)
|
||||
if message_result.callback is not None:
|
||||
message_result.callback()
|
||||
|
||||
@@ -116,20 +142,24 @@ class QQOfficial(Platform):
|
||||
self.waiting[session_id] = message
|
||||
|
||||
async def reply_msg(self,
|
||||
is_group: bool,
|
||||
message: NakuruGuildMessage,
|
||||
message: Union[botpy.message.Message, botpy.message.GroupMessage, botpy.message.DirectMessage, AstrBotMessage],
|
||||
res: Union[str, list]):
|
||||
'''
|
||||
回复频道消息
|
||||
'''
|
||||
self.logger.log(f"{message.sender.nickname}({message.sender.tiny_id}) <- {self.parse_message_outline(res)}", tag="QQ_OFFICIAL")
|
||||
if isinstance(message, AstrBotMessage):
|
||||
source = message.raw_message
|
||||
else:
|
||||
source = message
|
||||
assert isinstance(source, (botpy.message.Message, botpy.message.GroupMessage, botpy.message.DirectMessage))
|
||||
self.logger.log(f"{message.sender.nickname}({message.sender.user_id}) <- {self.parse_message_outline(res)}", tag="QQ_OFFICIAL")
|
||||
|
||||
plain_text = ''
|
||||
image_path = ''
|
||||
msg_ref = None
|
||||
|
||||
if isinstance(res, list):
|
||||
plain_text, image_path = gocq_compatible_send(res)
|
||||
plain_text, image_path = qq_official_message_parse(res)
|
||||
elif isinstance(res, str):
|
||||
plain_text = res
|
||||
|
||||
@@ -154,8 +184,8 @@ class QQOfficial(Platform):
|
||||
image = PILImage.open(io.BytesIO(await response.read()))
|
||||
image_path = gu.save_temp_img(image)
|
||||
|
||||
if message.raw_message is not None and image_path == '': # file_image与message_reference不能同时传入
|
||||
msg_ref = Reference(message_id=message.raw_message.id, ignore_get_message_error=False)
|
||||
if source is not None and image_path == '': # file_image与message_reference不能同时传入
|
||||
msg_ref = Reference(message_id=source.id, ignore_get_message_error=False)
|
||||
|
||||
# 到这里,我们得到了 plain_text,image_path,msg_ref
|
||||
data = {
|
||||
@@ -163,10 +193,15 @@ class QQOfficial(Platform):
|
||||
'msg_id': message.message_id,
|
||||
'message_reference': msg_ref
|
||||
}
|
||||
if is_group:
|
||||
data['channel_id'] = str(message.channel_id)
|
||||
if message.type == MessageType.GROUP_MESSAGE:
|
||||
data['group_openid'] = str(source.group_openid)
|
||||
elif message.type == MessageType.GUILD_MESSAGE:
|
||||
data['channel_id'] = source.channel_id
|
||||
elif message.type == MessageType.FRIEND_MESSAGE:
|
||||
# 目前只处理频道私聊
|
||||
data['guild_id'] = source.guild_id
|
||||
else:
|
||||
data['guild_id'] = str(message.guild_id)
|
||||
raise ValueError(f"未知的消息类型: {message.type}")
|
||||
if image_path != '':
|
||||
data['file_image'] = image_path
|
||||
|
||||
@@ -200,27 +235,48 @@ class QQOfficial(Platform):
|
||||
await self._send_wrapper(**data)
|
||||
|
||||
async def _send_wrapper(self, **kwargs):
|
||||
if 'channel_id' in kwargs:
|
||||
if 'group_openid' in kwargs:
|
||||
# QQ群组消息
|
||||
media = None
|
||||
# qq群组消息需要自行上传,暂时不处理
|
||||
# if 'file_image' in kwargs:
|
||||
# file_image_path = kwargs['file_image']
|
||||
# if file_image_path != "":
|
||||
# media = await self.upload_img(file_image_path, kwargs['group_openid'])
|
||||
# del kwargs['file_image']
|
||||
# if media is not None:
|
||||
# kwargs['msg_type'] = 7 # 富媒体
|
||||
await self.client.api.post_group_message(media=media, **kwargs)
|
||||
elif 'channel_id' in kwargs:
|
||||
# 频道消息
|
||||
if 'file_image' in kwargs:
|
||||
kwargs['file_image'] = kwargs['file_image'].replace("file://", "")
|
||||
await self.client.api.post_message(**kwargs)
|
||||
else:
|
||||
# 频道私聊消息
|
||||
if 'file_image' in kwargs:
|
||||
kwargs['file_image'] = kwargs['file_image'].replace("file://", "")
|
||||
await self.client.api.post_dms(**kwargs)
|
||||
|
||||
async def send_msg(self, channel_id: int, message_chain: list, message_id: int = None):
|
||||
async def send_msg(self,
|
||||
message_obj: Union[botpy.message.Message, botpy.message.GroupMessage, botpy.message.DirectMessage, AstrBotMessage],
|
||||
message_chain: List[BaseMessageComponent],
|
||||
):
|
||||
'''
|
||||
推送消息, 如果有 message_id,那么就是回复消息。
|
||||
'''
|
||||
_n = NakuruGuildMessage()
|
||||
_n.channel_id = channel_id
|
||||
_n.message_id = message_id
|
||||
await self.reply_msg(_n, message_chain)
|
||||
|
||||
async def send(self, message_obj, message_chain: list):
|
||||
'''
|
||||
发送信息。内容同 reply_msg。
|
||||
发送消息。目前只支持被动回复消息(即拥有一个 botpy Message 类型的 message_obj 传入)
|
||||
'''
|
||||
await self.reply_msg(message_obj, message_chain)
|
||||
|
||||
def wait_for_message(self, channel_id: int) -> NakuruGuildMessage:
|
||||
async def send(self,
|
||||
message_obj: Union[botpy.message.Message, botpy.message.GroupMessage, botpy.message.DirectMessage, AstrBotMessage],
|
||||
message_chain: List[BaseMessageComponent],
|
||||
):
|
||||
'''
|
||||
发送消息。目前只支持被动回复消息(即拥有一个 botpy Message 类型的 message_obj 传入)
|
||||
'''
|
||||
await self.reply_msg(message_obj, message_chain)
|
||||
|
||||
def wait_for_message(self, channel_id: int) -> AstrBotMessage:
|
||||
'''
|
||||
等待指定 channel_id 的下一条信息,超时 300s 后抛出异常
|
||||
'''
|
||||
@@ -235,4 +291,4 @@ class QQOfficial(Platform):
|
||||
cnt += 1
|
||||
if cnt > 300:
|
||||
raise Exception("等待消息超时。")
|
||||
time.sleep(1)
|
||||
time.sleep(1)()
|
||||
|
||||
Reference in New Issue
Block a user