Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Python CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.12']

steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
run: pipx install poetry
- name: Install dependencies
run: poetry install --all-extras
- name: Run pre-commit hooks
run: poetry run pre-commit run --all-files --show-diff-on-failure
- name: Run tests
run: poetry run pytest
19 changes: 19 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: release-please

on:
push:
branches:
- main

permissions:
contents: write
pull-requests: write

jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: googleapis/release-please-action@v4
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
22 changes: 22 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-yaml
- id: check-toml
- id: check-added-large-files

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.11
hooks:
- id: ruff
args: [--fix]
- id: ruff-format

- repo: https://github.com/commitizen-tools/commitizen
rev: v4.4.1
hooks:
- id: commitizen
stages: [commit-msg]
3 changes: 3 additions & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
".": "0.0.0"
}
95 changes: 95 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# DialogEngine

[![Python CI](https://github.com/k0te1ch/DialogEngine/actions/workflows/python-app.yml/badge.svg)](https://github.com/k0te1ch/DialogEngine/actions/workflows/python-app.yml)
[![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

`DialogEngine` — лёгкий движок многошаговых диалогов на чистом Python (stdlib, без
обязательных зависимостей). Помогает строить сложные form-driven сценарии и
Telegram-ботов без спагетти из хендлеров: схема диалога описывается данными, а
движок управляет навигацией, валидацией и состоянием сессии.

## Возможности

- Описание диалога данными (`dict` / JSON / список шагов) — без хардкода переходов.
- Условные переходы между шагами (`next` по значению ответа).
- Встроенная валидация ответов + кастомные валидаторы, синхронные и асинхронные.
- Резолверы текста с подстановкой из накопленных ответов (`{name}` и т.п.).
- Управление сессией: статусы `IN_PROGRESS / COMPLETED / CANCELLED`.
- Опциональные extras: `pydantic`-валидация, загрузка схем из YAML, интеграция с `aiogram`.

## Установка

```bash
pip install dialog-engine
# с дополнительными возможностями:
pip install "dialog-engine[validation,yaml,aiogram]"
```

Для разработки используется [Poetry](https://python-poetry.org/):

```bash
poetry install --all-extras
```

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

```python
from dialog_engine import DialogEngine

engine = DialogEngine.from_list([
{"id": "name", "type": "text", "text": "Как вас зовут?"},
{"id": "age", "type": "number", "text": "Сколько вам лет?", "min": 1},
])

session = engine.create_session()

while (step := engine.current_step(session)) is not None:
answer = input(engine.resolve_text(step, session) + " ")
try:
engine.submit(session, answer)
except ValueError as exc:
print("Ошибка:", exc)

print("Готово!", session.answers)
```

## Асинхронный режим

Движок поддерживает асинхронные валидаторы и резолверы текста через
`async_submit` / `async_resolve_text`. Полный пример —
[examples/async_validators_example.py](examples/async_validators_example.py).

## Основной API

- `DialogEngine` — загрузка схемы и управление потоком диалога.
- `DialogSession` / `SessionStatus` — состояние одного запуска диалога.
- `DialogStep` / `StepType` — описание шага и его тип.
- `validate` — встроенная валидация ответов.
- `DialogError`, `ValidationError`, `StepNotFoundError` — иерархия исключений.

## Разработка

```bash
poetry install --all-extras
poetry run pre-commit install --hook-type pre-commit --hook-type commit-msg
poetry run pytest
poetry run pre-commit run --all-files
```

Коммиты — по [Conventional Commits](https://www.conventionalcommits.org/);
формат проверяет хук `commitizen`. Релизы, теги и `CHANGELOG.md` полностью
автоматизированы через [release-please](https://github.com/googleapis/release-please).
Полный гайд с диаграммами — [docs/WORKFLOW.md](docs/WORKFLOW.md).

## Структура проекта

- `dialog_engine/` — исходный код библиотеки.
- `tests/` — набор тестов (`pytest`).
- `examples/` — примеры использования.
- `docs/WORKFLOW.md` — гайд по веткам, коммитам и релизам.
- `.github/workflows/` — CI и release-please.

## Лицензия

[MIT](LICENSE)
61 changes: 61 additions & 0 deletions dialog_engine/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""dialog_engine — universal multi-step dialog engine.

Quick start::

from dialog_engine import DialogEngine

engine = DialogEngine.from_file("dialogs/onboarding.json")
session = engine.create_session()

while (step := engine.current_step(session)) is not None:
answer = input(engine.resolve_text(step, session) + " ")
try:
engine.submit(session, answer)
except ValidationError as exc:
print("Error:", exc)

Public API
----------
Classes:
DialogEngine — loads a dialog schema, drives navigation
DialogSession — mutable run-time state for one dialog instance
DialogStep — a single step in the dialog schema
SessionStatus — enum: IN_PROGRESS / COMPLETED / CANCELLED

Exceptions:
DialogError — base exception
StepNotFoundError — unknown step ID referenced
ValidationError — submitted answer fails validation

Types:
StepType — Literal union of all supported step type strings
TextResolver — Callable used by the engine to resolve display text
"""

from .engine import DialogEngine, TextResolver
from .exceptions import DialogError, StepNotFoundError, ValidationError
from .session import DialogSession, SessionStatus
from .step import DialogStep, StepType
from .validators import validate

__version__ = "0.0.0" # x-release-please-version

__all__ = [
# Engine
"DialogEngine",
"TextResolver",
# Session
"DialogSession",
"SessionStatus",
# Step
"DialogStep",
"StepType",
# Validators
"validate",
# Exceptions
"DialogError",
"StepNotFoundError",
"ValidationError",
# Metadata
"__version__",
]
Loading
Loading