smart-bot-factory 0.2.0__tar.gz → 0.2.2__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 (103) hide show
  1. smart_bot_factory-0.2.2/.claude/settings.local.json +10 -0
  2. smart_bot_factory-0.2.2/.env.example +40 -0
  3. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/PKG-INFO +1 -1
  4. smart_bot_factory-0.2.2/best-valera.py +240 -0
  5. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/pyproject.toml +1 -1
  6. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/creation/bot_builder.py +169 -0
  7. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/handlers/handlers.py +151 -71
  8. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/uv.lock +1 -1
  9. smart_bot_factory-0.2.0/best-valera.py +0 -117
  10. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/.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
  11. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/.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
  12. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/.github/workflows/ci.yml +0 -0
  13. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/.github/workflows/publish-private.yml +0 -0
  14. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/.github/workflows/publish.yml +0 -0
  15. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/.gitignore +0 -0
  16. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/.python-version +0 -0
  17. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/CLIENTS_USAGE.md +0 -0
  18. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/Dockerfile +0 -0
  19. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/LICENSE +0 -0
  20. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/README.md +0 -0
  21. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/best-valera/prompts/1sales_context.txt +0 -0
  22. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/best-valera/prompts/2product_info.txt +0 -0
  23. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/best-valera/prompts/3objection_handling.txt +0 -0
  24. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/best-valera/prompts/final_instructions.txt +0 -0
  25. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/best-valera/prompts/help_message.txt +0 -0
  26. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/best-valera/prompts/welcome_message.txt +0 -0
  27. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/best-valera/tests/quick_scenarios.yaml +0 -0
  28. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/best-valera/tests/realistic_scenarios.yaml +0 -0
  29. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/best-valera/tests/scenario_examples.yaml +0 -0
  30. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/best-valera/welcome_files/welcome_file_msg.txt +0 -0
  31. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/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
  32. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/valera/prompts/2product_info.txt +0 -0
  33. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/valera/prompts/3objection_handling.txt +0 -0
  34. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/valera/prompts/final_instructions.txt +0 -0
  35. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/valera/prompts/help_message.txt +0 -0
  36. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/valera/prompts/welcome_message.txt +0 -0
  37. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/valera/tests/quick_scenarios.yaml +0 -0
  38. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/valera/tests/realistic_scenarios.yaml +0 -0
  39. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/valera/tests/scenario_examples.yaml +0 -0
  40. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/bots/valera/welcome_files/welcome_file_msg.txt +0 -0
  41. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/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
  42. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/configs/valera/cats//320/224/320/276/320/263/320/276/320/262/320/276/321/200.pdf" +0 -0
  43. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/configs/valera/cats//320/272/320/276/320/275/320/270.jpg" +0 -0
  44. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/configs/valera/cats//320/272/320/276/321/202.jpg" +0 -0
  45. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/configs/valera/cats//320/273/320/265/321/201.jpg" +0 -0
  46. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/configs/valera/tests/fixes_elina.yaml +0 -0
  47. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/configs/valera/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
  48. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/create_tag.sh +0 -0
  49. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/docker-compose.yml +0 -0
  50. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/env.example +0 -0
  51. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/requirements.txt +0 -0
  52. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/save_backup.sh +0 -0
  53. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/save_fixes.sh +0 -0
  54. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/__init__.py +0 -0
  55. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/admin/__init__.py +0 -0
  56. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/admin/admin_logic.py +0 -0
  57. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/admin/admin_manager.py +0 -0
  58. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/admin/admin_migration.sql +0 -0
  59. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/admin/admin_tester.py +0 -0
  60. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/admin/timeout_checker.py +0 -0
  61. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/analytics/analytics_manager.py +0 -0
  62. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/cli.py +0 -0
  63. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/config.py +0 -0
  64. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +0 -0
  65. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +0 -0
  66. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +0 -0
  67. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +0 -0
  68. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +0 -0
  69. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +0 -0
  70. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +0 -0
  71. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +0 -0
  72. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +0 -0
  73. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +0 -0
  74. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +0 -0
  75. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +0 -0
  76. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +0 -0
  77. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/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
  78. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/core/bot_utils.py +0 -0
  79. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/core/conversation_manager.py +0 -0
  80. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/core/decorators.py +0 -0
  81. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/core/message_sender.py +0 -0
  82. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/core/router.py +0 -0
  83. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/core/router_manager.py +0 -0
  84. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/core/states.py +0 -0
  85. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/core/telegram_router.py +0 -0
  86. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/creation/__init__.py +0 -0
  87. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/creation/bot_testing.py +0 -0
  88. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/database/database_structure.sql +0 -0
  89. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/database/schema.sql +0 -0
  90. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/event/__init__.py +0 -0
  91. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/integrations/openai_client.py +0 -0
  92. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/integrations/supabase_client.py +0 -0
  93. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/message/__init__.py +0 -0
  94. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/router/__init__.py +0 -0
  95. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/setup_checker.py +0 -0
  96. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/supabase/__init__.py +0 -0
  97. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/supabase/client.py +0 -0
  98. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/utils/__init__.py +0 -0
  99. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/utils/debug_routing.py +0 -0
  100. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/utils/prompt_loader.py +0 -0
  101. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/smart_bot_factory/utm_link_generator.py +0 -0
  102. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/system_prompt_example.txt +0 -0
  103. {smart_bot_factory-0.2.0 → smart_bot_factory-0.2.2}/valera.py +0 -0
