Compare commits
23 Commits
b60d8571d3
...
e8b7c71d25
| Author | SHA1 | Date | |
|---|---|---|---|
| e8b7c71d25 | |||
| aab87e16b2 | |||
| df383665dc | |||
| bd06b33343 | |||
| 7b70d1de18 | |||
| 5f2c908da4 | |||
| 1abbc16cc8 | |||
| 7b61ceaa58 | |||
| 37f7907398 | |||
| 9dab5f97fb | |||
| 0a3d1ca327 | |||
| 93043835d1 | |||
| 3548d0558f | |||
| 5ae4de6816 | |||
| d77288ea07 | |||
| 30cf778504 | |||
| dd1bdb5e37 | |||
| b20a46de24 | |||
| de05e7931a | |||
| a8727c71e9 | |||
| b6c11cd28a | |||
| 12f64f0805 | |||
| 3df4dd21b4 |
@@ -56,7 +56,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
## 📚 Документация
|
## 📚 Документация
|
||||||
|
|
||||||
В разработке...
|
[Тут](https://github.com/love-apples/maxapi/wiki)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
153
examples/keyboard/main.py
Normal file
153
examples/keyboard/main.py
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from maxapi import Bot, Dispatcher
|
||||||
|
|
||||||
|
# Кнопки
|
||||||
|
from maxapi.types import (
|
||||||
|
ChatButton,
|
||||||
|
LinkButton,
|
||||||
|
CallbackButton,
|
||||||
|
RequestGeoLocationButton,
|
||||||
|
MessageButton,
|
||||||
|
ButtonsPayload, # Для постройки клавиатуры без InlineKeyboardBuilder
|
||||||
|
RequestContactButton,
|
||||||
|
OpenAppButton,
|
||||||
|
)
|
||||||
|
|
||||||
|
from maxapi.types import (
|
||||||
|
MessageCreated,
|
||||||
|
MessageCallback,
|
||||||
|
MessageChatCreated,
|
||||||
|
CommandStart,
|
||||||
|
Command
|
||||||
|
)
|
||||||
|
|
||||||
|
from maxapi.utils.inline_keyboard import InlineKeyboardBuilder
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
bot = Bot('тут_ваш_токен')
|
||||||
|
dp = Dispatcher()
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(CommandStart())
|
||||||
|
async def echo(event: MessageCreated):
|
||||||
|
await event.message.answer(
|
||||||
|
(
|
||||||
|
'Привет! Мои команды:\n\n'
|
||||||
|
|
||||||
|
'/builder - Клавиатура из InlineKeyboardBuilder\n'
|
||||||
|
'/pyaload - Клавиатура из pydantic моделей\n'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(Command('builder'))
|
||||||
|
async def echo(event: MessageCreated):
|
||||||
|
builder = InlineKeyboardBuilder()
|
||||||
|
|
||||||
|
builder.row(
|
||||||
|
ChatButton(
|
||||||
|
text="Создать чат",
|
||||||
|
chat_title='Test',
|
||||||
|
chat_description='Test desc'
|
||||||
|
),
|
||||||
|
LinkButton(
|
||||||
|
text="Канал разработчика",
|
||||||
|
url="https://t.me/loveapples_dev"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
builder.row(
|
||||||
|
RequestGeoLocationButton(text="Геолокация"),
|
||||||
|
MessageButton(text="Сообщение"),
|
||||||
|
)
|
||||||
|
|
||||||
|
builder.row(
|
||||||
|
RequestContactButton(text="Контакт"),
|
||||||
|
OpenAppButton(
|
||||||
|
text="Приложение",
|
||||||
|
web_app=event.bot.me.username,
|
||||||
|
contact_id=event.bot.me.user_id
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
builder.row(
|
||||||
|
CallbackButton(
|
||||||
|
text='Callback',
|
||||||
|
payload='test',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
await event.message.answer(
|
||||||
|
text='Клавиатура из InlineKeyboardBuilder',
|
||||||
|
attachments=[
|
||||||
|
builder.as_markup()
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(Command('payload'))
|
||||||
|
async def echo(event: MessageCreated):
|
||||||
|
buttons = [
|
||||||
|
[
|
||||||
|
# кнопку типа "chat" убрали из документации,
|
||||||
|
# возможны баги
|
||||||
|
ChatButton(
|
||||||
|
text="Создать чат",
|
||||||
|
chat_title='Test',
|
||||||
|
chat_description='Test desc'
|
||||||
|
),
|
||||||
|
LinkButton(
|
||||||
|
text="Канал разработчика",
|
||||||
|
url="https://t.me/loveapples_dev"
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
RequestGeoLocationButton(text="Геолокация"),
|
||||||
|
MessageButton(text="Сообщение"),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
RequestContactButton(text="Контакт"),
|
||||||
|
OpenAppButton(
|
||||||
|
text="Приложение",
|
||||||
|
web_app=event.bot.me.username,
|
||||||
|
contact_id=event.bot.me.user_id
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
CallbackButton(
|
||||||
|
text='Callback',
|
||||||
|
payload='test',
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
buttons_payload = ButtonsPayload(buttons=buttons).pack()
|
||||||
|
|
||||||
|
await event.message.answer(
|
||||||
|
text='Клавиатура из pydantic моделей',
|
||||||
|
attachments=[
|
||||||
|
buttons_payload
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_chat_created()
|
||||||
|
async def callback(obj: MessageChatCreated):
|
||||||
|
await obj.bot.send_message(
|
||||||
|
chat_id=obj.chat.chat_id,
|
||||||
|
text=f'Чат создан! Ссылка: {obj.chat.link}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_callback()
|
||||||
|
async def callback(callback: MessageCallback):
|
||||||
|
await callback.message.answer('Вы нажали на Callback!')
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await dp.start_polling(bot)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
||||||
@@ -82,7 +82,8 @@ class Bot(BaseConnection):
|
|||||||
auto_requests: bool = True,
|
auto_requests: bool = True,
|
||||||
):
|
):
|
||||||
|
|
||||||
"""Инициализирует экземпляр бота с указанным токеном.
|
"""
|
||||||
|
Инициализирует экземпляр бота с указанным токеном.
|
||||||
|
|
||||||
:param token: Токен доступа к API бота
|
:param token: Токен доступа к API бота
|
||||||
:param parse_mode: Форматирование по умолчанию
|
:param parse_mode: Форматирование по умолчанию
|
||||||
@@ -103,6 +104,12 @@ class Bot(BaseConnection):
|
|||||||
self.notify = notify
|
self.notify = notify
|
||||||
self.auto_requests = auto_requests
|
self.auto_requests = auto_requests
|
||||||
|
|
||||||
|
self._me: User = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def me(self):
|
||||||
|
return self._me
|
||||||
|
|
||||||
def _resolve_notify(self, notify: Optional[bool]) -> Optional[bool]:
|
def _resolve_notify(self, notify: Optional[bool]) -> Optional[bool]:
|
||||||
return notify if notify is not None else self.notify
|
return notify if notify is not None else self.notify
|
||||||
|
|
||||||
@@ -120,7 +127,8 @@ class Bot(BaseConnection):
|
|||||||
parse_mode: Optional[ParseMode] = None
|
parse_mode: Optional[ParseMode] = None
|
||||||
) -> SendedMessage:
|
) -> SendedMessage:
|
||||||
|
|
||||||
"""Отправляет сообщение в чат или пользователю.
|
"""
|
||||||
|
Отправляет сообщение в чат или пользователю.
|
||||||
|
|
||||||
:param chat_id: ID чата для отправки (обязателен, если не указан user_id)
|
:param chat_id: ID чата для отправки (обязателен, если не указан user_id)
|
||||||
:param user_id: ID пользователя для отправки (обязателен, если не указан chat_id)
|
:param user_id: ID пользователя для отправки (обязателен, если не указан chat_id)
|
||||||
@@ -150,7 +158,8 @@ class Bot(BaseConnection):
|
|||||||
action: SenderAction = SenderAction.TYPING_ON
|
action: SenderAction = SenderAction.TYPING_ON
|
||||||
) -> SendedAction:
|
) -> SendedAction:
|
||||||
|
|
||||||
"""Отправляет действие в чат (например, "печатает").
|
"""
|
||||||
|
Отправляет действие в чат (например, "печатает").
|
||||||
|
|
||||||
:param chat_id: ID чата для отправки действия
|
:param chat_id: ID чата для отправки действия
|
||||||
:param action: Тип действия (по умолчанию SenderAction.TYPING_ON)
|
:param action: Тип действия (по умолчанию SenderAction.TYPING_ON)
|
||||||
@@ -174,7 +183,8 @@ class Bot(BaseConnection):
|
|||||||
parse_mode: Optional[ParseMode] = None
|
parse_mode: Optional[ParseMode] = None
|
||||||
) -> EditedMessage:
|
) -> EditedMessage:
|
||||||
|
|
||||||
"""Редактирует существующее сообщение.
|
"""
|
||||||
|
Редактирует существующее сообщение.
|
||||||
|
|
||||||
:param message_id: ID сообщения для редактирования
|
:param message_id: ID сообщения для редактирования
|
||||||
:param text: Новый текст сообщения
|
:param text: Новый текст сообщения
|
||||||
@@ -201,7 +211,8 @@ class Bot(BaseConnection):
|
|||||||
message_id: str
|
message_id: str
|
||||||
) -> DeletedMessage:
|
) -> DeletedMessage:
|
||||||
|
|
||||||
"""Удаляет сообщение.
|
"""
|
||||||
|
Удаляет сообщение.
|
||||||
|
|
||||||
:param message_id: ID сообщения для удаления
|
:param message_id: ID сообщения для удаления
|
||||||
|
|
||||||
@@ -218,7 +229,8 @@ class Bot(BaseConnection):
|
|||||||
chat_id: int
|
chat_id: int
|
||||||
) -> DeletedChat:
|
) -> DeletedChat:
|
||||||
|
|
||||||
"""Удаляет чат.
|
"""
|
||||||
|
Удаляет чат.
|
||||||
|
|
||||||
:param chat_id: ID чата для удаления
|
:param chat_id: ID чата для удаления
|
||||||
|
|
||||||
@@ -239,7 +251,8 @@ class Bot(BaseConnection):
|
|||||||
count: int = 50,
|
count: int = 50,
|
||||||
) -> Messages:
|
) -> Messages:
|
||||||
|
|
||||||
"""Получает сообщения из чата.
|
"""
|
||||||
|
Получает сообщения из чата.
|
||||||
|
|
||||||
:param chat_id: ID чата (обязателен, если не указаны message_ids)
|
:param chat_id: ID чата (обязателен, если не указаны message_ids)
|
||||||
:param message_ids: Список ID сообщений для получения
|
:param message_ids: Список ID сообщений для получения
|
||||||
@@ -264,7 +277,8 @@ class Bot(BaseConnection):
|
|||||||
message_id: str
|
message_id: str
|
||||||
) -> Messages:
|
) -> Messages:
|
||||||
|
|
||||||
"""Получает одно сообщение по ID.
|
"""
|
||||||
|
Получает одно сообщение по ID.
|
||||||
|
|
||||||
:param message_id: ID сообщения
|
:param message_id: ID сообщения
|
||||||
|
|
||||||
@@ -277,7 +291,8 @@ class Bot(BaseConnection):
|
|||||||
|
|
||||||
async def get_me(self) -> User:
|
async def get_me(self) -> User:
|
||||||
|
|
||||||
"""Получает информацию о текущем боте.
|
"""
|
||||||
|
Получает информацию о текущем боте.
|
||||||
|
|
||||||
:return: Объект пользователя бота
|
:return: Объект пользователя бота
|
||||||
"""
|
"""
|
||||||
@@ -289,7 +304,8 @@ class Bot(BaseConnection):
|
|||||||
chat_id: int
|
chat_id: int
|
||||||
) -> GettedPin:
|
) -> GettedPin:
|
||||||
|
|
||||||
"""Получает закрепленное сообщение в чате.
|
"""
|
||||||
|
Получает закрепленное сообщение в чате.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
|
|
||||||
@@ -309,7 +325,8 @@ class Bot(BaseConnection):
|
|||||||
photo: Dict[str, Any] = None
|
photo: Dict[str, Any] = None
|
||||||
) -> User:
|
) -> User:
|
||||||
|
|
||||||
"""Изменяет информацию о боте.
|
"""
|
||||||
|
Изменяет информацию о боте.
|
||||||
|
|
||||||
:param name: Новое имя бота
|
:param name: Новое имя бота
|
||||||
:param description: Новое описание бота
|
:param description: Новое описание бота
|
||||||
@@ -333,7 +350,8 @@ class Bot(BaseConnection):
|
|||||||
marker: int = None
|
marker: int = None
|
||||||
) -> Chats:
|
) -> Chats:
|
||||||
|
|
||||||
"""Получает список чатов бота.
|
"""
|
||||||
|
Получает список чатов бота.
|
||||||
|
|
||||||
:param count: Количество чатов (по умолчанию 50)
|
:param count: Количество чатов (по умолчанию 50)
|
||||||
:param marker: Маркер для пагинации
|
:param marker: Маркер для пагинации
|
||||||
@@ -352,7 +370,8 @@ class Bot(BaseConnection):
|
|||||||
link: str
|
link: str
|
||||||
) -> Chat:
|
) -> Chat:
|
||||||
|
|
||||||
"""Получает чат по ссылке.
|
"""
|
||||||
|
Получает чат по ссылке.
|
||||||
|
|
||||||
:param link: Ссылка на чат
|
:param link: Ссылка на чат
|
||||||
|
|
||||||
@@ -366,7 +385,8 @@ class Bot(BaseConnection):
|
|||||||
id: int
|
id: int
|
||||||
) -> Chat:
|
) -> Chat:
|
||||||
|
|
||||||
"""Получает чат по ID.
|
"""
|
||||||
|
Получает чат по ID.
|
||||||
|
|
||||||
:param id: ID чата
|
:param id: ID чата
|
||||||
|
|
||||||
@@ -384,7 +404,8 @@ class Bot(BaseConnection):
|
|||||||
notify: Optional[bool] = None,
|
notify: Optional[bool] = None,
|
||||||
) -> Chat:
|
) -> Chat:
|
||||||
|
|
||||||
"""Редактирует параметры чата.
|
"""
|
||||||
|
Редактирует параметры чата.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
:param icon: Данные иконки чата
|
:param icon: Данные иконки чата
|
||||||
@@ -409,7 +430,8 @@ class Bot(BaseConnection):
|
|||||||
video_token: str
|
video_token: str
|
||||||
) -> Video:
|
) -> Video:
|
||||||
|
|
||||||
"""Получает видео по токену.
|
"""
|
||||||
|
Получает видео по токену.
|
||||||
|
|
||||||
:param video_token: Токен видео
|
:param video_token: Токен видео
|
||||||
|
|
||||||
@@ -428,7 +450,8 @@ class Bot(BaseConnection):
|
|||||||
notification: str = None
|
notification: str = None
|
||||||
) -> SendedCallback:
|
) -> SendedCallback:
|
||||||
|
|
||||||
"""Отправляет callback ответ.
|
"""
|
||||||
|
Отправляет callback ответ.
|
||||||
|
|
||||||
:param callback_id: ID callback
|
:param callback_id: ID callback
|
||||||
:param message: Сообщение для отправки
|
:param message: Сообщение для отправки
|
||||||
@@ -451,7 +474,8 @@ class Bot(BaseConnection):
|
|||||||
notify: Optional[bool] = None
|
notify: Optional[bool] = None
|
||||||
) -> PinnedMessage:
|
) -> PinnedMessage:
|
||||||
|
|
||||||
"""Закрепляет сообщение в чате.
|
"""
|
||||||
|
Закрепляет сообщение в чате.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
:param message_id: ID сообщения
|
:param message_id: ID сообщения
|
||||||
@@ -472,7 +496,8 @@ class Bot(BaseConnection):
|
|||||||
chat_id: int,
|
chat_id: int,
|
||||||
) -> DeletedPinMessage:
|
) -> DeletedPinMessage:
|
||||||
|
|
||||||
"""Удаляет закрепленное сообщение в чате.
|
"""
|
||||||
|
Удаляет закрепленное сообщение в чате.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
|
|
||||||
@@ -489,7 +514,8 @@ class Bot(BaseConnection):
|
|||||||
chat_id: int,
|
chat_id: int,
|
||||||
) -> ChatMember:
|
) -> ChatMember:
|
||||||
|
|
||||||
"""Получает информацию о боте в конкретном чате.
|
"""
|
||||||
|
Получает информацию о боте в конкретном чате.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
|
|
||||||
@@ -506,7 +532,8 @@ class Bot(BaseConnection):
|
|||||||
chat_id: int,
|
chat_id: int,
|
||||||
) -> DeletedBotFromChat:
|
) -> DeletedBotFromChat:
|
||||||
|
|
||||||
"""Удаляет бота из чата.
|
"""
|
||||||
|
Удаляет бота из чата.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
|
|
||||||
@@ -523,7 +550,8 @@ class Bot(BaseConnection):
|
|||||||
chat_id: int,
|
chat_id: int,
|
||||||
) -> GettedListAdminChat:
|
) -> GettedListAdminChat:
|
||||||
|
|
||||||
"""Получает список администраторов чата.
|
"""
|
||||||
|
Получает список администраторов чата.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
|
|
||||||
@@ -542,7 +570,8 @@ class Bot(BaseConnection):
|
|||||||
marker: int = None
|
marker: int = None
|
||||||
) -> AddedListAdminChat:
|
) -> AddedListAdminChat:
|
||||||
|
|
||||||
"""Добавляет администраторов в чат.
|
"""
|
||||||
|
Добавляет администраторов в чат.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
:param admins: Список администраторов
|
:param admins: Список администраторов
|
||||||
@@ -564,7 +593,8 @@ class Bot(BaseConnection):
|
|||||||
user_id: int
|
user_id: int
|
||||||
) -> RemovedAdmin:
|
) -> RemovedAdmin:
|
||||||
|
|
||||||
"""Удаляет администратора из чата.
|
"""
|
||||||
|
Удаляет администратора из чата.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
:param user_id: ID пользователя
|
:param user_id: ID пользователя
|
||||||
@@ -586,7 +616,8 @@ class Bot(BaseConnection):
|
|||||||
count: int = None,
|
count: int = None,
|
||||||
) -> GettedMembersChat:
|
) -> GettedMembersChat:
|
||||||
|
|
||||||
"""Получает участников чата.
|
"""
|
||||||
|
Получает участников чата.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
:param user_ids: Список ID участников
|
:param user_ids: Список ID участников
|
||||||
@@ -610,7 +641,8 @@ class Bot(BaseConnection):
|
|||||||
user_id: int,
|
user_id: int,
|
||||||
) -> GettedMembersChat:
|
) -> GettedMembersChat:
|
||||||
|
|
||||||
"""Получает участника чата.
|
"""
|
||||||
|
Получает участника чата.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
:param user_id: ID участника
|
:param user_id: ID участника
|
||||||
@@ -632,7 +664,8 @@ class Bot(BaseConnection):
|
|||||||
user_ids: List[str],
|
user_ids: List[str],
|
||||||
) -> AddedMembersChat:
|
) -> AddedMembersChat:
|
||||||
|
|
||||||
"""Добавляет участников в чат.
|
"""
|
||||||
|
Добавляет участников в чат.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
:param user_ids: Список ID пользователей
|
:param user_ids: Список ID пользователей
|
||||||
@@ -653,7 +686,8 @@ class Bot(BaseConnection):
|
|||||||
block: bool = False,
|
block: bool = False,
|
||||||
) -> RemovedMemberChat:
|
) -> RemovedMemberChat:
|
||||||
|
|
||||||
"""Исключает участника из чата.
|
"""
|
||||||
|
Исключает участника из чата.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
:param user_id: ID пользователя
|
:param user_id: ID пользователя
|
||||||
@@ -673,7 +707,8 @@ class Bot(BaseConnection):
|
|||||||
self,
|
self,
|
||||||
) -> UpdateUnion:
|
) -> UpdateUnion:
|
||||||
|
|
||||||
"""Получает обновления для бота.
|
"""
|
||||||
|
Получает обновления для бота.
|
||||||
|
|
||||||
:return: Список обновлений
|
:return: Список обновлений
|
||||||
"""
|
"""
|
||||||
@@ -687,7 +722,8 @@ class Bot(BaseConnection):
|
|||||||
type: UploadType
|
type: UploadType
|
||||||
) -> GettedUploadUrl:
|
) -> GettedUploadUrl:
|
||||||
|
|
||||||
"""Получает URL для загрузки файлов.
|
"""
|
||||||
|
Получает URL для загрузки файлов.
|
||||||
|
|
||||||
:param type: Тип загружаемого файла
|
:param type: Тип загружаемого файла
|
||||||
|
|
||||||
@@ -704,7 +740,8 @@ class Bot(BaseConnection):
|
|||||||
*commands: BotCommand
|
*commands: BotCommand
|
||||||
) -> User:
|
) -> User:
|
||||||
|
|
||||||
"""Устанавливает список команд бота.
|
"""
|
||||||
|
Устанавливает список команд бота.
|
||||||
|
|
||||||
:param commands: Список команд
|
:param commands: Список команд
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import os
|
import os
|
||||||
|
import mimetypes
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
import aiofiles
|
import aiofiles
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
|
import puremagic
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from ..exceptions.invalid_token import InvalidToken
|
from ..exceptions.invalid_token import InvalidToken
|
||||||
@@ -135,6 +138,51 @@ class BaseConnection:
|
|||||||
|
|
||||||
return await response.text()
|
return await response.text()
|
||||||
|
|
||||||
|
async def upload_file_buffer(
|
||||||
|
self,
|
||||||
|
url: str,
|
||||||
|
buffer: bytes,
|
||||||
|
type: UploadType
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Загружает файл из буфера.
|
||||||
|
|
||||||
|
:param url: Конечная точка загрузки файла
|
||||||
|
:param buffer: Буфер (bytes)
|
||||||
|
:param type: Тип файла (video, image, audio, file)
|
||||||
|
|
||||||
|
:return: Сырой .text() ответ от сервера после загрузки файла
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
matches = puremagic.magic_string(buffer[:4096])
|
||||||
|
if matches:
|
||||||
|
mime_type = matches[0][1]
|
||||||
|
ext = mimetypes.guess_extension(mime_type) or ''
|
||||||
|
else:
|
||||||
|
mime_type = f"{type.value}/*"
|
||||||
|
ext = ''
|
||||||
|
except Exception:
|
||||||
|
mime_type = f"{type.value}/*"
|
||||||
|
ext = ''
|
||||||
|
|
||||||
|
basename = f'{uuid4()}{ext}'
|
||||||
|
|
||||||
|
form = aiohttp.FormData()
|
||||||
|
form.add_field(
|
||||||
|
name='data',
|
||||||
|
value=buffer,
|
||||||
|
filename=basename,
|
||||||
|
content_type=mime_type
|
||||||
|
)
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
response = await session.post(
|
||||||
|
url=url,
|
||||||
|
data=form
|
||||||
|
)
|
||||||
|
return await response.text()
|
||||||
|
|
||||||
async def download_file(
|
async def download_file(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
|
|||||||
@@ -36,12 +36,19 @@ GET_UPDATES_RETRY_DELAY = 5
|
|||||||
|
|
||||||
class Dispatcher:
|
class Dispatcher:
|
||||||
|
|
||||||
"""Основной класс для обработки событий бота.
|
"""
|
||||||
|
Основной класс для обработки событий бота.
|
||||||
|
|
||||||
Обеспечивает работу с вебхуком и поллингом, управляет обработчиками событий.
|
Обеспечивает запуск поллинга и вебхука, маршрутизацию событий,
|
||||||
|
применение middleware, фильтров и вызов соответствующих обработчиков.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Инициализация диспетчера.
|
||||||
|
"""
|
||||||
|
|
||||||
self.event_handlers: List[Handler] = []
|
self.event_handlers: List[Handler] = []
|
||||||
self.contexts: List[MemoryContext] = []
|
self.contexts: List[MemoryContext] = []
|
||||||
self.routers: List[Router] = []
|
self.routers: List[Router] = []
|
||||||
@@ -66,22 +73,34 @@ class Dispatcher:
|
|||||||
|
|
||||||
async def check_me(self):
|
async def check_me(self):
|
||||||
|
|
||||||
"""Проверяет и логирует информацию о боте."""
|
"""
|
||||||
|
Проверяет и логирует информацию о боте.
|
||||||
|
"""
|
||||||
|
|
||||||
me = await self.bot.get_me()
|
me = await self.bot.get_me()
|
||||||
|
|
||||||
|
self.bot._me = me
|
||||||
|
|
||||||
logger_dp.info(f'Бот: @{me.username} first_name={me.first_name} id={me.user_id}')
|
logger_dp.info(f'Бот: @{me.username} first_name={me.first_name} id={me.user_id}')
|
||||||
|
|
||||||
def include_routers(self, *routers: 'Router'):
|
def include_routers(self, *routers: 'Router'):
|
||||||
|
|
||||||
"""Добавляет обработчики из роутеров.
|
"""
|
||||||
|
Добавляет указанные роутеры в диспетчер.
|
||||||
|
|
||||||
Args:
|
:param routers: Роутеры для добавления.
|
||||||
*routers: Роутеры для включения
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.routers += [r for r in routers]
|
self.routers += [r for r in routers]
|
||||||
|
|
||||||
async def __ready(self, bot: Bot):
|
async def __ready(self, bot: Bot):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Подготавливает диспетчер: сохраняет бота, регистрирует обработчики, вызывает on_started.
|
||||||
|
|
||||||
|
:param bot: Экземпляр бота.
|
||||||
|
"""
|
||||||
|
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
await self.check_me()
|
await self.check_me()
|
||||||
|
|
||||||
@@ -96,14 +115,12 @@ class Dispatcher:
|
|||||||
|
|
||||||
def __get_memory_context(self, chat_id: int, user_id: int):
|
def __get_memory_context(self, chat_id: int, user_id: int):
|
||||||
|
|
||||||
"""Возвращает или создает контекст для чата и пользователя.
|
"""
|
||||||
|
Возвращает существующий или создает новый контекст по chat_id и user_id.
|
||||||
|
|
||||||
Args:
|
:param chat_id: Идентификатор чата.
|
||||||
chat_id: ID чата
|
:param user_id: Идентификатор пользователя.
|
||||||
user_id: ID пользователя
|
:return: Объект MemoryContext.
|
||||||
|
|
||||||
Returns:
|
|
||||||
Существующий или новый контекст
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for ctx in self.contexts:
|
for ctx in self.contexts:
|
||||||
@@ -121,6 +138,15 @@ class Dispatcher:
|
|||||||
result_data_kwargs: Dict[str, Any]
|
result_data_kwargs: Dict[str, Any]
|
||||||
):
|
):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Последовательно обрабатывает middleware цепочку.
|
||||||
|
|
||||||
|
:param middlewares: Список middleware.
|
||||||
|
:param event_object: Объект события.
|
||||||
|
:param result_data_kwargs: Аргументы, передаваемые обработчику.
|
||||||
|
:return: Изменённые аргументы или None.
|
||||||
|
"""
|
||||||
|
|
||||||
for middleware in middlewares:
|
for middleware in middlewares:
|
||||||
result = await middleware.process_middleware(
|
result = await middleware.process_middleware(
|
||||||
event_object=event_object,
|
event_object=event_object,
|
||||||
@@ -139,11 +165,12 @@ class Dispatcher:
|
|||||||
|
|
||||||
async def handle(self, event_object: UpdateUnion):
|
async def handle(self, event_object: UpdateUnion):
|
||||||
|
|
||||||
"""Обрабатывает событие.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
event_object: Объект события для обработки
|
|
||||||
"""
|
"""
|
||||||
|
Основной обработчик события. Применяет фильтры, middleware и вызывает подходящий handler.
|
||||||
|
|
||||||
|
:param event_object: Событие, пришедшее в бот.
|
||||||
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ids = event_object.get_ids()
|
ids = event_object.get_ids()
|
||||||
memory_context = self.__get_memory_context(*ids)
|
memory_context = self.__get_memory_context(*ids)
|
||||||
@@ -209,11 +236,12 @@ class Dispatcher:
|
|||||||
|
|
||||||
async def start_polling(self, bot: Bot):
|
async def start_polling(self, bot: Bot):
|
||||||
|
|
||||||
"""Запускает поллинг обновлений.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
bot: Экземпляр бота
|
|
||||||
"""
|
"""
|
||||||
|
Запускает цикл получения обновлений с сервера (long polling).
|
||||||
|
|
||||||
|
:param bot: Экземпляр бота.
|
||||||
|
"""
|
||||||
|
|
||||||
await self.__ready(bot)
|
await self.__ready(bot)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@@ -243,12 +271,12 @@ class Dispatcher:
|
|||||||
|
|
||||||
async def handle_webhook(self, bot: Bot, host: str = '0.0.0.0', port: int = 8080):
|
async def handle_webhook(self, bot: Bot, host: str = '0.0.0.0', port: int = 8080):
|
||||||
|
|
||||||
"""Запускает вебхук сервер.
|
"""
|
||||||
|
Запускает FastAPI-приложение для приёма обновлений через вебхук.
|
||||||
|
|
||||||
Args:
|
:param bot: Экземпляр бота.
|
||||||
bot: Экземпляр бота
|
:param host: Хост, на котором запускается сервер.
|
||||||
host: Хост для сервера
|
:param port: Порт сервера.
|
||||||
port: Порт для сервера
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await self.__ready(bot)
|
await self.__ready(bot)
|
||||||
@@ -277,7 +305,9 @@ class Dispatcher:
|
|||||||
|
|
||||||
class Router(Dispatcher):
|
class Router(Dispatcher):
|
||||||
|
|
||||||
"""Роутер для группировки обработчиков событий."""
|
"""
|
||||||
|
Роутер для группировки обработчиков событий.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -285,13 +315,30 @@ class Router(Dispatcher):
|
|||||||
|
|
||||||
class Event:
|
class Event:
|
||||||
|
|
||||||
"""Декоратор для регистрации обработчиков событий."""
|
"""
|
||||||
|
Декоратор для регистрации обработчиков событий.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, update_type: UpdateType, router: Dispatcher | Router):
|
def __init__(self, update_type: UpdateType, router: Dispatcher | Router):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Инициализирует событие-декоратор.
|
||||||
|
|
||||||
|
:param update_type: Тип события (UpdateType).
|
||||||
|
:param router: Роутер или диспетчер, в который регистрируется обработчик.
|
||||||
|
"""
|
||||||
|
|
||||||
self.update_type = update_type
|
self.update_type = update_type
|
||||||
self.router = router
|
self.router = router
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Регистрирует функцию как обработчик события.
|
||||||
|
|
||||||
|
:return: Исходная функция.
|
||||||
|
"""
|
||||||
|
|
||||||
def decorator(func_event: Callable):
|
def decorator(func_event: Callable):
|
||||||
|
|
||||||
if self.update_type == UpdateType.ON_STARTED:
|
if self.update_type == UpdateType.ON_STARTED:
|
||||||
|
|||||||
@@ -14,3 +14,5 @@ class ButtonType(str, Enum):
|
|||||||
LINK = 'link'
|
LINK = 'link'
|
||||||
REQUEST_GEO_LOCATION = 'request_geo_location'
|
REQUEST_GEO_LOCATION = 'request_geo_location'
|
||||||
CHAT = 'chat'
|
CHAT = 'chat'
|
||||||
|
MESSAGE = 'message'
|
||||||
|
OPEN_APP = 'open_app'
|
||||||
@@ -4,7 +4,7 @@ from magic_filter import F, MagicFilter
|
|||||||
|
|
||||||
from ..filters.middleware import BaseMiddleware
|
from ..filters.middleware import BaseMiddleware
|
||||||
|
|
||||||
from ..types.command import Command
|
from ..types.command import Command, CommandStart
|
||||||
|
|
||||||
from ..context.state_machine import State
|
from ..context.state_machine import State
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ class Handler:
|
|||||||
self.filters.append(arg)
|
self.filters.append(arg)
|
||||||
elif isinstance(arg, State):
|
elif isinstance(arg, State):
|
||||||
self.state = arg
|
self.state = arg
|
||||||
elif isinstance(arg, Command):
|
elif isinstance(arg, (Command, CommandStart)):
|
||||||
self.filters.insert(0, F.message.body.text.startswith(arg.command))
|
self.filters.insert(0, F.message.body.text.startswith(arg.command))
|
||||||
elif isinstance(arg, BaseMiddleware):
|
elif isinstance(arg, BaseMiddleware):
|
||||||
self.middlewares.append(arg)
|
self.middlewares.append(arg)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from .types.sended_message import SendedMessage
|
|||||||
from ..types.attachments.upload import AttachmentPayload, AttachmentUpload
|
from ..types.attachments.upload import AttachmentPayload, AttachmentUpload
|
||||||
from ..types.errors import Error
|
from ..types.errors import Error
|
||||||
from ..types.message import NewMessageLink
|
from ..types.message import NewMessageLink
|
||||||
from ..types.input_media import InputMedia
|
from ..types.input_media import InputMedia, InputMediaBuffer
|
||||||
from ..types.attachments.attachment import Attachment
|
from ..types.attachments.attachment import Attachment
|
||||||
|
|
||||||
from ..enums.upload_type import UploadType
|
from ..enums.upload_type import UploadType
|
||||||
@@ -67,7 +67,7 @@ class SendMessage(BaseConnection):
|
|||||||
|
|
||||||
async def __process_input_media(
|
async def __process_input_media(
|
||||||
self,
|
self,
|
||||||
att: InputMedia
|
att: InputMedia | InputMediaBuffer
|
||||||
):
|
):
|
||||||
|
|
||||||
# очень нестабильный метод независящий от модуля
|
# очень нестабильный метод независящий от модуля
|
||||||
@@ -85,11 +85,18 @@ class SendMessage(BaseConnection):
|
|||||||
|
|
||||||
upload = await self.bot.get_upload_url(att.type)
|
upload = await self.bot.get_upload_url(att.type)
|
||||||
|
|
||||||
upload_file_response = await self.upload_file(
|
if isinstance(att, InputMedia):
|
||||||
url=upload.url,
|
upload_file_response = await self.upload_file(
|
||||||
path=att.path,
|
url=upload.url,
|
||||||
type=att.type
|
path=att.path,
|
||||||
)
|
type=att.type,
|
||||||
|
)
|
||||||
|
elif isinstance(att, InputMediaBuffer):
|
||||||
|
upload_file_response = await self.upload_file_buffer(
|
||||||
|
url=upload.url,
|
||||||
|
buffer=att.buffer,
|
||||||
|
type=att.type,
|
||||||
|
)
|
||||||
|
|
||||||
if att.type in (UploadType.VIDEO, UploadType.AUDIO):
|
if att.type in (UploadType.VIDEO, UploadType.AUDIO):
|
||||||
token = upload.token
|
token = upload.token
|
||||||
@@ -134,7 +141,7 @@ class SendMessage(BaseConnection):
|
|||||||
|
|
||||||
for att in self.attachments:
|
for att in self.attachments:
|
||||||
|
|
||||||
if isinstance(att, InputMedia):
|
if isinstance(att, InputMedia) or isinstance(att, InputMediaBuffer):
|
||||||
input_media = await self.__process_input_media(att)
|
input_media = await self.__process_input_media(att)
|
||||||
json['attachments'].append(
|
json['attachments'].append(
|
||||||
input_media.model_dump()
|
input_media.model_dump()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from ..types.updates.user_added import UserAdded
|
|||||||
from ..types.updates.user_removed import UserRemoved
|
from ..types.updates.user_removed import UserRemoved
|
||||||
from ..types.updates import UpdateUnion
|
from ..types.updates import UpdateUnion
|
||||||
|
|
||||||
|
from ..types.attachments.attachment import Attachment
|
||||||
from ..types.attachments.attachment import PhotoAttachmentPayload
|
from ..types.attachments.attachment import PhotoAttachmentPayload
|
||||||
from ..types.attachments.attachment import OtherAttachmentPayload
|
from ..types.attachments.attachment import OtherAttachmentPayload
|
||||||
from ..types.attachments.attachment import ContactAttachmentPayload
|
from ..types.attachments.attachment import ContactAttachmentPayload
|
||||||
@@ -19,22 +20,31 @@ from ..types.attachments.attachment import StickerAttachmentPayload
|
|||||||
from ..types.attachments.buttons.callback_button import CallbackButton
|
from ..types.attachments.buttons.callback_button import CallbackButton
|
||||||
from ..types.attachments.buttons.chat_button import ChatButton
|
from ..types.attachments.buttons.chat_button import ChatButton
|
||||||
from ..types.attachments.buttons.link_button import LinkButton
|
from ..types.attachments.buttons.link_button import LinkButton
|
||||||
from ..types.attachments.buttons.request_contact import RequestContact
|
from ..types.attachments.buttons.request_contact import RequestContactButton
|
||||||
|
from ..types.attachments.buttons.open_app_button import OpenAppButton
|
||||||
from ..types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
|
from ..types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
|
||||||
|
from ..types.attachments.buttons.message_button import MessageButton
|
||||||
from ..types.message import Message
|
from ..types.message import Message
|
||||||
|
|
||||||
from ..types.command import Command, BotCommand
|
from ..types.command import Command, BotCommand, CommandStart
|
||||||
|
|
||||||
from .input_media import InputMedia
|
from .input_media import InputMedia
|
||||||
|
from .input_media import InputMediaBuffer
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
CommandStart,
|
||||||
|
OpenAppButton,
|
||||||
|
Message,
|
||||||
|
Attachment,
|
||||||
|
InputMediaBuffer,
|
||||||
|
MessageButton,
|
||||||
UpdateUnion,
|
UpdateUnion,
|
||||||
InputMedia,
|
InputMedia,
|
||||||
BotCommand,
|
BotCommand,
|
||||||
CallbackButton,
|
CallbackButton,
|
||||||
ChatButton,
|
ChatButton,
|
||||||
LinkButton,
|
LinkButton,
|
||||||
RequestContact,
|
RequestContactButton,
|
||||||
RequestGeoLocationButton,
|
RequestGeoLocationButton,
|
||||||
Command,
|
Command,
|
||||||
PhotoAttachmentPayload,
|
PhotoAttachmentPayload,
|
||||||
|
|||||||
@@ -83,6 +83,12 @@ class ButtonsPayload(BaseModel):
|
|||||||
|
|
||||||
buttons: List[List[InlineButtonUnion]]
|
buttons: List[List[InlineButtonUnion]]
|
||||||
|
|
||||||
|
def pack(self):
|
||||||
|
return Attachment(
|
||||||
|
type=AttachmentType.INLINE_KEYBOARD,
|
||||||
|
payload=self
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Attachment(BaseModel):
|
class Attachment(BaseModel):
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ from typing import Union
|
|||||||
from .callback_button import CallbackButton
|
from .callback_button import CallbackButton
|
||||||
from .chat_button import ChatButton
|
from .chat_button import ChatButton
|
||||||
from .link_button import LinkButton
|
from .link_button import LinkButton
|
||||||
from .request_contact import RequestContact
|
from .request_contact import RequestContactButton
|
||||||
from .request_geo_location_button import RequestGeoLocationButton
|
from .request_geo_location_button import RequestGeoLocationButton
|
||||||
|
from .message_button import MessageButton
|
||||||
|
from .open_app_button import OpenAppButton
|
||||||
|
|
||||||
InlineButtonUnion = Union[
|
InlineButtonUnion = Union[
|
||||||
CallbackButton,
|
CallbackButton,
|
||||||
ChatButton,
|
ChatButton,
|
||||||
LinkButton,
|
LinkButton,
|
||||||
RequestContact,
|
RequestContactButton,
|
||||||
RequestGeoLocationButton
|
RequestGeoLocationButton,
|
||||||
|
MessageButton,
|
||||||
|
OpenAppButton
|
||||||
]
|
]
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from ....enums.button_type import ButtonType
|
||||||
|
|
||||||
from .button import Button
|
from .button import Button
|
||||||
|
|
||||||
|
|
||||||
@@ -12,4 +14,5 @@ class LinkButton(Button):
|
|||||||
url: Ссылка для перехода (должна содержать http/https)
|
url: Ссылка для перехода (должна содержать http/https)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
type: ButtonType = ButtonType.LINK
|
||||||
url: Optional[str] = None
|
url: Optional[str] = None
|
||||||
19
maxapi/types/attachments/buttons/message_button.py
Normal file
19
maxapi/types/attachments/buttons/message_button.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from ....enums.button_type import ButtonType
|
||||||
|
|
||||||
|
from .button import Button
|
||||||
|
|
||||||
|
|
||||||
|
class MessageButton(Button):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Кнопка для отправки текста
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type: Тип кнопки (определяет её поведение и функционал)
|
||||||
|
text: Отправляемый текст
|
||||||
|
"""
|
||||||
|
|
||||||
|
type: ButtonType = ButtonType.MESSAGE
|
||||||
|
text: str
|
||||||
22
maxapi/types/attachments/buttons/open_app_button.py
Normal file
22
maxapi/types/attachments/buttons/open_app_button.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from ....enums.button_type import ButtonType
|
||||||
|
|
||||||
|
from .button import Button
|
||||||
|
|
||||||
|
|
||||||
|
class OpenAppButton(Button):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Кнопка для открытия приложения
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
text: Видимый текст кнопки
|
||||||
|
web_app: Публичное имя (username) бота или ссылка на него, чьё мини-приложение надо запустить
|
||||||
|
contact_id: Идентификатор бота, чьё мини-приложение надо запустить
|
||||||
|
"""
|
||||||
|
|
||||||
|
type: ButtonType = ButtonType.OPEN_APP
|
||||||
|
text: str
|
||||||
|
web_app: Optional[str] = None
|
||||||
|
contact_id: Optional[int] = None
|
||||||
@@ -1,8 +1,18 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from ....enums.button_type import ButtonType
|
||||||
|
|
||||||
from .button import Button
|
from .button import Button
|
||||||
|
|
||||||
|
|
||||||
class RequestContact(Button):
|
class RequestContactButton(Button):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Кнопка с контактом.
|
Кнопка с контактом
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: Текст кнопки
|
||||||
"""
|
"""
|
||||||
...
|
|
||||||
|
type: ButtonType = ButtonType.REQUEST_CONTACT
|
||||||
|
text: str
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from ....enums.button_type import ButtonType
|
||||||
|
|
||||||
from .button import Button
|
from .button import Button
|
||||||
|
|
||||||
|
|
||||||
@@ -10,4 +12,5 @@ class RequestGeoLocationButton(Button):
|
|||||||
подтверждения пользователя (по умолчанию False)
|
подтверждения пользователя (по умолчанию False)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
type: ButtonType = ButtonType.REQUEST_GEO_LOCATION
|
||||||
quick: bool = False
|
quick: bool = False
|
||||||
@@ -41,3 +41,18 @@ class BotCommand(BaseModel):
|
|||||||
|
|
||||||
name: str
|
name: str
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class CommandStart(Command):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Класс для представления команды /start бота.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
prefix (str): Префикс команды. По умолчанию '/'.
|
||||||
|
"""
|
||||||
|
|
||||||
|
text = 'start'
|
||||||
|
|
||||||
|
def __init__(self, prefix: str = '/'):
|
||||||
|
self.prefix = prefix
|
||||||
@@ -1,34 +1,38 @@
|
|||||||
import mimetypes
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import puremagic
|
||||||
|
|
||||||
from ..enums.upload_type import UploadType
|
from ..enums.upload_type import UploadType
|
||||||
|
|
||||||
|
|
||||||
class InputMedia:
|
if TYPE_CHECKING:
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
|
||||||
|
class InputMedia:
|
||||||
"""
|
"""
|
||||||
Класс для представления медиафайла.
|
Класс для представления медиафайла.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
path (str): Путь к файлу.
|
path (str): Путь к файлу.
|
||||||
type (UploadType): Тип файла, определенный на основе MIME-типа.
|
type (UploadType): Тип файла, определенный на основе содержимого (MIME-типа).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, path: str):
|
def __init__(self, path: str):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Инициализирует объект медиафайла.
|
Инициализирует объект медиафайла.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
path (str): Путь к файлу.
|
path (str): Путь к файлу.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.path = path
|
self.path = path
|
||||||
self.type = self.__detect_file_type(path)
|
self.type = self.__detect_file_type(path)
|
||||||
|
|
||||||
def __detect_file_type(self, path: str) -> UploadType:
|
def __detect_file_type(self, path: str) -> UploadType:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Определяет тип файла на основе его MIME-типа.
|
Определяет тип файла на основе его содержимого (MIME-типа).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
path (str): Путь к файлу.
|
path (str): Путь к файлу.
|
||||||
@@ -36,8 +40,17 @@ class InputMedia:
|
|||||||
Returns:
|
Returns:
|
||||||
UploadType: Тип файла (VIDEO, IMAGE, AUDIO или FILE).
|
UploadType: Тип файла (VIDEO, IMAGE, AUDIO или FILE).
|
||||||
"""
|
"""
|
||||||
|
with open(path, 'rb') as f:
|
||||||
|
sample = f.read(4096)
|
||||||
|
|
||||||
mime_type, _ = mimetypes.guess_type(path)
|
try:
|
||||||
|
matches = puremagic.magic_string(sample)
|
||||||
|
if matches:
|
||||||
|
mime_type = matches[0].mime_type
|
||||||
|
else:
|
||||||
|
mime_type = None
|
||||||
|
except Exception:
|
||||||
|
mime_type = None
|
||||||
|
|
||||||
if mime_type is None:
|
if mime_type is None:
|
||||||
return UploadType.FILE
|
return UploadType.FILE
|
||||||
@@ -50,3 +63,44 @@ class InputMedia:
|
|||||||
return UploadType.AUDIO
|
return UploadType.AUDIO
|
||||||
else:
|
else:
|
||||||
return UploadType.FILE
|
return UploadType.FILE
|
||||||
|
|
||||||
|
|
||||||
|
class InputMediaBuffer:
|
||||||
|
"""
|
||||||
|
Класс для представления медиафайла из буфера.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
buffer (BytesIO): Буфер с содержимым файла.
|
||||||
|
type (UploadType): Тип файла, определенный по содержимому.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, buffer: BytesIO):
|
||||||
|
"""
|
||||||
|
Инициализирует объект медиафайла из буфера.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
buffer (IO): Буфер с содержимым файла.
|
||||||
|
"""
|
||||||
|
self.buffer = buffer
|
||||||
|
self.type = self.__detect_file_type(buffer)
|
||||||
|
|
||||||
|
def __detect_file_type(self, buffer: BytesIO) -> UploadType:
|
||||||
|
try:
|
||||||
|
matches = puremagic.magic_string(buffer)
|
||||||
|
if matches:
|
||||||
|
mime_type = matches[0].mime_type
|
||||||
|
else:
|
||||||
|
mime_type = None
|
||||||
|
except Exception:
|
||||||
|
mime_type = None
|
||||||
|
|
||||||
|
if mime_type is None:
|
||||||
|
return UploadType.FILE
|
||||||
|
if mime_type.startswith('video/'):
|
||||||
|
return UploadType.VIDEO
|
||||||
|
elif mime_type.startswith('image/'):
|
||||||
|
return UploadType.IMAGE
|
||||||
|
elif mime_type.startswith('audio/'):
|
||||||
|
return UploadType.AUDIO
|
||||||
|
else:
|
||||||
|
return UploadType.FILE
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "maxapi"
|
name = "maxapi"
|
||||||
version = "0.8.7"
|
version = "0.8.9"
|
||||||
description = "Библиотека для разработки чат-ботов с помощью API мессенджера MAX"
|
description = "Библиотека для разработки чат-ботов с помощью API мессенджера MAX"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
@@ -19,6 +19,7 @@ dependencies = [
|
|||||||
"pydantic>=1.8.0",
|
"pydantic>=1.8.0",
|
||||||
"uvicorn>=0.15.0",
|
"uvicorn>=0.15.0",
|
||||||
"aiofiles==24.1.0",
|
"aiofiles==24.1.0",
|
||||||
|
"puremagic==1.30"
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
@@ -30,3 +31,6 @@ license-files = []
|
|||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools>=68.0.0", "wheel"]
|
requires = ["setuptools>=68.0.0", "wheel"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
include = ["maxapi*", "wiki*", "examples*"]
|
||||||
284
wiki/bot_methods.md
Normal file
284
wiki/bot_methods.md
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
# Методы класса Bot
|
||||||
|
|
||||||
|
## 💬 Работа с сообщениями
|
||||||
|
|
||||||
|
### `send_message(...)`
|
||||||
|
|
||||||
|
**Описание:** Отправить сообщение в чат или пользователю.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `chat_id` *(int)* — ID чата. Обязателен, если не указан `user_id`.
|
||||||
|
* `user_id` *(int)* — ID пользователя. Обязателен, если не указан `chat_id`.
|
||||||
|
* `text` *(str)* — текст сообщения.
|
||||||
|
* `attachments` *(List\[Attachment])* — вложения (фото, видео и т.д.).
|
||||||
|
* `link` *(NewMessageLink)* — объект для создания ссылочного сообщения.
|
||||||
|
* `notify` *(bool)* — отправлять ли уведомление (по умолчанию берётся из настроек бота).
|
||||||
|
* `parse_mode` *(ParseMode)* — форматирование текста (например, `ParseMode.HTML`).
|
||||||
|
|
||||||
|
**Возвращает:** `SendedMessage` — объект отправленного сообщения.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `edit_message(...)`
|
||||||
|
|
||||||
|
**Описание:** Редактировать существующее сообщение.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `message_id` *(str)* — ID сообщения, полученное ранее в `SendedMessage.id`.
|
||||||
|
* `text`, `attachments`, `link`, `notify`, `parse_mode` — см. `send_message`.
|
||||||
|
|
||||||
|
**Возвращает:** `EditedMessage` — объект изменённого сообщения.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `delete_message(message_id)`
|
||||||
|
|
||||||
|
**Описание:** Удалить сообщение по его ID.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `message_id` *(str)* — ID сообщения.
|
||||||
|
|
||||||
|
**Возвращает:** `DeletedMessage` — результат удаления.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `get_messages(...)`
|
||||||
|
|
||||||
|
**Описание:** Получить список сообщений.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `chat_id` *(int)* — ID чата.
|
||||||
|
* `message_ids` *(List\[str])* — список ID сообщений.
|
||||||
|
* `from_time` / `to_time` *(datetime | int)* — диапазон по времени.
|
||||||
|
* `count` *(int)* — сколько сообщений вернуть (по умолчанию 50).
|
||||||
|
|
||||||
|
**Возвращает:** `Messages` — список объектов сообщений.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `get_message(message_id)`
|
||||||
|
|
||||||
|
**Описание:** Получить одно сообщение по ID.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `message_id` *(str)* — ID сообщения.
|
||||||
|
|
||||||
|
**Возвращает:** `Messages` — содержит одно сообщение в списке.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `pin_message(...)`
|
||||||
|
|
||||||
|
**Описание:** Закрепить сообщение в чате.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `chat_id` *(int)* — ID чата.
|
||||||
|
* `message_id` *(str)* — ID сообщения.
|
||||||
|
* `notify` *(bool)* — уведомление.
|
||||||
|
|
||||||
|
**Возвращает:** `PinnedMessage`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `delete_pin_message(chat_id)`
|
||||||
|
|
||||||
|
**Описание:** Удалить закреплённое сообщение.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `chat_id` *(int)* — ID чата.
|
||||||
|
|
||||||
|
**Возвращает:** `DeletedPinMessage`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤖 Информация о боте
|
||||||
|
|
||||||
|
### `get_me()`
|
||||||
|
|
||||||
|
**Описание:** Получить объект бота.
|
||||||
|
|
||||||
|
**Возвращает:** `User` — текущий бот.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `change_info(...)`
|
||||||
|
|
||||||
|
**Описание:** Изменить профиль бота.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `name` *(str)* — новое имя.
|
||||||
|
* `description` *(str)* — описание.
|
||||||
|
* `commands` *(List\[BotCommand])* — команды (name + description).
|
||||||
|
* `photo` *(Dict)* — `{ "url": ..., "token": ... }` — загруженное изображение. URL можно получить через `get_upload_url(...)`.
|
||||||
|
|
||||||
|
**Возвращает:** `User`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `set_my_commands(*commands)`
|
||||||
|
|
||||||
|
**Описание:** Установить команды бота.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `commands` *(BotCommand)* — команды, например `BotCommand(name="help", description="Справка")`
|
||||||
|
|
||||||
|
**Возвращает:** `User`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 👥 Работа с чатами
|
||||||
|
|
||||||
|
### `get_chats(...)`
|
||||||
|
|
||||||
|
**Описание:** Получить список чатов.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `count` *(int)* — количество (по умолчанию 50).
|
||||||
|
* `marker` *(int)* — маркер страницы.
|
||||||
|
|
||||||
|
**Возвращает:** `Chats`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `get_chat_by_id(id)` / `get_chat_by_link(link)`
|
||||||
|
|
||||||
|
**Описание:** Получить объект чата по ID или публичной ссылке.
|
||||||
|
|
||||||
|
**Возвращает:** `Chat`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `edit_chat(...)`
|
||||||
|
|
||||||
|
**Описание:** Изменить чат.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `chat_id`, `title`, `pin`, `notify` — как выше.
|
||||||
|
* `icon` *(PhotoAttachmentRequestPayload)* — вложение фото, загруженное через `get_upload_url(...)` и `download_file(...)`.
|
||||||
|
|
||||||
|
**Возвращает:** `Chat`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `delete_chat(chat_id)`
|
||||||
|
|
||||||
|
Удаляет чат.
|
||||||
|
|
||||||
|
**Возвращает:** `DeletedChat`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 👤 Работа с участниками чатов
|
||||||
|
|
||||||
|
### `get_chat_members(...)` / `get_chat_member(...)`
|
||||||
|
|
||||||
|
**Описание:** Получить одного или нескольких участников.
|
||||||
|
|
||||||
|
**Возвращает:** `GettedMembersChat` (у него есть `.members`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `add_chat_members(...)`
|
||||||
|
|
||||||
|
**Описание:** Добавить участников.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `chat_id`, `user_ids` *(List\[str])* — список строковых ID.
|
||||||
|
|
||||||
|
**Возвращает:** `AddedMembersChat`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `kick_chat_member(...)`
|
||||||
|
|
||||||
|
**Описание:** Исключить и опционально заблокировать.
|
||||||
|
|
||||||
|
**Возвращает:** `RemovedMemberChat`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `get_list_admin_chat(...)` / `add_list_admin_chat(...)` / `remove_admin(...)`
|
||||||
|
|
||||||
|
**Описание:** Управление администраторами.
|
||||||
|
|
||||||
|
**Возвращают:** `GettedListAdminChat`, `AddedListAdminChat`, `RemovedAdmin`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `get_me_from_chat(...)`
|
||||||
|
|
||||||
|
**Описание:** Получить, кем является бот в чате.
|
||||||
|
|
||||||
|
**Возвращает:** `ChatMember`
|
||||||
|
|
||||||
|
### `delete_me_from_chat(...)`
|
||||||
|
|
||||||
|
**Удаляет бота из чата.**
|
||||||
|
|
||||||
|
**Возвращает:** `DeletedBotFromChat`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Обновления и действия
|
||||||
|
|
||||||
|
### `get_updates()`
|
||||||
|
|
||||||
|
**Описание:** Получить события (новости, сообщения и т.д.).
|
||||||
|
|
||||||
|
**Возвращает:** `UpdateUnion`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `send_action(...)`
|
||||||
|
|
||||||
|
**Описание:** Отправить "печатает..." и т.д.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `chat_id`, `action` *(SenderAction)* — например, `SenderAction.TYPING_ON`
|
||||||
|
|
||||||
|
**Возвращает:** `SendedAction`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `send_callback(...)`
|
||||||
|
|
||||||
|
**Описание:** Ответ на callback-кнопку.
|
||||||
|
|
||||||
|
**Аргументы:**
|
||||||
|
|
||||||
|
* `callback_id`, `message`, `notification`
|
||||||
|
|
||||||
|
**Возвращает:** `SendedCallback`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📎 Медиа и файлы
|
||||||
|
|
||||||
|
### `get_video(video_token)`
|
||||||
|
|
||||||
|
**Возвращает:** `Video`
|
||||||
|
|
||||||
|
### `get_upload_url(type)`
|
||||||
|
|
||||||
|
**Аргументы:** `type` *(UploadType)* — например, `UploadType.IMAGE`
|
||||||
|
|
||||||
|
**Возвращает:** `GettedUploadUrl` (у него есть `.url`)
|
||||||
|
|
||||||
|
### `download_file(path, url, token)` (НЕАКТУАЛЬНО)
|
||||||
|
|
||||||
|
**Описание:** Скачивает файл, используя URL и токен.
|
||||||
|
|
||||||
|
**Возвращает:** статус загрузки
|
||||||
35
wiki/events.md
Normal file
35
wiki/events.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# События
|
||||||
|
|
||||||
|
Для обработки разных типов обновлений используются события (Event). Ниже перечислены основные события и их назначение.
|
||||||
|
|
||||||
|
| Событие | Описание |
|
||||||
|
|-----------------------|----------------------------------------------------------------------------------------------|
|
||||||
|
| `message_created` | Создание нового сообщения (пользователь отправил сообщение) |
|
||||||
|
| `bot_added` | Бот добавлен в чат |
|
||||||
|
| `bot_removed` | Бот удалён из чата |
|
||||||
|
| `bot_started` | Пользователь запустил бота |
|
||||||
|
| `chat_title_changed` | Изменено название чата |
|
||||||
|
| `message_callback` | Пользователь нажал на callback-кнопку (inline button) |
|
||||||
|
| `message_chat_created`| Срабатывает когда пользователь нажал на кнопку с действием "Создать чат" (работает некорректно со стороны API MAX, ждем исправлений) |
|
||||||
|
| `message_edited` | Сообщение было отредактировано |
|
||||||
|
| `message_removed` | Сообщение было удалено |
|
||||||
|
| `user_added` | Пользователь добавлен в чат |
|
||||||
|
| `user_removed` | Пользователь удалён из чата |
|
||||||
|
| `on_started` | Бот запущен (**внутреннее** событие библиотеки) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Пример использования
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dp.message_created()
|
||||||
|
async def on_message(event: MessageCreated):
|
||||||
|
... # обработка нового сообщения
|
||||||
|
|
||||||
|
@dp.bot_added()
|
||||||
|
async def on_bot_added(event: BotAdded):
|
||||||
|
... # логика при добавлении бота
|
||||||
|
|
||||||
|
@dp.message_callback()
|
||||||
|
async def on_callback(event: MessageCallback):
|
||||||
|
... # обработка нажатия на callback-кнопку
|
||||||
65
wiki/handlers.md
Normal file
65
wiki/handlers.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# Философия хендлеров или как задается хендлер в maxapi
|
||||||
|
|
||||||
|
Для регистрации хендлера в maxapi используется объект `Dispatcher` или `Router` и декоратор с указанием типа события и фильтра.
|
||||||
|
|
||||||
|
## Общий синтаксис
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dp.<тип_события>(<фильтры>)
|
||||||
|
async def <имя_функции>(event: <тип_события>):
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
* `dp` — экземпляр `Dispatcher`
|
||||||
|
|
||||||
|
* `<тип_события>` — тип события (например, `message_created`)
|
||||||
|
|
||||||
|
* `<фильтр>` — условие `MagicFilter`, по которому срабатывает хендлер (например, наличие текста в сообщении)
|
||||||
|
|
||||||
|
* `event` — объект события с данными (например, `MessageCreated`)
|
||||||
|
|
||||||
|
## Пример
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dp.message_created(F.message.body.text)
|
||||||
|
async def echo(event: MessageCreated):
|
||||||
|
await event.message.answer(f"Повторяю за вами: {event.message.body.text}")
|
||||||
|
```
|
||||||
|
|
||||||
|
* `@dp.message_created` — хендлер на событие создания сообщения
|
||||||
|
|
||||||
|
* `F.message.body.text` — фильтр: сработает только если в сообщении есть текст
|
||||||
|
|
||||||
|
* `echo` — асинхронная функция-обработчик, которая принимает событие `MessageCreated`
|
||||||
|
|
||||||
|
* В теле функции вызывается метод `answer` для отправки ответа с повтором текста
|
||||||
|
|
||||||
|
|
||||||
|
## Полный код
|
||||||
|
|
||||||
|
```python
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from maxapi import Bot, Dispatcher
|
||||||
|
from maxapi.filters import F
|
||||||
|
from maxapi.types import MessageCreated
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
bot = Bot('тут_ваш_токен')
|
||||||
|
dp = Dispatcher()
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(F.message.body.text)
|
||||||
|
async def echo(event: MessageCreated):
|
||||||
|
await event.message.answer(f"Повторяю за вами: {event.message.body.text}")
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await dp.start_polling(bot)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
||||||
|
```
|
||||||
99
wiki/memory_context.md
Normal file
99
wiki/memory_context.md
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# MemoryContext
|
||||||
|
|
||||||
|
Контекст данных пользователя с поддержкой асинхронных блокировок. Используется для хранения и управления состоянием пользователя в рамках сессии.
|
||||||
|
|
||||||
|
При передаче в хендлер события `message_chat_created` в качестве атрибута `chat_id` идёт идентификатор созданного чата, а `user_id` - идентификатора бота!
|
||||||
|
|
||||||
|
## Класс: `MemoryContext`
|
||||||
|
|
||||||
|
```python
|
||||||
|
MemoryContext(chat_id: int, user_id: int)
|
||||||
|
````
|
||||||
|
|
||||||
|
### Аргументы:
|
||||||
|
|
||||||
|
* `chat_id` (`int`): Идентификатор чата.
|
||||||
|
* `user_id` (`int`): Идентификатор пользователя.
|
||||||
|
|
||||||
|
|
||||||
|
## Методы
|
||||||
|
|
||||||
|
### `async def get_data() -> dict[str, Any]`
|
||||||
|
|
||||||
|
Возвращает текущие данные контекста.
|
||||||
|
|
||||||
|
#### Возвращает:
|
||||||
|
|
||||||
|
* `dict[str, Any]`: Словарь с текущими данными пользователя.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `async def set_data(data: dict[str, Any])`
|
||||||
|
|
||||||
|
Полностью заменяет контекст данных.
|
||||||
|
|
||||||
|
#### Аргументы:
|
||||||
|
|
||||||
|
* `data` (`dict[str, Any]`): Новый словарь данных, заменяющий текущий.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `async def update_data(**kwargs)`
|
||||||
|
|
||||||
|
Обновляет текущий контекст, добавляя или изменяя переданные пары ключ-значение.
|
||||||
|
|
||||||
|
#### Аргументы:
|
||||||
|
|
||||||
|
* `**kwargs`: Ключи и значения для обновления контекста.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `async def set_state(state: State | str = None)`
|
||||||
|
|
||||||
|
Устанавливает новое состояние пользователя или сбрасывает его.
|
||||||
|
|
||||||
|
#### Аргументы:
|
||||||
|
|
||||||
|
* `state` (`State | str | None`): Новое состояние. Если `None` — состояние будет сброшено.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `async def get_state() -> State | None`
|
||||||
|
|
||||||
|
Возвращает текущее состояние пользователя.
|
||||||
|
|
||||||
|
#### Возвращает:
|
||||||
|
|
||||||
|
* `State | None`: Текущее состояние или `None`, если не установлено.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `async def clear()`
|
||||||
|
|
||||||
|
Очищает все данные контекста и сбрасывает состояние.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Пример использования
|
||||||
|
|
||||||
|
[Полный пример](https://github.com/love-apples/maxapi/tree/main/examples/router_with_input_media)
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dp.message_created(Command('clear'))
|
||||||
|
async def hello(event: MessageCreated, context: MemoryContext):
|
||||||
|
await context.clear()
|
||||||
|
await event.message.answer(f"Ваш контекст был очищен!")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(Command('data'))
|
||||||
|
async def hello(event: MessageCreated, context: MemoryContext):
|
||||||
|
data = await context.get_data()
|
||||||
|
await event.message.answer(f"Ваша контекстная память: {str(data)}")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(Command('context'))
|
||||||
|
@dp.message_created(Command('state'))
|
||||||
|
async def hello(event: MessageCreated, context: MemoryContext):
|
||||||
|
data = await context.get_state()
|
||||||
|
await event.message.answer(f"Ваше контекстное состояние: {str(data)}")
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user