JSON-driven step dialog engine with conditional steps and optional aiogram helpers
Project description
dialog-engine
Библиотека для описания пошаговых диалогов (мастеров, анкет, визардов) в JSON или YAML. Вы задаёте список шагов и тип каждого шага; при необходимости шаги можно показывать или пропускать в зависимости от уже собранных данных (контекста). Ядро не привязано к Telegram — его можно использовать в веб-приложениях, CLI и т.д. Дополнительно есть интеграция с aiogram 3 (готовые inline-клавиатуры под типичные сценарии).
Лицензия: исходный код открыт для просмотра (source-available), но изменение и распространение изменённой версии запрещены; в своих проектах вы можете устанавливать пакет и использовать его как библиотеку без переписывания кода библиотеки. Это не «open source» в смысле Open Source Initiative: по определению OSD право на модификацию и производные работы обязательно. Подробности — в LICENSE.
Требования: Python 3.10+.
Установка
Минимальная установка (только ядро, без зависимостей):
pip install dialog-engine
Дополнительные возможности подключаются extras (установите только то, что нужно):
| Extra | Назначение |
|---|---|
validation |
Строгая проверка структуры JSON через Pydantic |
yaml |
Загрузка диалогов из YAML-файлов (PyYAML) |
aiogram |
Хелперы для inline-клавиатур под aiogram 3 |
Примеры:
pip install dialog-engine[validation]
pip install dialog-engine[yaml,aiogram]
pip install dialog-engine[validation,yaml,aiogram]
Разработка пакета из клонированного репозитория:
pip install -e ".[dev]"
Идея в двух словах
- В файле описывается массив шагов (
steps). У каждого шага естьid,typeи полеtext(часто это ключ для i18n или просто текст вопроса). - Во время работы приложение хранит контекст — обычный словарь (например ответы пользователя:
{"email": "...", "plan": "pro"}). Ключи в условиях совпадают с ключами контекста. - Движок
DialogEngineумеет по контексту определить, какие шаги видимы, и вычислить следующий/предыдущий видимый шаг — без ручныхifв коде для каждого сценария.
Формат JSON
Корень файла — либо объект с полем steps, либо сразу массив шагов:
{
"steps": [
{ "id": "name", "type": "text", "text": "question-name", "required": true },
{ "id": "plan", "type": "choice", "text": "question-plan", "required": true,
"choices": { "free": "plan-free", "pro": "plan-pro" } }
]
}
Поля шага
| Поле | Обязательно | Описание |
|---|---|---|
id |
да | Уникальный идентификатор шага; по нему удобно сохранять ответ в контексте (context[id] = ...). |
type |
да | Логический тип шага. В ядре допустимы произвольные строки; типичные: text, choice, photo — интерпретация на стороне вашего UI. |
text |
да | Текст вопроса или ключ локализации (библиотека его не переводит). |
required |
нет, по умолчанию true |
Обязательность шага (для вашей логики и extras aiogram — кнопка «Пропустить»). |
choices |
для choice |
Объект "значение_ответа": "ключ_подписи" — подписи снова передаются в translate() в aiogram-extra. |
min, max |
для шагов с вложениями | Для типа photo в примерах это минимальное и максимальное число файлов; в объекте DialogStep они хранятся как min_photos / max_photos. |
skip_when |
нет | Условие: если выполняется — шаг не показывается (пропускается при навигации). |
show_when |
нет | Если задано — шаг показывается только когда условие выполняется. Если не задано и skip_when не срабатывает — шаг виден. |
Условия skip_when и show_when
Задаются одним объектом или списком объектов (логика И — все перечисленные условия должны выполняться).
Каждое условие:
field— имя поля в контексте (строка).- Ровно одно из:
equals— значение в контексте должно быть равно этому значению;in— значение должно входить в список;not_in— значение не должно входить в список.
Пример: не показывать шаг загрузки фото карты, если владелец карты — третье лицо (значение в контексте заранее записано, например после шага choice):
{
"id": "bank_card_photo",
"type": "photo",
"text": "upload-card",
"required": false,
"min": 1,
"max": 1,
"skip_when": { "field": "card_owner", "equals": "third" }
}
Если поля field в контексте нет, сравнение идёт с None (например equals с конкретной строкой не сработает).
Python API: ядро
Загрузка
from pathlib import Path
from dialog_engine import DialogEngine
engine = DialogEngine.from_file(Path("wizard.json"))
# или из строки JSON:
engine = DialogEngine.from_json_string('{"steps": [...]}')
# или из списка dict (например после своего парсера):
engine = DialogEngine.from_list([{...}, {...}])
Объект шага DialogStep
Поля соответствуют JSON; у фото-диапазона в коде имена min_photos / max_photos.
Навигация и прогресс
Контекст — любой Mapping (часто обычный dict с ответами пользователя).
ctx = {"card_owner": "self"}
# Индексы шагов в конфиге — «сырые» (0 .. len-1). Видимость зависит от ctx.
engine.get_step(0) # шаг по индексу или None
engine.get_step_by_id("email") # (index, DialogStep) или None
engine.total() # число шагов в файле (все подряд)
engine.effective_total(ctx) # сколько шагов видно при данном контексте
engine.effective_position(3, ctx) # номер среди видимых (1-based) или None, если индекс скрыт
engine.next_index(2, ctx) # следующий видимый индекс после 2, или None — конец
engine.previous_index(5, ctx) # предыдущий видимый, или None
engine.visible_indices(ctx) # список сырых индексов видимых шагов по порядку
engine.first_visible_index(ctx)
engine.iter_visible_steps(ctx) # итератор (index, DialogStep) только по видимым
engine.is_last(4) # последний ли индекс в конфиге (без учёта скрытых)
engine.is_last_visible(4, ctx) # последний ли среди видимых
Проверка видимости одного шага
from dialog_engine import step_is_visible
if step_is_visible(step, ctx):
...
Полезно при фильтрации обязательных полей или при построении сводки только по актуальным шагам.
Дополнения (extras)
Pydantic (validation)
После pip install dialog-engine[validation] можно проверять структуру данных до загрузки в движок:
from dialog_engine.pydantic_schema import validate_dialog_data
import json
with open("wizard.json", encoding="utf-8") as f:
data = json.load(f)
validate_dialog_data(data) # при ошибке — ValidationError
Имеет смысл в CI и в редакторах конфигов.
YAML (yaml)
from dialog_engine.loaders import from_yaml_file
engine = from_yaml_file("wizard.yaml")
Корень YAML — как в JSON: steps: [...] или список шагов.
aiogram 3 (aiogram)
from dialog_engine.integrations.aiogram import (
KeyboardCallbacks,
build_step_keyboard,
build_photo_keyboard,
)
# translate — функция вида lambda key: str, возвращающая подпись кнопки/строки
kb = build_step_keyboard(
step,
translate,
show_back=True,
current_value=context.get(step.id),
keep_button_text=..., # опционально, готовая строка для «оставить»
)
kb = build_photo_keyboard(
translate,
show_done=True,
show_keep=False,
keep_button_text=None,
show_clear=True,
show_skip=True,
)
По умолчанию callback_data совместимы с префиксами вроде dialog_choice:field_id:key, dialog_skip, dialog_back и т.д. Свои значения можно задать через KeyboardCallbacks (поля skip, back, keep, photo_done, photo_clear, choice_prefix и метод choice_data(step_id, key)).
Командная строка
После установки пакета:
dialog-engine-validate путь/к/диалог.json
Проверяется синтаксис JSON и возможность собрать DialogEngine.
Строгая проверка схемы (нужен extra validation):
dialog-engine-validate --strict путь/к/диалог.json
То же через модуль:
python -m dialog_engine путь/к/диалог.json
Коды выхода: 0 — успех, иначе ошибка (в т.ч. отсутствие файла или --strict без Pydantic).
Как встроить в приложение
- Загрузите диалог один раз (или при смене файла) через
DialogEngine.from_file. - В состоянии сессии храните текущий индекс шага (сырой индекс в массиве
steps) и контекст (ответы). - После каждого ответа обновляйте контекст, например
context[step.id] = value. - Для перехода вперёд используйте
next_index(current_index, context); если вернулосьNone— диалог закончен (или нужно перейти на экран подтверждения). - Для «Назад» —
previous_index(current_index, context). - Для индикатора «Шаг 2 из 5» используйте
effective_positionиeffective_total, чтобы число шагов учитывало скрытые поskip_when/show_when.
Типы text / choice / photo в JSON — соглашение; библиотека не отправляет сообщения и не качает файлы. Реализацию ввода-вывода делаете вы (Telegram, HTTP, TUI и т.д.).
Авторы
| GitHub | ||
|---|---|---|
| Данила Шубин | @ShyDamn | den03062003@gmail.com |
| Савелий Хвостов | @k0te1ch | khvostov40@gmail.com |
Репозиторий: github.com/ShyDamn/dialog-engine.
Лицензия
Текст лицензии — в файле LICENSE (англ.). Кратко:
- можно устанавливать, запускать и подключать пакет в своих приложениях;
- можно распространять неизменённые копии (в т.ч. через PyPI), с сохранением уведомления об авторских правах и текста лицензии;
- нельзя изменять исходники библиотеки, создавать производные работы на их основе и распространять изменённые версии;
- отчёты об ошибках и предложения по улучшению приветствуются через репозиторий, но это не разрешение на форк с правками.
Для сравнения: лицензии Creative Commons с условием NoDerivatives (например CC BY-ND) близки по духу («не переделывать и не распространять переделки»), но CC не рекомендует применять свои лицензии к ПО; поэтому здесь используется отдельный текст, заточенный под программное обеспечение.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dialog_engine-0.1.0.tar.gz.
File metadata
- Download URL: dialog_engine-0.1.0.tar.gz
- Upload date:
- Size: 16.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c27b9449d0392dc11eb94b2d5ede2e4d2754c557a2165a6c7e8cfca2cb431700
|
|
| MD5 |
f6f65e1ff62479d0a373550d18a0619d
|
|
| BLAKE2b-256 |
f0489689f5220769f4eee413ea14113ca4c2548bca142ca7a1cc574d22555afa
|
File details
Details for the file dialog_engine-0.1.0-py3-none-any.whl.
File metadata
- Download URL: dialog_engine-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ca12f238d1fcc90caac6008425598e66fa9450a682bdc22ae3190f7664b8378
|
|
| MD5 |
44f7ab6d4b0a1d7c23d76dc9e960e99e
|
|
| BLAKE2b-256 |
dba96749518bd2e054779c7e0d43eda27277aeaffa658e97dedc7b80eeaf2bf9
|