Skip to main content

Документация по библиотеке aiogram_dialog_survey

Обзор

Библиотека aiogram_dialog_survey предоставляет инструменты для легкого создания больших интерактивных анкет в Telegram ботах на основе aiogram и aiogram_dialog. Основные возможности:

  • Поддержка различных типов вопросов: текстовый ввод, выбор одного варианта, множественный выбор
  • Генерация диалоговых окон для каждого вопроса. Ощутимо уменьшает кол-во повторяющегося, рутинного кода
  • Кастомизация обработчиков событий. Достаточно написать один обработчик, который будет взаимодействовать с ответами от пользователя

Быстрый старт

Установка

pip install aiogram_dialog_survey

Минимальный пример бота

from aiogram import Bot, Dispatcher, types
from aiogram.filters import CommandStart
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram_dialog import DialogManager, setup_dialogs

from aiogram_dialog_survey import Survey, StartSurvey
from aiogram_dialog_survey.entities.question import WidgetType, Question
from aiogram_dialog_survey.entities.button import Button

# Определяем вопросы анкеты
questions = [
    Question(
        name="name",
        widget_type=WidgetType.TEXT_INPUT,
        text="Как вас зовут?",
        is_required=True
    ),
    Question(
        name="age",
        widget_type=WidgetType.SELECT,
        text="Сколько вам лет?",
        is_required=True,
        buttons=[
            Button(text="До 18", callback="under_18"),
            Button(text="18-25", callback="18_25"),
            Button(text="26-35", callback="26_35"),
            Button(text="Старше 35", callback="over_35"),
        ]
    )
]

# Создаем анкету
survey = Survey(name="user_survey", questions=questions)


async def start_handler(message: types.Message, dialog_manager: DialogManager):
    await dialog_manager.start(survey.state_manager.get_first_state())


async def main():
    bot = Bot(token="YOUR_BOT_TOKEN")
    dp = Dispatcher(storage=MemoryStorage())

    # Регистрируем анкету как диалог
    dp.include_router(survey.to_dialog())
    dp.message.register(start_handler, CommandStart())

    setup_dialogs(dp)
    await dp.start_polling(bot)

Создание анкеты

Определение вопросов

Вопросы определяются с помощью класса Question:

from aiogram_dialog_survey.interface import Question
from aiogram_dialog_survey.entities.question import WidgetType
from aiogram_dialog_survey.entities.button import Button

# Вопросы, их типы и варианты ответов можно хранить в БД или в любом другом удобном месте, чтобы не засорять кодовую базу проекта и сосредоточится на более важных аспектах
questions = [
    Question(
        name="username",  # уникальный идентификатор вопроса
        question_type=WidgetType.TEXT_INPUT,  # тип вопроса
        text="Введите ваше имя:",  # текст вопроса
        is_required=True  # обязательный ли вопрос
    ),
    Question(
        name="hobbies",
        question_type=WidgetType.MULTISELECT,
        text="Выберите ваши увлечения:",
        is_required=False,
        buttons=[
            Button(text="Спорт", callback="sport"),
            Button(text="Музыка", callback="music"),
            Button(text="Кино", callback="movies"),
        ]
    ),
    #
    # еще очень-очень много вопросов
    #
    Question(
        name="height",
        question_type=WidgetType.TEXT_INPUT,
        text="Введите ваш рост:",
        is_required=True
    ),
]

Доступные типы вопросов:

  1. QuestionType.TEXT - текстовый ввод
  2. QuestionType.SELECT - выбор одного варианта из списка
  3. QuestionType.MULTISELECT - множественный выбор

Создание анкеты

from aiogram_dialog_survey import Survey

survey = Survey(
    name="user_survey",  # уникальное имя анкеты
    questions=questions,  # список вопросов
    use_numbering=True  # показывать нумерацию вопросов (по умолчанию True)
)

Подключение анкеты к роутеру

Подключение происходит точно так же, как с обычными aiogram-dialog диалогами

