smart-bot-factory 0.1.4__py3-none-any.whl → 0.1.6__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.

Potentially problematic release.


This version of smart-bot-factory might be problematic. Click here for more details.

Files changed (38) hide show
  1. smart_bot_factory/__init__.py +0 -30
  2. smart_bot_factory/admin/admin_logic.py +11 -11
  3. smart_bot_factory/cli.py +147 -85
  4. smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +2 -0
  5. smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +95 -28
  6. smart_bot_factory/core/bot_utils.py +224 -88
  7. smart_bot_factory/core/conversation_manager.py +542 -535
  8. smart_bot_factory/core/decorators.py +927 -230
  9. smart_bot_factory/core/message_sender.py +2 -7
  10. smart_bot_factory/core/router.py +173 -0
  11. smart_bot_factory/core/router_manager.py +166 -0
  12. smart_bot_factory/creation/__init__.py +1 -2
  13. smart_bot_factory/creation/bot_builder.py +103 -13
  14. smart_bot_factory/creation/bot_testing.py +74 -13
  15. smart_bot_factory/event/__init__.py +12 -0
  16. smart_bot_factory/handlers/handlers.py +10 -2
  17. smart_bot_factory/integrations/supabase_client.py +272 -2
  18. smart_bot_factory/message/__init__.py +12 -0
  19. smart_bot_factory/router/__init__.py +9 -0
  20. smart_bot_factory/supabase/__init__.py +7 -0
  21. smart_bot_factory-0.1.6.dist-info/METADATA +466 -0
  22. {smart_bot_factory-0.1.4.dist-info → smart_bot_factory-0.1.6.dist-info}/RECORD +26 -31
  23. smart_bot_factory/analytics/__init__.py +0 -7
  24. smart_bot_factory/configs/growthmed-helper/prompts/1sales_context.txt +0 -9
  25. smart_bot_factory/configs/growthmed-helper/prompts/2product_info.txt +0 -582
  26. smart_bot_factory/configs/growthmed-helper/prompts/3objection_handling.txt +0 -66
  27. smart_bot_factory/configs/growthmed-helper/prompts/final_instructions.txt +0 -232
  28. smart_bot_factory/configs/growthmed-helper/prompts/help_message.txt +0 -28
  29. smart_bot_factory/configs/growthmed-helper/prompts/welcome_message.txt +0 -7
  30. smart_bot_factory/configs/growthmed-helper/welcome_file/welcome_file_msg.txt +0 -16
  31. smart_bot_factory/configs/growthmed-helper/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
  32. smart_bot_factory/core/__init__.py +0 -22
  33. smart_bot_factory/integrations/__init__.py +0 -9
  34. smart_bot_factory-0.1.4.dist-info/METADATA +0 -126
  35. /smart_bot_factory/{configs/growthmed-helper/env_example.txt → supabase/example_usage.py} +0 -0
  36. {smart_bot_factory-0.1.4.dist-info → smart_bot_factory-0.1.6.dist-info}/WHEEL +0 -0
  37. {smart_bot_factory-0.1.4.dist-info → smart_bot_factory-0.1.6.dist-info}/entry_points.txt +0 -0
  38. {smart_bot_factory-0.1.4.dist-info → smart_bot_factory-0.1.6.dist-info}/licenses/LICENSE +0 -0
