Message - объект сообщения Max. Он содержит текст, ID чата, отправителя,
вложения и удобные методы: answer(), reply(), pin(), delete(),
read(), react() и unreact().
from pymax import Client, Message, MessageDeleteEvent
client = Client(phone="+79990000000", work_dir="cache")
@client.on_message()
async def on_message(message: Message, client: Client) -> None:
print(message.text)
@client.on_message_edit()
async def on_edit(message: Message, client: Client) -> None:
print("edited:", message.text)
@client.on_message_delete()
async def on_delete(event: MessageDeleteEvent, client: Client) -> None:
print("deleted in chat:", event.chat_id)message = await client.get_message(
chat_id=123456,
message_id=987654,
)
messages = await client.get_messages(
chat_id=123456,
message_ids=[987654, 987655],
)
if message is not None:
await message.edit("Обновленный текст")Через клиент то же редактирование доступно как
client.edit_message(chat_id, message_id, text, ...).
Новые вложения передаются через attachments.
Через клиент:
await client.send_message(chat_id=123456, text="Привет")Через сообщение из handler-а:
@client.on_message()
async def on_message(message: Message, client: Client) -> None:
await message.answer("Ответ в тот же чат")
await message.reply("Ответ реплаем")
await message.forward(chat_id=654321)Переслать сообщение напрямую через клиент можно с указанием исходного и целевого чатов:
await client.forward_message(
chat_id=654321,
message_id=987654,
source_chat_id=123456,
)@client.on_message()
async def on_message(message: Message, client: Client) -> None:
if message.text == "/pin":
await message.pin()
elif message.text == "/read":
await message.read()
elif message.text == "/like":
await message.react("👍")
elif message.text == "/reactions":
reactions = await message.get_reactions()
print(reactions)
elif message.text == "/delete":
await message.delete(for_me=False)Note
У низкоуровневого client.read_message(...) есть особенность Max:
для отметки прочтения TCP-клиент ожидает message_id как int, а
WebSocket-клиент - как str. Если вызываете метод напрямую, выбирайте
тип по клиенту.
Начиная с 2.2.0 доступны отдельные обработчики набора текста, присутствия,
прочтения и реакций:
from pymax import (
Client,
MessageReadEvent,
PresenceEvent,
ReactionUpdateEvent,
TypingEvent,
)
@client.on_typing()
async def typing(event: TypingEvent, client: Client) -> None:
print(event.chat_id, event.user_id)
@client.on_presence()
async def presence(event: PresenceEvent, client: Client) -> None:
print(event.user_id, event.presence.status)
@client.on_message_read()
async def read(event: MessageReadEvent, client: Client) -> None:
print(event.chat_id, event.mark)
@client.on_reaction_update()
async def reactions(event: ReactionUpdateEvent, client: Client) -> None:
print(event.message_id, event.total_count)history = await client.fetch_history(chat_id=123456, backward=50)
for message in history or []:
print(message.id, message.text)fetch_history() принимает item_type. По умолчанию используются обычные
сообщения; для отложенных сообщений передайте ItemType.DELAYED из
pymax.api.messages.enums.
Max присылает разные формы событий. Некоторые payload-ы содержат полный объект
сообщения, а некоторые - только часть данных. Поэтому Message.chat_id,
sender, attaches, reaction_info, status и другие поля могут
быть пустыми.
Практическое правило: перед действиями, которым нужен чат, проверяйте
message.chat_id.
@client.on_message()
async def on_message(message: Message, client: Client) -> None:
if message.chat_id is None:
return
await message.answer("ok")Входящие вложения лежат в message.attaches. Тип вложения определяется по
полю type: фото, видео, файл, стикер, аудио, контакт, звонок, share или
inline-клавиатура.
from pymax import Client, Message
from pymax.types.domain import FileAttachment, PhotoAttachment
@client.on_message()
async def on_message(message: Message, client: Client) -> None:
if message.chat_id is None:
return
for attach in message.attaches:
if isinstance(attach, PhotoAttachment):
print("photo:", attach.photo_id, attach.base_url)
elif isinstance(attach, FileAttachment):
file_info = await client.get_file_by_id(
chat_id=message.chat_id,
message_id=message.id,
file_id=attach.file_id,
)
print(file_info.url if file_info else "no url")Message is not bound to a client- Методы
message.answer()и похожие работают на сообщениях, полученных через клиент. Если вы создалиMessageвручную через Pydantic, он не знает, каким клиентом выполнить действие. Message does not contain chat_id- В событии нет ID чата. Используйте
client.send_message(...)только если знаетеchat_idиз другого источника. - Pydantic validation error на attachments
- Max мог прислать новый или неполный тип вложения. Включите debug-логи,
посмотрите raw payload через
on_rawи обновите PyMax или добавьте обработку нового формата.