smart-bot-factory 0.3.5__tar.gz → 0.3.7__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.
Potentially problematic release.
This version of smart-bot-factory might be problematic. Click here for more details.
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/PKG-INFO +233 -20
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/README.md +232 -19
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/best-valera.py +32 -3
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/prompts/final_instructions.txt +1 -1
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/pyproject.toml +1 -1
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/core/bot_utils.py +23 -1
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/core/decorators.py +120 -12
- smart_bot_factory-0.3.7/smart_bot_factory/dashboard/__init__.py +5 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/handlers/handlers.py +16 -4
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/integrations/supabase_client.py +4 -3
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/uv.lock +1 -1
- smart_bot_factory-0.3.5/smart_bot_factory/admin/admin_migration.sql +0 -136
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/.github/ISSUE_TEMPLATE//342/234/250-/320/267/320/260/320/277/321/200/320/276/321/201-/321/204/321/203/320/275/320/272/321/206/320/270/320/270.md" +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/.github/ISSUE_TEMPLATE//360/237/220/233-/320/261/320/260/320/263-/321/200/320/265/320/277/320/276/321/200/321/202.md" +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/.github/workflows/ci.yml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/.github/workflows/publish-private.yml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/.github/workflows/publish.yml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/.gitignore +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/.python-version +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/LICENSE +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/prompts/1sales_context.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/prompts/2product_info.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/prompts/3objection_handling.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/prompts/help_message.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/prompts/welcome_message.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/tests/quick_scenarios.yaml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/tests/realistic_scenarios.yaml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/tests/scenario_examples.yaml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/welcome_files/welcome_file_msg.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/best-valera/welcome_files//320/247/320/265/320/272 /320/273/320/270/321/201/321/202 /320/277/320/276 152/320/244/320/227 /320/270 323/320/244/320/227 /320/264/320/273/321/217 /320/274/320/265/320/264/320/270/321/206/320/270/320/275/321/213.pdf" +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/valera/prompts/2product_info.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/valera/prompts/3objection_handling.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/valera/prompts/final_instructions.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/valera/prompts/help_message.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/valera/prompts/welcome_message.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/valera/tests/quick_scenarios.yaml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/valera/tests/realistic_scenarios.yaml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/valera/tests/scenario_examples.yaml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/valera/welcome_files/welcome_file_msg.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/bots/valera/welcome_files//320/247/320/265/320/272 /320/273/320/270/321/201/321/202 /320/277/320/276 152/320/244/320/227 /320/270 323/320/244/320/227 /320/264/320/273/321/217 /320/274/320/265/320/264/320/270/321/206/320/270/320/275/321/213.pdf" +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/publish.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/__init__.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/admin/__init__.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/admin/admin_events.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/admin/admin_logic.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/admin/admin_manager.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/admin/admin_tester.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/admin/timeout_checker.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/aiogram_calendar/__init__.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/aiogram_calendar/common.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/aiogram_calendar/dialog_calendar.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/aiogram_calendar/schemas.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/aiogram_calendar/simple_calendar.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/analytics/analytics_manager.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/cli.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/config.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/configs/growthmed-october-24/welcome_file//320/247/320/265/320/272 /320/273/320/270/321/201/321/202 /320/277/320/276 152/320/244/320/227 /320/270 323/320/244/320/227 /320/264/320/273/321/217 /320/274/320/265/320/264/320/270/321/206/320/270/320/275/321/213.pdf" +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/core/conversation_manager.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/core/message_sender.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/core/router.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/core/router_manager.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/core/states.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/creation/__init__.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/creation/bot_builder.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/creation/bot_testing.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/event/__init__.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/integrations/openai_client.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/message/__init__.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/router/__init__.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/setup_checker.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/supabase/__init__.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/supabase/client.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/utils/__init__.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/utils/debug_routing.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/utils/prompt_loader.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/utils/user_prompt_loader.py +0 -0
- {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.7}/smart_bot_factory/utm_link_generator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: smart-bot-factory
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: Библиотека для создания умных чат-ботов
|
|
5
5
|
Author-email: Kopatych <eserov73@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -44,6 +44,7 @@ Description-Content-Type: text/markdown
|
|
|
44
44
|
- [event_handler](#event_handler---обработчики-событий)
|
|
45
45
|
- [schedule_task](#schedule_task---запланированные-задачи)
|
|
46
46
|
- [global_handler](#global_handler---глобальные-обработчики)
|
|
47
|
+
- [Dashboard Info](#-dashboard-info---отправка-данных-в-дашборд)
|
|
47
48
|
- [Хуки для кастомизации](#-хуки-для-кастомизации)
|
|
48
49
|
- [Telegram роутеры](#-telegram-роутеры)
|
|
49
50
|
- [Расширенные возможности](#-расширенные-возможности)
|
|
@@ -187,9 +188,10 @@ sbf link
|
|
|
187
188
|
|
|
188
189
|
```python
|
|
189
190
|
@event_router.event_handler(
|
|
190
|
-
event_type: str,
|
|
191
|
-
notify: bool = False,
|
|
192
|
-
once_only: bool = True
|
|
191
|
+
event_type: str, # Тип события
|
|
192
|
+
notify: bool = False, # Уведомлять админов
|
|
193
|
+
once_only: bool = True, # Выполнять только 1 раз
|
|
194
|
+
send_ai_response: bool = True # Отправлять ответ от ИИ
|
|
193
195
|
)
|
|
194
196
|
async def handler(user_id: int, event_data: str):
|
|
195
197
|
# Ваш код
|
|
@@ -201,6 +203,7 @@ async def handler(user_id: int, event_data: str):
|
|
|
201
203
|
- **`event_type`** (обязательный) - Уникальное имя события
|
|
202
204
|
- **`notify`** (по умолчанию `False`) - Отправлять уведомление админам после выполнения
|
|
203
205
|
- **`once_only`** (по умолчанию `True`) - Если `True`, событие выполнится только 1 раз для пользователя
|
|
206
|
+
- **`send_ai_response`** (по умолчанию `True`) - Если `False`, ИИ НЕ отправит сообщение после выполнения обработчика
|
|
204
207
|
|
|
205
208
|
**Как работает:**
|
|
206
209
|
|
|
@@ -235,6 +238,16 @@ async def handle_question(user_id: int, question: str):
|
|
|
235
238
|
"""Обрабатывает вопросы (может быть много)"""
|
|
236
239
|
# Логика обработки
|
|
237
240
|
return {"status": "answered"}
|
|
241
|
+
|
|
242
|
+
# БЕЗ отправки ответа от ИИ
|
|
243
|
+
@event_router.event_handler("silent_event", send_ai_response=False)
|
|
244
|
+
async def handle_silent(user_id: int, event_data: str):
|
|
245
|
+
"""
|
|
246
|
+
Выполняет логику БЕЗ отправки сообщения от ИИ
|
|
247
|
+
Используйте когда хотите только собрать данные без ответа пользователю
|
|
248
|
+
"""
|
|
249
|
+
await send_message_by_human(user_id, "✅ Данные сохранены")
|
|
250
|
+
return {"status": "saved"}
|
|
238
251
|
```
|
|
239
252
|
|
|
240
253
|
---
|
|
@@ -247,12 +260,13 @@ async def handle_question(user_id: int, question: str):
|
|
|
247
260
|
|
|
248
261
|
```python
|
|
249
262
|
@event_router.schedule_task(
|
|
250
|
-
task_name: str,
|
|
251
|
-
delay: Union[str, int],
|
|
252
|
-
notify: bool = False,
|
|
253
|
-
smart_check: bool = True,
|
|
254
|
-
once_only: bool = True,
|
|
255
|
-
event_type: Union[str, Callable] = None # Источник времени события
|
|
263
|
+
task_name: str, # Название задачи
|
|
264
|
+
delay: Union[str, int], # Задержка: "1h 30m" или секунды
|
|
265
|
+
notify: bool = False, # Уведомлять админов
|
|
266
|
+
smart_check: bool = True, # Умная проверка активности
|
|
267
|
+
once_only: bool = True, # Выполнять только 1 раз
|
|
268
|
+
event_type: Union[str, Callable] = None, # Источник времени события
|
|
269
|
+
send_ai_response: bool = True # Отправлять ответ от ИИ
|
|
256
270
|
)
|
|
257
271
|
async def handler(user_id: int, user_data: str):
|
|
258
272
|
# Ваш код
|
|
@@ -273,6 +287,7 @@ async def handler(user_id: int, user_data: str):
|
|
|
273
287
|
- **`event_type`** (опционально) - Источник времени события:
|
|
274
288
|
- **Строка**: `"appointment_booking"` - ищет событие в БД и вычисляет время
|
|
275
289
|
- **Функция**: `async def(user_id, user_data) -> datetime` - кастомная логика
|
|
290
|
+
- **`send_ai_response`** (по умолчанию `True`) - Если `False`, ИИ НЕ отправит сообщение после выполнения задачи
|
|
276
291
|
|
|
277
292
|
**Формула времени с `event_type`:**
|
|
278
293
|
|
|
@@ -362,11 +377,12 @@ async def important_reminder(user_id: int, text: str):
|
|
|
362
377
|
|
|
363
378
|
```python
|
|
364
379
|
@event_router.global_handler(
|
|
365
|
-
handler_type: str,
|
|
366
|
-
delay: Union[str, int],
|
|
367
|
-
notify: bool = False,
|
|
368
|
-
once_only: bool = True,
|
|
369
|
-
event_type: Union[str, Callable] = None # Источник времени
|
|
380
|
+
handler_type: str, # Тип обработчика
|
|
381
|
+
delay: Union[str, int], # Задержка
|
|
382
|
+
notify: bool = False, # Уведомлять админов
|
|
383
|
+
once_only: bool = True, # Выполнять только 1 раз
|
|
384
|
+
event_type: Union[str, Callable] = None, # Источник времени
|
|
385
|
+
send_ai_response: bool = True # Отправлять ответ от ИИ
|
|
370
386
|
)
|
|
371
387
|
async def handler(handler_data: str):
|
|
372
388
|
# Ваш код
|
|
@@ -420,6 +436,173 @@ async def notify_promo_ending(handler_data: str):
|
|
|
420
436
|
|
|
421
437
|
---
|
|
422
438
|
|
|
439
|
+
## 📊 Dashboard Info - Отправка данных в дашборд
|
|
440
|
+
|
|
441
|
+
**Назначение:** Позволяет отправлять информацию о событиях в дашборд (таблица `scheduled_events`, столбец `info_dashboard`) для аналитики и мониторинга.
|
|
442
|
+
|
|
443
|
+
### Как работает
|
|
444
|
+
|
|
445
|
+
1. Обработчик события возвращает результат с полем `'info'`
|
|
446
|
+
2. Система автоматически извлекает это поле и записывает в `info_dashboard` таблицы
|
|
447
|
+
3. Функция `prepare_dashboard_info` автоматически:
|
|
448
|
+
- Получает `username` из таблицы `sales_users`
|
|
449
|
+
- Форматирует строку с подстановкой данных
|
|
450
|
+
- Добавляет московское время (UTC+3)
|
|
451
|
+
|
|
452
|
+
### Сигнатура
|
|
453
|
+
|
|
454
|
+
```python
|
|
455
|
+
from smart_bot_factory.dashboard import prepare_dashboard_info
|
|
456
|
+
|
|
457
|
+
dashboard_data = await prepare_dashboard_info(
|
|
458
|
+
description_template: str, # Строка с {username}, например "{username} купил подписку"
|
|
459
|
+
title: str, # Заголовок для дашборда
|
|
460
|
+
user_id: int # Telegram ID пользователя
|
|
461
|
+
)
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
**Возвращает:**
|
|
465
|
+
|
|
466
|
+
```python
|
|
467
|
+
{
|
|
468
|
+
'title': 'Заголовок',
|
|
469
|
+
'description': '@username123 купил подписку', # С подстановкой реального username
|
|
470
|
+
'created_at': '2025-10-18T15:30:45.123456+03:00' # Московское время
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Примеры использования
|
|
475
|
+
|
|
476
|
+
#### С event_handler
|
|
477
|
+
|
|
478
|
+
```python
|
|
479
|
+
from smart_bot_factory.dashboard import prepare_dashboard_info
|
|
480
|
+
|
|
481
|
+
@event_router.event_handler("collect_phone", notify=True, once_only=True)
|
|
482
|
+
async def handle_phone_collection(user_id: int, phone_number: str):
|
|
483
|
+
"""Сохраняет телефон клиента"""
|
|
484
|
+
|
|
485
|
+
# Ваша бизнес-логика
|
|
486
|
+
session = await supabase_client.get_active_session(user_id)
|
|
487
|
+
if session:
|
|
488
|
+
metadata = session.get('metadata', {})
|
|
489
|
+
metadata['phone'] = phone_number
|
|
490
|
+
await supabase_client.update_session_metadata(session['id'], metadata)
|
|
491
|
+
|
|
492
|
+
await send_message_by_human(
|
|
493
|
+
user_id=user_id,
|
|
494
|
+
message_text=f"✅ Спасибо! Ваш номер {phone_number} сохранен"
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
# 📊 Возвращаем результат С данными для дашборда
|
|
498
|
+
return {
|
|
499
|
+
"status": "success",
|
|
500
|
+
"phone": phone_number,
|
|
501
|
+
"info": await prepare_dashboard_info(
|
|
502
|
+
description_template="{username} оставил номер телефона",
|
|
503
|
+
title="Новый контакт",
|
|
504
|
+
user_id=user_id
|
|
505
|
+
)
|
|
506
|
+
}
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
#### С schedule_task
|
|
510
|
+
|
|
511
|
+
```python
|
|
512
|
+
@event_router.schedule_task("follow_up", delay="24h", smart_check=True)
|
|
513
|
+
async def send_follow_up(user_id: int, reminder_text: str):
|
|
514
|
+
"""Напоминание через 24 часа"""
|
|
515
|
+
|
|
516
|
+
await send_message_by_human(
|
|
517
|
+
user_id=user_id,
|
|
518
|
+
message_text=f"👋 {reminder_text}"
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
# 📊 Работает и для задач!
|
|
522
|
+
return {
|
|
523
|
+
"status": "sent",
|
|
524
|
+
"type": "follow_up",
|
|
525
|
+
"info": await prepare_dashboard_info(
|
|
526
|
+
description_template="{username} получил напоминание",
|
|
527
|
+
title="Напоминание отправлено",
|
|
528
|
+
user_id=user_id
|
|
529
|
+
)
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
#### БЕЗ дашборда
|
|
534
|
+
|
|
535
|
+
Если не нужно отправлять данные в дашборд - просто не добавляйте поле `'info'`:
|
|
536
|
+
|
|
537
|
+
```python
|
|
538
|
+
@event_router.event_handler("collect_name", once_only=False)
|
|
539
|
+
async def handle_name_collection(user_id: int, client_name: str):
|
|
540
|
+
"""БЕЗ дашборда - просто сохраняем имя"""
|
|
541
|
+
|
|
542
|
+
await send_message_by_human(
|
|
543
|
+
user_id=user_id,
|
|
544
|
+
message_text=f"✅ Спасибо! Ваше имя {client_name} сохранено"
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
# Возвращаем БЕЗ поля 'info' - дашборд останется пустым
|
|
548
|
+
return {"status": "success"}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### Что попадает в БД
|
|
552
|
+
|
|
553
|
+
**События С дашбордом:**
|
|
554
|
+
|
|
555
|
+
```sql
|
|
556
|
+
SELECT * FROM scheduled_events WHERE id = '123';
|
|
557
|
+
|
|
558
|
+
id: 123
|
|
559
|
+
event_type: collect_phone
|
|
560
|
+
event_category: user_event
|
|
561
|
+
user_id: 12345
|
|
562
|
+
status: completed
|
|
563
|
+
result_data: {"status": "success", "phone": "+79001234567", "info": {...}}
|
|
564
|
+
info_dashboard: {
|
|
565
|
+
"title": "Новый контакт",
|
|
566
|
+
"description": "@username123 оставил номер телефона",
|
|
567
|
+
"created_at": "2025-10-18T15:30:45+03:00"
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
**События БЕЗ дашборда:**
|
|
572
|
+
|
|
573
|
+
```sql
|
|
574
|
+
SELECT * FROM scheduled_events WHERE id = '124';
|
|
575
|
+
|
|
576
|
+
id: 124
|
|
577
|
+
event_type: collect_name
|
|
578
|
+
event_category: user_event
|
|
579
|
+
user_id: 12345
|
|
580
|
+
status: completed
|
|
581
|
+
result_data: {"status": "success"}
|
|
582
|
+
info_dashboard: NULL ← Остается пустым
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
### Форматирование строк
|
|
586
|
+
|
|
587
|
+
Функция `prepare_dashboard_info` поддерживает подстановку `{username}`:
|
|
588
|
+
|
|
589
|
+
```python
|
|
590
|
+
# Примеры шаблонов:
|
|
591
|
+
"{username} купил подписку на 1 год"
|
|
592
|
+
"{username} оставил контакт"
|
|
593
|
+
"{username} записался на консультацию"
|
|
594
|
+
"{username} задал вопрос о продукте"
|
|
595
|
+
"{username} завершил оплату"
|
|
596
|
+
|
|
597
|
+
# После подстановки:
|
|
598
|
+
"@user123 купил подписку на 1 год"
|
|
599
|
+
"@ivan_petrov оставил контакт"
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
Если пользователь не найден в `sales_users` - будет использован fallback: `user_12345`
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
423
606
|
## 🎣 Хуки для кастомизации
|
|
424
607
|
|
|
425
608
|
Хуки позволяют внедрять свою логику в стандартную обработку сообщений без переписывания всей функции.
|
|
@@ -813,16 +996,46 @@ DEBUG_MODE=false
|
|
|
813
996
|
|
|
814
997
|
## 🎯 Сравнение декораторов
|
|
815
998
|
|
|
816
|
-
| Декоратор | Когда выполняется | Для кого |
|
|
817
|
-
|
|
818
|
-
| `@event_handler` | Немедленно | 1 пользователь | `event_type`, `notify`, `once_only` |
|
|
819
|
-
| `@schedule_task` | Через время | 1 пользователь | `task_name`, `delay`, `event_type`, `smart_check`, `once_only`, `notify` |
|
|
820
|
-
| `@global_handler` | Через время | Все пользователи | `handler_type`, `delay`, `event_type`, `once_only`, `notify` |
|
|
999
|
+
| Декоратор | Когда выполняется | Для кого | Ключевые параметры |
|
|
1000
|
+
|-----------|-------------------|----------|--------------------|
|
|
1001
|
+
| `@event_handler` | Немедленно | 1 пользователь | `event_type`, `notify`, `once_only`, `send_ai_response` |
|
|
1002
|
+
| `@schedule_task` | Через время | 1 пользователь | `task_name`, `delay`, `event_type`, `smart_check`, `once_only`, `notify`, `send_ai_response` |
|
|
1003
|
+
| `@global_handler` | Через время | Все пользователи | `handler_type`, `delay`, `event_type`, `once_only`, `notify`, `send_ai_response` |
|
|
821
1004
|
|
|
822
1005
|
---
|
|
823
1006
|
|
|
824
1007
|
## 🔑 Ключевые концепции
|
|
825
1008
|
|
|
1009
|
+
### `send_ai_response=True`
|
|
1010
|
+
|
|
1011
|
+
Контролирует отправку сообщения от ИИ после выполнения обработчика:
|
|
1012
|
+
|
|
1013
|
+
- **`True`** (по умолчанию) - ИИ отправит сообщение пользователю после выполнения обработчика
|
|
1014
|
+
- **`False`** - ИИ НЕ отправит сообщение (используйте когда нужна только фоновая обработка или когда отправляете сообщение вручную)
|
|
1015
|
+
|
|
1016
|
+
**Когда использовать `send_ai_response=False`:**
|
|
1017
|
+
|
|
1018
|
+
- Когда нужно только собрать данные без ответа пользователю
|
|
1019
|
+
- Когда вы сами отправляете сообщение через `send_message_by_human()`
|
|
1020
|
+
- Для фоновых задач без взаимодействия с пользователем
|
|
1021
|
+
|
|
1022
|
+
```python
|
|
1023
|
+
# ИИ отправит сообщение (по умолчанию)
|
|
1024
|
+
@event_router.event_handler("collect_phone")
|
|
1025
|
+
async def save_phone(user_id: int, phone: str):
|
|
1026
|
+
# Сохраняем телефон
|
|
1027
|
+
# ИИ автоматически отправит сообщение после выполнения
|
|
1028
|
+
return {"status": "success"}
|
|
1029
|
+
|
|
1030
|
+
# ИИ НЕ отправит сообщение
|
|
1031
|
+
@event_router.event_handler("collect_name", send_ai_response=False)
|
|
1032
|
+
async def save_name(user_id: int, name: str):
|
|
1033
|
+
# Сохраняем имя
|
|
1034
|
+
await send_message_by_human(user_id, f"✅ Имя {name} сохранено")
|
|
1035
|
+
# ИИ не будет отправлять свое сообщение
|
|
1036
|
+
return {"status": "success"}
|
|
1037
|
+
```
|
|
1038
|
+
|
|
826
1039
|
### `once_only=True`
|
|
827
1040
|
|
|
828
1041
|
Гарантирует выполнение события только 1 раз для пользователя:
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
- [event_handler](#event_handler---обработчики-событий)
|
|
12
12
|
- [schedule_task](#schedule_task---запланированные-задачи)
|
|
13
13
|
- [global_handler](#global_handler---глобальные-обработчики)
|
|
14
|
+
- [Dashboard Info](#-dashboard-info---отправка-данных-в-дашборд)
|
|
14
15
|
- [Хуки для кастомизации](#-хуки-для-кастомизации)
|
|
15
16
|
- [Telegram роутеры](#-telegram-роутеры)
|
|
16
17
|
- [Расширенные возможности](#-расширенные-возможности)
|
|
@@ -154,9 +155,10 @@ sbf link
|
|
|
154
155
|
|
|
155
156
|
```python
|
|
156
157
|
@event_router.event_handler(
|
|
157
|
-
event_type: str,
|
|
158
|
-
notify: bool = False,
|
|
159
|
-
once_only: bool = True
|
|
158
|
+
event_type: str, # Тип события
|
|
159
|
+
notify: bool = False, # Уведомлять админов
|
|
160
|
+
once_only: bool = True, # Выполнять только 1 раз
|
|
161
|
+
send_ai_response: bool = True # Отправлять ответ от ИИ
|
|
160
162
|
)
|
|
161
163
|
async def handler(user_id: int, event_data: str):
|
|
162
164
|
# Ваш код
|
|
@@ -168,6 +170,7 @@ async def handler(user_id: int, event_data: str):
|
|
|
168
170
|
- **`event_type`** (обязательный) - Уникальное имя события
|
|
169
171
|
- **`notify`** (по умолчанию `False`) - Отправлять уведомление админам после выполнения
|
|
170
172
|
- **`once_only`** (по умолчанию `True`) - Если `True`, событие выполнится только 1 раз для пользователя
|
|
173
|
+
- **`send_ai_response`** (по умолчанию `True`) - Если `False`, ИИ НЕ отправит сообщение после выполнения обработчика
|
|
171
174
|
|
|
172
175
|
**Как работает:**
|
|
173
176
|
|
|
@@ -202,6 +205,16 @@ async def handle_question(user_id: int, question: str):
|
|
|
202
205
|
"""Обрабатывает вопросы (может быть много)"""
|
|
203
206
|
# Логика обработки
|
|
204
207
|
return {"status": "answered"}
|
|
208
|
+
|
|
209
|
+
# БЕЗ отправки ответа от ИИ
|
|
210
|
+
@event_router.event_handler("silent_event", send_ai_response=False)
|
|
211
|
+
async def handle_silent(user_id: int, event_data: str):
|
|
212
|
+
"""
|
|
213
|
+
Выполняет логику БЕЗ отправки сообщения от ИИ
|
|
214
|
+
Используйте когда хотите только собрать данные без ответа пользователю
|
|
215
|
+
"""
|
|
216
|
+
await send_message_by_human(user_id, "✅ Данные сохранены")
|
|
217
|
+
return {"status": "saved"}
|
|
205
218
|
```
|
|
206
219
|
|
|
207
220
|
---
|
|
@@ -214,12 +227,13 @@ async def handle_question(user_id: int, question: str):
|
|
|
214
227
|
|
|
215
228
|
```python
|
|
216
229
|
@event_router.schedule_task(
|
|
217
|
-
task_name: str,
|
|
218
|
-
delay: Union[str, int],
|
|
219
|
-
notify: bool = False,
|
|
220
|
-
smart_check: bool = True,
|
|
221
|
-
once_only: bool = True,
|
|
222
|
-
event_type: Union[str, Callable] = None # Источник времени события
|
|
230
|
+
task_name: str, # Название задачи
|
|
231
|
+
delay: Union[str, int], # Задержка: "1h 30m" или секунды
|
|
232
|
+
notify: bool = False, # Уведомлять админов
|
|
233
|
+
smart_check: bool = True, # Умная проверка активности
|
|
234
|
+
once_only: bool = True, # Выполнять только 1 раз
|
|
235
|
+
event_type: Union[str, Callable] = None, # Источник времени события
|
|
236
|
+
send_ai_response: bool = True # Отправлять ответ от ИИ
|
|
223
237
|
)
|
|
224
238
|
async def handler(user_id: int, user_data: str):
|
|
225
239
|
# Ваш код
|
|
@@ -240,6 +254,7 @@ async def handler(user_id: int, user_data: str):
|
|
|
240
254
|
- **`event_type`** (опционально) - Источник времени события:
|
|
241
255
|
- **Строка**: `"appointment_booking"` - ищет событие в БД и вычисляет время
|
|
242
256
|
- **Функция**: `async def(user_id, user_data) -> datetime` - кастомная логика
|
|
257
|
+
- **`send_ai_response`** (по умолчанию `True`) - Если `False`, ИИ НЕ отправит сообщение после выполнения задачи
|
|
243
258
|
|
|
244
259
|
**Формула времени с `event_type`:**
|
|
245
260
|
|
|
@@ -329,11 +344,12 @@ async def important_reminder(user_id: int, text: str):
|
|
|
329
344
|
|
|
330
345
|
```python
|
|
331
346
|
@event_router.global_handler(
|
|
332
|
-
handler_type: str,
|
|
333
|
-
delay: Union[str, int],
|
|
334
|
-
notify: bool = False,
|
|
335
|
-
once_only: bool = True,
|
|
336
|
-
event_type: Union[str, Callable] = None # Источник времени
|
|
347
|
+
handler_type: str, # Тип обработчика
|
|
348
|
+
delay: Union[str, int], # Задержка
|
|
349
|
+
notify: bool = False, # Уведомлять админов
|
|
350
|
+
once_only: bool = True, # Выполнять только 1 раз
|
|
351
|
+
event_type: Union[str, Callable] = None, # Источник времени
|
|
352
|
+
send_ai_response: bool = True # Отправлять ответ от ИИ
|
|
337
353
|
)
|
|
338
354
|
async def handler(handler_data: str):
|
|
339
355
|
# Ваш код
|
|
@@ -387,6 +403,173 @@ async def notify_promo_ending(handler_data: str):
|
|
|
387
403
|
|
|
388
404
|
---
|
|
389
405
|
|
|
406
|
+
## 📊 Dashboard Info - Отправка данных в дашборд
|
|
407
|
+
|
|
408
|
+
**Назначение:** Позволяет отправлять информацию о событиях в дашборд (таблица `scheduled_events`, столбец `info_dashboard`) для аналитики и мониторинга.
|
|
409
|
+
|
|
410
|
+
### Как работает
|
|
411
|
+
|
|
412
|
+
1. Обработчик события возвращает результат с полем `'info'`
|
|
413
|
+
2. Система автоматически извлекает это поле и записывает в `info_dashboard` таблицы
|
|
414
|
+
3. Функция `prepare_dashboard_info` автоматически:
|
|
415
|
+
- Получает `username` из таблицы `sales_users`
|
|
416
|
+
- Форматирует строку с подстановкой данных
|
|
417
|
+
- Добавляет московское время (UTC+3)
|
|
418
|
+
|
|
419
|
+
### Сигнатура
|
|
420
|
+
|
|
421
|
+
```python
|
|
422
|
+
from smart_bot_factory.dashboard import prepare_dashboard_info
|
|
423
|
+
|
|
424
|
+
dashboard_data = await prepare_dashboard_info(
|
|
425
|
+
description_template: str, # Строка с {username}, например "{username} купил подписку"
|
|
426
|
+
title: str, # Заголовок для дашборда
|
|
427
|
+
user_id: int # Telegram ID пользователя
|
|
428
|
+
)
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**Возвращает:**
|
|
432
|
+
|
|
433
|
+
```python
|
|
434
|
+
{
|
|
435
|
+
'title': 'Заголовок',
|
|
436
|
+
'description': '@username123 купил подписку', # С подстановкой реального username
|
|
437
|
+
'created_at': '2025-10-18T15:30:45.123456+03:00' # Московское время
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Примеры использования
|
|
442
|
+
|
|
443
|
+
#### С event_handler
|
|
444
|
+
|
|
445
|
+
```python
|
|
446
|
+
from smart_bot_factory.dashboard import prepare_dashboard_info
|
|
447
|
+
|
|
448
|
+
@event_router.event_handler("collect_phone", notify=True, once_only=True)
|
|
449
|
+
async def handle_phone_collection(user_id: int, phone_number: str):
|
|
450
|
+
"""Сохраняет телефон клиента"""
|
|
451
|
+
|
|
452
|
+
# Ваша бизнес-логика
|
|
453
|
+
session = await supabase_client.get_active_session(user_id)
|
|
454
|
+
if session:
|
|
455
|
+
metadata = session.get('metadata', {})
|
|
456
|
+
metadata['phone'] = phone_number
|
|
457
|
+
await supabase_client.update_session_metadata(session['id'], metadata)
|
|
458
|
+
|
|
459
|
+
await send_message_by_human(
|
|
460
|
+
user_id=user_id,
|
|
461
|
+
message_text=f"✅ Спасибо! Ваш номер {phone_number} сохранен"
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
# 📊 Возвращаем результат С данными для дашборда
|
|
465
|
+
return {
|
|
466
|
+
"status": "success",
|
|
467
|
+
"phone": phone_number,
|
|
468
|
+
"info": await prepare_dashboard_info(
|
|
469
|
+
description_template="{username} оставил номер телефона",
|
|
470
|
+
title="Новый контакт",
|
|
471
|
+
user_id=user_id
|
|
472
|
+
)
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
#### С schedule_task
|
|
477
|
+
|
|
478
|
+
```python
|
|
479
|
+
@event_router.schedule_task("follow_up", delay="24h", smart_check=True)
|
|
480
|
+
async def send_follow_up(user_id: int, reminder_text: str):
|
|
481
|
+
"""Напоминание через 24 часа"""
|
|
482
|
+
|
|
483
|
+
await send_message_by_human(
|
|
484
|
+
user_id=user_id,
|
|
485
|
+
message_text=f"👋 {reminder_text}"
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
# 📊 Работает и для задач!
|
|
489
|
+
return {
|
|
490
|
+
"status": "sent",
|
|
491
|
+
"type": "follow_up",
|
|
492
|
+
"info": await prepare_dashboard_info(
|
|
493
|
+
description_template="{username} получил напоминание",
|
|
494
|
+
title="Напоминание отправлено",
|
|
495
|
+
user_id=user_id
|
|
496
|
+
)
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
#### БЕЗ дашборда
|
|
501
|
+
|
|
502
|
+
Если не нужно отправлять данные в дашборд - просто не добавляйте поле `'info'`:
|
|
503
|
+
|
|
504
|
+
```python
|
|
505
|
+
@event_router.event_handler("collect_name", once_only=False)
|
|
506
|
+
async def handle_name_collection(user_id: int, client_name: str):
|
|
507
|
+
"""БЕЗ дашборда - просто сохраняем имя"""
|
|
508
|
+
|
|
509
|
+
await send_message_by_human(
|
|
510
|
+
user_id=user_id,
|
|
511
|
+
message_text=f"✅ Спасибо! Ваше имя {client_name} сохранено"
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
# Возвращаем БЕЗ поля 'info' - дашборд останется пустым
|
|
515
|
+
return {"status": "success"}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Что попадает в БД
|
|
519
|
+
|
|
520
|
+
**События С дашбордом:**
|
|
521
|
+
|
|
522
|
+
```sql
|
|
523
|
+
SELECT * FROM scheduled_events WHERE id = '123';
|
|
524
|
+
|
|
525
|
+
id: 123
|
|
526
|
+
event_type: collect_phone
|
|
527
|
+
event_category: user_event
|
|
528
|
+
user_id: 12345
|
|
529
|
+
status: completed
|
|
530
|
+
result_data: {"status": "success", "phone": "+79001234567", "info": {...}}
|
|
531
|
+
info_dashboard: {
|
|
532
|
+
"title": "Новый контакт",
|
|
533
|
+
"description": "@username123 оставил номер телефона",
|
|
534
|
+
"created_at": "2025-10-18T15:30:45+03:00"
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
**События БЕЗ дашборда:**
|
|
539
|
+
|
|
540
|
+
```sql
|
|
541
|
+
SELECT * FROM scheduled_events WHERE id = '124';
|
|
542
|
+
|
|
543
|
+
id: 124
|
|
544
|
+
event_type: collect_name
|
|
545
|
+
event_category: user_event
|
|
546
|
+
user_id: 12345
|
|
547
|
+
status: completed
|
|
548
|
+
result_data: {"status": "success"}
|
|
549
|
+
info_dashboard: NULL ← Остается пустым
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Форматирование строк
|
|
553
|
+
|
|
554
|
+
Функция `prepare_dashboard_info` поддерживает подстановку `{username}`:
|
|
555
|
+
|
|
556
|
+
```python
|
|
557
|
+
# Примеры шаблонов:
|
|
558
|
+
"{username} купил подписку на 1 год"
|
|
559
|
+
"{username} оставил контакт"
|
|
560
|
+
"{username} записался на консультацию"
|
|
561
|
+
"{username} задал вопрос о продукте"
|
|
562
|
+
"{username} завершил оплату"
|
|
563
|
+
|
|
564
|
+
# После подстановки:
|
|
565
|
+
"@user123 купил подписку на 1 год"
|
|
566
|
+
"@ivan_petrov оставил контакт"
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
Если пользователь не найден в `sales_users` - будет использован fallback: `user_12345`
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
390
573
|
## 🎣 Хуки для кастомизации
|
|
391
574
|
|
|
392
575
|
Хуки позволяют внедрять свою логику в стандартную обработку сообщений без переписывания всей функции.
|
|
@@ -780,16 +963,46 @@ DEBUG_MODE=false
|
|
|
780
963
|
|
|
781
964
|
## 🎯 Сравнение декораторов
|
|
782
965
|
|
|
783
|
-
| Декоратор | Когда выполняется | Для кого |
|
|
784
|
-
|
|
785
|
-
| `@event_handler` | Немедленно | 1 пользователь | `event_type`, `notify`, `once_only` |
|
|
786
|
-
| `@schedule_task` | Через время | 1 пользователь | `task_name`, `delay`, `event_type`, `smart_check`, `once_only`, `notify` |
|
|
787
|
-
| `@global_handler` | Через время | Все пользователи | `handler_type`, `delay`, `event_type`, `once_only`, `notify` |
|
|
966
|
+
| Декоратор | Когда выполняется | Для кого | Ключевые параметры |
|
|
967
|
+
|-----------|-------------------|----------|--------------------|
|
|
968
|
+
| `@event_handler` | Немедленно | 1 пользователь | `event_type`, `notify`, `once_only`, `send_ai_response` |
|
|
969
|
+
| `@schedule_task` | Через время | 1 пользователь | `task_name`, `delay`, `event_type`, `smart_check`, `once_only`, `notify`, `send_ai_response` |
|
|
970
|
+
| `@global_handler` | Через время | Все пользователи | `handler_type`, `delay`, `event_type`, `once_only`, `notify`, `send_ai_response` |
|
|
788
971
|
|
|
789
972
|
---
|
|
790
973
|
|
|
791
974
|
## 🔑 Ключевые концепции
|
|
792
975
|
|
|
976
|
+
### `send_ai_response=True`
|
|
977
|
+
|
|
978
|
+
Контролирует отправку сообщения от ИИ после выполнения обработчика:
|
|
979
|
+
|
|
980
|
+
- **`True`** (по умолчанию) - ИИ отправит сообщение пользователю после выполнения обработчика
|
|
981
|
+
- **`False`** - ИИ НЕ отправит сообщение (используйте когда нужна только фоновая обработка или когда отправляете сообщение вручную)
|
|
982
|
+
|
|
983
|
+
**Когда использовать `send_ai_response=False`:**
|
|
984
|
+
|
|
985
|
+
- Когда нужно только собрать данные без ответа пользователю
|
|
986
|
+
- Когда вы сами отправляете сообщение через `send_message_by_human()`
|
|
987
|
+
- Для фоновых задач без взаимодействия с пользователем
|
|
988
|
+
|
|
989
|
+
```python
|
|
990
|
+
# ИИ отправит сообщение (по умолчанию)
|
|
991
|
+
@event_router.event_handler("collect_phone")
|
|
992
|
+
async def save_phone(user_id: int, phone: str):
|
|
993
|
+
# Сохраняем телефон
|
|
994
|
+
# ИИ автоматически отправит сообщение после выполнения
|
|
995
|
+
return {"status": "success"}
|
|
996
|
+
|
|
997
|
+
# ИИ НЕ отправит сообщение
|
|
998
|
+
@event_router.event_handler("collect_name", send_ai_response=False)
|
|
999
|
+
async def save_name(user_id: int, name: str):
|
|
1000
|
+
# Сохраняем имя
|
|
1001
|
+
await send_message_by_human(user_id, f"✅ Имя {name} сохранено")
|
|
1002
|
+
# ИИ не будет отправлять свое сообщение
|
|
1003
|
+
return {"status": "success"}
|
|
1004
|
+
```
|
|
1005
|
+
|
|
793
1006
|
### `once_only=True`
|
|
794
1007
|
|
|
795
1008
|
Гарантирует выполнение события только 1 раз для пользователя:
|