@@ -29,14 +29,9 @@ async def send_message_by_ai(
29
29
  try:
30
30
  # Импортируем необходимые компоненты
31
31
  from .bot_utils import parse_ai_response, process_events
32
- from .config import Config
33
- from .openai_client import OpenAIClient
34
- from .supabase_client import SupabaseClient
35
- from .prompt_loader import PromptLoader
36
- from aiogram import Bot
37
32
 
38
33
  # Получаем компоненты из глобального контекста
39
- from .handlers import get_global_var
34
+ from ..handlers.handlers import get_global_var
40
35
  bot = get_global_var('bot')
41
36
  supabase_client = get_global_var('supabase_client')
42
37
  openai_client = get_global_var('openai_client')
@@ -211,7 +206,7 @@ async def send_message_by_human(
211
206
  """
212
207
  try:
213
208
  # Импортируем необходимые компоненты
214
- from .handlers import get_global_var
209
+ from ..handlers.handlers import get_global_var
215
210
  bot = get_global_var('bot')
216
211
  supabase_client = get_global_var('supabase_client')
217
212
 
@@ -0,0 +1,173 @@
1
+ """
2
+ Роутер для Smart Bot Factory - аналог aiogram Router
3
+ """
4
+
5
+ from typing import Dict, Any, Callable
6
+ import logging
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class Router:
11
+ """
12
+ Роутер для организации обработчиков событий, задач и глобальных обработчиков
13
+ """
14
+
15
+ def __init__(self, name: str = None):
16
+ """
17
+ Инициализация роутера
18
+
19
+ Args:
20
+ name: Имя роутера для логирования
21
+ """
22
+ self.name = name or f"Router_{id(self)}"
23
+ self._event_handlers: Dict[str, Dict[str, Any]] = {}
24
+ self._scheduled_tasks: Dict[str, Dict[str, Any]] = {}
25
+ self._global_handlers: Dict[str, Dict[str, Any]] = {}
26
+
27
+ logger.info(f"🔄 Создан роутер: {self.name}")
28
+
29
+ def event_handler(self, event_type: str, notify: bool = False, once_only: bool = True):
30
+ """
31
+ Декоратор для регистрации обработчика события в роутере
32
+
33
+ Args:
34
+ event_type: Тип события
35
+ notify: Уведомлять ли админов
36
+ once_only: Выполнять ли только один раз
37
+ """
38
+ def decorator(func: Callable) -> Callable:
39
+ self._event_handlers[event_type] = {
40
+ 'handler': func,
41
+ 'name': func.__name__,
42
+ 'notify': notify,
43
+ 'once_only': once_only,
44
+ 'router': self.name
45
+ }
46
+
47
+ logger.info(f"📝 Роутер {self.name}: зарегистрирован обработчик события '{event_type}': {func.__name__}")
48
+
49
+ from functools import wraps
50
+ @wraps(func)
51
+ async def wrapper(*args, **kwargs):
52
+ try:
53
+ return await func(*args, **kwargs)
54
+ except Exception as e:
55
+ logger.error(f"Ошибка выполнения обработчика '{event_type}' в роутере {self.name}: {e}")
56
+ raise
57
+ return wrapper
58
+ return decorator
59
+
60
+ def schedule_task(self, task_name: str, notify: bool = False, smart_check: bool = True, once_only: bool = True):
61
+ """
62
+ Декоратор для регистрации запланированной задачи в роутере
63
+
64
+ Args:
65
+ task_name: Название задачи
66
+ notify: Уведомлять ли админов
67
+ smart_check: Использовать ли умную проверку
68
+ once_only: Выполнять ли только один раз
69
+ """
70
+ def decorator(func: Callable) -> Callable:
71
+ self._scheduled_tasks[task_name] = {
72
+ 'handler': func,
73
+ 'name': func.__name__,
74
+ 'notify': notify,
75
+ 'smart_check': smart_check,
76
+ 'once_only': once_only,
77
+ 'router': self.name
78
+ }
79
+
80
+ logger.info(f"⏰ Роутер {self.name}: зарегистрирована задача '{task_name}': {func.__name__}")
81
+
82
+ from functools import wraps
83
+ @wraps(func)
84
+ async def wrapper(*args, **kwargs):
85
+ try:
86
+ return await func(*args, **kwargs)
87
+ except Exception as e:
88
+ logger.error(f"Ошибка выполнения задачи '{task_name}' в роутере {self.name}: {e}")
89
+ raise
90
+ return wrapper
91
+ return decorator
92
+
93
+ def global_handler(self, handler_type: str, notify: bool = False, once_only: bool = True):
94
+ """
95
+ Декоратор для регистрации глобального обработчика в роутере
96
+
97
+ Args:
98
+ handler_type: Тип глобального обработчика
99
+ notify: Уведомлять ли админов
100
+ once_only: Выполнять ли только один раз
101
+ """
102
+ def decorator(func: Callable) -> Callable:
103
+ self._global_handlers[handler_type] = {
104
+ 'handler': func,
105
+ 'name': func.__name__,
106
+ 'notify': notify,
107
+ 'once_only': once_only,
108
+ 'router': self.name
109
+ }
110
+
111
+ logger.info(f"🌍 Роутер {self.name}: зарегистрирован глобальный обработчик '{handler_type}': {func.__name__}")
112
+
113
+ from functools import wraps
114
+ @wraps(func)
115
+ async def wrapper(*args, **kwargs):
116
+ try:
117
+ return await func(*args, **kwargs)
118
+ except Exception as e:
119
+ logger.error(f"Ошибка выполнения глобального обработчика '{handler_type}' в роутере {self.name}: {e}")
120
+ raise
121
+ return wrapper
122
+ return decorator
123
+
124
+ def get_event_handlers(self) -> Dict[str, Dict[str, Any]]:
125
+ """Получает все обработчики событий роутера"""
126
+ return self._event_handlers.copy()
127
+
128
+ def get_scheduled_tasks(self) -> Dict[str, Dict[str, Any]]:
129
+ """Получает все запланированные задачи роутера"""
130
+ return self._scheduled_tasks.copy()
131
+
132
+ def get_global_handlers(self) -> Dict[str, Dict[str, Any]]:
133
+ """Получает все глобальные обработчики роутера"""
134
+ return self._global_handlers.copy()
135
+
136
+ def get_all_handlers(self) -> Dict[str, Dict[str, Any]]:
137
+ """Получает все обработчики роутера"""
138
+ all_handlers = {}
139
+ all_handlers.update(self._event_handlers)
140
+ all_handlers.update(self._scheduled_tasks)
141
+ all_handlers.update(self._global_handlers)
142
+ return all_handlers
143
+
144
+ def include_router(self, router: 'Router'):
145
+ """
146
+ Включает другой роутер в текущий
147
+
148
+ Args:
149
+ router: Роутер для включения
150
+ """
151
+ # Добавляем обработчики событий
152
+ for event_type, handler_info in router.get_event_handlers().items():
153
+ if event_type in self._event_handlers:
154
+ logger.warning(f"⚠️ Конфликт обработчиков событий '{event_type}' между роутерами {self.name} и {router.name}")
155
+ self._event_handlers[event_type] = handler_info
156
+
157
+ # Добавляем запланированные задачи
158
+ for task_name, task_info in router.get_scheduled_tasks().items():
159
+ if task_name in self._scheduled_tasks:
160
+ logger.warning(f"⚠️ Конфликт задач '{task_name}' между роутерами {self.name} и {router.name}")
161
+ self._scheduled_tasks[task_name] = task_info
162
+
163
+ # Добавляем глобальные обработчики
164
+ for handler_type, handler_info in router.get_global_handlers().items():
165
+ if handler_type in self._global_handlers:
166
+ logger.warning(f"⚠️ Конфликт глобальных обработчиков '{handler_type}' между роутерами {self.name} и {router.name}")
167
+ self._global_handlers[handler_type] = handler_info
168
+
169
+ logger.info(f"🔗 Роутер {self.name}: включен роутер {router.name}")
170
+
171
+ def __repr__(self):
172
+ return f"Router(name='{self.name}', events={len(self._event_handlers)}, tasks={len(self._scheduled_tasks)}, globals={len(self._global_handlers)})"
173
+
@@ -0,0 +1,166 @@
1
+ """
2
+ Менеджер роутеров для Smart Bot Factory
3
+ """
4
+
5
+ from typing import Dict, List, Any, Optional
6
+ import logging
7
+ from .router import Router
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class RouterManager:
12
+ """
13
+ Менеджер для управления роутерами и их обработчиками
14
+ """
15
+
16
+ def __init__(self):
17
+ self._routers: List[Router] = []
18
+ self._combined_handlers: Dict[str, Dict[str, Any]] = {
19
+ 'event_handlers': {},
20
+ 'scheduled_tasks': {},
21
+ 'global_handlers': {}
22
+ }
23
+
24
+ logger.info("🔄 Создан менеджер роутеров")
25
+
26
+ def register_router(self, router: Router):
27
+ """
28
+ Регистрирует роутер в менеджере
29
+
30
+ Args:
31
+ router: Роутер для регистрации
32
+ """
33
+ if router not in self._routers:
34
+ self._routers.append(router)
35
+ self._update_combined_handlers()
36
+ logger.info(f"✅ Зарегистрирован роутер: {router.name}")
37
+ else:
38
+ logger.warning(f"⚠️ Роутер {router.name} уже зарегистрирован")
39
+
40
+ def unregister_router(self, router: Router):
41
+ """
42
+ Отменяет регистрацию роутера
43
+
44
+ Args:
45
+ router: Роутер для отмены регистрации
46
+ """
47
+ if router in self._routers:
48
+ self._routers.remove(router)
49
+ self._update_combined_handlers()
50
+ logger.info(f"❌ Отменена регистрация роутера: {router.name}")
51
+ else:
52
+ logger.warning(f"⚠️ Роутер {router.name} не найден в зарегистрированных")
53
+
54
+ def _update_combined_handlers(self):
55
+ """Обновляет объединенные обработчики всех роутеров"""
56
+ # Очищаем текущие обработчики
57
+ self._combined_handlers = {
58
+ 'event_handlers': {},
59
+ 'scheduled_tasks': {},
60
+ 'global_handlers': {}
61
+ }
62
+
63
+ # Собираем обработчики из всех роутеров
64
+ for router in self._routers:
65
+ # Обработчики событий
66
+ for event_type, handler_info in router.get_event_handlers().items():
67
+ if event_type in self._combined_handlers['event_handlers']:
68
+ existing_router = self._combined_handlers['event_handlers'][event_type]['router']
69
+ logger.warning(f"⚠️ Конфликт обработчиков событий '{event_type}' между роутерами {existing_router} и {router.name}")
70
+ self._combined_handlers['event_handlers'][event_type] = handler_info
71
+
72
+ # Запланированные задачи
73
+ for task_name, task_info in router.get_scheduled_tasks().items():
74
+ if task_name in self._combined_handlers['scheduled_tasks']:
75
+ existing_router = self._combined_handlers['scheduled_tasks'][task_name]['router']
76
+ logger.warning(f"⚠️ Конфликт задач '{task_name}' между роутерами {existing_router} и {router.name}")
77
+ self._combined_handlers['scheduled_tasks'][task_name] = task_info
78
+
79
+ # Глобальные обработчики
80
+ for handler_type, handler_info in router.get_global_handlers().items():
81
+ if handler_type in self._combined_handlers['global_handlers']:
82
+ existing_router = self._combined_handlers['global_handlers'][handler_type]['router']
83
+ logger.warning(f"⚠️ Конфликт глобальных обработчиков '{handler_type}' между роутерами {existing_router} и {router.name}")
84
+ self._combined_handlers['global_handlers'][handler_type] = handler_info
85
+
86
+ total_handlers = (len(self._combined_handlers['event_handlers']) +
87
+ len(self._combined_handlers['scheduled_tasks']) +
88
+ len(self._combined_handlers['global_handlers']))
89
+
90
+ logger.info(f"📊 Обновлены объединенные обработчики: {total_handlers} обработчиков из {len(self._routers)} роутеров")
91
+
92
+ def get_event_handlers(self) -> Dict[str, Dict[str, Any]]:
93
+ """Получает все обработчики событий"""
94
+ return self._combined_handlers['event_handlers'].copy()
95
+
96
+ def get_scheduled_tasks(self) -> Dict[str, Dict[str, Any]]:
97
+ """Получает все запланированные задачи"""
98
+ return self._combined_handlers['scheduled_tasks'].copy()
99
+
100
+ def get_global_handlers(self) -> Dict[str, Dict[str, Any]]:
101
+ """Получает все глобальные обработчики"""
102
+ return self._combined_handlers['global_handlers'].copy()
103
+
104
+ def get_all_handlers(self) -> Dict[str, Dict[str, Any]]:
105
+ """Получает все обработчики всех типов"""
106
+ all_handlers = {}
107
+ all_handlers.update(self._combined_handlers['event_handlers'])
108
+ all_handlers.update(self._combined_handlers['scheduled_tasks'])
109
+ all_handlers.update(self._combined_handlers['global_handlers'])
110
+ return all_handlers
111
+
112
+ def get_handlers_for_prompt(self) -> str:
113
+ """Возвращает описание всех обработчиков для добавления в промпт ИИ"""
114
+ prompt_parts: List[str] = []
115
+
116
+ if not any(self._combined_handlers.values()):
117
+ return ""
118
+
119
+ if self._combined_handlers['event_handlers']:
120
+ prompt_parts.append("ДОСТУПНЫЕ ОБРАБОТЧИКИ СОБЫТИЙ:")
121
+ for event_type, handler_info in self._combined_handlers['event_handlers'].items():
122
+ router_name = handler_info.get('router', 'unknown')
123
+ prompt_parts.append(f"- {event_type}: {handler_info['name']} (роутер: {router_name})")
124
+
125
+ if self._combined_handlers['scheduled_tasks']:
126
+ prompt_parts.append("\nДОСТУПНЫЕ ЗАДАЧИ ДЛЯ ПЛАНИРОВАНИЯ:")
127
+ for task_name, task_info in self._combined_handlers['scheduled_tasks'].items():
128
+ router_name = task_info.get('router', 'unknown')
129
+ prompt_parts.append(f"- {task_name}: {task_info['name']} (роутер: {router_name})")
130
+
131
+ if self._combined_handlers['global_handlers']:
132
+ prompt_parts.append("\nДОСТУПНЫЕ ГЛОБАЛЬНЫЕ ОБРАБОТЧИКИ:")
133
+ for handler_type, handler_info in self._combined_handlers['global_handlers'].items():
134
+ router_name = handler_info.get('router', 'unknown')
135
+ prompt_parts.append(f"- {handler_type}: {handler_info['name']} (роутер: {router_name})")
136
+
137
+ return "\n".join(prompt_parts)
138
+
139
+ def get_router_by_name(self, name: str) -> Optional[Router]:
140
+ """Получает роутер по имени"""
141
+ for router in self._routers:
142
+ if router.name == name:
143
+ return router
144
+ return None
145
+
146
+ def get_router_stats(self) -> Dict[str, Any]:
147
+ """Получает статистику по роутерам"""
148
+ stats = {
149
+ "total_routers": len(self._routers),
150
+ "routers": []
151
+ }
152
+
153
+ for router in self._routers:
154
+ router_stats = {
155
+ "name": router.name,
156
+ "event_handlers": len(router.get_event_handlers()),
157
+ "scheduled_tasks": len(router.get_scheduled_tasks()),
158
+ "global_handlers": len(router.get_global_handlers())
159
+ }
160
+ stats["routers"].append(router_stats)
161
+
162
+ return stats
163
+
164
+ def __repr__(self):
165
+ return f"RouterManager(routers={len(self._routers)}, handlers={len(self.get_all_handlers())})"
166
+
@@ -3,6 +3,5 @@ Creation модули smart_bot_factory
3
3
  """
4
4
 
5
5
  from ..creation.bot_builder import BotBuilder
6
- from ..creation.bot_testing import main as bot_testing_main
7
6
 
8
- __all__ = ['BotBuilder', 'bot_testing_main']
7
+ __all__ = ['BotBuilder']
@@ -3,19 +3,19 @@
3
3
  """
4
4
 
5
5
  import os
6
- import sys
7
- import asyncio
8
6
  import logging
9
7
  from pathlib import Path
10
- from typing import Optional, Dict, Any, List
8
+ from typing import Optional, Dict, Any
11
9
 
12
10
  from ..config import Config
13
11
  from ..integrations.openai_client import OpenAIClient
14
12
  from ..integrations.supabase_client import SupabaseClient
15
13
  from ..core.conversation_manager import ConversationManager
16
14
  from ..admin.admin_manager import AdminManager
15
+ from ..analytics.analytics_manager import AnalyticsManager
17
16
  from ..utils.prompt_loader import PromptLoader
18
17
  from ..core.decorators import get_handlers_for_prompt
18
+ from ..core.router_manager import RouterManager
19
19
 
20
20
  logger = logging.getLogger(__name__)
21
21
 
@@ -42,7 +42,9 @@ class BotBuilder:
42
42
  self.supabase_client: Optional[SupabaseClient] = None
43
43
  self.conversation_manager: Optional[ConversationManager] = None
44
44
  self.admin_manager: Optional[AdminManager] = None
45
+ self.analytics_manager: Optional[AnalyticsManager] = None
45
46
  self.prompt_loader: Optional[PromptLoader] = None
47
+ self.router_manager: Optional[RouterManager] = None
46
48
 
47
49
  # Флаги инициализации
48
50
  self._initialized = False
@@ -146,10 +148,24 @@ class BotBuilder:
146
148
  await self.admin_manager.sync_admins_from_config()
147
149
  logger.info(f"✅ Admin Manager инициализирован")
148
150
 
151
+ # Analytics Manager
152
+ self.analytics_manager = AnalyticsManager(self.supabase_client)
153
+ logger.info(f"✅ Analytics Manager инициализирован")
154
+
149
155
  # Conversation Manager
150
- self.conversation_manager = ConversationManager(self.supabase_client, self.admin_manager)
156
+ parse_mode = os.environ.get('MESSAGE_PARSE_MODE', 'Markdown')
157
+ admin_session_timeout_minutes = int(os.environ.get('ADMIN_SESSION_TIMEOUT_MINUTES', '30'))
158
+
159
+ self.conversation_manager = ConversationManager(self.supabase_client, self.admin_manager, parse_mode, admin_session_timeout_minutes)
151
160
  logger.info(f"✅ Conversation Manager инициализирован")
152
161
 
162
+ # Router Manager (создаем только если еще не создан)
163
+ if not self.router_manager:
164
+ self.router_manager = RouterManager()
165
+ logger.info(f"✅ Router Manager инициализирован")
166
+ else:
167
+ logger.info(f"✅ Router Manager уже был создан ранее")
168
+
153
169
  # Prompt Loader
154
170
  self.prompt_loader = PromptLoader(
155
171
  prompts_dir=self.config.PROMT_FILES_DIR
@@ -164,7 +180,11 @@ class BotBuilder:
164
180
  logger.info(f"🔧 Обновление промптов с информацией об обработчиках")
165
181
 
166
182
  # Получаем информацию о доступных обработчиках
167
- event_handlers_info = get_handlers_for_prompt()
183
+ # Сначала пробуем получить из роутеров, если нет - из старых декораторов
184
+ if self.router_manager:
185
+ event_handlers_info = self.router_manager.get_handlers_for_prompt()
186
+ else:
187
+ event_handlers_info = get_handlers_for_prompt()
168
188
 
169
189
  # Если есть обработчики, добавляем их в системный промпт
170
190
  if event_handlers_info:
@@ -192,6 +212,7 @@ class BotBuilder:
192
212
  "supabase_client": self.supabase_client is not None,
193
213
  "conversation_manager": self.conversation_manager is not None,
194
214
  "admin_manager": self.admin_manager is not None,
215
+ "analytics_manager": self.analytics_manager is not None,
195
216
  "prompt_loader": self.prompt_loader is not None
196
217
  },
197
218
  "tools": {
@@ -199,6 +220,62 @@ class BotBuilder:
199
220
  }
200
221
  }
201
222
 
223
+ def set_global_vars_in_module(self, module_name: str):
224
+ """
225
+ Устанавливает глобальные переменные в указанном модуле для удобного доступа
226
+
227
+ Args:
228
+ module_name: Имя модуля (например, 'valera', 'my_bot')
229
+ """
230
+ try:
231
+ import sys
232
+ import importlib
233
+
234
+ # Получаем модуль бота
235
+ bot_module = sys.modules.get(module_name)
236
+ if not bot_module:
237
+ # Пытаемся импортировать модуль, если он не загружен
238
+ try:
239
+ bot_module = importlib.import_module(module_name)
240
+ logger.info(f"📦 Модуль '{module_name}' импортирован для установки глобальных переменных")
241
+ except ImportError as ie:
242
+ logger.warning(f"⚠️ Не удалось импортировать модуль '{module_name}': {ie}")
243
+ return
244
+
245
+ # Устанавливаем глобальные переменные
246
+ bot_module.supabase_client = self.supabase_client
247
+ bot_module.openai_client = self.openai_client
248
+ bot_module.config = self.config
249
+ bot_module.admin_manager = self.admin_manager
250
+ bot_module.analytics_manager = self.analytics_manager
251
+ bot_module.conversation_manager = self.conversation_manager
252
+ bot_module.prompt_loader = self.prompt_loader
253
+
254
+ logger.info(f"✅ Глобальные переменные установлены в модуле '{module_name}'")
255
+
256
+ except Exception as e:
257
+ logger.warning(f"⚠️ Не удалось установить глобальные переменные в модуле '{module_name}': {e}")
258
+
259
+ def register_router(self, router):
260
+ """
261
+ Регистрирует роутер в менеджере роутеров
262
+
263
+ Args:
264
+ router: Роутер для регистрации
265
+ """
266
+ # Если RouterManager еще не инициализирован, создаем его
267
+ if not self.router_manager:
268
+ from ..core.router_manager import RouterManager
269
+ self.router_manager = RouterManager()
270
+ logger.info(f"✅ Router Manager создан для регистрации роутера '{router.name}'")
271
+
272
+ self.router_manager.register_router(router)
273
+ logger.info(f"✅ Роутер '{router.name}' зарегистрирован в боте {self.bot_id}")
274
+
275
+ def get_router_manager(self) -> RouterManager:
276
+ """Получает менеджер роутеров"""
277
+ return self.router_manager
278
+
202
279
  async def start(self):
203
280
  """
204
281
  Запускает бота (аналог main.py)
@@ -228,8 +305,7 @@ class BotBuilder:
228
305
  prompts_status = await self.prompt_loader.validate_prompts()
229
306
  logger.info(f"Статус промптов: {prompts_status}")
230
307
 
231
- # Устанавливаем глобальные переменные ДО импорта обработчиков
232
- import sys
308
+
233
309
  import importlib
234
310
 
235
311
  # Устанавливаем глобальные переменные в модулях handlers и admin_logic
@@ -242,6 +318,7 @@ class BotBuilder:
242
318
  handlers_module.openai_client = self.openai_client
243
319
  handlers_module.prompt_loader = self.prompt_loader
244
320
  handlers_module.admin_manager = self.admin_manager
321
+ handlers_module.analytics_manager = self.analytics_manager
245
322
  handlers_module.conversation_manager = self.conversation_manager
246
323
  logger.info("✅ Глобальные переменные установлены в handlers")
247
324
  except Exception as e:
@@ -256,6 +333,7 @@ class BotBuilder:
256
333
  admin_logic_module.openai_client = self.openai_client
257
334
  admin_logic_module.prompt_loader = self.prompt_loader
258
335
  admin_logic_module.admin_manager = self.admin_manager
336
+ admin_logic_module.analytics_manager = self.analytics_manager
259
337
  admin_logic_module.conversation_manager = self.conversation_manager
260
338
  logger.info("✅ Глобальные переменные установлены в admin_logic")
261
339
  except Exception as e:
@@ -271,6 +349,7 @@ class BotBuilder:
271
349
  bot_utils_module.openai_client = self.openai_client
272
350
  bot_utils_module.prompt_loader = self.prompt_loader
273
351
  bot_utils_module.admin_manager = self.admin_manager
352
+ bot_utils_module.analytics_manager = self.analytics_manager
274
353
  bot_utils_module.conversation_manager = self.conversation_manager
275
354
  logger.info("✅ Глобальные переменные установлены в bot_utils")
276
355
  except Exception as e:
@@ -301,6 +380,17 @@ class BotBuilder:
301
380
  setup_admin_handlers(dp) # Админские команды (/админ, /стат, /чат)
302
381
  setup_handlers(dp) # Основные пользовательские обработчики
303
382
 
383
+ # Устанавливаем глобальные переменные в модуле бота для удобного доступа
384
+ self.set_global_vars_in_module(self.bot_id)
385
+
386
+
387
+ # Устанавливаем роутер-менеджер в декораторы
388
+ if self.router_manager:
389
+ from ..core.decorators import set_router_manager
390
+ set_router_manager(self.router_manager)
391
+
392
+ # Фоновые задачи выполняются через asyncio.create_task в decorators.py
393
+
304
394
  # Логируем информацию о запуске
305
395
  logger.info(f"✅ Бот {self.bot_id} запущен и готов к работе!")
306
396
  logger.info(f" 📊 Изоляция данных: bot_id = {self.config.BOT_ID}")
@@ -308,12 +398,12 @@ class BotBuilder:
308
398
  logger.info(f" 📝 Загружено промптов: {len(self.config.PROMPT_FILES)}")
309
399
 
310
400
  # Четкое сообщение о запуске
311
- print(f"\nБОТ {self.bot_id.upper()} УСПЕШНО ЗАПУЩЕН!")
312
- print(f"Telegram Bot ID: {self.config.BOT_ID}")
313
- print(f"Админов: {len(self.config.ADMIN_TELEGRAM_IDS)}")
314
- print(f"Промптов: {len(self.config.PROMPT_FILES)}")
315
- print(f"Ожидание сообщений...")
316
- print(f"Для остановки нажмите Ctrl+C\n")
401
+ print(f"\n🤖 БОТ {self.bot_id.upper()} УСПЕШНО ЗАПУЩЕН!")
402
+ print(f"📱 Telegram Bot ID: {self.config.BOT_ID}")
403
+ print(f"👑 Админов: {len(self.config.ADMIN_TELEGRAM_IDS)}")
404
+ print(f"📝 Промптов: {len(self.config.PROMPT_FILES)}")
405
+ print(f"Ожидание сообщений...")
406
+ print(f"⏹️ Для остановки нажмите Ctrl+C\n")
317
407
 
318
408
  # Запуск polling (бесконечная обработка сообщений)
319
409
  await dp.start_polling(bot)