smart-bot-factory 1.1.1__py3-none-any.whl

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.
Files changed (73) hide show
  1. smart_bot_factory/__init__.py +3 -0
  2. smart_bot_factory/admin/__init__.py +18 -0
  3. smart_bot_factory/admin/admin_events.py +1223 -0
  4. smart_bot_factory/admin/admin_logic.py +553 -0
  5. smart_bot_factory/admin/admin_manager.py +156 -0
  6. smart_bot_factory/admin/admin_tester.py +157 -0
  7. smart_bot_factory/admin/timeout_checker.py +547 -0
  8. smart_bot_factory/aiogram_calendar/__init__.py +14 -0
  9. smart_bot_factory/aiogram_calendar/common.py +64 -0
  10. smart_bot_factory/aiogram_calendar/dialog_calendar.py +259 -0
  11. smart_bot_factory/aiogram_calendar/schemas.py +99 -0
  12. smart_bot_factory/aiogram_calendar/simple_calendar.py +224 -0
  13. smart_bot_factory/analytics/analytics_manager.py +414 -0
  14. smart_bot_factory/cli.py +806 -0
  15. smart_bot_factory/config.py +258 -0
  16. smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +16 -0
  17. smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +582 -0
  18. smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +66 -0
  19. smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +212 -0
  20. smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +28 -0
  21. smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +8 -0
  22. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +818 -0
  23. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +32 -0
  24. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +35 -0
  25. smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +133 -0
  26. smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +108 -0
  27. smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +46 -0
  28. smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +16 -0
  29. smart_bot_factory/configs/growthmed-october-24/welcome_file//342/225/250/320/267/342/225/250/342/225/241/342/225/250/342/225/221 /342/225/250/342/225/227/342/225/250/342/225/225/342/225/244/320/221/342/225/244/320/222 /342/225/250/342/224/220/342/225/250/342/225/233 152/342/225/250/320/264/342/225/250/320/247 /342/225/250/342/225/225 323/342/225/250/320/264/342/225/250/320/247 /342/225/250/342/224/244/342/225/250/342/225/227/342/225/244/320/237 /342/225/250/342/225/235/342/225/250/342/225/241/342/225/250/342/224/244/342/225/250/342/225/225/342/225/244/320/226/342/225/250/342/225/225/342/225/250/342/225/234/342/225/244/320/233.pdf +0 -0
  30. smart_bot_factory/core/bot_utils.py +1108 -0
  31. smart_bot_factory/core/conversation_manager.py +653 -0
  32. smart_bot_factory/core/decorators.py +2464 -0
  33. smart_bot_factory/core/message_sender.py +729 -0
  34. smart_bot_factory/core/router.py +347 -0
  35. smart_bot_factory/core/router_manager.py +218 -0
  36. smart_bot_factory/core/states.py +27 -0
  37. smart_bot_factory/creation/__init__.py +7 -0
  38. smart_bot_factory/creation/bot_builder.py +1093 -0
  39. smart_bot_factory/creation/bot_testing.py +1122 -0
  40. smart_bot_factory/dashboard/__init__.py +3 -0
  41. smart_bot_factory/event/__init__.py +7 -0
  42. smart_bot_factory/handlers/handlers.py +2013 -0
  43. smart_bot_factory/integrations/langchain_openai.py +542 -0
  44. smart_bot_factory/integrations/openai_client.py +513 -0
  45. smart_bot_factory/integrations/supabase_client.py +1678 -0
  46. smart_bot_factory/memory/__init__.py +8 -0
  47. smart_bot_factory/memory/memory_manager.py +299 -0
  48. smart_bot_factory/memory/static_memory.py +214 -0
  49. smart_bot_factory/message/__init__.py +56 -0
  50. smart_bot_factory/rag/__init__.py +5 -0
  51. smart_bot_factory/rag/decorators.py +29 -0
  52. smart_bot_factory/rag/router.py +54 -0
  53. smart_bot_factory/rag/templates/__init__.py +3 -0
  54. smart_bot_factory/rag/templates/create_table.sql +7 -0
  55. smart_bot_factory/rag/templates/create_table_and_function_template.py +94 -0
  56. smart_bot_factory/rag/templates/match_function.sql +61 -0
  57. smart_bot_factory/rag/templates/match_services_template.py +82 -0
  58. smart_bot_factory/rag/vectorstore.py +449 -0
  59. smart_bot_factory/router/__init__.py +10 -0
  60. smart_bot_factory/setup_checker.py +512 -0
  61. smart_bot_factory/supabase/__init__.py +7 -0
  62. smart_bot_factory/supabase/client.py +631 -0
  63. smart_bot_factory/utils/__init__.py +11 -0
  64. smart_bot_factory/utils/debug_routing.py +114 -0
  65. smart_bot_factory/utils/prompt_loader.py +529 -0
  66. smart_bot_factory/utils/tool_router.py +68 -0
  67. smart_bot_factory/utils/user_prompt_loader.py +55 -0
  68. smart_bot_factory/utm_link_generator.py +123 -0
  69. smart_bot_factory-1.1.1.dist-info/METADATA +1135 -0
  70. smart_bot_factory-1.1.1.dist-info/RECORD +73 -0
  71. smart_bot_factory-1.1.1.dist-info/WHEEL +4 -0
  72. smart_bot_factory-1.1.1.dist-info/entry_points.txt +2 -0
  73. smart_bot_factory-1.1.1.dist-info/licenses/LICENSE +24 -0
