Добавлен метод set_my_commands у bot
This commit is contained in:
parent
9591780152
commit
85f58913c3
@ -19,7 +19,7 @@
|
||||
|
||||
pip install maxapi==0.1
|
||||
|
||||
Запуск бота из папки example:
|
||||
Запуск бота из папки https://github.com/love-apples/maxapi/tree/main/example:
|
||||
|
||||
python example.py
|
||||
```
|
||||
|
151
example.py
Normal file
151
example.py
Normal file
@ -0,0 +1,151 @@
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from maxapi import Bot, Dispatcher, F
|
||||
from maxapi.context import MemoryContext, State, StatesGroup
|
||||
from maxapi.types import Command, MessageCreated, CallbackButton, MessageCallback, BotCommand
|
||||
from maxapi.utils.inline_keyboard import InlineKeyboardBuilder
|
||||
|
||||
from for_example import router
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
bot = Bot('f9LHodD0cOL5NY7All_9xJRh5ZhPw6bRvq_0Adm8-1bZZEHdRy6_ZHDMNVPejUYNZg7Zhty-wKHNv2X2WJBQ')
|
||||
dp = Dispatcher()
|
||||
dp.include_routers(router)
|
||||
|
||||
|
||||
start_text = '''Пример чат-бота для MAX 💙
|
||||
|
||||
Мои команды:
|
||||
|
||||
/clear очищает ваш контекст
|
||||
/state или /context показывают ваше контекстное состояние
|
||||
/data показывает вашу контекстную память
|
||||
'''
|
||||
|
||||
|
||||
class Form(StatesGroup):
|
||||
name = State()
|
||||
age = State()
|
||||
|
||||
|
||||
@dp.on_started()
|
||||
async def _():
|
||||
logging.info('Бот стартовал!')
|
||||
|
||||
|
||||
@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)}")
|
||||
|
||||
|
||||
@dp.message_created(Command('start'))
|
||||
async def hello(event: MessageCreated):
|
||||
builder = InlineKeyboardBuilder()
|
||||
|
||||
builder.row(
|
||||
CallbackButton(
|
||||
text='Ввести свое имя',
|
||||
payload='btn_1'
|
||||
),
|
||||
CallbackButton(
|
||||
text='Ввести свой возраст',
|
||||
payload='btn_2'
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
CallbackButton(
|
||||
text='Не хочу',
|
||||
payload='btn_3'
|
||||
)
|
||||
)
|
||||
|
||||
await event.message.answer(
|
||||
text=start_text,
|
||||
attachments=[builder.as_markup()] # Для MAX клавиатура это вложение,
|
||||
) # поэтому она в списке вложений
|
||||
|
||||
|
||||
@dp.message_callback(F.callback.payload == 'btn_1')
|
||||
async def hello(event: MessageCallback, context: MemoryContext):
|
||||
await context.set_state(Form.name)
|
||||
await event.message.delete()
|
||||
await event.message.answer(f'Отправьте свое имя:')
|
||||
|
||||
|
||||
@dp.message_callback(F.callback.payload == 'btn_2')
|
||||
async def hello(event: MessageCallback, context: MemoryContext):
|
||||
await context.set_state(Form.age)
|
||||
await event.message.delete()
|
||||
await event.message.answer(f'Отправьте ваш возраст:')
|
||||
|
||||
|
||||
@dp.message_callback(F.callback.payload == 'btn_3')
|
||||
async def hello(event: MessageCallback, context: MemoryContext):
|
||||
await event.message.delete()
|
||||
await event.message.answer(f'Ну ладно 🥲')
|
||||
|
||||
|
||||
@dp.message_created(F.message.body.text, Form.name)
|
||||
async def hello(event: MessageCreated, context: MemoryContext):
|
||||
await context.update_data(name=event.message.body.text)
|
||||
|
||||
data = await context.get_data()
|
||||
|
||||
await event.message.answer(f"Приятно познакомиться, {data['name'].title()}!")
|
||||
|
||||
|
||||
@dp.message_created(F.message.body.text, Form.age)
|
||||
async def hello(event: MessageCreated, context: MemoryContext):
|
||||
await context.update_data(age=event.message.body.text)
|
||||
|
||||
await event.message.answer(f"Ого! А мне всего пару недель 😁")
|
||||
|
||||
|
||||
async def main():
|
||||
await bot.set_my_commands(
|
||||
BotCommand(
|
||||
name='/start',
|
||||
description='Перезапустить бота'
|
||||
),
|
||||
BotCommand(
|
||||
name='/clear',
|
||||
description='Очищает ваш контекст'
|
||||
),
|
||||
BotCommand(
|
||||
name='/state',
|
||||
description='Показывают ваше контекстное состояние'
|
||||
),
|
||||
BotCommand(
|
||||
name='/data',
|
||||
description='Показывает вашу контекстную память'
|
||||
),
|
||||
BotCommand(
|
||||
name='/context',
|
||||
description='Показывают ваше контекстное состояние'
|
||||
)
|
||||
)
|
||||
await dp.start_polling(bot)
|
||||
# await dp.handle_webhook(
|
||||
# bot=bot,
|
||||
# host='localhost',
|
||||
# port=8080
|
||||
# )
|
||||
|
||||
|
||||
asyncio.run(main())
|
10
for_example.py
Normal file
10
for_example.py
Normal file
@ -0,0 +1,10 @@
|
||||
from maxapi import F, Router
|
||||
from maxapi.types import Command, MessageCreated
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.message_created(Command('router'))
|
||||
async def hello(obj: MessageCreated):
|
||||
file = __file__.split('\\')[-1]
|
||||
await obj.message.answer(f"Пишу тебе из роута {file}")
|
@ -34,7 +34,8 @@ from .enums.sender_action import SenderAction
|
||||
from .types.attachments.attachment import Attachment
|
||||
from .types.attachments.image import PhotoAttachmentRequestPayload
|
||||
from .types.message import NewMessageLink
|
||||
from .types.users import BotCommand, ChatAdmin
|
||||
from .types.users import ChatAdmin
|
||||
from .types.command import BotCommand
|
||||
|
||||
from .connection.base import BaseConnection
|
||||
|
||||
@ -46,12 +47,11 @@ class Bot(BaseConnection):
|
||||
|
||||
def __init__(self, token: str):
|
||||
super().__init__()
|
||||
|
||||
self.bot = self
|
||||
|
||||
self.__token = token
|
||||
self.params = {
|
||||
'access_token': self.__token
|
||||
}
|
||||
self.params = {'access_token': self.__token}
|
||||
self.marker_updates = None
|
||||
|
||||
async def send_message(
|
||||
@ -335,4 +335,13 @@ class Bot(BaseConnection):
|
||||
):
|
||||
return await GetUpdates(
|
||||
bot=self,
|
||||
).request()
|
||||
|
||||
async def set_my_commands(
|
||||
self,
|
||||
*commands: BotCommand
|
||||
):
|
||||
return await ChangeInfo(
|
||||
bot=self,
|
||||
commands=list(commands)
|
||||
).request()
|
@ -26,11 +26,14 @@ class MemoryContext:
|
||||
self._context.update(kwargs)
|
||||
|
||||
async def set_state(self, state: State | str = None):
|
||||
self._state = state
|
||||
async with self._lock:
|
||||
self._state = state
|
||||
|
||||
async def get_state(self):
|
||||
return self._state
|
||||
async with self._lock:
|
||||
return self._state
|
||||
|
||||
async def clear(self):
|
||||
self._state = None
|
||||
self._context = {}
|
||||
async with self._lock:
|
||||
self._state = None
|
||||
self._context = {}
|
||||
|
@ -57,6 +57,8 @@ class Dispatcher:
|
||||
return new_ctx
|
||||
|
||||
async def handle(self, event_object: UpdateUnion):
|
||||
is_handled = False
|
||||
|
||||
for handler in self.event_handlers:
|
||||
|
||||
if not handler.update_type == event_object.update_type:
|
||||
@ -66,9 +68,9 @@ class Dispatcher:
|
||||
if not filter_attrs(event_object, *handler.filters):
|
||||
continue
|
||||
|
||||
memory_context = self.get_memory_context(
|
||||
*event_object.get_ids()
|
||||
)
|
||||
ids = event_object.get_ids()
|
||||
|
||||
memory_context = self.get_memory_context(*ids)
|
||||
|
||||
if not handler.state == await memory_context.get_state() \
|
||||
and handler.state:
|
||||
@ -82,14 +84,16 @@ class Dispatcher:
|
||||
if not key in func_args:
|
||||
del kwargs[key]
|
||||
|
||||
if kwargs:
|
||||
await handler.func_event(event_object, **kwargs)
|
||||
else:
|
||||
await handler.func_event(event_object, **kwargs)
|
||||
await handler.func_event(event_object, **kwargs)
|
||||
|
||||
logger_dp.info(f'Обработано: {event_object.update_type}')
|
||||
logger_dp.info(f'Обработано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
|
||||
|
||||
is_handled = True
|
||||
break
|
||||
|
||||
if not is_handled:
|
||||
logger_dp.info(f'Проигнорировано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
|
||||
|
||||
async def start_polling(self, bot: Bot):
|
||||
self.bot = bot
|
||||
|
||||
|
@ -5,6 +5,7 @@ from magic_filter import F, MagicFilter
|
||||
from ..types.command import Command
|
||||
from ..context.state_machine import State
|
||||
from ..enums.update import UpdateType
|
||||
from ..loggers import logger_dp
|
||||
|
||||
|
||||
class Handler:
|
||||
@ -28,4 +29,7 @@ class Handler:
|
||||
elif isinstance(arg, State):
|
||||
self.state = arg
|
||||
elif isinstance(arg, Command):
|
||||
self.filters.insert(0, F.message.body.text == arg.command)
|
||||
self.filters.insert(0, F.message.body.text == arg.command)
|
||||
else:
|
||||
logger_dp.info(f'Обнаружен неизвестный фильтр `{arg}` при '
|
||||
f'регистрации функции `{func_event.__name__}`')
|
@ -2,7 +2,8 @@
|
||||
|
||||
from typing import Any, Dict, List, TYPE_CHECKING
|
||||
|
||||
from ..types.users import BotCommand, User
|
||||
from ..types.users import User
|
||||
from ..types.command import BotCommand
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
@ -5,10 +5,8 @@ from typing import Any, Dict, List, TYPE_CHECKING
|
||||
from collections import Counter
|
||||
|
||||
from ..types.attachments.image import PhotoAttachmentRequestPayload
|
||||
|
||||
from ..types.chats import Chat
|
||||
|
||||
from ..types.users import BotCommand, User
|
||||
from ..types.command import Command
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
@ -21,9 +21,10 @@ from ..types.attachments.buttons.link_button import LinkButton
|
||||
from ..types.attachments.buttons.request_contact import RequestContact
|
||||
from ..types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
|
||||
|
||||
from ..types.command import Command
|
||||
from ..types.command import Command, BotCommand
|
||||
|
||||
__all__ = [
|
||||
BotCommand,
|
||||
CallbackButton,
|
||||
ChatButton,
|
||||
LinkButton,
|
||||
|
@ -1,4 +1,8 @@
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Command:
|
||||
def __init__(self, text: str, prefix: str = '/'):
|
||||
self.text = text
|
||||
@ -6,4 +10,9 @@ class Command:
|
||||
|
||||
@property
|
||||
def command(self):
|
||||
return self.prefix + self.text
|
||||
return self.prefix + self.text
|
||||
|
||||
|
||||
class BotCommand(BaseModel):
|
||||
name: str
|
||||
description: Optional[str] = None
|
@ -51,7 +51,7 @@ class MessageCallback(Update):
|
||||
bot: Optional[Bot]
|
||||
|
||||
def get_ids(self):
|
||||
return (self.message.recipient.chat_id, self.message.recipient.user_id)
|
||||
return (self.message.recipient.chat_id, self.callback.user.user_id)
|
||||
|
||||
async def answer(
|
||||
self,
|
||||
|
@ -19,4 +19,4 @@ class MessageCreated(Update):
|
||||
bot: Optional[Bot]
|
||||
|
||||
def get_ids(self):
|
||||
return (self.message.recipient.chat_id, self.message.recipient.user_id)
|
||||
return (self.message.recipient.chat_id, self.message.sender.user_id)
|
@ -3,11 +3,7 @@ from typing import List, Optional
|
||||
from datetime import datetime
|
||||
|
||||
from ..enums.chat_permission import ChatPermission
|
||||
|
||||
|
||||
class BotCommand(BaseModel):
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
from ..types.command import BotCommand
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
|
Loading…
x
Reference in New Issue
Block a user