@@ -0,0 +1,10 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(awk:*)",
5
+ "Bash(python:*)"
6
+ ],
7
+ "deny": [],
8
+ "ask": []
9
+ }
10
+ }
@@ -0,0 +1,40 @@
1
+ # Telegram
2
+ TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
3
+
4
+ # Supabase
5
+ SUPABASE_URL=https://your-project.supabase.co
6
+ SUPABASE_KEY=your_supabase_anon_key
7
+
8
+ # OpenAI
9
+ OPENAI_API_KEY=sk-your-openai-api-key
10
+ OPENAI_MODEL=gpt-5-mini
11
+ OPENAI_MAX_TOKENS=1500
12
+ OPENAI_TEMPERATURE=0.7
13
+
14
+ # Промпты (каталог)
15
+ PROMT_FILES_DIR=prompts
16
+
17
+ # Файл после приветствия с подписью (если он есть - грузим его в папку welcome_file, если нет - ничего не делаем)
18
+ WELCOME_FILE_URL=welcome_file/
19
+ WELCOME_FILE_MSG=welcome_file_msg.txt
20
+
21
+ # 🆕 Администраторы (через запятую)
22
+ # Укажите Telegram ID админов
23
+ ADMIN_TELEGRAM_IDS=123456789,987654321
24
+ ADMIN_SESSION_TIMEOUT_MINUTES=30
25
+
26
+ # 🆕 Режим отладки (показывать JSON пользователям)
27
+ DEBUG_MODE=false
28
+
29
+ # Дополнительные настройки
30
+ MAX_CONTEXT_MESSAGES=50
31
+ LOG_LEVEL=INFO
32
+ MESSAGE_PARSE_MODE=Markdown
33
+
34
+ # Настройки продаж
35
+ LEAD_QUALIFICATION_THRESHOLD=7
36
+ SESSION_TIMEOUT_HOURS=24
37
+
38
+ # ⚠️ ВАЖНО: BOT_ID теперь НЕ нужен в .env!
39
+ # Bot ID автоматически определяется из имени файла запускалки
40
+ # Например: python growthmed-october-24.py → BOT_ID = growthmed-october-24
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smart-bot-factory
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Библиотека для создания умных чат-ботов
5
5
  Author-email: Kopatych <kopatych@example.com>
6
6
  License: MIT