@@ -0,0 +1,258 @@
1
+ # Обновленный config.py с автоопределением bot_id
2
+
3
+ import logging
4
+ import os
5
+ from dataclasses import dataclass, field
6
+ from pathlib import Path
7
+ from typing import List
8
+
9
+ # Переменные из .env файла загружаются в BotBuilder
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ @dataclass
15
+ class Config:
16
+ """Конфигурация приложения"""
17
+
18
+ # 🆕 Bot ID автоматически из переменной окружения (устанавливается в запускалке)
19
+ BOT_ID: str = field(init=False)
20
+
21
+ # Telegram Bot Token
22
+ TELEGRAM_BOT_TOKEN: str = os.getenv("TELEGRAM_BOT_TOKEN", "")
23
+
24
+ # Supabase настройки
25
+ SUPABASE_URL: str = os.getenv("SUPABASE_URL", "")
26
+ SUPABASE_KEY: str = os.getenv("SUPABASE_KEY", "")
27
+
28
+ # OpenAI настройки
29
+ OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "")
30
+ OPENAI_MODEL: str = os.getenv("OPENAI_MODEL", "gpt-5-mini")
31
+ OPENAI_MAX_TOKENS: int = int(os.getenv("OPENAI_MAX_TOKENS", "1500"))
32
+ OPENAI_TEMPERATURE: float = float(os.getenv("OPENAI_TEMPERATURE", "0.7"))
33
+
34
+ # Каталог с файлами промптов
35
+ PROMT_FILES_DIR: str = os.getenv("PROMT_FILES_DIR", "prompts")
36
+
37
+ # Файл после стартого сообщения
38
+ WELCOME_FILE_DIR: str = os.getenv("WELCOME_FILE_URL", "welcome_file")
39
+ WELCOME_FILE_MSG: str = os.getenv("WELCOME_FILE_MSG", "welcome_file_msg.txt")
40
+
41
+ # Настройки базы данных
42
+ MAX_CONTEXT_MESSAGES: int = int(os.getenv("MAX_CONTEXT_MESSAGES", "50"))
43
+ HISTORY_MIN_MESSAGES: int = int(os.getenv("HISTORY_MIN_MESSAGES", "4"))
44
+ HISTORY_MAX_TOKENS: int = int(os.getenv("HISTORY_MAX_TOKENS", "5000"))
45
+
46
+ # Настройки логирования
47
+ LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
48
+
49
+ # Настройки продаж
50
+ LEAD_QUALIFICATION_THRESHOLD: int = int(
51
+ os.getenv("LEAD_QUALIFICATION_THRESHOLD", "7")
52
+ )
53
+ SESSION_TIMEOUT_HOURS: int = int(os.getenv("SESSION_TIMEOUT_HOURS", "24"))
54
+
55
+ # Настройки форматирования сообщений
56
+ MESSAGE_PARSE_MODE: str = os.getenv("MESSAGE_PARSE_MODE", "Markdown")
57
+
58
+ # Список найденных файлов промптов (заполняется автоматически)
59
+ PROMPT_FILES: List[str] = field(default_factory=list)
60
+
61
+ # Администраторы (заполняется из переменной окружения)
62
+ ADMIN_TELEGRAM_IDS: List[int] = field(default_factory=list)
63
+ ADMIN_SESSION_TIMEOUT_MINUTES: int = int(
64
+ os.getenv("ADMIN_SESSION_TIMEOUT_MINUTES", "30")
65
+ )
66
+
67
+ # Режим отладки - показывать JSON пользователю
68
+ DEBUG_MODE: bool = os.getenv("DEBUG_MODE", "false").lower() == "true"
69
+
70
+ def __post_init__(self):
71
+ """Проверка обязательных параметров и инициализация"""
72
+
73
+ # 🆕 Автоматически получаем BOT_ID из переменной окружения
74
+ self.BOT_ID = os.getenv("BOT_ID", "")
75
+
76
+ if not self.BOT_ID or not self.BOT_ID.strip():
77
+ error_msg = "BOT_ID не установлен. Запускайте бота через запускалку (например: python growthmed-october-24.py)"
78
+ logger.error(error_msg)
79
+ raise ValueError(error_msg)
80
+
81
+ # Проверяем формат BOT_ID
82
+ import re
83
+
84
+ if not re.match(r"^[a-z0-9\-]+$", self.BOT_ID):
85
+ error_msg = f"BOT_ID должен содержать только латинские буквы, цифры и дефисы: {self.BOT_ID}"
86
+ logger.error(error_msg)
87
+ raise ValueError(error_msg)
88
+
89
+ # Сканируем каталог с промптами
90
+ self._scan_prompt_files()
91
+
92
+ # Парсим список админов
93
+ self._parse_admin_ids()
94
+
95
+ # Проверяем обязательные поля
96
+ required_fields = [
97
+ "TELEGRAM_BOT_TOKEN",
98
+ "SUPABASE_URL",
99
+ "SUPABASE_KEY",
100
+ "OPENAI_API_KEY",
101
+ ]
102
+
103
+ missing_fields = []
104
+ for field_name in required_fields:
105
+ if not getattr(self, field_name):
106
+ missing_fields.append(field_name)
107
+
108
+ if missing_fields:
109
+ error_msg = f"Отсутствуют обязательные переменные окружения: {', '.join(missing_fields)}"
110
+ logger.error(error_msg)
111
+ raise ValueError(error_msg)
112
+
113
+ # Настройка уровня логирования
114
+ log_level = getattr(logging, self.LOG_LEVEL.upper(), logging.INFO)
115
+
116
+ # Настраиваем корневой логгер
117
+ root_logger = logging.getLogger()
118
+ root_logger.setLevel(log_level)
119
+
120
+ # Настраиваем форматтер
121
+ if not root_logger.handlers:
122
+ handler = logging.StreamHandler()
123
+ formatter = logging.Formatter(
124
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
125
+ )
126
+ handler.setFormatter(formatter)
127
+ root_logger.addHandler(handler)
128
+
129
+ # Устанавливаем уровень для всех модулей
130
+ logging.getLogger("openai_client").setLevel(log_level)
131
+ logging.getLogger("supabase_client").setLevel(log_level)
132
+ logging.getLogger("handlers").setLevel(log_level)
133
+ logging.getLogger("bot_utils").setLevel(log_level)
134
+ logging.getLogger("conversation_manager").setLevel(log_level)
135
+ logging.getLogger("admin_manager").setLevel(log_level)
136
+ logging.getLogger("prompt_loader").setLevel(log_level)
137
+ logging.getLogger("admin_logic").setLevel(log_level)
138
+ logging.getLogger("debug_routing").setLevel(log_level)
139
+
140
+ # Валидация значений
141
+ if self.OPENAI_MAX_TOKENS < 100 or self.OPENAI_MAX_TOKENS > 4000:
142
+ logger.warning(
143
+ f"Необычное значение OPENAI_MAX_TOKENS: {self.OPENAI_MAX_TOKENS}"
144
+ )
145
+
146
+ if self.OPENAI_TEMPERATURE < 0 or self.OPENAI_TEMPERATURE > 1:
147
+ logger.warning(
148
+ f"Необычное значение OPENAI_TEMPERATURE: {self.OPENAI_TEMPERATURE}"
149
+ )
150
+
151
+ logger.info("✅ Конфигурация загружена успешно")
152
+ logger.info(f"🤖 Bot ID (автоопределен): {self.BOT_ID}")
153
+ logger.debug(f"Модель OpenAI: {self.OPENAI_MODEL}")
154
+ logger.debug(f"Каталог промптов: {self.PROMT_FILES_DIR}")
155
+ logger.debug(f"Найдено файлов: {len(self.PROMPT_FILES)}")
156
+ logger.info(f"👥 Админов настроено: {len(self.ADMIN_TELEGRAM_IDS)}")
157
+ if self.DEBUG_MODE:
158
+ logger.warning(
159
+ "🐛 Режим отладки ВКЛЮЧЕН - JSON будет показываться пользователям"
160
+ )
161
+
162
+ def get_summary(self) -> dict:
163
+ """Возвращает сводку конфигурации (без секретов)"""
164
+ return {
165
+ "bot_id": self.BOT_ID, # 🆕 автоопределенный
166
+ "openai_model": self.OPENAI_MODEL,
167
+ "max_tokens": self.OPENAI_MAX_TOKENS,
168
+ "temperature": self.OPENAI_TEMPERATURE,
169
+ "prompts_dir": self.PROMT_FILES_DIR,
170
+ "max_context": self.MAX_CONTEXT_MESSAGES,
171
+ "log_level": self.LOG_LEVEL,
172
+ "prompt_files_count": len(self.PROMPT_FILES),
173
+ "prompt_files": self.PROMPT_FILES,
174
+ "has_telegram_token": bool(self.TELEGRAM_BOT_TOKEN),
175
+ "has_supabase_config": bool(self.SUPABASE_URL and self.SUPABASE_KEY),
176
+ "has_openai_key": bool(self.OPENAI_API_KEY),
177
+ "admin_count": len(self.ADMIN_TELEGRAM_IDS),
178
+ "debug_mode": self.DEBUG_MODE,
179
+ }
180
+
181
+ def _parse_admin_ids(self):
182
+ """Парсит список ID админов из переменной окружения"""
183
+ admin_ids_str = os.getenv("ADMIN_TELEGRAM_IDS", "")
184
+
185
+ if not admin_ids_str.strip():
186
+ logger.warning(
187
+ "⚠️ ADMIN_TELEGRAM_IDS не настроен - админские функции недоступны"
188
+ )
189
+ return
190
+
191
+ try:
192
+ # Парсим строку вида "123456,789012,345678"
193
+ ids = admin_ids_str.split(",")
194
+ admin_ids = [int(id_str.strip()) for id_str in ids if id_str.strip()]
195
+
196
+ if not admin_ids:
197
+ logger.warning(
198
+ "⚠️ ADMIN_TELEGRAM_IDS пуст - админские функции недоступны"
199
+ )
200
+ else:
201
+ self.ADMIN_TELEGRAM_IDS.extend(admin_ids)
202
+ logger.info(f"👥 Загружены админы: {self.ADMIN_TELEGRAM_IDS}")
203
+
204
+ except ValueError as e:
205
+ logger.error(f"❌ Ошибка парсинга ADMIN_TELEGRAM_IDS: {e}")
206
+ logger.error(" Формат должен быть: ADMIN_TELEGRAM_IDS=123456,789012")
207
+
208
+ def _scan_prompt_files(self):
209
+ """Сканирует каталог с промптами и проверяет необходимые файлы"""
210
+ prompts_dir = Path(self.PROMT_FILES_DIR).absolute()
211
+
212
+ # Проверяем существование каталога
213
+ if not prompts_dir.exists():
214
+ error_msg = f"Каталог с промптами не найден: {prompts_dir.absolute()}"
215
+ logger.error(error_msg)
216
+ raise FileNotFoundError(error_msg)
217
+
218
+ if not prompts_dir.is_dir():
219
+ error_msg = f"Путь не является каталогом: {prompts_dir.absolute()}"
220
+ logger.error(error_msg)
221
+ raise NotADirectoryError(error_msg)
222
+
223
+ # Ищем все .txt файлы
224
+ txt_files = list(prompts_dir.glob("*.txt"))
225
+
226
+ if not txt_files:
227
+ error_msg = (
228
+ f"В каталоге {prompts_dir.absolute()} не найдено ни одного .txt файла"
229
+ )
230
+ logger.error(error_msg)
231
+ raise FileNotFoundError(error_msg)
232
+
233
+ # Проверяем обязательное наличие welcome_message.txt
234
+ welcome_file = prompts_dir / "welcome_message.txt"
235
+ if not welcome_file.exists():
236
+ error_msg = (
237
+ f"Обязательный файл welcome_message.txt не найден в {prompts_dir}"
238
+ )
239
+ logger.error(error_msg)
240
+ raise FileNotFoundError(error_msg)
241
+
242
+ # Формируем список файлов промптов (исключая welcome_message.txt и help_message.txt)
243
+ excluded_files = {"welcome_message.txt", "help_message.txt"}
244
+ for txt_file in txt_files:
245
+ if txt_file.name not in excluded_files:
246
+ self.PROMPT_FILES.append(txt_file.name)
247
+
248
+ if not self.PROMPT_FILES:
249
+ error_msg = f"В каталоге {prompts_dir.absolute()} найден только welcome_message.txt, но нет других файлов промптов"
250
+ logger.error(error_msg)
251
+ raise FileNotFoundError(error_msg)
252
+
253
+ # Сортируем для предсказуемого порядка
254
+ self.PROMPT_FILES.sort()
255
+
256
+ logger.info(f"📁 Найдено файлов промптов: {len(self.PROMPT_FILES)}")
257
+ logger.info(f"📝 Файлы промптов: {', '.join(self.PROMPT_FILES)}")
258
+ logger.info("👋 Файл приветствия: welcome_message.txt")
@@ -0,0 +1,16 @@
1
+ <role>Ты - персональный помощник по росту медицинского бизнеса.</role>
2
+ <role>Ты - персональный помощник по росту медицинского бизнеса.</role>
3
+
4
+ <task>твоя задача - проконсультировать о конференции GrowthMED в Москве 24-25 октября,
5
+ рассказать почему и кому она важна и полезна, а также записать человека на конференцию
6
+ или на консультацию с менеджером по конференции.
7
+
8
+ Если же конференция неинтересна или билет уже куплен - выяснить текущие проблемы-цели бизнеса пользователя
9
+ и предложить услуги самого GrowthMED или ее партнеров.
10
+ <task>твоя задача - проконсультировать о конференции GrowthMED в Москве 24-25 октября,
11
+ рассказать почему и кому она важна и полезна, а также записать человека на конференцию
12
+ или на консультацию с менеджером по конференции.
13
+
14
+ Если же конференция неинтересна или билет уже куплен - выяснить текущие проблемы-цели бизнеса пользователя
15
+ и предложить услуги самого GrowthMED или ее партнеров.
16
+ </task>