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,347 @@
1
+ """
2
+ EventRouter для Smart Bot Factory - роутер для событий, задач и глобальных обработчиков
3
+ """
4
+
5
+ import logging
6
+ from typing import Any, Callable, Dict, Union
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class EventRouter:
12
+ """
13
+ Роутер для организации обработчиков событий, задач и глобальных обработчиков
14
+ """
15
+
16
+ def __init__(self, name: str = None):
17
+ """
18
+ Инициализация роутера
19
+
20
+ Args:
21
+ name: Имя роутера для логирования
22
+ """
23
+ self.name = name or f"EventRouter_{id(self)}"
24
+ self._event_handlers: Dict[str, Dict[str, Any]] = {}
25
+ self._scheduled_tasks: Dict[str, Dict[str, Any]] = {}
26
+ self._global_handlers: Dict[str, Dict[str, Any]] = {}
27
+
28
+ logger.info(f"🔄 Создан роутер: {self.name}")
29
+
30
+ def event_handler(
31
+ self,
32
+ event_type: str,
33
+ notify: bool = False,
34
+ once_only: bool = True,
35
+ send_ai_response: bool = True,
36
+ ):
37
+ """
38
+ Декоратор для регистрации обработчика события в роутере
39
+
40
+ Args:
41
+ event_type: Тип события
42
+ notify: Уведомлять ли админов
43
+ once_only: Выполнять ли только один раз
44
+ send_ai_response: Отправлять ли сообщение от ИИ после обработки события (по умолчанию True)
45
+ """
46
+
47
+ def decorator(func: Callable) -> Callable:
48
+ self._event_handlers[event_type] = {
49
+ "handler": func,
50
+ "name": func.__name__,
51
+ "notify": notify,
52
+ "once_only": once_only,
53
+ "send_ai_response": send_ai_response,
54
+ "router": self.name,
55
+ }
56
+
57
+ logger.info(
58
+ f"📝 Роутер {self.name}: зарегистрирован обработчик события '{event_type}': {func.__name__}"
59
+ )
60
+
61
+ from functools import wraps
62
+
63
+ @wraps(func)
64
+ async def wrapper(*args, **kwargs):
65
+ try:
66
+ result = await func(*args, **kwargs)
67
+
68
+ # Автоматически добавляем флаги notify и send_ai_response к результату
69
+ if isinstance(result, dict):
70
+ result["notify"] = notify
71
+ result["send_ai_response"] = send_ai_response
72
+ else:
73
+ # Если результат не словарь, создаем словарь
74
+ result = {
75
+ "status": "success",
76
+ "result": result,
77
+ "notify": notify,
78
+ "send_ai_response": send_ai_response,
79
+ }
80
+
81
+ return result
82
+ except Exception as e:
83
+ logger.error(
84
+ f"Ошибка выполнения обработчика '{event_type}' в роутере {self.name}: {e}"
85
+ )
86
+ raise
87
+
88
+ return wrapper
89
+
90
+ return decorator
91
+
92
+ def schedule_task(
93
+ self,
94
+ task_name: str,
95
+ notify: bool = False,
96
+ notify_time: str = "after", # 'after' или 'before'
97
+ smart_check: bool = True,
98
+ once_only: bool = True,
99
+ delay: Union[str, int] = None,
100
+ event_type: Union[str, Callable] = None,
101
+ send_ai_response: bool = True,
102
+ ):
103
+ """
104
+ Декоратор для регистрации запланированной задачи в роутере
105
+
106
+ Args:
107
+ task_name: Название задачи
108
+ notify: Уведомлять ли админов
109
+ notify_time: Когда отправлять уведомление админам:
110
+ - 'before': при создании задачи
111
+ - 'after': после успешного выполнения (по умолчанию)
112
+ smart_check: Использовать ли умную проверку
113
+ once_only: Выполнять ли только один раз
114
+ delay: Время задержки в удобном формате (например, "1h 30m", "45m", 3600) - ОБЯЗАТЕЛЬНО
115
+ event_type: Источник времени события - ОПЦИОНАЛЬНО:
116
+ - str: Тип события для поиска в БД (например, 'appointment_booking')
117
+ - Callable: Функция async def(user_id, user_data) -> datetime
118
+ send_ai_response: Отправлять ли сообщение от ИИ после выполнения задачи (по умолчанию True)
119
+ """
120
+
121
+ def decorator(func: Callable) -> Callable:
122
+ # Время ОБЯЗАТЕЛЬНО должно быть указано
123
+ if delay is None:
124
+ raise ValueError(
125
+ f"Для задачи '{task_name}' в роутере {self.name} ОБЯЗАТЕЛЬНО нужно указать параметр delay"
126
+ )
127
+
128
+ # Импортируем функцию парсинга времени
129
+ from .decorators import parse_time_string
130
+
131
+ # Парсим время
132
+ try:
133
+ default_delay_seconds = parse_time_string(delay)
134
+ if event_type:
135
+ logger.info(
136
+ f"⏰ Роутер {self.name}: задача '{task_name}' настроена как напоминание о событии '{event_type}' за {delay} ({default_delay_seconds}с)"
137
+ )
138
+ else:
139
+ logger.info(
140
+ f"⏰ Роутер {self.name}: задача '{task_name}' настроена с задержкой: {delay} ({default_delay_seconds}с)"
141
+ )
142
+ except ValueError as e:
143
+ logger.error(
144
+ f"❌ Ошибка парсинга времени для задачи '{task_name}' в роутере {self.name}: {e}"
145
+ )
146
+ raise
147
+
148
+ # Проверяем корректность notify_time
149
+ if notify_time not in ["before", "after"]:
150
+ raise ValueError(f"notify_time должен быть 'before' или 'after', получено: {notify_time}")
151
+
152
+ self._scheduled_tasks[task_name] = {
153
+ "handler": func,
154
+ "name": func.__name__,
155
+ "notify": notify,
156
+ "notify_time": notify_time, # Когда отправлять уведомление
157
+ "smart_check": smart_check,
158
+ "once_only": once_only,
159
+ "router": self.name,
160
+ "default_delay": default_delay_seconds,
161
+ "event_type": event_type, # Новое поле для типа события
162
+ "send_ai_response": send_ai_response,
163
+ }
164
+
165
+ if event_type:
166
+ logger.info(
167
+ f"⏰ Роутер {self.name}: зарегистрирована задача-напоминание '{task_name}' для события '{event_type}': {func.__name__}"
168
+ )
169
+ else:
170
+ logger.info(
171
+ f"⏰ Роутер {self.name}: зарегистрирована задача '{task_name}': {func.__name__}"
172
+ )
173
+
174
+ from functools import wraps
175
+
176
+ @wraps(func)
177
+ async def wrapper(*args, **kwargs):
178
+ try:
179
+ result = await func(*args, **kwargs)
180
+
181
+ # Автоматически добавляем флаги notify и send_ai_response к результату
182
+ if isinstance(result, dict):
183
+ result["notify"] = notify
184
+ result["send_ai_response"] = send_ai_response
185
+ else:
186
+ # Если результат не словарь, создаем словарь
187
+ result = {
188
+ "status": "success",
189
+ "result": result,
190
+ "notify": notify,
191
+ "send_ai_response": send_ai_response,
192
+ }
193
+
194
+ return result
195
+ except Exception as e:
196
+ logger.error(
197
+ f"Ошибка выполнения задачи '{task_name}' в роутере {self.name}: {e}"
198
+ )
199
+ raise
200
+
201
+ return wrapper
202
+
203
+ return decorator
204
+
205
+ def global_handler(
206
+ self,
207
+ handler_type: str,
208
+ notify: bool = False,
209
+ once_only: bool = True,
210
+ delay: Union[str, int] = None,
211
+ event_type: Union[str, Callable] = None,
212
+ send_ai_response: bool = True,
213
+ ):
214
+ """
215
+ Декоратор для регистрации глобального обработчика в роутере
216
+
217
+ Args:
218
+ handler_type: Тип глобального обработчика
219
+ notify: Уведомлять ли админов
220
+ once_only: Выполнять ли только один раз
221
+ delay: Время задержки в удобном формате (например, "1h 30m", "45m", 3600) - ОБЯЗАТЕЛЬНО
222
+ send_ai_response: Отправлять ли сообщение от ИИ после выполнения обработчика (по умолчанию True)
223
+ """
224
+
225
+ def decorator(func: Callable) -> Callable:
226
+ # Время ОБЯЗАТЕЛЬНО должно быть указано
227
+ if delay is None:
228
+ raise ValueError(
229
+ f"Для глобального обработчика '{handler_type}' в роутере {self.name} ОБЯЗАТЕЛЬНО нужно указать параметр delay"
230
+ )
231
+
232
+ # Импортируем функцию парсинга времени
233
+ from .decorators import parse_time_string
234
+
235
+ # Парсим время
236
+ try:
237
+ default_delay_seconds = parse_time_string(delay)
238
+ logger.info(
239
+ f"🌍 Роутер {self.name}: глобальный обработчик '{handler_type}' настроен с задержкой: {delay} ({default_delay_seconds}с)"
240
+ )
241
+ except ValueError as e:
242
+ logger.error(
243
+ f"❌ Ошибка парсинга времени для глобального обработчика '{handler_type}' в роутере {self.name}: {e}"
244
+ )
245
+ raise
246
+
247
+ self._global_handlers[handler_type] = {
248
+ "handler": func,
249
+ "name": func.__name__,
250
+ "notify": notify,
251
+ "once_only": once_only,
252
+ "router": self.name,
253
+ "default_delay": default_delay_seconds,
254
+ "event_type": event_type, # Добавляем event_type для глобальных обработчиков
255
+ "send_ai_response": send_ai_response,
256
+ }
257
+
258
+ logger.info(
259
+ f"🌍 Роутер {self.name}: зарегистрирован глобальный обработчик '{handler_type}': {func.__name__}"
260
+ )
261
+
262
+ from functools import wraps
263
+
264
+ @wraps(func)
265
+ async def wrapper(*args, **kwargs):
266
+ try:
267
+ result = await func(*args, **kwargs)
268
+
269
+ # Автоматически добавляем флаги notify и send_ai_response к результату
270
+ if isinstance(result, dict):
271
+ result["notify"] = notify
272
+ result["send_ai_response"] = send_ai_response
273
+ else:
274
+ # Если результат не словарь, создаем словарь
275
+ result = {
276
+ "status": "success",
277
+ "result": result,
278
+ "notify": notify,
279
+ "send_ai_response": send_ai_response,
280
+ }
281
+
282
+ return result
283
+ except Exception as e:
284
+ logger.error(
285
+ f"Ошибка выполнения глобального обработчика '{handler_type}' в роутере {self.name}: {e}"
286
+ )
287
+ raise
288
+
289
+ return wrapper
290
+
291
+ return decorator
292
+
293
+ def get_event_handlers(self) -> Dict[str, Dict[str, Any]]:
294
+ """Получает все обработчики событий роутера"""
295
+ return self._event_handlers.copy()
296
+
297
+ def get_scheduled_tasks(self) -> Dict[str, Dict[str, Any]]:
298
+ """Получает все запланированные задачи роутера"""
299
+ return self._scheduled_tasks.copy()
300
+
301
+ def get_global_handlers(self) -> Dict[str, Dict[str, Any]]:
302
+ """Получает все глобальные обработчики роутера"""
303
+ return self._global_handlers.copy()
304
+
305
+ def get_all_handlers(self) -> Dict[str, Dict[str, Any]]:
306
+ """Получает все обработчики роутера"""
307
+ all_handlers = {}
308
+ all_handlers.update(self._event_handlers)
309
+ all_handlers.update(self._scheduled_tasks)
310
+ all_handlers.update(self._global_handlers)
311
+ return all_handlers
312
+
313
+ def include_router(self, router: "EventRouter"):
314
+ """
315
+ Включает другой роутер в текущий
316
+
317
+ Args:
318
+ router: EventRouter для включения
319
+ """
320
+ # Добавляем обработчики событий
321
+ for event_type, handler_info in router.get_event_handlers().items():
322
+ if event_type in self._event_handlers:
323
+ logger.warning(
324
+ f"⚠️ Конфликт обработчиков событий '{event_type}' между роутерами {self.name} и {router.name}"
325
+ )
326
+ self._event_handlers[event_type] = handler_info
327
+
328
+ # Добавляем запланированные задачи
329
+ for task_name, task_info in router.get_scheduled_tasks().items():
330
+ if task_name in self._scheduled_tasks:
331
+ logger.warning(
332
+ f"⚠️ Конфликт задач '{task_name}' между роутерами {self.name} и {router.name}"
333
+ )
334
+ self._scheduled_tasks[task_name] = task_info
335
+
336
+ # Добавляем глобальные обработчики
337
+ for handler_type, handler_info in router.get_global_handlers().items():
338
+ if handler_type in self._global_handlers:
339
+ logger.warning(
340
+ f"⚠️ Конфликт глобальных обработчиков '{handler_type}' между роутерами {self.name} и {router.name}"
341
+ )
342
+ self._global_handlers[handler_type] = handler_info
343
+
344
+ logger.info(f"🔗 Роутер {self.name}: включен роутер {router.name}")
345
+
346
+ def __repr__(self):
347
+ return f"EventRouter(name='{self.name}', events={len(self._event_handlers)}, tasks={len(self._scheduled_tasks)}, globals={len(self._global_handlers)})"
@@ -0,0 +1,218 @@
1
+ """
2
+ Менеджер роутеров для Smart Bot Factory
3
+ """
4
+
5
+ import logging
6
+ from typing import Any, Dict, List, Optional
7
+
8
+ from .router import EventRouter
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class RouterManager:
14
+ """
15
+ Менеджер для управления роутерами событий и их обработчиками
16
+ """
17
+
18
+ def __init__(self):
19
+ self._routers: List[EventRouter] = []
20
+ self._combined_handlers: Dict[str, Dict[str, Any]] = {
21
+ "event_handlers": {},
22
+ "scheduled_tasks": {},
23
+ "global_handlers": {},
24
+ }
25
+
26
+ logger.info("🔄 Создан менеджер роутеров")
27
+
28
+ def register_router(self, router: EventRouter):
29
+ """
30
+ Регистрирует роутер событий в менеджере
31
+
32
+ Args:
33
+ router: EventRouter для регистрации
34
+ """
35
+ if router not in self._routers:
36
+ self._routers.append(router)
37
+ self._update_combined_handlers()
38
+ logger.info(f"✅ Зарегистрирован роутер: {router.name}")
39
+ else:
40
+ logger.warning(f"⚠️ Роутер {router.name} уже зарегистрирован")
41
+
42
+ def unregister_router(self, router: EventRouter):
43
+ """
44
+ Отменяет регистрацию роутера событий
45
+
46
+ Args:
47
+ router: EventRouter для отмены регистрации
48
+ """
49
+ if router in self._routers:
50
+ self._routers.remove(router)
51
+ self._update_combined_handlers()
52
+ logger.info(f"❌ Отменена регистрация роутера: {router.name}")
53
+ else:
54
+ logger.warning(f"⚠️ Роутер {router.name} не найден в зарегистрированных")
55
+
56
+ def _update_combined_handlers(self):
57
+ """Обновляет объединенные обработчики всех роутеров"""
58
+ # Очищаем текущие обработчики
59
+ self._combined_handlers = {
60
+ "event_handlers": {},
61
+ "scheduled_tasks": {},
62
+ "global_handlers": {},
63
+ }
64
+
65
+ logger.debug(
66
+ f"🔍 RouterManager._update_combined_handlers(): обновляем обработчики для {len(self._routers)} роутеров"
67
+ )
68
+
69
+ # Собираем обработчики из всех роутеров
70
+ for router in self._routers:
71
+ logger.debug(f"🔍 Обрабатываем роутер: {router.name}")
72
+
73
+ # Обработчики событий
74
+ event_handlers = router.get_event_handlers()
75
+ logger.debug(
76
+ f"🔍 Роутер {router.name}: {len(event_handlers)} обработчиков событий"
77
+ )
78
+ for event_type, handler_info in event_handlers.items():
79
+ if event_type in self._combined_handlers["event_handlers"]:
80
+ existing_router = self._combined_handlers["event_handlers"][
81
+ event_type
82
+ ]["router"]
83
+ logger.warning(
84
+ f"⚠️ Конфликт обработчиков событий '{event_type}' между роутерами {existing_router} и {router.name}"
85
+ )
86
+ self._combined_handlers["event_handlers"][event_type] = handler_info
87
+
88
+ # Запланированные задачи
89
+ scheduled_tasks = router.get_scheduled_tasks()
90
+ logger.debug(
91
+ f"🔍 Роутер {router.name}: {len(scheduled_tasks)} запланированных задач: {list(scheduled_tasks.keys())}"
92
+ )
93
+ for task_name, task_info in scheduled_tasks.items():
94
+ if task_name in self._combined_handlers["scheduled_tasks"]:
95
+ existing_router = self._combined_handlers["scheduled_tasks"][
96
+ task_name
97
+ ]["router"]
98
+ logger.warning(
99
+ f"⚠️ Конфликт задач '{task_name}' между роутерами {existing_router} и {router.name}"
100
+ )
101
+ self._combined_handlers["scheduled_tasks"][task_name] = task_info
102
+
103
+ # Глобальные обработчики
104
+ global_handlers = router.get_global_handlers()
105
+ logger.debug(
106
+ f"🔍 Роутер {router.name}: {len(global_handlers)} глобальных обработчиков"
107
+ )
108
+ for handler_type, handler_info in global_handlers.items():
109
+ if handler_type in self._combined_handlers["global_handlers"]:
110
+ existing_router = self._combined_handlers["global_handlers"][
111
+ handler_type
112
+ ]["router"]
113
+ logger.warning(
114
+ f"⚠️ Конфликт глобальных обработчиков '{handler_type}' между роутерами {existing_router} и {router.name}"
115
+ )
116
+ self._combined_handlers["global_handlers"][handler_type] = handler_info
117
+
118
+ logger.debug(
119
+ f"🔍 RouterManager._update_combined_handlers(): итого - {len(self._combined_handlers['scheduled_tasks'])} задач: {list(self._combined_handlers['scheduled_tasks'].keys())}"
120
+ )
121
+
122
+ total_handlers = (
123
+ len(self._combined_handlers["event_handlers"])
124
+ + len(self._combined_handlers["scheduled_tasks"])
125
+ + len(self._combined_handlers["global_handlers"])
126
+ )
127
+
128
+ logger.info(
129
+ f"📊 Обновлены объединенные обработчики: {total_handlers} обработчиков из {len(self._routers)} роутеров"
130
+ )
131
+
132
+ def get_event_handlers(self) -> Dict[str, Dict[str, Any]]:
133
+ """Получает все обработчики событий"""
134
+ return self._combined_handlers["event_handlers"].copy()
135
+
136
+ def get_scheduled_tasks(self) -> Dict[str, Dict[str, Any]]:
137
+ """Получает все запланированные задачи"""
138
+ tasks = self._combined_handlers["scheduled_tasks"].copy()
139
+ logger.debug(
140
+ f"🔍 RouterManager.get_scheduled_tasks(): возвращаем {len(tasks)} задач: {list(tasks.keys())}"
141
+ )
142
+ return tasks
143
+
144
+ def get_global_handlers(self) -> Dict[str, Dict[str, Any]]:
145
+ """Получает все глобальные обработчики"""
146
+ return self._combined_handlers["global_handlers"].copy()
147
+
148
+ def get_all_handlers(self) -> Dict[str, Dict[str, Any]]:
149
+ """Получает все обработчики всех типов"""
150
+ all_handlers = {}
151
+ all_handlers.update(self._combined_handlers["event_handlers"])
152
+ all_handlers.update(self._combined_handlers["scheduled_tasks"])
153
+ all_handlers.update(self._combined_handlers["global_handlers"])
154
+ return all_handlers
155
+
156
+ def get_handlers_for_prompt(self) -> str:
157
+ """Возвращает описание всех обработчиков для добавления в промпт ИИ"""
158
+ prompt_parts: List[str] = []
159
+
160
+ if not any(self._combined_handlers.values()):
161
+ return ""
162
+
163
+ if self._combined_handlers["event_handlers"]:
164
+ prompt_parts.append("ДОСТУПНЫЕ ОБРАБОТЧИКИ СОБЫТИЙ:")
165
+ for event_type, handler_info in self._combined_handlers[
166
+ "event_handlers"
167
+ ].items():
168
+ router_name = handler_info.get("router", "unknown")
169
+ prompt_parts.append(
170
+ f"- {event_type}: {handler_info['name']} (роутер: {router_name})"
171
+ )
172
+
173
+ if self._combined_handlers["scheduled_tasks"]:
174
+ prompt_parts.append("\nДОСТУПНЫЕ ЗАДАЧИ ДЛЯ ПЛАНИРОВАНИЯ:")
175
+ for task_name, task_info in self._combined_handlers[
176
+ "scheduled_tasks"
177
+ ].items():
178
+ router_name = task_info.get("router", "unknown")
179
+ prompt_parts.append(
180
+ f"- {task_name}: {task_info['name']} (роутер: {router_name})"
181
+ )
182
+
183
+ if self._combined_handlers["global_handlers"]:
184
+ prompt_parts.append("\nДОСТУПНЫЕ ГЛОБАЛЬНЫЕ ОБРАБОТЧИКИ:")
185
+ for handler_type, handler_info in self._combined_handlers[
186
+ "global_handlers"
187
+ ].items():
188
+ router_name = handler_info.get("router", "unknown")
189
+ prompt_parts.append(
190
+ f"- {handler_type}: {handler_info['name']} (роутер: {router_name})"
191
+ )
192
+
193
+ return "\n".join(prompt_parts)
194
+
195
+ def get_router_by_name(self, name: str) -> Optional[EventRouter]:
196
+ """Получает роутер событий по имени"""
197
+ for router in self._routers:
198
+ if router.name == name:
199
+ return router
200
+ return None
201
+
202
+ def get_router_stats(self) -> Dict[str, Any]:
203
+ """Получает статистику по роутерам"""
204
+ stats = {"total_routers": len(self._routers), "routers": []}
205
+
206
+ for router in self._routers:
207
+ router_stats = {
208
+ "name": router.name,
209
+ "event_handlers": len(router.get_event_handlers()),
210
+ "scheduled_tasks": len(router.get_scheduled_tasks()),
211
+ "global_handlers": len(router.get_global_handlers()),
212
+ }
213
+ stats["routers"].append(router_stats)
214
+
215
+ return stats
216
+
217
+ def __repr__(self):
218
+ return f"RouterManager(routers={len(self._routers)}, handlers={len(self.get_all_handlers())})"
@@ -0,0 +1,27 @@
1
+ """
2
+ Состояния FSM для бота
3
+ """
4
+
5
+ from aiogram.fsm.state import State, StatesGroup
6
+
7
+
8
+ class UserStates(StatesGroup):
9
+ waiting_for_message = State()
10
+ admin_chat = State() # пользователь в диалоге с админом
11
+
12
+ voice_confirmation = State() # ожидание подтверждения распознанного текста
13
+ voice_editing = State() # редактирование распознанного текста
14
+
15
+
16
+ class AdminStates(StatesGroup):
17
+ admin_mode = State()
18
+ in_conversation = State()
19
+
20
+ # Состояния для создания события
21
+ create_event_name = State()
22
+ create_event_date = State()
23
+ create_event_time = State()
24
+ create_event_segment = State()
25
+ create_event_message = State()
26
+ create_event_files = State()
27
+ create_event_confirm = State()
@@ -0,0 +1,7 @@
1
+ """
2
+ Creation модули smart_bot_factory
3
+ """
4
+
5
+ from ..creation.bot_builder import BotBuilder
6
+
7
+ __all__ = ["BotBuilder"]