@@ -0,0 +1,240 @@
1
+ import asyncio
2
+ import logging
3
+
4
+ from smart_bot_factory.router import EventRouter, TelegramRouter
5
+ from smart_bot_factory.message import send_message_by_human, send_message_to_users_by_stage
6
+ from smart_bot_factory.supabase import SupabaseClient
7
+ from smart_bot_factory.creation import BotBuilder
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ # =============================================================================
12
+ # СОЗДАНИЕ РОУТЕРОВ
13
+ # =============================================================================
14
+
15
+ # Роутер для событий (бизнес-логика)
16
+ event_router = EventRouter("best-valera_events")
17
+
18
+ # Роутер для Telegram (команды и сообщения)
19
+ telegram_router_1 = TelegramRouter("best-valera_telegram")
20
+ telegram_router_2 = TelegramRouter("best-valera_telegram_2")
21
+
22
+ supabase_client = SupabaseClient("best-valera")
23
+
24
+ # =============================================================================
25
+ # ИНИЦИАЛИЗАЦИЯ BOT BUILDER (нужен для декоратора on_start)
26
+ # =============================================================================
27
+
28
+ bot_builder = BotBuilder("best-valera")
29
+
30
+ # =============================================================================
31
+ # TELEGRAM ОБРАБОТЧИКИ (используем прямой aiogram API)
32
+ # =============================================================================
33
+
34
+ from aiogram import F
35
+ from aiogram.filters import Command
36
+ from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
37
+ from aiogram.fsm.context import FSMContext
38
+
39
+ # =============================================================================
40
+ # ОБРАБОТЧИК on_start (вызывается после стандартного /start)
41
+ # =============================================================================
42
+
43
+ @bot_builder.on_start
44
+ async def custom_start_handler(user_id: int, session_id: str, message: Message, state: FSMContext):
45
+ """
46
+ Вызывается после стандартной логики /start
47
+ Здесь можно отправить дополнительные сообщения, кнопки и т.д.
48
+ """
49
+ # Пример: отправляем сообщение с кнопками
50
+ keyboard = InlineKeyboardMarkup(inline_keyboard=[
51
+ [InlineKeyboardButton(text="📖 Каталог", callback_data="catalog")],
52
+ [InlineKeyboardButton(text="💰 Цены", callback_data="prices")],
53
+ [InlineKeyboardButton(text="📞 Связаться", callback_data="contact")]
54
+ ])
55
+
56
+ await message.answer(
57
+ "🎯 Что вас интересует?",
58
+ reply_markup=keyboard
59
+ )
60
+
61
+ # =============================================================================
62
+ # ХУКИ ДЛЯ КАСТОМИЗАЦИИ ОБРАБОТКИ СООБЩЕНИЙ
63
+ # =============================================================================
64
+
65
+ # ХУК 1: Валидация сообщений
66
+ @bot_builder.validate_message
67
+ async def validate_service_names(message, supabase_client):
68
+ """Проверяем корректность названий услуг"""
69
+ # Пример: блокируем неправильные названия
70
+ incorrect_names = ["массаш", "педекюр", "макияш"]
71
+
72
+ if message.text:
73
+ for incorrect in incorrect_names:
74
+ if incorrect in message.text.lower():
75
+ await message.answer(
76
+ f"❗ Возможно, вы имели в виду другую услугу?\n"
77
+ f"Пожалуйста, уточните название"
78
+ )
79
+ return False # Прерываем обработку AI
80
+
81
+ return True # Продолжаем обработку
82
+
83
+ # ХУК 2: Обогащение промпта
84
+ @bot_builder.enrich_prompt
85
+ async def add_client_info_to_prompt(system_prompt, user_id, session_id, supabase_client):
86
+ """Добавляем информацию о клиенте в промпт"""
87
+ try:
88
+ session = await supabase_client.get_active_session(user_id)
89
+
90
+ if session and session.get('metadata'):
91
+ phone = session['metadata'].get('phone')
92
+ name = session['metadata'].get('confirmed_name') or session['metadata'].get('telegram_name')
93
+
94
+ if phone:
95
+ client_info = f"\n\nИНФОРМАЦИЯ О КЛИЕНТЕ:\n- Телефон: {phone}"
96
+ if name:
97
+ client_info += f"\n- Имя: {name}"
98
+ client_info += "\n\n⚠️ ВАЖНО: При создании записи используй ЭТОТ телефон и имя!"
99
+
100
+ return system_prompt + client_info
101
+ except Exception as e:
102
+ logger.error(f"Ошибка обогащения промпта: {e}")
103
+
104
+ return system_prompt
105
+
106
+ # ХУК 3: Обогащение контекста (например, данные из внешнего API)
107
+ @bot_builder.enrich_context
108
+ async def add_external_api_data(messages, user_id, session_id):
109
+ """Добавляем данные из внешних систем"""
110
+ # Пример: можно добавить расписание из YClients, данные из CRM и т.д.
111
+ # messages.append({
112
+ # "role": "system",
113
+ # "content": "Реальное доступное время: ..."
114
+ # })
115
+ return messages
116
+
117
+ # ХУК 4: Обработка ответа AI
118
+ @bot_builder.process_response
119
+ async def add_promo_to_price_response(response_text, ai_metadata, user_id):
120
+ """Добавляем промо-код к ответам о ценах"""
121
+ if "цен" in response_text.lower() or "стоимост" in response_text.lower():
122
+ response_text += "\n\n🎁 Промокод FIRST10 для скидки 10% на первый визит!"
123
+
124
+ return response_text, ai_metadata
125
+
126
+ # ХУК 5: Фильтр отправки
127
+ @bot_builder.filter_send
128
+ async def allow_all_messages(user_id, response_text):
129
+ """Разрешаем все сообщения (можно добавить блокировку по условию)"""
130
+ # Пример: блокировка во время обработки
131
+ # if is_processing(user_id):
132
+ # return False
133
+ return True
134
+
135
+ @telegram_router_1.router.message(Command("price", "цена"))
136
+ async def handle_price_command(message: Message, state: FSMContext):
137
+ """Обработчик команды /price"""
138
+ await message.answer(
139
+ "💰 Наши цены:\n\n"
140
+ "📦 Базовый пакет - 1000₽\n"
141
+ "📦 Стандартный - 2000₽\n"
142
+ "📦 Премиум - 5000₽"
143
+ )
144
+
145
+ @telegram_router_2.router.message(F.text & (F.text.lower().contains("цена") | F.text.lower().contains("стоимость")))
146
+ async def handle_price_question(message: Message, state: FSMContext):
147
+ """Обработчик вопросов о цене"""
148
+ await message.answer("💡 Напишите /price чтобы увидеть актуальные цены")
149
+
150
+ # Обработчики callback'ов от кнопок в on_start
151
+ @telegram_router_1.router.callback_query(F.data == "catalog")
152
+ async def handle_catalog(callback: CallbackQuery, state: FSMContext):
153
+ """Обработка кнопки Каталог"""
154
+ await callback.answer()
155
+ await callback.message.answer("📖 Вот наш каталог товаров:\n\n1. Товар 1\n2. Товар 2\n3. Товар 3")
156
+
157
+ @telegram_router_1.router.callback_query(F.data == "prices")
158
+ async def handle_prices(callback: CallbackQuery, state: FSMContext):
159
+ """Обработка кнопки Цены"""
160
+ await callback.answer()
161
+ await callback.message.answer("💰 Наши цены:\n\n📦 Базовый - 1000₽\n📦 Премиум - 5000₽")
162
+
163
+ @telegram_router_1.router.callback_query(F.data == "contact")
164
+ async def handle_contact(callback: CallbackQuery, state: FSMContext):
165
+ """Обработка кнопки Связаться"""
166
+ await callback.answer()
167
+ await callback.message.answer("📞 Свяжитесь с нами:\n\nТелефон: +7 (999) 123-45-67\nEmail: info@example.com")
168
+
169
+ # =============================================================================
170
+ # ОБРАБОТЧИКИ СОБЫТИЙ (бизнес-логика)
171
+ # =============================================================================
172
+
173
+ @event_router.event_handler("example_event")
174
+ async def handle_example_event(user_id: int, event_data: str):
175
+ """Пример обработчика события"""
176
+ await send_message_by_human(
177
+ user_id=user_id,
178
+ message_text=f"✅ Событие обработано! Данные: {event_data}"
179
+ )
180
+
181
+ return {
182
+ "status": "success",
183
+ "message": "Событие обработано"
184
+ }
185
+
186
+ # =============================================================================
187
+ # ВРЕМЕННЫЕ ЗАДАЧИ ДЛЯ ОДНОГО ПОЛЬЗОВАТЕЛЯ
188
+ # =============================================================================
189
+
190
+ @event_router.schedule_task("send_reminder", delay="1h")
191
+ async def send_user_reminder(user_id: int, reminder_text: str):
192
+ """Отправляет напоминание пользователю"""
193
+ await send_message_by_human(
194
+ user_id=user_id,
195
+ message_text=f"🔔 Напоминание: {reminder_text}"
196
+ )
197
+
198
+ return {
199
+ "status": "reminder_sent",
200
+ "message": f"Напоминание отправлено пользователю {user_id}"
201
+ }
202
+
203
+ # =============================================================================
204
+ # ГЛОБАЛЬНЫЕ ОБРАБОТЧИКИ (для всех пользователей)
205
+ # =============================================================================
206
+
207
+ @event_router.global_handler("mass_notification", delay="1h", notify=True)
208
+ async def send_global_announcement(announcement_text: str):
209
+ """Отправляет анонс всем пользователям бота"""
210
+
211
+ await send_message_to_users_by_stage(
212
+ stage="introduction",
213
+ message_text=announcement_text,
214
+ bot_id="best-valera"
215
+ )
216
+
217
+ # =============================================================================
218
+ # ОСНОВНАЯ ФУНКЦИЯ
219
+ # =============================================================================
220
+
221
+ async def main():
222
+ """Основная функция запуска бота"""
223
+ try:
224
+ # bot_builder уже создан выше (для декоратора @bot_builder.on_start)
225
+
226
+ # Регистрируем роутеры ПЕРЕД сборкой (можно по одному или несколько сразу)
227
+ bot_builder.register_routers(event_router) # Роутеры событий
228
+ bot_builder.register_telegram_routers(telegram_router_1, telegram_router_2) # Telegram роутеры
229
+
230
+ await bot_builder.build()
231
+
232
+ # Запускаем бота
233
+ await bot_builder.start()
234
+
235
+ except Exception as e:
236
+ print(f"❌ Ошибка запуска бота: {e}")
237
+ raise
238
+
239
+ if __name__ == "__main__":
240
+ asyncio.run(main())
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "smart-bot-factory"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  description = "Библиотека для создания умных чат-ботов"
5
5
  authors = [
6
6
  {name = "Kopatych", email = "kopatych@example.com"}
@@ -46,6 +46,14 @@ class BotBuilder:
46
46
  self.prompt_loader: Optional[PromptLoader] = None
47
47
  self.router_manager: Optional[RouterManager] = None
48
48
  self._telegram_routers: List = [] # Список Telegram роутеров
49
+ self._start_handlers: List = [] # Список обработчиков on_start
50
+
51
+ # Хуки для кастомизации process_user_message
52
+ self._message_validators: List = [] # Валидация ДО обработки
53
+ self._prompt_enrichers: List = [] # Обогащение системного промпта
54
+ self._context_enrichers: List = [] # Обогащение контекста для AI
55
+ self._response_processors: List = [] # Обработка ответа AI
56
+ self._send_filters: List = [] # Фильтры перед отправкой пользователю
49
57
 
50
58
  # Флаги инициализации
51
59
  self._initialized = False
@@ -326,6 +334,165 @@ class BotBuilder:
326
334
 
327
335
  logger.info(f"✅ Зарегистрировано {len(telegram_routers)} Telegram роутеров")
328
336
 
337
+ def on_start(self, handler):
338
+ """
339
+ Регистрирует обработчик, который вызывается после стандартной логики /start
340
+
341
+ Обработчик получает доступ к:
342
+ - user_id: int - ID пользователя Telegram
343
+ - session_id: str - ID созданной сессии
344
+ - message: Message - Объект сообщения от aiogram
345
+ - state: FSMContext - Контекст состояния
346
+
347
+ Args:
348
+ handler: Async функция с сигнатурой:
349
+ async def handler(user_id: int, session_id: str, message: Message, state: FSMContext)
350
+
351
+ Example:
352
+ @bot_builder.on_start
353
+ async def my_start_handler(user_id, session_id, message, state):
354
+ keyboard = InlineKeyboardMarkup(...)
355
+ await message.answer("Выберите действие:", reply_markup=keyboard)
356
+ """
357
+ if not callable(handler):
358
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
359
+
360
+ self._start_handlers.append(handler)
361
+ logger.info(f"✅ Зарегистрирован обработчик on_start: {handler.__name__}")
362
+ return handler # Возвращаем handler для использования как декоратор
363
+
364
+ def get_start_handlers(self) -> List:
365
+ """Получает список обработчиков on_start"""
366
+ return self._start_handlers.copy()
367
+
368
+ # ========== ХУКИ ДЛЯ КАСТОМИЗАЦИИ ОБРАБОТКИ СООБЩЕНИЙ ==========
369
+
370
+ def validate_message(self, handler):
371
+ """
372
+ Регистрирует валидатор сообщений (вызывается ДО обработки AI)
373
+
374
+ Если валидатор возвращает False, обработка прерывается
375
+
376
+ Args:
377
+ handler: async def(message: Message, supabase_client) -> bool
378
+
379
+ Example:
380
+ @bot_builder.validate_message
381
+ async def check_service_names(message, supabase_client):
382
+ if "неправильное название" in message.text:
383
+ await message.answer("Пожалуйста, уточните название услуги")
384
+ return False # Прерываем обработку
385
+ return True # Продолжаем
386
+ """
387
+ if not callable(handler):
388
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
389
+
390
+ self._message_validators.append(handler)
391
+ logger.info(f"✅ Зарегистрирован валидатор сообщений: {handler.__name__}")
392
+ return handler
393
+
394
+ def enrich_prompt(self, handler):
395
+ """
396
+ Регистрирует обогатитель системного промпта
397
+
398
+ Args:
399
+ handler: async def(system_prompt: str, user_id: int, session_id: str, supabase_client) -> str
400
+
401
+ Example:
402
+ @bot_builder.enrich_prompt
403
+ async def add_client_info(system_prompt, user_id, session_id, supabase_client):
404
+ session = await supabase_client.get_active_session(user_id)
405
+ phone = session.get('metadata', {}).get('phone')
406
+ if phone:
407
+ return f"{system_prompt}\\n\\nТелефон клиента: {phone}"
408
+ return system_prompt
409
+ """
410
+ if not callable(handler):
411
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
412
+
413
+ self._prompt_enrichers.append(handler)
414
+ logger.info(f"✅ Зарегистрирован обогатитель промпта: {handler.__name__}")
415
+ return handler
416
+
417
+ def enrich_context(self, handler):
418
+ """
419
+ Регистрирует обогатитель контекста для AI (messages array)
420
+
421
+ Args:
422
+ handler: async def(messages: List[dict], user_id: int, session_id: str) -> List[dict]
423
+
424
+ Example:
425
+ @bot_builder.enrich_context
426
+ async def add_external_data(messages, user_id, session_id):
427
+ # Добавляем данные из внешнего API
428
+ messages.append({
429
+ "role": "system",
430
+ "content": "Дополнительная информация..."
431
+ })
432
+ return messages
433
+ """
434
+ if not callable(handler):
435
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
436
+
437
+ self._context_enrichers.append(handler)
438
+ logger.info(f"✅ Зарегистрирован обогатитель контекста: {handler.__name__}")
439
+ return handler
440
+
441
+ def process_response(self, handler):
442
+ """
443
+ Регистрирует обработчик ответа AI (ПОСЛЕ получения ответа)
444
+
445
+ Args:
446
+ handler: async def(response_text: str, ai_metadata: dict, user_id: int) -> tuple[str, dict]
447
+
448
+ Example:
449
+ @bot_builder.process_response
450
+ async def modify_response(response_text, ai_metadata, user_id):
451
+ # Модифицируем ответ
452
+ if "цена" in response_text.lower():
453
+ response_text += "\\n\\n💰 Актуальные цены на сайте"
454
+ return response_text, ai_metadata
455
+ """
456
+ if not callable(handler):
457
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
458
+
459
+ self._response_processors.append(handler)
460
+ logger.info(f"✅ Зарегистрирован обработчик ответа: {handler.__name__}")
461
+ return handler
462
+
463
+ def filter_send(self, handler):
464
+ """
465
+ Регистрирует фильтр отправки (может блокировать отправку пользователю)
466
+
467
+ Если фильтр возвращает False, сообщение НЕ отправляется
468
+
469
+ Args:
470
+ handler: async def(user_id: int, response_text: str) -> bool
471
+
472
+ Example:
473
+ @bot_builder.filter_send
474
+ async def block_during_process(user_id, response_text):
475
+ if is_processing(user_id):
476
+ return False # Не отправляем
477
+ return True # Отправляем
478
+ """
479
+ if not callable(handler):
480
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
481
+
482
+ self._send_filters.append(handler)
483
+ logger.info(f"✅ Зарегистрирован фильтр отправки: {handler.__name__}")
484
+ return handler
485
+
486
+ def get_message_hooks(self) -> Dict[str, List]:
487
+ """Получает все хуки для обработки сообщений"""
488
+ return {
489
+ 'validators': self._message_validators.copy(),
490
+ 'prompt_enrichers': self._prompt_enrichers.copy(),
491
+ 'context_enrichers': self._context_enrichers.copy(),
492
+ 'response_processors': self._response_processors.copy(),
493
+ 'send_filters': self._send_filters.copy()
494
+ }
495
+
329
496
  def get_router_manager(self) -> RouterManager:
330
497
  """Получает менеджер роутеров событий"""
331
498
  return self.router_manager
@@ -374,6 +541,8 @@ class BotBuilder:
374
541
  handlers_module.admin_manager = self.admin_manager
375
542
  handlers_module.analytics_manager = self.analytics_manager
376
543
  handlers_module.conversation_manager = self.conversation_manager
544
+ handlers_module.start_handlers = self._start_handlers # Передаем обработчики on_start
545
+ handlers_module.message_hooks = self.get_message_hooks() # Передаем хуки для обработки сообщений
377
546
  logger.info("✅ Глобальные переменные установлены в handlers")
378
547
  except Exception as e:
379
548
  logger.warning(f"⚠️ Не удалось установить глобальные переменные в handlers: {e}")