dialog-engine 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dialog_engine-0.1.0/.gitignore +8 -0
- dialog_engine-0.1.0/LICENSE +62 -0
- dialog_engine-0.1.0/PKG-INFO +381 -0
- dialog_engine-0.1.0/PUBLISHING.md +65 -0
- dialog_engine-0.1.0/README.md +283 -0
- dialog_engine-0.1.0/pyproject.toml +69 -0
- dialog_engine-0.1.0/src/dialog_engine/__init__.py +14 -0
- dialog_engine-0.1.0/src/dialog_engine/__main__.py +4 -0
- dialog_engine-0.1.0/src/dialog_engine/cli.py +79 -0
- dialog_engine-0.1.0/src/dialog_engine/engine.py +111 -0
- dialog_engine-0.1.0/src/dialog_engine/integrations/__init__.py +1 -0
- dialog_engine-0.1.0/src/dialog_engine/integrations/aiogram/__init__.py +13 -0
- dialog_engine-0.1.0/src/dialog_engine/integrations/aiogram/keyboards.py +125 -0
- dialog_engine-0.1.0/src/dialog_engine/loaders.py +24 -0
- dialog_engine-0.1.0/src/dialog_engine/py.typed +0 -0
- dialog_engine-0.1.0/src/dialog_engine/pydantic_schema.py +42 -0
- dialog_engine-0.1.0/src/dialog_engine/step.py +55 -0
- dialog_engine-0.1.0/src/dialog_engine/visibility.py +57 -0
- dialog_engine-0.1.0/tests/test_engine.py +64 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Dialog Engine — Source-Available License (v1)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Danila Shubin, Saveliy Khvostov. All rights reserved.
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS
|
|
6
|
+
|
|
7
|
+
1. Definitions. "Software" means the dialog-engine package, its source code,
|
|
8
|
+
object code (if any), and documentation distributed with it.
|
|
9
|
+
|
|
10
|
+
2. Grant of use. Subject to this License, you are granted a worldwide,
|
|
11
|
+
royalty-free, non-exclusive license to:
|
|
12
|
+
(a) install and run the Software;
|
|
13
|
+
(b) import, call, and link to the Software as a library in your own
|
|
14
|
+
programs;
|
|
15
|
+
(c) copy and redistribute unmodified copies of the Software (including
|
|
16
|
+
through package indexes such as PyPI), provided that you retain this
|
|
17
|
+
License and copyright notices.
|
|
18
|
+
|
|
19
|
+
3. Modification and derivatives PROHIBITED. You may not modify, adapt,
|
|
20
|
+
translate, merge, or otherwise create derivative works of the Software.
|
|
21
|
+
You may not distribute the Software, or any part of it, if you have changed
|
|
22
|
+
its source files. You may not publicly fork or publish a variant of this
|
|
23
|
+
project that includes altered library source code.
|
|
24
|
+
|
|
25
|
+
Bug reports and feature suggestions are welcome through the channels
|
|
26
|
+
indicated in the project repository; they do not constitute permission to
|
|
27
|
+
modify and redistribute.
|
|
28
|
+
|
|
29
|
+
4. No reverse engineering for circumvention. You may not circumvent the
|
|
30
|
+
restrictions in section 3 by decompiling or disassembling the Software except
|
|
31
|
+
to the extent that applicable law expressly permits and cannot be waived.
|
|
32
|
+
|
|
33
|
+
5. Attribution. Redistributions of the Software must reproduce this License
|
|
34
|
+
and the copyright notice above.
|
|
35
|
+
|
|
36
|
+
6. No trademark. This License does not grant permission to use trade names,
|
|
37
|
+
trademarks, or service marks of the copyright holders, except as required
|
|
38
|
+
for reasonable and customary use in describing the origin of the Software.
|
|
39
|
+
|
|
40
|
+
7. Disclaimer of warranty. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
|
|
41
|
+
OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
42
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
43
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
44
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
45
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
46
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
47
|
+
|
|
48
|
+
8. Termination. If you violate this License, your rights under it terminate
|
|
49
|
+
automatically.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
Note on "open source": This license is NOT an Open Source Initiative (OSI)
|
|
54
|
+
approved license, because it does not grant the freedom to modify and share
|
|
55
|
+
modified versions — a requirement of the Open Source Definition. It is a
|
|
56
|
+
source-available license: the source is visible for transparency and
|
|
57
|
+
auditing, but changing and redistributing changed source is not permitted.
|
|
58
|
+
|
|
59
|
+
For comparison, Creative Commons offers "NoDerivatives" variants (e.g. CC BY-ND),
|
|
60
|
+
but Creative Commons discourages using CC licenses for software; a dedicated
|
|
61
|
+
software license (such as this text) is a common approach when you want
|
|
62
|
+
use-without-modification terms.
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dialog-engine
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: JSON-driven step dialog engine with conditional steps and optional aiogram helpers
|
|
5
|
+
Project-URL: Homepage, https://github.com/ShyDamn/dialog-engine
|
|
6
|
+
Project-URL: Documentation, https://github.com/ShyDamn/dialog-engine#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/ShyDamn/dialog-engine
|
|
8
|
+
Project-URL: Issues, https://github.com/ShyDamn/dialog-engine/issues
|
|
9
|
+
Author-email: Danila Shubin <den03062003@gmail.com>, Saveliy Khvostov <khvostov40@gmail.com>
|
|
10
|
+
License: Dialog Engine — Source-Available License (v1)
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 Danila Shubin, Saveliy Khvostov. All rights reserved.
|
|
13
|
+
|
|
14
|
+
TERMS AND CONDITIONS
|
|
15
|
+
|
|
16
|
+
1. Definitions. "Software" means the dialog-engine package, its source code,
|
|
17
|
+
object code (if any), and documentation distributed with it.
|
|
18
|
+
|
|
19
|
+
2. Grant of use. Subject to this License, you are granted a worldwide,
|
|
20
|
+
royalty-free, non-exclusive license to:
|
|
21
|
+
(a) install and run the Software;
|
|
22
|
+
(b) import, call, and link to the Software as a library in your own
|
|
23
|
+
programs;
|
|
24
|
+
(c) copy and redistribute unmodified copies of the Software (including
|
|
25
|
+
through package indexes such as PyPI), provided that you retain this
|
|
26
|
+
License and copyright notices.
|
|
27
|
+
|
|
28
|
+
3. Modification and derivatives PROHIBITED. You may not modify, adapt,
|
|
29
|
+
translate, merge, or otherwise create derivative works of the Software.
|
|
30
|
+
You may not distribute the Software, or any part of it, if you have changed
|
|
31
|
+
its source files. You may not publicly fork or publish a variant of this
|
|
32
|
+
project that includes altered library source code.
|
|
33
|
+
|
|
34
|
+
Bug reports and feature suggestions are welcome through the channels
|
|
35
|
+
indicated in the project repository; they do not constitute permission to
|
|
36
|
+
modify and redistribute.
|
|
37
|
+
|
|
38
|
+
4. No reverse engineering for circumvention. You may not circumvent the
|
|
39
|
+
restrictions in section 3 by decompiling or disassembling the Software except
|
|
40
|
+
to the extent that applicable law expressly permits and cannot be waived.
|
|
41
|
+
|
|
42
|
+
5. Attribution. Redistributions of the Software must reproduce this License
|
|
43
|
+
and the copyright notice above.
|
|
44
|
+
|
|
45
|
+
6. No trademark. This License does not grant permission to use trade names,
|
|
46
|
+
trademarks, or service marks of the copyright holders, except as required
|
|
47
|
+
for reasonable and customary use in describing the origin of the Software.
|
|
48
|
+
|
|
49
|
+
7. Disclaimer of warranty. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
|
|
50
|
+
OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
51
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
52
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
53
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
54
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
55
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
56
|
+
|
|
57
|
+
8. Termination. If you violate this License, your rights under it terminate
|
|
58
|
+
automatically.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
Note on "open source": This license is NOT an Open Source Initiative (OSI)
|
|
63
|
+
approved license, because it does not grant the freedom to modify and share
|
|
64
|
+
modified versions — a requirement of the Open Source Definition. It is a
|
|
65
|
+
source-available license: the source is visible for transparency and
|
|
66
|
+
auditing, but changing and redistributing changed source is not permitted.
|
|
67
|
+
|
|
68
|
+
For comparison, Creative Commons offers "NoDerivatives" variants (e.g. CC BY-ND),
|
|
69
|
+
but Creative Commons discourages using CC licenses for software; a dedicated
|
|
70
|
+
software license (such as this text) is a common approach when you want
|
|
71
|
+
use-without-modification terms.
|
|
72
|
+
License-File: LICENSE
|
|
73
|
+
Keywords: aiogram,dialog,json,steps,telegram,wizard
|
|
74
|
+
Classifier: Development Status :: 4 - Beta
|
|
75
|
+
Classifier: Intended Audience :: Developers
|
|
76
|
+
Classifier: License :: Other/Proprietary License
|
|
77
|
+
Classifier: Programming Language :: Python :: 3
|
|
78
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
79
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
80
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
81
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
82
|
+
Classifier: Typing :: Typed
|
|
83
|
+
Requires-Python: >=3.10
|
|
84
|
+
Provides-Extra: aiogram
|
|
85
|
+
Requires-Dist: aiogram<4,>=3.0; extra == 'aiogram'
|
|
86
|
+
Provides-Extra: dev
|
|
87
|
+
Requires-Dist: aiogram<4,>=3.0; extra == 'dev'
|
|
88
|
+
Requires-Dist: pydantic<3,>=2.0; extra == 'dev'
|
|
89
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
90
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
91
|
+
Requires-Dist: pyyaml>=6.0; extra == 'dev'
|
|
92
|
+
Requires-Dist: ruff>=0.8.0; extra == 'dev'
|
|
93
|
+
Provides-Extra: validation
|
|
94
|
+
Requires-Dist: pydantic<3,>=2.0; extra == 'validation'
|
|
95
|
+
Provides-Extra: yaml
|
|
96
|
+
Requires-Dist: pyyaml>=6.0; extra == 'yaml'
|
|
97
|
+
Description-Content-Type: text/markdown
|
|
98
|
+
|
|
99
|
+
# dialog-engine
|
|
100
|
+
|
|
101
|
+
Библиотека для описания **пошаговых диалогов** (мастеров, анкет, визардов) в JSON или YAML. Вы задаёте список шагов и тип каждого шага; при необходимости шаги можно **показывать или пропускать** в зависимости от уже собранных данных (**контекста**). Ядро не привязано к Telegram — его можно использовать в веб-приложениях, CLI и т.д. Дополнительно есть интеграция с **aiogram 3** (готовые inline-клавиатуры под типичные сценарии).
|
|
102
|
+
|
|
103
|
+
**Лицензия:** исходный код открыт для просмотра (**source-available**), но **изменение и распространение изменённой версии запрещены**; в своих проектах вы можете **устанавливать пакет и использовать его как библиотеку** без переписывания кода библиотеки. Это **не** «open source» в смысле [Open Source Initiative](https://opensource.org/osd): по определению OSD право на модификацию и производные работы обязательно. Подробности — в [LICENSE](LICENSE).
|
|
104
|
+
|
|
105
|
+
**Требования:** Python 3.10+.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Установка
|
|
110
|
+
|
|
111
|
+
Минимальная установка (только ядро, без зависимостей):
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pip install dialog-engine
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Дополнительные возможности подключаются **extras** (установите только то, что нужно):
|
|
118
|
+
|
|
119
|
+
| Extra | Назначение |
|
|
120
|
+
|-------|------------|
|
|
121
|
+
| `validation` | Строгая проверка структуры JSON через Pydantic |
|
|
122
|
+
| `yaml` | Загрузка диалогов из YAML-файлов (PyYAML) |
|
|
123
|
+
| `aiogram` | Хелперы для inline-клавиатур под aiogram 3 |
|
|
124
|
+
|
|
125
|
+
Примеры:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pip install dialog-engine[validation]
|
|
129
|
+
pip install dialog-engine[yaml,aiogram]
|
|
130
|
+
pip install dialog-engine[validation,yaml,aiogram]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Разработка пакета из клонированного репозитория:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pip install -e ".[dev]"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Идея в двух словах
|
|
142
|
+
|
|
143
|
+
1. В файле описывается массив **шагов** (`steps`). У каждого шага есть `id`, `type` и поле `text` (часто это ключ для i18n или просто текст вопроса).
|
|
144
|
+
2. Во время работы приложение хранит **контекст** — обычный словарь (например ответы пользователя: `{"email": "...", "plan": "pro"}`). Ключи в условиях совпадают с ключами контекста.
|
|
145
|
+
3. Движок **`DialogEngine`** умеет по контексту определить, какие шаги **видимы**, и вычислить **следующий/предыдущий** видимый шаг — без ручных `if` в коде для каждого сценария.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Формат JSON
|
|
150
|
+
|
|
151
|
+
Корень файла — либо объект с полем `steps`, либо сразу массив шагов:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"steps": [
|
|
156
|
+
{ "id": "name", "type": "text", "text": "question-name", "required": true },
|
|
157
|
+
{ "id": "plan", "type": "choice", "text": "question-plan", "required": true,
|
|
158
|
+
"choices": { "free": "plan-free", "pro": "plan-pro" } }
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Поля шага
|
|
164
|
+
|
|
165
|
+
| Поле | Обязательно | Описание |
|
|
166
|
+
|------|-------------|----------|
|
|
167
|
+
| `id` | да | Уникальный идентификатор шага; по нему удобно сохранять ответ в контексте (`context[id] = ...`). |
|
|
168
|
+
| `type` | да | Логический тип шага. В ядре допустимы произвольные строки; типичные: `text`, `choice`, `photo` — интерпретация на стороне вашего UI. |
|
|
169
|
+
| `text` | да | Текст вопроса или ключ локализации (библиотека его не переводит). |
|
|
170
|
+
| `required` | нет, по умолчанию `true` | Обязательность шага (для вашей логики и extras aiogram — кнопка «Пропустить»). |
|
|
171
|
+
| `choices` | для `choice` | Объект `"значение_ответа": "ключ_подписи"` — подписи снова передаются в `translate()` в aiogram-extra. |
|
|
172
|
+
| `min`, `max` | для шагов с вложениями | Для типа `photo` в примерах это минимальное и максимальное число файлов; в объекте `DialogStep` они хранятся как `min_photos` / `max_photos`. |
|
|
173
|
+
| `skip_when` | нет | Условие: если выполняется — шаг **не показывается** (пропускается при навигации). |
|
|
174
|
+
| `show_when` | нет | Если задано — шаг показывается **только** когда условие выполняется. Если не задано и `skip_when` не срабатывает — шаг виден. |
|
|
175
|
+
|
|
176
|
+
### Условия `skip_when` и `show_when`
|
|
177
|
+
|
|
178
|
+
Задаются одним объектом или списком объектов (логика **И** — все перечисленные условия должны выполняться).
|
|
179
|
+
|
|
180
|
+
Каждое условие:
|
|
181
|
+
|
|
182
|
+
- `field` — имя поля в контексте (строка).
|
|
183
|
+
- Ровно одно из:
|
|
184
|
+
- `equals` — значение в контексте должно быть равно этому значению;
|
|
185
|
+
- `in` — значение должно входить в список;
|
|
186
|
+
- `not_in` — значение **не** должно входить в список.
|
|
187
|
+
|
|
188
|
+
Пример: не показывать шаг загрузки фото карты, если владелец карты — третье лицо (значение в контексте заранее записано, например после шага `choice`):
|
|
189
|
+
|
|
190
|
+
```json
|
|
191
|
+
{
|
|
192
|
+
"id": "bank_card_photo",
|
|
193
|
+
"type": "photo",
|
|
194
|
+
"text": "upload-card",
|
|
195
|
+
"required": false,
|
|
196
|
+
"min": 1,
|
|
197
|
+
"max": 1,
|
|
198
|
+
"skip_when": { "field": "card_owner", "equals": "third" }
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Если поля `field` в контексте нет, сравнение идёт с `None` (например `equals` с конкретной строкой не сработает).
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Python API: ядро
|
|
207
|
+
|
|
208
|
+
### Загрузка
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
from pathlib import Path
|
|
212
|
+
from dialog_engine import DialogEngine
|
|
213
|
+
|
|
214
|
+
engine = DialogEngine.from_file(Path("wizard.json"))
|
|
215
|
+
# или из строки JSON:
|
|
216
|
+
engine = DialogEngine.from_json_string('{"steps": [...]}')
|
|
217
|
+
# или из списка dict (например после своего парсера):
|
|
218
|
+
engine = DialogEngine.from_list([{...}, {...}])
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Объект шага `DialogStep`
|
|
222
|
+
|
|
223
|
+
Поля соответствуют JSON; у фото-диапазона в коде имена `min_photos` / `max_photos`.
|
|
224
|
+
|
|
225
|
+
### Навигация и прогресс
|
|
226
|
+
|
|
227
|
+
Контекст — любой `Mapping` (часто обычный `dict` с ответами пользователя).
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
ctx = {"card_owner": "self"}
|
|
231
|
+
|
|
232
|
+
# Индексы шагов в конфиге — «сырые» (0 .. len-1). Видимость зависит от ctx.
|
|
233
|
+
engine.get_step(0) # шаг по индексу или None
|
|
234
|
+
engine.get_step_by_id("email") # (index, DialogStep) или None
|
|
235
|
+
|
|
236
|
+
engine.total() # число шагов в файле (все подряд)
|
|
237
|
+
engine.effective_total(ctx) # сколько шагов видно при данном контексте
|
|
238
|
+
engine.effective_position(3, ctx) # номер среди видимых (1-based) или None, если индекс скрыт
|
|
239
|
+
|
|
240
|
+
engine.next_index(2, ctx) # следующий видимый индекс после 2, или None — конец
|
|
241
|
+
engine.previous_index(5, ctx) # предыдущий видимый, или None
|
|
242
|
+
engine.visible_indices(ctx) # список сырых индексов видимых шагов по порядку
|
|
243
|
+
engine.first_visible_index(ctx)
|
|
244
|
+
engine.iter_visible_steps(ctx) # итератор (index, DialogStep) только по видимым
|
|
245
|
+
|
|
246
|
+
engine.is_last(4) # последний ли индекс в конфиге (без учёта скрытых)
|
|
247
|
+
engine.is_last_visible(4, ctx) # последний ли среди видимых
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Проверка видимости одного шага
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
from dialog_engine import step_is_visible
|
|
254
|
+
|
|
255
|
+
if step_is_visible(step, ctx):
|
|
256
|
+
...
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Полезно при фильтрации обязательных полей или при построении сводки только по актуальным шагам.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Дополнения (extras)
|
|
264
|
+
|
|
265
|
+
### Pydantic (`validation`)
|
|
266
|
+
|
|
267
|
+
После `pip install dialog-engine[validation]` можно проверять структуру данных до загрузки в движок:
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
from dialog_engine.pydantic_schema import validate_dialog_data
|
|
271
|
+
import json
|
|
272
|
+
|
|
273
|
+
with open("wizard.json", encoding="utf-8") as f:
|
|
274
|
+
data = json.load(f)
|
|
275
|
+
validate_dialog_data(data) # при ошибке — ValidationError
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Имеет смысл в CI и в редакторах конфигов.
|
|
279
|
+
|
|
280
|
+
### YAML (`yaml`)
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
from dialog_engine.loaders import from_yaml_file
|
|
284
|
+
|
|
285
|
+
engine = from_yaml_file("wizard.yaml")
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Корень YAML — как в JSON: `steps: [...]` или список шагов.
|
|
289
|
+
|
|
290
|
+
### aiogram 3 (`aiogram`)
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
from dialog_engine.integrations.aiogram import (
|
|
294
|
+
KeyboardCallbacks,
|
|
295
|
+
build_step_keyboard,
|
|
296
|
+
build_photo_keyboard,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
# translate — функция вида lambda key: str, возвращающая подпись кнопки/строки
|
|
300
|
+
kb = build_step_keyboard(
|
|
301
|
+
step,
|
|
302
|
+
translate,
|
|
303
|
+
show_back=True,
|
|
304
|
+
current_value=context.get(step.id),
|
|
305
|
+
keep_button_text=..., # опционально, готовая строка для «оставить»
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
kb = build_photo_keyboard(
|
|
309
|
+
translate,
|
|
310
|
+
show_done=True,
|
|
311
|
+
show_keep=False,
|
|
312
|
+
keep_button_text=None,
|
|
313
|
+
show_clear=True,
|
|
314
|
+
show_skip=True,
|
|
315
|
+
)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
По умолчанию `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)`).
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Командная строка
|
|
323
|
+
|
|
324
|
+
После установки пакета:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
dialog-engine-validate путь/к/диалог.json
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Проверяется синтаксис JSON и возможность собрать `DialogEngine`.
|
|
331
|
+
|
|
332
|
+
Строгая проверка схемы (нужен extra `validation`):
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
dialog-engine-validate --strict путь/к/диалог.json
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
То же через модуль:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
python -m dialog_engine путь/к/диалог.json
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Коды выхода: `0` — успех, иначе ошибка (в т.ч. отсутствие файла или `--strict` без Pydantic).
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Как встроить в приложение
|
|
349
|
+
|
|
350
|
+
1. Загрузите диалог один раз (или при смене файла) через `DialogEngine.from_file`.
|
|
351
|
+
2. В состоянии сессии храните **текущий индекс** шага (сырой индекс в массиве `steps`) и **контекст** (ответы).
|
|
352
|
+
3. После каждого ответа обновляйте контекст, например `context[step.id] = value`.
|
|
353
|
+
4. Для перехода вперёд используйте `next_index(current_index, context)`; если вернулось `None` — диалог закончен (или нужно перейти на экран подтверждения).
|
|
354
|
+
5. Для «Назад» — `previous_index(current_index, context)`.
|
|
355
|
+
6. Для индикатора «Шаг 2 из 5» используйте `effective_position` и `effective_total`, чтобы число шагов учитывало скрытые по `skip_when` / `show_when`.
|
|
356
|
+
|
|
357
|
+
Типы `text` / `choice` / `photo` в JSON — соглашение; библиотека не отправляет сообщения и не качает файлы. Реализацию ввода-вывода делаете вы (Telegram, HTTP, TUI и т.д.).
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Авторы
|
|
362
|
+
|
|
363
|
+
| | GitHub | Email |
|
|
364
|
+
|---|--------|-------|
|
|
365
|
+
| **Данила Шубин** | [@ShyDamn](https://github.com/ShyDamn) | [den03062003@gmail.com](mailto:den03062003@gmail.com) |
|
|
366
|
+
| **Савелий Хвостов** | [@k0te1ch](https://github.com/k0te1ch) | [khvostov40@gmail.com](mailto:khvostov40@gmail.com) |
|
|
367
|
+
|
|
368
|
+
Репозиторий: [github.com/ShyDamn/dialog-engine](https://github.com/ShyDamn/dialog-engine).
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Лицензия
|
|
373
|
+
|
|
374
|
+
Текст лицензии — в файле [LICENSE](LICENSE) (англ.). Кратко:
|
|
375
|
+
|
|
376
|
+
- можно **устанавливать**, **запускать** и **подключать** пакет в своих приложениях;
|
|
377
|
+
- можно **распространять неизменённые** копии (в т.ч. через PyPI), с сохранением уведомления об авторских правах и текста лицензии;
|
|
378
|
+
- **нельзя** изменять исходники библиотеки, создавать производные работы на их основе и распространять изменённые версии;
|
|
379
|
+
- отчёты об ошибках и предложения по улучшению приветствуются через репозиторий, но это **не** разрешение на форк с правками.
|
|
380
|
+
|
|
381
|
+
Для сравнения: лицензии Creative Commons с условием **NoDerivatives** (например [CC BY-ND](https://creativecommons.org/licenses/by-nd/4.0/)) близки по духу («не переделывать и не распространять переделки»), но CC **не рекомендует** применять свои лицензии к ПО; поэтому здесь используется отдельный текст, заточенный под программное обеспечение.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Публикация и сопровождение (для автора репозитория)
|
|
2
|
+
|
|
3
|
+
Этот файл не для пользователей библиотеки. Здесь — чеклист релиза на PyPI и сопутствующие задачи.
|
|
4
|
+
|
|
5
|
+
## Перед первым релизом
|
|
6
|
+
|
|
7
|
+
1. **Имя на PyPI** — убедиться, что имя дистрибутива (`dialog-engine` в `pyproject.toml`) свободно или зарезервировано: https://pypi.org/project/dialog-engine/
|
|
8
|
+
2. **Метаданные** в `[project]` файла `pyproject.toml`:
|
|
9
|
+
- `authors` (Danila Shubin, Saveliy Khvostov), `license = { file = "LICENSE" }`, `readme`
|
|
10
|
+
- `project.urls` — репозиторий [github.com/ShyDamn/dialog-engine](https://github.com/ShyDamn/dialog-engine) (владелец: ShyDamn)
|
|
11
|
+
3. **Версия** — синхронизировать `version` в `pyproject.toml` и при необходимости `__version__` в `src/dialog_engine/__init__.py`.
|
|
12
|
+
|
|
13
|
+
## Сборка артефактов
|
|
14
|
+
|
|
15
|
+
Из каталога `DialogEngine` (где лежит `pyproject.toml`):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install build
|
|
19
|
+
python -m build --outdir dist .
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
В `dist/` появятся `.tar.gz` (sdist) и `.whl` (wheel).
|
|
23
|
+
|
|
24
|
+
Проверка установки колёса в чистом окружении:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install dist/dialog_engine-*.whl
|
|
28
|
+
python -c "import dialog_engine; print(dialog_engine.__version__)"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## TestPyPI (рекомендуется перед боем)
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install twine
|
|
35
|
+
twine upload --repository testpypi dist/*
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Установка с тестового индекса:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install -i https://test.pypi.org/simple/ dialog-engine==<версия>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## PyPI (production)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
twine upload dist/*
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Потребуются учётные данные PyPI (API token или логин/пароль). Не коммитьте токены в репозиторий — используйте `~/.pypirc` или переменные окружения / секреты CI.
|
|
51
|
+
|
|
52
|
+
## Релиз на GitHub
|
|
53
|
+
|
|
54
|
+
1. Обновить версию и changelog (если ведёте).
|
|
55
|
+
2. Создать тег `v0.x.y` и запушить.
|
|
56
|
+
3. Прикрепить к релизу файлы из `dist/` или полагаться на автосборку workflow (если настроена).
|
|
57
|
+
|
|
58
|
+
## CI
|
|
59
|
+
|
|
60
|
+
В монорепозитории ArrowMediaBot workflow: `.github/workflows/dialog-engine-ci.yml` (пути `DialogEngine/**`). После выноса библиотеки в отдельный репозиторий перенесите workflow в корень и уберите `working-directory: DialogEngine`, либо оставьте структуру с подпапкой — по ситуации.
|
|
61
|
+
|
|
62
|
+
## После релиза
|
|
63
|
+
|
|
64
|
+
- Проверить страницу проекта на PyPI (описание, ссылки).
|
|
65
|
+
- При необходимости обновить зависимость в приложениях: `dialog-engine = "^0.x.y"` вместо `path = ...`.
|