from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage

bot = Bot(token="YOUR_BOT_TOKEN")
dp = Dispatcher(storage=MemoryStorage())

# Добавляем анкету как диалог
dp.include_router(survey.to_dialog())

Кастомизация

Пользовательские обработчики событий

Вы можете создать собственный обработчик событий, унаследовавшись от IWindowHandler:

from aiogram_dialog_survey.protocols.handler import HandlerProtocol
from aiogram_dialog_survey.entities.action_type import ActionType
from aiogram_dialog import DialogManager


class CustomHandler(HandlerProtocol):
    @staticmethod
    async def process_handler(
        manager: DialogManager,
        question_name: str,
        action_type: ActionType
    ) -> None:
        answer = manager.dialog_data.get(question_name)
        # Кастомная логика обработки событий

    print(f"Пользователь ответил: "
    {answer}
    " на вопрос {question_name}")

    # Использование кастомного обработчика
    survey = Survey(
        name="custom_survey",
        questions=questions,
        handler=CustomHandler
    )

Такой обработчик отлично подойдет, если вы хотите каждый раз, когда пользователь отвечает на вопрос, обрабатывать его и, допустим, записывать в БД ответ пользователя и его прогресс прохождения анкеты.

В process_handler вы так же можете запускать еще subdialog в зависимости от ответа

from aiogram_dialog_survey.protocols.handler import HandlerProtocol
from aiogram_dialog_survey.entities.action_type import ActionType
from aiogram_dialog import DialogManager

from your_module import music_artist_survey


class CustomHandler(HandlerProtocol):
    @staticmethod
    async def process_handler(
        manager: DialogManager,
        question_name: str,
        action_type: ActionType
    ) -> None:
        answer = manager.dialog_data.get(question_name)

    if question_name == 'do_you_like_music' and answer == 'yes':
        manager.start(music_artist_survey.state_manager.get_first_state())

Обработка результатов анкеты

Для обработки результатов анкеты можно использовать callback-функцию on_process_result:

async def survey_result_handler(result, dialog_manager: DialogManager):
    print("Результаты анкеты:", result)
    await dialog_manager.event.answer("Спасибо за заполнение анкеты!")

survey_dialog = survey.to_dialog(on_process_result=survey_result_handler)

Расширенные возможности

Интеграция с существующими диалогами

Вы можете добавить анкету как часть большего диалога, в данном примере, StartSurvey напустить subdialog с анкетой, по завершению которой вы можете получить результат в вашем обработчике on_result:

from aiogram.fsm.state import StatesGroup, State
from aiogram_dialog import Dialog, Window
from aiogram_dialog.widgets.kbd import Button
from aiogram_dialog.widgets.text import Const
from aiogram_dialog_survey import StartSurvey

class MainSG(StatesGroup):
    start = State()
    survey = State()
    finish = State()

main_dialog = Dialog(
    Window(
        Const("Добро пожаловать!"),
        StartSurvey(
            Const("Начать анкету"),
            survey,
            id="start_survey"
        ),
        state=MainSG.start,
    ),
    Window(
        Const("Спасибо за участие!"),
        state=MainSG.finish,
    )
)

async def survey_result_handler(result, dialog_manager: DialogManager):
    print("Результаты анкеты:", result)
    await dialog_manager.switch_to(state=MainSG.finish)

survey_dialog = survey.to_dialog(on_process_result=survey_result_handler)
# Добавляем оба диалога в диспетчер
dp.include_routers(main_dialog, survey_dialog)

Примеры использования

Полный пример бота с анкетой

import logging
from aiogram import Bot, Dispatcher, types
from aiogram.filters import CommandStart
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram_dialog import DialogManager, setup_dialogs

from aiogram_dialog_survey import Survey
from aiogram_dialog_survey.interface import Question
from aiogram_dialog_survey.entities.question import WidgetType
from aiogram_dialog_survey.entities.button import Button

