Добавлен метод set_my_commands у bot
This commit is contained in:
parent
9591780152
commit
85f58913c3
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
pip install maxapi==0.1
|
pip install maxapi==0.1
|
||||||
|
|
||||||
Запуск бота из папки example:
|
Запуск бота из папки https://github.com/love-apples/maxapi/tree/main/example:
|
||||||
|
|
||||||
python example.py
|
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.attachment import Attachment
|
||||||
from .types.attachments.image import PhotoAttachmentRequestPayload
|
from .types.attachments.image import PhotoAttachmentRequestPayload
|
||||||
from .types.message import NewMessageLink
|
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
|
from .connection.base import BaseConnection
|
||||||
|
|
||||||
@ -46,12 +47,11 @@ class Bot(BaseConnection):
|
|||||||
|
|
||||||
def __init__(self, token: str):
|
def __init__(self, token: str):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.bot = self
|
self.bot = self
|
||||||
|
|
||||||
self.__token = token
|
self.__token = token
|
||||||
self.params = {
|
self.params = {'access_token': self.__token}
|
||||||
'access_token': self.__token
|
|
||||||
}
|
|
||||||
self.marker_updates = None
|
self.marker_updates = None
|
||||||
|
|
||||||
async def send_message(
|
async def send_message(
|
||||||
@ -335,4 +335,13 @@ class Bot(BaseConnection):
|
|||||||
):
|
):
|
||||||
return await GetUpdates(
|
return await GetUpdates(
|
||||||
bot=self,
|
bot=self,
|
||||||
|
).request()
|
||||||
|
|
||||||
|
async def set_my_commands(
|
||||||
|
self,
|
||||||
|
*commands: BotCommand
|
||||||
|
):
|
||||||
|
return await ChangeInfo(
|
||||||
|
bot=self,
|
||||||
|
commands=list(commands)
|
||||||
).request()
|
).request()
|
@ -26,11 +26,14 @@ class MemoryContext:
|
|||||||
self._context.update(kwargs)
|
self._context.update(kwargs)
|
||||||
|
|
||||||
async def set_state(self, state: State | str = None):
|
async def set_state(self, state: State | str = None):
|
||||||
self._state = state
|
async with self._lock:
|
||||||
|
self._state = state
|
||||||
|
|
||||||
async def get_state(self):
|
async def get_state(self):
|
||||||
return self._state
|
async with self._lock:
|
||||||
|
return self._state
|
||||||
|
|
||||||
async def clear(self):
|
async def clear(self):
|
||||||
self._state = None
|
async with self._lock:
|
||||||
self._context = {}
|
self._state = None
|
||||||
|
self._context = {}
|
||||||
|
@ -57,6 +57,8 @@ class Dispatcher:
|
|||||||
return new_ctx
|
return new_ctx
|
||||||
|
|
||||||
async def handle(self, event_object: UpdateUnion):
|
async def handle(self, event_object: UpdateUnion):
|
||||||
|
is_handled = False
|
||||||
|
|
||||||
for handler in self.event_handlers:
|
for handler in self.event_handlers:
|
||||||
|
|
||||||
if not handler.update_type == event_object.update_type:
|
if not handler.update_type == event_object.update_type:
|
||||||
@ -66,9 +68,9 @@ class Dispatcher:
|
|||||||
if not filter_attrs(event_object, *handler.filters):
|
if not filter_attrs(event_object, *handler.filters):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
memory_context = self.get_memory_context(
|
ids = event_object.get_ids()
|
||||||
*event_object.get_ids()
|
|
||||||
)
|
memory_context = self.get_memory_context(*ids)
|
||||||
|
|
||||||
if not handler.state == await memory_context.get_state() \
|
if not handler.state == await memory_context.get_state() \
|
||||||
and handler.state:
|
and handler.state:
|
||||||
@ -82,14 +84,16 @@ class Dispatcher:
|
|||||||
if not key in func_args:
|
if not key in func_args:
|
||||||
del kwargs[key]
|
del kwargs[key]
|
||||||
|
|
||||||
if kwargs:
|
await handler.func_event(event_object, **kwargs)
|
||||||
await handler.func_event(event_object, **kwargs)
|
|
||||||
else:
|
|
||||||
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
|
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):
|
async def start_polling(self, bot: Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ from magic_filter import F, MagicFilter
|
|||||||
from ..types.command import Command
|
from ..types.command import Command
|
||||||
from ..context.state_machine import State
|
from ..context.state_machine import State
|
||||||
from ..enums.update import UpdateType
|
from ..enums.update import UpdateType
|
||||||
|
from ..loggers import logger_dp
|
||||||
|
|
||||||
|
|
||||||
class Handler:
|
class Handler:
|
||||||
@ -28,4 +29,7 @@ class Handler:
|
|||||||
elif isinstance(arg, State):
|
elif isinstance(arg, State):
|
||||||
self.state = arg
|
self.state = arg
|
||||||
elif isinstance(arg, Command):
|
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 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.http_method import HTTPMethod
|
||||||
from ..enums.api_path import ApiPath
|
from ..enums.api_path import ApiPath
|
||||||
|
@ -5,10 +5,8 @@ from typing import Any, Dict, List, TYPE_CHECKING
|
|||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
from ..types.attachments.image import PhotoAttachmentRequestPayload
|
from ..types.attachments.image import PhotoAttachmentRequestPayload
|
||||||
|
|
||||||
from ..types.chats import Chat
|
from ..types.chats import Chat
|
||||||
|
from ..types.command import Command
|
||||||
from ..types.users import BotCommand, User
|
|
||||||
|
|
||||||
from ..enums.http_method import HTTPMethod
|
from ..enums.http_method import HTTPMethod
|
||||||
from ..enums.api_path import ApiPath
|
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_contact import RequestContact
|
||||||
from ..types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
|
from ..types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
|
||||||
|
|
||||||
from ..types.command import Command
|
from ..types.command import Command, BotCommand
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
BotCommand,
|
||||||
CallbackButton,
|
CallbackButton,
|
||||||
ChatButton,
|
ChatButton,
|
||||||
LinkButton,
|
LinkButton,
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class Command:
|
class Command:
|
||||||
def __init__(self, text: str, prefix: str = '/'):
|
def __init__(self, text: str, prefix: str = '/'):
|
||||||
self.text = text
|
self.text = text
|
||||||
@ -6,4 +10,9 @@ class Command:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def command(self):
|
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]
|
bot: Optional[Bot]
|
||||||
|
|
||||||
def get_ids(self):
|
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(
|
async def answer(
|
||||||
self,
|
self,
|
||||||
|
@ -19,4 +19,4 @@ class MessageCreated(Update):
|
|||||||
bot: Optional[Bot]
|
bot: Optional[Bot]
|
||||||
|
|
||||||
def get_ids(self):
|
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 datetime import datetime
|
||||||
|
|
||||||
from ..enums.chat_permission import ChatPermission
|
from ..enums.chat_permission import ChatPermission
|
||||||
|
from ..types.command import BotCommand
|
||||||
|
|
||||||
class BotCommand(BaseModel):
|
|
||||||
name: str
|
|
||||||
description: Optional[str] = None
|
|
||||||
|
|
||||||
|
|
||||||
class User(BaseModel):
|
class User(BaseModel):
|
||||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="maxapi",
|
name="maxapi",
|
||||||
version="0.1",
|
version="0.3",
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
description="Библиотека для взаимодействия с API мессенджера MAX",
|
description="Библиотека для взаимодействия с API мессенджера MAX",
|
||||||
long_description=open("README.md", encoding='utf-8').read(),
|
long_description=open("README.md", encoding='utf-8').read(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user