tishka17 / aiogram_dialog Goto Github PK
View Code? Open in Web Editor NEWGUI framework on top of aiogram
Home Page: https://aiogram-dialog.readthedocs.io
License: Apache License 2.0
GUI framework on top of aiogram
Home Page: https://aiogram-dialog.readthedocs.io
License: Apache License 2.0
First of all, thank you @Tishka17 for your great work.
Description
I want to create something like Store Bucket, where user can write manually item that he needs, and this item that he adds will appear in Store Bucket.
Questions
Select(
Format("{item}"),
items=[], # How to get list of items from state like 'ManageItemsSG.show_items'?
item_id_getter=lambda x: x,
id="Item",
on_click=show_item,
),
async def show_items(m: Message, dialog_manager: DialogManager):
# Will StartMode.NORMAL save user's items list?
await dialog_manager.start(ManageItemsSG.show_items, mode=StartMode.NORMAL)
My code:
import asyncio
import logging
from aiogram import Bot, Dispatcher
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher.filters.state import StatesGroup, State
from aiogram.types import Message
from aiogram_dialog import (
Dialog, DialogManager, DialogRegistry, Window, StartMode, ChatEvent
)
from aiogram_dialog.widgets.input import MessageInput
from aiogram_dialog.widgets.kbd import (
Button, Back, Cancel, Row, Select
)
from aiogram_dialog.widgets.text import Const, Format
API_TOKEN = "API_TOKEN"
class ManageItemsSG(StatesGroup):
show_items = State()
item_manager = State()
new_item = State()
async def get_item_list(dialog_manager: DialogManager, **kwargs):
Item = dialog_manager.current_context().dialog_data.get("Item", None)
return {
"Item": Item,
}
async def add_item_request(c: ChatEvent, select: Select, dialog_manager: DialogManager):
await dialog_manager.start(ManageItemsSG.new_item)
async def add_item(m: Message, dialog: Dialog, dialog_manager: DialogManager):
dialog_manager.current_context().dialog_data["Item"] = m.text
await m.answer(f"Your Item '{m.text}' added")
await dialog_manager.start(ManageItemsSG.show_items, mode=StartMode.NORMAL)
async def show_item(c: ChatEvent, select: Select, dialog_manager: DialogManager, item_id: str):
dialog_manager.current_context().dialog_data["Item"] = item_id
await dialog_manager.dialog().next(dialog_manager)
async def show_item_data(c: ChatEvent, select: Select, dialog_manager: DialogManager):
Item = dialog_manager.current_context().dialog_data.get("Item", "")
await c.message.answer(f"Show data for: {Item}")
await dialog_manager.done()
async def remove_item(c: ChatEvent, select: Select, dialog_manager: DialogManager):
Item = dialog_manager.current_context().dialog_data.get("Item", "")
await c.message.answer(f"Item {Item} removed")
await dialog_manager.done()
dial_items_manager = Dialog(
Window(
'Your item list',
Select(
Format("{item}"),
items=[], # How to get list of items from state like 'ManageItemsSG.show_items'?
item_id_getter=lambda x: x,
id="Item",
on_click=show_item,
),
Row(
Button(
Const('Add item to list'),
id="add_item",
on_click=add_item_request,
)
),
Cancel(),
state=ManageItemsSG.show_items,
getter=get_item_list,
),
Window(
Format("What to do with Item {Item}?"),
Row(
Back(),
Button(Const("Show Item"), on_click=show_item_data, id="show_item_data"),
Button(Const("Remove Item"), on_click=remove_item, id="remove_item"),
),
state=ManageItemsSG.item_manager,
getter=get_item_list,
),
Window(
Const("Write Item which need to add"),
MessageInput(add_item),
state=ManageItemsSG.new_item,
getter=get_item_list,
),
)
async def show_items(m: Message, dialog_manager: DialogManager):
# Will StartMode.NORMAL save user's items list?
await dialog_manager.start(ManageItemsSG.show_items, mode=StartMode.NORMAL)
async def main():
# real main
logging.basicConfig(level=logging.INFO)
logging.getLogger("aiogram_dialog").setLevel(logging.DEBUG)
storage = MemoryStorage()
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot, storage=storage)
registry = DialogRegistry(dp)
dp.register_message_handler(show_items, text="/show_items", state="*")
registry.register(dial_items_manager)
await dp.start_polling()
if __name__ == '__main__':
asyncio.run(main())
Thanks for any your response.
We want to see some widgets filled on dialog start.
Probably we can pass defaults through window getter or other way for all current existing statefull widgets
Widget to render list of items as text. Format must get same variables as in Select button widget.
Usage example:
List(Format("* [{n}] {item.name}"), item="users", sep="\n")
Prototype to start with:
class List(Text):
def __init__(self, field: str, when: WhenCondition = None):
super().__init__(when)
self.field = field
async def _render_text(self, data: Dict, manager: DialogManager) -> str:
return "\n".join(data[self.field])
It helps to reduce the api calls hence less overhead.
Check code for reference in aiogram webhook example: https://github.com/aiogram/aiogram/blob/dea94d2574893f4d0e7df358852a543ef9214217/examples/webhook_example.py#L34
More description can be found here: telegram-bot-rb/telegram-bot#59 (comment)
Hi, I'm working to integrate aiogram-dialog with IoT project. The basic idea is to read temperature from device and show into Telegram bot (It is a MQTT/Telegram integration).
I would like if someone could give me an example to understand how to change an specific user context variable from a task periodic
added by me. In my working example I have did it but using global variables, which is not the best solution.
Also I have readed about middleware class but I didn't understand if it has something to do here.
I will appreciate any kind of help.
import asyncio
import logging
import random
from aiogram import Bot, Dispatcher
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher.filters.state import StatesGroup, State
from aiogram.types import Message, CallbackQuery
from aiogram_dialog import Dialog, DialogManager, Window, DialogRegistry, BaseDialogManager, \
StartMode
from aiogram_dialog.widgets.kbd import Button
from aiogram_dialog.widgets.text import Const, Multi, Progress, Format
API_TOKEN = "YOUR TOKEN"
temperature = 0
# ---------------------------------------------------------------------------------
# States
class MainSG(StatesGroup):
get_temp = State()
# Getter
async def get_bg_data(dialog_manager: DialogManager, **kwargs):
return {
"temp": dialog_manager.current_context().dialog_data.get("temp", 0),
}
async def refresh_temp(c: CallbackQuery, button: Button, manager: DialogManager):
await manager.update({
"temp": temperature ,
})
main_menu = Dialog(
Window(
Const("Clik to obtain temperature"),
Button(Format("Your temp: {temp} °C"), id="b1", on_click=refresh_temp ),
state=MainSG.get_temp,
getter=get_bg_data
),
)
async def start(m: Message, dialog_manager: DialogManager):
await dialog_manager.start(MainSG.get_temp, mode=StartMode.RESET_STACK)
logging.basicConfig(level=logging.INFO)
logging.getLogger("aiogram_dialog").setLevel(logging.DEBUG)
storage = MemoryStorage()
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot, storage=storage)
registry = DialogRegistry(dp)
registry.register(main_menu)
dp.register_message_handler(start, text="/start", state="*")
async def main():
await dp.start_polling()
# MyTask Function that receive temperature and pass to context variables
async def periodic(sleep_for):
global temperature
while True:
ID = 111111111 # Simulated ID from know user linked to device
# -----------------------------------
# Here I thin we must add the magic but at the moment I'm using
# a global variable
temperature = random.randint(20,35) # simulate temperature reading
# -----------------------------------
await asyncio.sleep(sleep_for)
async def runner():
await asyncio.gather(main(),periodic(2))
if __name__ == '__main__':
asyncio.run(runner())
Example:
from typing import List, Sequence, Tuple
from aiogram.dispatcher.filters.state import State
from graphviz import Digraph
from aiogram_dialog import Dialog
from aiogram_dialog.widgets.kbd import Group, Back, Cancel, Start, SwitchTo, Next
def edge(dot, state1, state2, *args, **kwargs):
dot.edge(str(id(state1)), str(id(state2)), *args, **kwargs)
def walk_keyboard(dot, dialog, starts: List[Tuple[State, State]], current_state: State, keyboards: Sequence):
for kbd in keyboards:
if isinstance(kbd, Group):
walk_keyboard(dot, dialog, starts, current_state, kbd.buttons)
elif isinstance(kbd, Start):
edge(dot, current_state, kbd.state, label="start")
elif isinstance(kbd, SwitchTo):
edge(dot, current_state, kbd.state, label="switch")
elif isinstance(kbd, Next):
new_state = dialog.states[dialog.states.index(current_state) + 1]
edge(dot, current_state, new_state, label="next")
elif isinstance(kbd, Back):
new_state = dialog.states[dialog.states.index(current_state) - 1]
edge(dot, current_state, new_state, label="back")
elif isinstance(kbd, Cancel):
for from_, to_ in starts:
if to_.group == current_state.group:
edge(dot, current_state, from_, label="cancel")
def find_starts(current_state, keyboards: Sequence):
for kbd in keyboards:
if isinstance(kbd, Group):
yield from find_starts(current_state, kbd.buttons)
elif isinstance(kbd, Start):
yield current_state, kbd.state
def render(dialogs: List[Dialog]):
dot = Digraph(name='AiogramDialog', engine='fdp')
dot.attr(label='Aiogram Dialog')
dot.attr(fontname='Ubuntu')
dot.attr(fontcolor='#000088')
dot.attr(fontcolor='#000088')
for dialog in dialogs:
with dot.subgraph(name=f"cluster_{dialog.states_group_name()}") as subgraph:
subgraph.attr(label=dialog.states_group_name())
subgraph.attr(style='filled', color='#f0f0f0')
for window in dialog.windows.values():
subgraph.node(str(id(window.get_state())), window.get_state().state)
starts = []
for dialog in dialogs:
for window in dialog.windows.values():
starts.extend(find_starts(window.get_state(), [window.keyboard]))
for dialog in dialogs:
for window in dialog.windows.values():
walk_keyboard(dot, dialog, starts, window.get_state(), [window.keyboard])
dot.render("graph") # filename will be `graph.pdf`
if __name__ == '__main__':
render([
# here put you dialogs
])
When user cancels a top dialog it's messages stays in chat and can be misunderstood by users.
It's better to remove or edit it into some neutral
async def next(self, manager: DialogManager):
if not manager.current_context():
raise ValueError("No intent")
print(self.states)
print(self.states.index(manager.current_context().state))
print(self.states.index(manager.current_context().state) + 1)
new_state = self.states[self.states.index(manager.current_context().state) + 1]
await self.switch_to(new_state, manager)
When I'm pressing scroll arrows -> throwing an index error.
Here is the output with the additional print statements
[<State 'Link[0.0.1:1'>, <State 'Link[0.0.1:2'>]
1
2
Task exception was never retrieved
future: <Task finished name='Task-28' coro=<Dispatcher._process_polling_updates() done, defined at /Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py:409> exception=IndexError('list index out of range')>
Traceback (most recent call last):
File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 417, in _process_polling_updates
for responses in itertools.chain.from_iterable(await self.process_updates(updates, fast)):
File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 238, in process_updates
return await asyncio.gather(*tasks)
File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/handler.py", line 116, in notify
response = await handler_obj.handler(*args, **partial_data)
File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 286, in process_update
return await self.callback_query_handlers.notify(update.callback_query)
File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/handler.py", line 116, in notify
response = await handler_obj.handler(*args, **partial_data)
File "/Users/mac/Documents/PycharmProjects/CustomBot/main.py", line 321, in callback
await dialog_manager.dialog().next(dialog_manager)
File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram_dialog/dialog.py", line 78, in next
new_state = self.states[self.states.index(manager.current_context().state) + 1]
IndexError: list index out of range
It is possible to generate HTML preview for all windows, so user can view it from any place without using telegram.
Requirements for user:
getter
Requirements for reuslt:
parse_mode
is used for correct rendering# /app/test.py
from aiogram import Bot, Dispatcher, executor
from aiogram.contrib.fsm_storage.redis import RedisStorage2
from aiogram.dispatcher.filters.state import StatesGroup, State
from aiogram.types import Message
from aiogram_dialog import Window, Dialog, DialogRegistry, DialogManager, StartMode
from aiogram_dialog.widgets.kbd import Button
from aiogram_dialog.widgets.text import Const
from datetime import date
from aiogram.types import CallbackQuery
from aiogram_dialog import DialogManager
from aiogram_dialog.widgets.kbd import Calendar
async def on_date_selected(c: CallbackQuery, widget, manager: DialogManager, selected_date: date):
await c.answer(str(selected_date))
storage = RedisStorage2('redis')
bot = Bot(token='TOKEN')
dp = Dispatcher(bot, storage=storage)
registry = DialogRegistry(dp)
class MySG(StatesGroup):
main = State()
main_window = Window(
Const("Hello, unknown person"),
Calendar(id='calendar', on_click=on_date_selected),
state=MySG.main,
)
dialog = Dialog(main_window)
registry.register(dialog)
@dp.message_handler(commands=["start"])
async def start(m: Message, dialog_manager: DialogManager):
await dialog_manager.start(MySG.main, mode=StartMode.RESET_STACK)
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)
sid@83cfd5fbfc97:/app$ python test.py
Updates were skipped successfully.
Task exception was never retrieved
future: <Task finished name='Task-9' coro=<Dispatcher._process_polling_updates() done, defined at /home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py:409> exception=TypeError('Object of type date is not JSON serializable')>
Traceback (most recent call last):
File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 417, in _process_polling_updates
for responses in itertools.chain.from_iterable(await self.process_updates(updates, fast)):
File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 238, in process_updates
return await asyncio.gather(*tasks)
File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/handler.py", line 116, in notify
response = await handler_obj.handler(*args, **partial_data)
File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 259, in process_update
return await self.message_handlers.notify(update.message)
File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/handler.py", line 129, in notify
await self.dispatcher.middleware.trigger(f"post_process_{self.middleware_key}",
File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/middlewares.py", line 53, in trigger
await app.trigger(action, args)
File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/middlewares.py", line 106, in trigger
await handler(*args)
File "/home/sid/.local/lib/python3.9/site-packages/aiogram_dialog/context/intent_filter.py", line 66, in on_post_process_message
await proxy.save_context(data.pop(CONTEXT_KEY))
File "/home/sid/.local/lib/python3.9/site-packages/aiogram_dialog/context/storage.py", line 45, in save_context
await self.storage.set_data(
File "/home/sid/.local/lib/python3.9/site-packages/aiogram/contrib/fsm_storage/redis.py", line 307, in set_data
await redis.set(key, json.dumps(data), expire=self._data_ttl)
File "/home/sid/.local/lib/python3.9/site-packages/aiogram/utils/json.py", line 43, in dumps
return json.dumps(data, ensure_ascii=False)
File "/usr/local/lib/python3.9/json/__init__.py", line 234, in dumps
return cls(
File "/usr/local/lib/python3.9/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/lib/python3.9/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/local/lib/python3.9/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type date is not JSON serializable
For exaple based on rating widget
https://paste.ubuntu.com/p/4k2ZzV8ZVg/
https://t.me/aiogram_ru/479528
when
There is not enough widget with the ability to format text with object data. For instance:
Window(
FormatFromObj('Hello, {obj.from_user.first_name}') # obj is instance of CallbackQuery or Message
)
MessageNotModified appears on quick presses, not depending on min_selected
File "/home/tishka17/src/aiogram_dialog/aiogram_dialog/dialog.py", line 119, in _callback_handler
await self.show(dialog_manager)
File "/home/tishka17/src/aiogram_dialog/aiogram_dialog/dialog.py", line 104, in show
message = await window.show(self, manager)
File "/home/tishka17/src/aiogram_dialog/aiogram_dialog/window.py", line 66, in show
return await event.message.edit_text(
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/types/message.py", line 2526, in edit_text
return await self.bot.edit_message_text(
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/bot/bot.py", line 2216, in edit_message_text
result = await self.request(api.Methods.EDIT_MESSAGE_TEXT, payload)
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/bot/base.py", line 208, in request
return await api.make_request(self.session, self.server, self.__token, method, data, files,
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/bot/api.py", line 140, in make_request
return check_result(method, response.content_type, response.status, await response.text())
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/bot/api.py", line 115, in check_result
exceptions.BadRequest.detect(description)
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/utils/exceptions.py", line 139, in detect
raise err(cls.text or description)
aiogram.utils.exceptions.MessageNotModified: Message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message
As I see in subdialog.py, it's possible to get the user id from m.chat.id. But that requires moving from one window in a dialog to another. What if I just created a dialog and the user didn't move between windows?
Thanks in advance!
Same as RESET_STATE but without showing new dialog instead
Example from docs:
import operator
from aiogram_dialog.widgets.kbd import Multiselect
from aiogram_dialog.widgets.text import Format
# let's assume this is our window data getter
async def get_data(**kwargs):
fruits = [
("Apple", '1'),
("Pear", '2'),
("Orange", '3'),
("Banana", '4'),
]
return {
"fruits": fruits,
"count": len(fruits),
}
fruits_kbd = Multiselect(
Format("✓ {item[0]}"), # E.g `✓ Apple`
Format("{item[0]}"),
id="m_fruits",
item_id_getter=operator.itemgetter(1),
items="fruits",
)
So try to set a min_selected
parameter:
fruits_kbd = Multiselect(
Format("✓ {item[0]}"), # E.g `✓ Apple`
Format("{item[0]}"),
id="m_fruits",
item_id_getter=operator.itemgetter(1),
items="fruits",
min_selected=3
)
Bug: if you click on item it will be marked as selected (✓ Apple), second click on item (to disable them) will thrown an error:
aiogram.utils.exceptions.MessageNotModified: Message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message
str
can be automatically converted to Const
(or Format
?)list
/tuple
can be converted to Mutli
/Group
ItemIdGetter
in Select
probably can be replaced with Format
-like text widgetError is raised on python3.9.7
i created a couple of forms, through aiogram_dialog everything works great. But I also want to use the custom shapes I created. By creating a handler @ dp.callback_query_handler (lambda call: True) All callbacks are handled by aiogram_dialog.registry or so. My global @ dp.callback_query_handler (lambda call: True) doesn't fire. How to register my custom callback? The goal is to use a callback for the InlineKeyboardButton
@dp.message_handler()
async def echo(message: types.Message):
inline = [InlineKeyboardButton('Управление', callback_data='control'),
InlineKeyboardButton('Настройка', callback_data='settings')]
markup = InlineKeyboardMarkup(inline, one_time_keyboard=True, resize_keyboard=True)
await message.answer(message.text, reply_markup=markup)
#this block of code is ignored when callback
@dp.callback_query_handler(lambda call: True)
async def process_callback_button(callback_query: types.CallbackQuery):
await bot.answer_callback_query(callback_query.id)
await bot.send_message(callback_query.from_user.id, 'Тест калбек!')
async def main():
storage = MemoryStorage()
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot, storage=storage)
dp.register_message_handler(pwd_handler, text="/start", state="*")
registry = DialogRegistry(dp) #
registry.register(main_window)
registry.register(pwd_window)
await dp.start_polling()
. . .
Hey there 👋
Currently, the ScrollingGroup doesn't stop to scroll when it gets to the last page.
So instead of stopping and doing nothing, it scrolls through the same page "in-place". Whenever you want to go back --> you have to click the same amount of times.
Would be nice to have no scrolling as a default
Do not allow clicking "next" until user fills Rasio/Multiselect or other widgets.
More usecases?
render_html
added to render_text
Const
/Format
render_html should do autoescaping.Const
/Format
mode=html disables escaping and forbids rendering as simple textJinja
only html is supportedrender_text
Sometimes we need to show alert on button click.
It is better to do automatically.
Also it can be done when clicking only some buttons in select
Visible, but ignore clicks
в диалогах встроить возможность диалог открыть для юзера или для чата. То есть записать user_id в Intent и при обработке сообщений/кликов проверять его
Dialogs, that can work without switching global state.
Idea:
launch_mod
для диалогов, влияющий на стек. Например:
If in an answer of inline mode(input_message_content), add the inline button (with registered dialogs), then when it is pressed, middleware will give the error.
File "/home/*****/PycharmProjects/*****/venv/lib/python3.9/site-packages/aiogram_dialog/context/intent_filter.py", line 104, in on_pre_process_callback_query
chat_id=event.message.chat.id,
AttributeError: 'NoneType' object has no attribute 'chat'
Temporary solution:
In aiogram_dialog/context/intent_filter.py
in on_pre_process_callback_query
add the following line
chat_id=event.message.chat.id if hasattr(event, "chat") else ""
last_media_id по идеи должен быть типа MediaId а не int, но вот нужно както с циклическим импортом разобратся
Hi @Tishka17 ! , first of all cograts for your project, I'm very impressed about it.
I 'm new in programming, but may be you can give me a help.
I'm working in an IOT application where I have to create a task named periodic(sleep_for)
in which I read a tuple (Telegram ID user , str message) from a queue every 5 seconds and then message is sent to user id.
In this simplified code I have created a task to do something similar.
How could I implement the task execution working under aiogram_dialog ?
Thank you!!
import logging
import asyncio
import aiogram.utils.markdown as md
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters import Text
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import ParseMode
from aiogram.utils import executor
logging.basicConfig(level=logging.INFO)
# ---------------------------------------------------
API_TOKEN = 'Your TOKEN'
YOUR_ID = xxxxxxx36
# ---------------------------------------------------
bot = Bot(token=API_TOKEN)
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)
class Form(StatesGroup):
name = State()
looper = State()
@dp.message_handler(commands='start')
async def cmd_start(message: types.Message):
#Conversation's entry point
await Form.name.set()
await message.reply("Hi there! What's your name?")
@dp.message_handler(state=Form.name)
async def process_name(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['name'] = message.text
await message.reply("Your name is:" + str( data['name'] + "\nWrite anything and I will replay your name"))
await Form.looper.set()
@dp.message_handler(state=Form.looper)
async def process_loop(message: types.Message, state: FSMContext):
async with state.proxy() as data:
await message.reply("Your name is:" + str( data['name']))
await Form.looper.set()
async def periodic(sleep_for):
global YOUR_ID
counter = 0
while True:
msg = "Counter: " + str (counter)
counter +=1
await bot.send_message(chat_id=YOUR_ID, text = msg , disable_notification=True)
await asyncio.sleep(sleep_for)
if __name__ == '__main__':
loop= asyncio.get_event_loop ()
loop.create_task (periodic(5))
executor.start_polling(dp, skip_updates=True)
Kinda of middleware, that injects data into result of data getter
At least we need on_start
and on_close
For example, refresh dialog or close one.
Hi, first THX for the library :-)
i try to use python 3.7 and aiogram-dialog 1.0.2
If i use
from aiogram_dialog import Dialog
i get the error
ImportError: cannot import name 'Protocol' from 'typing'
seems that on line 3 in dialog.py
from typing import Protocol
is used
according to my typing.pyi - file, and some other documentation
# Protocol is only present in 3.8 and later, but mypy needs it unconditionally
Protocol: _SpecialForm = ...
Protocol needs at least python 3.8
ist there any older version that support python 3.7?
https://docs.aiogram.dev/en/latest/telegram/types/chat.html#aiogram.types.chat.Chat.get_member
Probably must be optional
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.