# Настройка логирования
logging.basicConfig(level=logging.INFO)

# Определение вопросов анкеты
questions = [
    Question(
        name="name",
        question_type=WidgetType.TEXT_INPUT,
        text="Как вас зовут?",
        is_required=True
    ),
    Question(
        name="age_group",
        question_type=WidgetType.SELECT,
        text="Ваша возрастная группа?",
        is_required=True,
        buttons=[
            Button(text="До 18", callback="under_18"),
            Button(text="18-25", callback="18_25"),
            Button(text="26-35", callback="26_35"),
            Button(text="36-45", callback="36_45"),
            Button(text="Старше 45", callback="over_45"),
        ]
    ),
    Question(
        name="interests",
        question_type=WidgetType.MULTISELECT,
        text="Какие темы вам интересны? (можно выбрать несколько)",
        is_required=False,
        buttons=[
            Button(text="Технологии", callback="tech"),
            Button(text="Наука", callback="science"),
            Button(text="Искусство", callback="art"),
            Button(text="Спорт", callback="sport"),
        ]
    )
]

# Создание анкеты
survey = Survey(
    name="user_profile",
    questions=questions,
    use_numbering=True
)


async def start_handler(message: types.Message, dialog_manager: DialogManager):
    # метод get_first_state() можно использовать, если вы хотите запустить анкету не с помощью кнопки StartSurvey, как мы это делаем в существующем диалоге, а благодаря dialog_manager
    await dialog_manager.start(survey.state_manager.get_first_state())


async def survey_result_handler(result, dialog_manager: DialogManager):
    await dialog_manager.event.answer(
        "Спасибо за заполнение анкеты! Ваши ответы сохранены."
    )
    logging.info("Сохраняем результаты анкеты: %s", result)


async def main():
    bot = Bot(token="YOUR_BOT_TOKEN")
    dp = Dispatcher(storage=MemoryStorage())

    # Добавляем анкету с обработчиком результатов
    dp.include_router(survey.to_dialog(on_process_result=survey_result_handler))
    dp.message.register(start_handler, CommandStart())

    setup_dialogs(dp)
    await dp.start_polling(bot)


if __name__ == "__main__":
    import asyncio

    asyncio.run(main())

Metadata

Release files for aiogram-dialog-survey 0.3.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aiogram-dialog-survey 0.3.2
File Size Uploaded Provenance Actions
aiogram_dialog_survey-0.3.2.tar.gz 19.2 kB Without provenance Details for aiogram_dialog_survey-0.3.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for aiogram-dialog-survey 0.3.2
File Interpreter ABI Platform Actions
aiogram_dialog_survey-0.3.2-py3-none-any.whl Python 3 none any Details for aiogram_dialog_survey-0.3.2-py3-none-any.whl

Total release size: 46.7 kB

Release files / aiogram_dialog_survey-0.3.2.tar.gz

Download URL aiogram_dialog_survey-0.3.2.tar.gz
Size 19.2 kB
Tags Source
SHA-256 checksum
How to use checksums
ffed8f2cebb0dca1632999cde114a52f19e2df5945936b6bd0d365c34f86b7d6
BLAKE2b-256 checksum
How to use checksums
b56cd414173073ab055d06cbb3a106c9bad2bbfdbb96f1a0b5d8410f97e1bb0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.0.1 CPython/3.10.12 Linux/6.8.0-60-generic

Release files / aiogram_dialog_survey-0.3.2-py3-none-any.whl

Download URL aiogram_dialog_survey-0.3.2-py3-none-any.whl
Size 27.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e49fc67bddee6a599539ebbcc18df1e1542179faed7a8eec2678c39138264460
BLAKE2b-256 checksum
How to use checksums
58aff35e1458d7e4911df037322e0a0b91e9d6c087983ba579a324c468683d0d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.0.1 CPython/3.10.12 Linux/6.8.0-60-generic

Security for aiogram-dialog-survey 0.3.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page