Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

from astrbot.api import logger
from astrbot.api.event import AstrMessageEvent, MessageChain
from astrbot.api.message_components import File, Image, Plain, Record, Video
from astrbot.api.message_components import At, File, Image, Plain, Record, Video
from astrbot.api.platform import AstrBotMessage, PlatformMetadata
from astrbot.core.utils.media_utils import MediaResolver, file_uri_to_path, is_file_uri

Expand Down Expand Up @@ -196,6 +196,28 @@ def _extract_response_message_id(ret) -> str | None:
ret_id = getattr(ret, "id", None)
return str(ret_id) if ret_id is not None else None

@staticmethod
def _get_mention_id(component: At) -> str | None:
qq = getattr(component, "qq", None)
if not qq:
return None
qq_id = str(qq)
return qq_id if qq_id != "all" else None

@classmethod
def _has_mention(cls, message: MessageChain) -> bool:
return any(
isinstance(component, At) and cls._get_mention_id(component) is not None
for component in message.chain
)

@staticmethod
def _set_media_payload(payload: dict, media: Media, plain_text: str) -> None:
payload["media"] = media
payload["msg_type"] = 7
payload.pop("markdown", None)
payload["content"] = plain_text or None

@staticmethod
def _split_message_chain_by_media(message: MessageChain) -> list[MessageChain]:
chunks: list[MessageChain] = []
Expand Down Expand Up @@ -304,9 +326,10 @@ async def _post_send_one(
):
plain_text = plain_text + "\n"

