smart-bot-factory 0.3.5__tar.gz → 0.3.6__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.

Files changed (90) hide show
  1. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/PKG-INFO +233 -20
  2. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/README.md +232 -19
  3. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/best-valera.py +32 -3
  4. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/best-valera/prompts/final_instructions.txt +1 -1
  5. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/pyproject.toml +1 -1
  6. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/core/bot_utils.py +9 -1
  7. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/core/decorators.py +88 -6
  8. smart_bot_factory-0.3.6/smart_bot_factory/dashboard/__init__.py +5 -0
  9. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/integrations/supabase_client.py +4 -3
  10. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/uv.lock +1 -1
  11. smart_bot_factory-0.3.5/smart_bot_factory/admin/admin_migration.sql +0 -136
  12. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/.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
  13. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/.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
  14. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/.github/workflows/ci.yml +0 -0
  15. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/.github/workflows/publish-private.yml +0 -0
  16. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/.github/workflows/publish.yml +0 -0
  17. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/.gitignore +0 -0
  18. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/.python-version +0 -0
  19. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/LICENSE +0 -0
  20. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/best-valera/prompts/1sales_context.txt +0 -0
  21. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/best-valera/prompts/2product_info.txt +0 -0
  22. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/best-valera/prompts/3objection_handling.txt +0 -0
  23. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/best-valera/prompts/help_message.txt +0 -0
  24. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/best-valera/prompts/welcome_message.txt +0 -0
  25. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/best-valera/tests/quick_scenarios.yaml +0 -0
  26. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/best-valera/tests/realistic_scenarios.yaml +0 -0
  27. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/best-valera/tests/scenario_examples.yaml +0 -0
  28. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/best-valera/welcome_files/welcome_file_msg.txt +0 -0
  29. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/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
  30. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/valera/prompts/2product_info.txt +0 -0
  31. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/valera/prompts/3objection_handling.txt +0 -0
  32. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/valera/prompts/final_instructions.txt +0 -0
  33. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/valera/prompts/help_message.txt +0 -0
  34. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/valera/prompts/welcome_message.txt +0 -0
  35. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/valera/tests/quick_scenarios.yaml +0 -0
  36. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/valera/tests/realistic_scenarios.yaml +0 -0
  37. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/valera/tests/scenario_examples.yaml +0 -0
  38. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/bots/valera/welcome_files/welcome_file_msg.txt +0 -0
  39. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/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
  40. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/publish.py +0 -0
  41. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/__init__.py +0 -0
  42. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/admin/__init__.py +0 -0
  43. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/admin/admin_events.py +0 -0
  44. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/admin/admin_logic.py +0 -0
  45. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/admin/admin_manager.py +0 -0
  46. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/admin/admin_tester.py +0 -0
  47. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/admin/timeout_checker.py +0 -0
  48. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/aiogram_calendar/__init__.py +0 -0
  49. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/aiogram_calendar/common.py +0 -0
  50. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/aiogram_calendar/dialog_calendar.py +0 -0
  51. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/aiogram_calendar/schemas.py +0 -0
  52. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/aiogram_calendar/simple_calendar.py +0 -0
  53. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/analytics/analytics_manager.py +0 -0
  54. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/cli.py +0 -0
  55. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/config.py +0 -0
  56. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +0 -0
  57. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +0 -0
  58. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +0 -0
  59. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +0 -0
  60. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +0 -0
  61. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +0 -0
  62. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +0 -0
  63. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +0 -0
  64. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +0 -0
  65. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +0 -0
  66. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +0 -0
  67. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +0 -0
  68. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +0 -0
  69. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/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
  70. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/core/conversation_manager.py +0 -0
  71. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/core/message_sender.py +0 -0
  72. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/core/router.py +0 -0
  73. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/core/router_manager.py +0 -0
  74. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/core/states.py +0 -0
  75. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/creation/__init__.py +0 -0
  76. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/creation/bot_builder.py +0 -0
  77. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/creation/bot_testing.py +0 -0
  78. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/event/__init__.py +0 -0
  79. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/handlers/handlers.py +0 -0
  80. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/integrations/openai_client.py +0 -0
  81. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/message/__init__.py +0 -0
  82. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/router/__init__.py +0 -0
  83. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/setup_checker.py +0 -0
  84. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/supabase/__init__.py +0 -0
  85. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/supabase/client.py +0 -0
  86. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/utils/__init__.py +0 -0
  87. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/utils/debug_routing.py +0 -0
  88. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/utils/prompt_loader.py +0 -0
  89. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/smart_bot_factory/utils/user_prompt_loader.py +0 -0
  90. {smart_bot_factory-0.3.5 → smart_bot_factory-0.3.6}/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.5
3
+ Version: 0.3.6
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 # Выполнять только 1 раз
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], # Задержка: "1h 30m" или секунды
252
- notify: bool = False, # Уведомлять админов
253
- smart_check: bool = True, # Умная проверка активности
254
- once_only: bool = True, # Выполнять только 1 раз
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, # Выполнять только 1 раз
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 # Выполнять только 1 раз
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], # Задержка: "1h 30m" или секунды
219
- notify: bool = False, # Уведомлять админов
220
- smart_check: bool = True, # Умная проверка активности
221
- once_only: bool = True, # Выполнять только 1 раз
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, # Выполнять только 1 раз
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 раз для пользователя: