mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-16 17:47:06 +08:00
- Updated `LegacyContext.send_message` to handle rich message chains using `send_chain`. - Introduced `LegacyStar` class for backward compatibility with legacy plugins. - Added `register` decorator for legacy plugin metadata. - Enhanced `MessageChain` class with `to_payload` and `is_plain_text_only` methods. - Updated `AstrMessageEvent.send` method to utilize `send_chain` for rich messages. - Implemented `send_chain` method in `PlatformClient` for sending complex message structures. - Added capability routing for `platform.send_chain`. - Introduced tests for new functionality, ensuring compatibility with legacy plugins and message handling.
110 lines
3.3 KiB
Python
110 lines
3.3 KiB
Python
"""旧版消息链兼容实现。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
from . import components as Comp
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class MessageChain:
|
|
chain: list[Comp.BaseMessageComponent] = field(default_factory=list)
|
|
use_t2i_: bool | None = None
|
|
type: str | None = None
|
|
|
|
def message(self, message: str) -> "MessageChain":
|
|
self.chain.append(Comp.Plain(text=message))
|
|
return self
|
|
|
|
def at(self, name: str, qq: str) -> "MessageChain":
|
|
self.chain.append(Comp.At(user_id=qq, user_name=name))
|
|
return self
|
|
|
|
def at_all(self) -> "MessageChain":
|
|
self.chain.append(Comp.AtAll())
|
|
return self
|
|
|
|
def error(self, message: str) -> "MessageChain":
|
|
self.chain.append(Comp.Plain(text=message))
|
|
return self
|
|
|
|
def url_image(self, url: str) -> "MessageChain":
|
|
self.chain.append(Comp.Image(file=url))
|
|
return self
|
|
|
|
def file_image(self, path: str) -> "MessageChain":
|
|
self.chain.append(Comp.Image(file=path))
|
|
return self
|
|
|
|
def base64_image(self, base64_str: str) -> "MessageChain":
|
|
self.chain.append(Comp.Image(file=base64_str))
|
|
return self
|
|
|
|
def use_t2i(self, use_t2i: bool) -> "MessageChain":
|
|
self.use_t2i_ = use_t2i
|
|
return self
|
|
|
|
def to_payload(self) -> list[dict[str, Any]]:
|
|
payload: list[dict[str, Any]] = []
|
|
for component in self.chain:
|
|
if isinstance(component, dict):
|
|
payload.append(dict(component))
|
|
continue
|
|
to_dict = getattr(component, "to_dict", None)
|
|
if callable(to_dict):
|
|
payload.append(to_dict())
|
|
continue
|
|
model_dump = getattr(component, "model_dump", None)
|
|
if callable(model_dump):
|
|
payload.append(model_dump())
|
|
continue
|
|
payload.append({"type": "Unknown", "text": str(component)})
|
|
return payload
|
|
|
|
def is_plain_text_only(self) -> bool:
|
|
if not self.chain:
|
|
return False
|
|
for component in self.chain:
|
|
if isinstance(component, Comp.Plain):
|
|
continue
|
|
if isinstance(component, dict) and str(component.get("type")) in {
|
|
"Plain",
|
|
"plain",
|
|
"text",
|
|
}:
|
|
continue
|
|
return False
|
|
return True
|
|
|
|
def get_plain_text(self) -> str:
|
|
return " ".join(
|
|
component.text
|
|
for component in self.chain
|
|
if isinstance(component, Comp.Plain)
|
|
)
|
|
|
|
def squash_plain(self) -> "MessageChain":
|
|
if not self.chain:
|
|
return self
|
|
|
|
new_chain: list[Comp.BaseMessageComponent] = []
|
|
first_plain: Comp.Plain | None = None
|
|
plain_texts: list[str] = []
|
|
|
|
for component in self.chain:
|
|
if isinstance(component, Comp.Plain):
|
|
if first_plain is None:
|
|
first_plain = component
|
|
new_chain.append(component)
|
|
plain_texts.append(component.text)
|
|
else:
|
|
new_chain.append(component)
|
|
|
|
if first_plain is not None:
|
|
first_plain.text = "".join(plain_texts)
|
|
|
|
self.chain = new_chain
|
|
return self
|