# 根据消息链的 use_markdown_ 标记决定发送模式
# QQ only resolves <@openid> mentions in Markdown messages.
has_mention = self._has_mention(message_to_send)
use_md = getattr(self.send_buffer, "use_markdown_", None)
if use_md is False:
if use_md is False and not has_mention:
payload: dict = {
"content": plain_text,
"msg_type": 0,
Expand Down Expand Up @@ -336,32 +359,23 @@ async def _post_send_one(
self.IMAGE_FILE_TYPE,
group_openid=source.group_openid,
)
payload["media"] = media
payload["msg_type"] = 7
payload.pop("markdown", None)
payload["content"] = plain_text or None
self._set_media_payload(payload, media, plain_text)
if record_file_path: # group record msg
media = await self.upload_group_and_c2c_media(
record_file_path,
self.VOICE_FILE_TYPE,
group_openid=source.group_openid,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
payload.pop("markdown", None)
payload["content"] = plain_text or None
self._set_media_payload(payload, media, plain_text)
if video_file_source:
media = await self.upload_group_and_c2c_media(
video_file_source,
self.VIDEO_FILE_TYPE,
group_openid=source.group_openid,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
payload.pop("markdown", None)
payload["content"] = plain_text or None
self._set_media_payload(payload, media, plain_text)
if file_source:
media = await self.upload_group_and_c2c_media(
file_source,
Expand All @@ -370,10 +384,7 @@ async def _post_send_one(
group_openid=source.group_openid,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
payload.pop("markdown", None)
payload["content"] = plain_text or None
self._set_media_payload(payload, media, plain_text)
ret = await self._send_with_markdown_fallback(
send_func=lambda retry_payload: self.bot.api.post_group_message(
group_openid=source.group_openid, # type: ignore
Expand All @@ -391,32 +402,23 @@ async def _post_send_one(
self.IMAGE_FILE_TYPE,
openid=source.author.user_openid,
)
payload["media"] = media
payload["msg_type"] = 7
payload.pop("markdown", None)
payload["content"] = plain_text or None
self._set_media_payload(payload, media, plain_text)
if record_file_path: # c2c record
media = await self.upload_group_and_c2c_media(
record_file_path,
self.VOICE_FILE_TYPE,
openid=source.author.user_openid,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
payload.pop("markdown", None)
payload["content"] = plain_text or None
self._set_media_payload(payload, media, plain_text)
if video_file_source:
media = await self.upload_group_and_c2c_media(
video_file_source,
self.VIDEO_FILE_TYPE,
openid=source.author.user_openid,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
payload.pop("markdown", None)
payload["content"] = plain_text or None
self._set_media_payload(payload, media, plain_text)
if file_source:
media = await self.upload_group_and_c2c_media(
file_source,
Expand All @@ -425,10 +427,7 @@ async def _post_send_one(
openid=source.author.user_openid,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
payload.pop("markdown", None)
payload["content"] = plain_text or None
self._set_media_payload(payload, media, plain_text)
if stream:
ret = await self._send_with_markdown_fallback(
send_func=lambda retry_payload: self.post_c2c_message(
Expand Down Expand Up @@ -741,6 +740,10 @@ async def _parse_to_qqofficial(message: MessageChain):
for i in message.chain:
if isinstance(i, Plain):
plain_text += i.text
elif isinstance(i, At):
qq_id = QQOfficialMessageEvent._get_mention_id(i)
if qq_id:
plain_text += f"<@{qq_id}>"
Comment thread
IQ-Director marked this conversation as resolved.
elif isinstance(i, Image) and not image_base64:
if not i.file:
raise ValueError("Unsupported image file format")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,17 @@ async def _send_by_session_common(
)
return

payload: dict[str, Any] = {"content": plain_text}
has_mention = QQOfficialMessageEvent._has_mention(message_chain)
use_markdown = (
has_mention or getattr(message_chain, "use_markdown_", None) is True
)
if use_markdown and plain_text:
payload: dict[str, Any] = {
"markdown": botpy.types.message.MarkdownPayload(content=plain_text),
"msg_type": 2,
}
else:
payload = {"content": plain_text, "msg_type": 0}
if msg_id and not allow_group_proactive_send:
payload["msg_id"] = msg_id
ret: Any = None
Expand All @@ -395,8 +405,9 @@ async def _send_by_session_common(
QQOfficialMessageEvent.IMAGE_FILE_TYPE,
group_openid=session.session_id,
)
payload["media"] = media
payload["msg_type"] = 7
QQOfficialMessageEvent._set_media_payload(
payload, media, plain_text
)
if record_file_path:
media = await QQOfficialMessageEvent.upload_group_and_c2c_media(
send_helper, # type: ignore
Expand All @@ -405,8 +416,9 @@ async def _send_by_session_common(
group_openid=session.session_id,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
QQOfficialMessageEvent._set_media_payload(
payload, media, plain_text
)
if video_file_source:
media = await QQOfficialMessageEvent.upload_group_and_c2c_media(
send_helper, # type: ignore
Expand All @@ -415,8 +427,9 @@ async def _send_by_session_common(
group_openid=session.session_id,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
QQOfficialMessageEvent._set_media_payload(
payload, media, plain_text
)
payload.pop("msg_id", None)
if file_source:
media = await QQOfficialMessageEvent.upload_group_and_c2c_media(
Expand All @@ -427,8 +440,9 @@ async def _send_by_session_common(
group_openid=session.session_id,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
QQOfficialMessageEvent._set_media_payload(
payload, media, plain_text
)
payload.pop("msg_id", None)
ret = await self.client.api.post_group_message(
group_openid=session.session_id,
Expand All @@ -437,6 +451,7 @@ async def _send_by_session_common(
else:
if image_path:
payload["file_image"] = image_path
payload.pop("msg_type", None)
ret = await self.client.api.post_message(
channel_id=session.session_id,
**payload,
Expand All @@ -454,8 +469,7 @@ async def _send_by_session_common(
QQOfficialMessageEvent.IMAGE_FILE_TYPE,
openid=session.session_id,
)
payload["media"] = media
payload["msg_type"] = 7
QQOfficialMessageEvent._set_media_payload(payload, media, plain_text)
if record_file_path:
media = await QQOfficialMessageEvent.upload_group_and_c2c_media(
send_helper, # type: ignore
Expand All @@ -464,8 +478,9 @@ async def _send_by_session_common(
openid=session.session_id,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
QQOfficialMessageEvent._set_media_payload(
payload, media, plain_text
)
if video_file_source:
media = await QQOfficialMessageEvent.upload_group_and_c2c_media(
send_helper, # type: ignore
Expand All @@ -474,8 +489,9 @@ async def _send_by_session_common(
openid=session.session_id,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
QQOfficialMessageEvent._set_media_payload(
payload, media, plain_text
)
if file_source:
media = await QQOfficialMessageEvent.upload_group_and_c2c_media(
send_helper, # type: ignore
Expand All @@ -485,8 +501,9 @@ async def _send_by_session_common(
openid=session.session_id,
)
if media:
payload["media"] = media
payload["msg_type"] = 7
QQOfficialMessageEvent._set_media_payload(
payload, media, plain_text
)

ret = await QQOfficialMessageEvent.post_c2c_message(
send_helper, # type: ignore
Expand Down Expand Up @@ -697,6 +714,17 @@ def replace_face(match):
# Match face tags: <faceType=...>
return re.sub(r"<faceType=\d+[^>]*>", replace_face, content)

@staticmethod
def _strip_bot_mention_markup(content: str | None, mention_id: str) -> str:
normalized = content or ""
for markup in (
f'<qqbot-at-user id="{mention_id}" />',
f"<@{mention_id}>",
f"<@!{mention_id}>",
):
normalized = normalized.replace(markup, "")
return normalized

@staticmethod
async def _parse_from_qqofficial(
message: botpy.message.Message
Expand Down Expand Up @@ -781,12 +809,10 @@ async def _parse_from_qqofficial(
group_mentioned = bool(bot_mention_ids) or force_group_mention
plain_content_raw = message.content or ""
for mention_id in bot_mention_ids:
plain_content_raw = plain_content_raw.replace(
f"<@{mention_id}>",
"",
).replace(
f"<@!{mention_id}>",
"",
plain_content_raw = (
QQOfficialPlatformAdapter._strip_bot_mention_markup(
plain_content_raw, mention_id
)
)
abm.message_str = QQOfficialPlatformAdapter._parse_face_message(
plain_content_raw.strip()
Expand Down Expand Up @@ -823,9 +849,8 @@ async def _parse_from_qqofficial(
abm.self_id = ""

plain_content = QQOfficialPlatformAdapter._parse_face_message(
message.content.replace(
"<@!" + str(abm.self_id) + ">",
"",
QQOfficialPlatformAdapter._strip_bot_mention_markup(
message.content, str(abm.self_id)
).strip()
)

Expand Down
Loading