smart-bot-factory 0.1.0__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.

@@ -0,0 +1,337 @@
1
+ """
2
+ Строитель ботов для Smart Bot Factory
3
+ """
4
+
5
+ import os
6
+ import sys
7
+ import asyncio
8
+ import logging
9
+ from pathlib import Path
10
+ from typing import Optional, Dict, Any, List
11
+
12
+ from ..integrations import (
13
+ Config, OpenAIClient, SupabaseClient,
14
+ ConversationManager, AdminManager, PromptLoader
15
+ )
16
+ from ..events.decorators import get_handlers_for_prompt
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+ class BotBuilder:
21
+ """
22
+ Строитель ботов, который использует существующие файлы проекта
23
+ и добавляет новые возможности через декораторы
24
+ """
25
+
26
+ def __init__(self, bot_id: str, config_dir: Optional[Path] = None):
27
+ """
28
+ Инициализация строителя бота
29
+
30
+ Args:
31
+ bot_id: Идентификатор бота
32
+ config_dir: Путь к директории конфигурации (по умолчанию configs/bot_id)
33
+ """
34
+ self.bot_id = bot_id
35
+ self.config_dir = config_dir or Path("bots") / bot_id
36
+
37
+ # Компоненты бота
38
+ self.config: Optional[Config] = None
39
+ self.openai_client: Optional[OpenAIClient] = None
40
+ self.supabase_client: Optional[SupabaseClient] = None
41
+ self.conversation_manager: Optional[ConversationManager] = None
42
+ self.admin_manager: Optional[AdminManager] = None
43
+ self.prompt_loader: Optional[PromptLoader] = None
44
+
45
+ # Флаги инициализации
46
+ self._initialized = False
47
+
48
+ logger.info(f"🏗️ Создан BotBuilder для бота: {bot_id}")
49
+
50
+ async def build(self) -> 'BotBuilder':
51
+ """
52
+ Строит и инициализирует все компоненты бота
53
+
54
+ Returns:
55
+ BotBuilder: Возвращает self для цепочки вызовов
56
+ """
57
+ if self._initialized:
58
+ logger.warning(f"⚠️ Бот {self.bot_id} уже инициализирован")
59
+ return self
60
+
61
+ try:
62
+ logger.info(f"🚀 Начинаем сборку бота {self.bot_id}")
63
+
64
+ # 1. Инициализируем конфигурацию
65
+ await self._init_config()
66
+
67
+ # 2. Инициализируем клиенты
68
+ await self._init_clients()
69
+
70
+ # 3. Инициализируем менеджеры
71
+ await self._init_managers()
72
+
73
+ # 4. Обновляем промпты с информацией о доступных инструментах
74
+ await self._update_prompts_with_tools()
75
+
76
+ self._initialized = True
77
+ logger.info(f"✅ Бот {self.bot_id} успешно собран и готов к работе")
78
+
79
+ return self
80
+
81
+ except Exception as e:
82
+ logger.error(f"❌ Ошибка при сборке бота {self.bot_id}: {e}")
83
+ raise
84
+
85
+ async def _init_config(self):
86
+ """Инициализация конфигурации"""
87
+ logger.info(f"⚙️ Инициализация конфигурации для {self.bot_id}")
88
+
89
+ # Устанавливаем BOT_ID в переменные окружения
90
+ os.environ['BOT_ID'] = self.bot_id
91
+
92
+ # Загружаем .env файл если существует
93
+ env_file = self.config_dir / ".env"
94
+ if env_file.exists():
95
+ from dotenv import load_dotenv
96
+ load_dotenv(env_file)
97
+ logger.info(f"📄 Загружен .env файл: {env_file}")
98
+
99
+ # Проверяем, установлен ли уже путь к промптам в файле запускалки
100
+ if "PROMT_FILES_DIR" in os.environ:
101
+ logger.info(f"📁 Путь к промптам уже установлен: {os.environ['PROMT_FILES_DIR']}")
102
+ else:
103
+ # Устанавливаем правильный путь к промптам ПОСЛЕ загрузки .env
104
+ # Берем значение из .env и добавляем к пути bots/bot-id/
105
+ prompts_subdir = os.environ.get("PROMT_FILES_DIR", "prompts")
106
+ logger.info(f"🔍 PROMT_FILES_DIR из .env: {prompts_subdir}")
107
+ logger.info(f"🔍 config_dir: {self.config_dir}")
108
+
109
+ prompts_dir = self.config_dir / prompts_subdir
110
+ logger.info(f"🔍 Полный путь к промптам: {prompts_dir}")
111
+ logger.info(f"🔍 Существует ли папка: {prompts_dir.exists()}")
112
+
113
+ # ВАЖНО: Устанавливаем правильный путь ДО создания Config
114
+ if prompts_dir.exists():
115
+ os.environ["PROMT_FILES_DIR"] = str(prompts_dir)
116
+ logger.info(f"📁 Установлен путь к промптам: {prompts_dir}")
117
+ else:
118
+ logger.error(f"❌ Папка с промптами не найдена: {prompts_dir}")
119
+ # Устанавливаем путь даже если папки нет, чтобы Config не упал
120
+ os.environ["PROMT_FILES_DIR"] = str(prompts_dir)
121
+
122
+ # Создаем конфигурацию
123
+ logger.info(f"🔍 PROMT_FILES_DIR перед созданием Config: {os.environ.get('PROMT_FILES_DIR')}")
124
+ self.config = Config()
125
+ logger.info(f"✅ Конфигурация инициализирована")
126
+
127
+ async def _init_clients(self):
128
+ """Инициализация клиентов"""
129
+ logger.info(f"🔌 Инициализация клиентов для {self.bot_id}")
130
+
131
+ # OpenAI клиент
132
+ self.openai_client = OpenAIClient(
133
+ api_key=self.config.OPENAI_API_KEY,
134
+ model=self.config.OPENAI_MODEL,
135
+ max_tokens=self.config.OPENAI_MAX_TOKENS,
136
+ temperature=self.config.OPENAI_TEMPERATURE
137
+ )
138
+ logger.info(f"✅ OpenAI клиент инициализирован")
139
+
140
+ # Supabase клиент
141
+ self.supabase_client = SupabaseClient(
142
+ url=self.config.SUPABASE_URL,
143
+ key=self.config.SUPABASE_KEY,
144
+ bot_id=self.bot_id
145
+ )
146
+ await self.supabase_client.initialize()
147
+ logger.info(f"✅ Supabase клиент инициализирован")
148
+
149
+ async def _init_managers(self):
150
+ """Инициализация менеджеров"""
151
+ logger.info(f"👥 Инициализация менеджеров для {self.bot_id}")
152
+
153
+ # Admin Manager
154
+ self.admin_manager = AdminManager(self.config, self.supabase_client)
155
+ await self.admin_manager.sync_admins_from_config()
156
+ logger.info(f"✅ Admin Manager инициализирован")
157
+
158
+ # Conversation Manager
159
+ self.conversation_manager = ConversationManager(self.supabase_client, self.admin_manager)
160
+ logger.info(f"✅ Conversation Manager инициализирован")
161
+
162
+ # Prompt Loader
163
+ self.prompt_loader = PromptLoader(
164
+ prompts_dir=self.config.PROMT_FILES_DIR,
165
+ prompt_files=self.config.PROMPT_FILES
166
+ )
167
+ await self.prompt_loader.validate_prompts()
168
+ logger.info(f"✅ Prompt Loader инициализирован")
169
+
170
+ async def _update_prompts_with_tools(self):
171
+ """
172
+ Обновляет промпты информацией о доступных обработчиках событий
173
+ """
174
+ logger.info(f"🔧 Обновление промптов с информацией об обработчиках")
175
+
176
+ # Получаем информацию о доступных обработчиках
177
+ event_handlers_info = get_handlers_for_prompt()
178
+
179
+ # Если есть обработчики, добавляем их в системный промпт
180
+ if event_handlers_info:
181
+ # Сохраняем информацию о обработчиках для использования в handlers.py
182
+ self._tools_prompt = event_handlers_info
183
+
184
+ logger.info(f"✅ Промпты обновлены с информацией об обработчиках")
185
+ else:
186
+ self._tools_prompt = ""
187
+ logger.info(f"ℹ️ Нет зарегистрированных обработчиков")
188
+
189
+ def get_tools_prompt(self) -> str:
190
+ """Возвращает промпт с информацией об инструментах"""
191
+ return getattr(self, '_tools_prompt', '')
192
+
193
+ def get_status(self) -> Dict[str, Any]:
194
+ """Возвращает статус бота"""
195
+ return {
196
+ "bot_id": self.bot_id,
197
+ "initialized": self._initialized,
198
+ "config_dir": str(self.config_dir),
199
+ "components": {
200
+ "config": self.config is not None,
201
+ "openai_client": self.openai_client is not None,
202
+ "supabase_client": self.supabase_client is not None,
203
+ "conversation_manager": self.conversation_manager is not None,
204
+ "admin_manager": self.admin_manager is not None,
205
+ "prompt_loader": self.prompt_loader is not None
206
+ },
207
+ "tools": {
208
+ "event_handlers": len(get_handlers_for_prompt().split('\n')) if get_handlers_for_prompt() else 0
209
+ }
210
+ }
211
+
212
+ async def start(self):
213
+ """
214
+ Запускает бота (аналог main.py)
215
+ """
216
+ if not self._initialized:
217
+ raise RuntimeError(f"Бот {self.bot_id} не инициализирован. Вызовите build() сначала")
218
+
219
+ logger.info(f"🚀 Запускаем бота {self.bot_id}")
220
+
221
+ try:
222
+ # Импортируем необходимые компоненты
223
+ from aiogram import Bot, Dispatcher
224
+ from aiogram.fsm.storage.memory import MemoryStorage
225
+
226
+ # Создаем бота и диспетчер
227
+ bot = Bot(token=self.config.TELEGRAM_BOT_TOKEN)
228
+ storage = MemoryStorage()
229
+ dp = Dispatcher(storage=storage)
230
+
231
+ # Инициализируем базу данных
232
+ await self.supabase_client.initialize()
233
+
234
+ # Синхронизируем админов из конфигурации
235
+ await self.admin_manager.sync_admins_from_config()
236
+
237
+ # Проверяем доступность промптов
238
+ prompts_status = await self.prompt_loader.validate_prompts()
239
+ logger.info(f"Статус промптов: {prompts_status}")
240
+
241
+ # Устанавливаем глобальные переменные ДО импорта обработчиков
242
+ import sys
243
+ import importlib
244
+
245
+ # Устанавливаем глобальные переменные в модулях handlers и admin_logic
246
+ try:
247
+ handlers_module = importlib.import_module('handlers')
248
+ handlers_module.config = self.config
249
+ handlers_module.bot = bot
250
+ handlers_module.dp = dp
251
+ handlers_module.supabase_client = self.supabase_client
252
+ handlers_module.openai_client = self.openai_client
253
+ handlers_module.prompt_loader = self.prompt_loader
254
+ handlers_module.admin_manager = self.admin_manager
255
+ handlers_module.conversation_manager = self.conversation_manager
256
+ logger.info("✅ Глобальные переменные установлены в handlers")
257
+ except Exception as e:
258
+ logger.warning(f"⚠️ Не удалось установить глобальные переменные в handlers: {e}")
259
+
260
+ try:
261
+ admin_logic_module = importlib.import_module('admin_logic')
262
+ admin_logic_module.config = self.config
263
+ admin_logic_module.bot = bot
264
+ admin_logic_module.dp = dp
265
+ admin_logic_module.supabase_client = self.supabase_client
266
+ admin_logic_module.openai_client = self.openai_client
267
+ admin_logic_module.prompt_loader = self.prompt_loader
268
+ admin_logic_module.admin_manager = self.admin_manager
269
+ admin_logic_module.conversation_manager = self.conversation_manager
270
+ logger.info("✅ Глобальные переменные установлены в admin_logic")
271
+ except Exception as e:
272
+ logger.warning(f"⚠️ Не удалось установить глобальные переменные в admin_logic: {e}")
273
+
274
+ # Также устанавливаем в bot_utils
275
+ try:
276
+ bot_utils_module = importlib.import_module('bot_utils')
277
+ bot_utils_module.config = self.config
278
+ bot_utils_module.bot = bot
279
+ bot_utils_module.dp = dp
280
+ bot_utils_module.supabase_client = self.supabase_client
281
+ bot_utils_module.openai_client = self.openai_client
282
+ bot_utils_module.prompt_loader = self.prompt_loader
283
+ bot_utils_module.admin_manager = self.admin_manager
284
+ bot_utils_module.conversation_manager = self.conversation_manager
285
+ logger.info("✅ Глобальные переменные установлены в bot_utils")
286
+ except Exception as e:
287
+ logger.warning(f"⚠️ Не удалось установить глобальные переменные в bot_utils: {e}")
288
+
289
+ # Также устанавливаем в debug_routing
290
+ try:
291
+ debug_routing_module = importlib.import_module('debug_routing')
292
+ debug_routing_module.config = self.config
293
+ debug_routing_module.bot = bot
294
+ debug_routing_module.dp = dp
295
+ debug_routing_module.supabase_client = self.supabase_client
296
+ debug_routing_module.openai_client = self.openai_client
297
+ debug_routing_module.prompt_loader = self.prompt_loader
298
+ debug_routing_module.admin_manager = self.admin_manager
299
+ debug_routing_module.conversation_manager = self.conversation_manager
300
+ logger.info("✅ Глобальные переменные установлены в debug_routing")
301
+ except Exception as e:
302
+ logger.warning(f"⚠️ Не удалось установить глобальные переменные в debug_routing: {e}")
303
+
304
+ # Теперь импортируем и настраиваем обработчики
305
+ from ..integrations import setup_handlers, setup_admin_handlers, setup_utils_handlers
306
+
307
+ # Настраиваем обработчики запросов
308
+ setup_utils_handlers(dp) # Утилитарные команды (/status, /help)
309
+ setup_admin_handlers(dp) # Админские команды (/админ, /стат, /чат)
310
+ setup_handlers(dp) # Основные пользовательские обработчики
311
+
312
+ # Логируем информацию о запуске
313
+ logger.info(f"✅ Бот {self.bot_id} запущен и готов к работе!")
314
+ logger.info(f" 📊 Изоляция данных: bot_id = {self.config.BOT_ID}")
315
+ logger.info(f" 👑 Админов настроено: {len(self.config.ADMIN_TELEGRAM_IDS)}")
316
+ logger.info(f" 📝 Загружено промптов: {len(self.config.PROMPT_FILES)}")
317
+
318
+ # Четкое сообщение о запуске
319
+ print(f"\n🚀 БОТ {self.bot_id.upper()} УСПЕШНО ЗАПУЩЕН!")
320
+ print(f"📱 Telegram Bot ID: {self.config.BOT_ID}")
321
+ print(f"👑 Админов: {len(self.config.ADMIN_TELEGRAM_IDS)}")
322
+ print(f"📝 Промптов: {len(self.config.PROMPT_FILES)}")
323
+ print(f"🔄 Ожидание сообщений...")
324
+ print(f"⏹️ Для остановки нажмите Ctrl+C\n")
325
+
326
+ # Запуск polling (бесконечная обработка сообщений)
327
+ await dp.start_polling(bot)
328
+
329
+ except Exception as e:
330
+ logger.error(f"❌ Ошибка при запуске бота {self.bot_id}: {e}")
331
+ import traceback
332
+ logger.error(f"Стек ошибки: {traceback.format_exc()}")
333
+ raise
334
+ finally:
335
+ # Очистка ресурсов при завершении
336
+ if 'bot' in locals():
337
+ await bot.session.close()
@@ -0,0 +1,27 @@
1
+ """
2
+ Система событий для Smart Bot Factory
3
+ """
4
+
5
+ from .decorators import (
6
+ event_handler,
7
+ schedule_task,
8
+ get_event_handlers,
9
+ get_scheduled_tasks,
10
+ get_handlers_for_prompt,
11
+ execute_event_handler,
12
+ execute_scheduled_task,
13
+ schedule_task_for_later,
14
+ execute_scheduled_task_from_event
15
+ )
16
+
17
+ __all__ = [
18
+ 'event_handler',
19
+ 'schedule_task',
20
+ 'get_event_handlers',
21
+ 'get_scheduled_tasks',
22
+ 'get_handlers_for_prompt',
23
+ 'execute_event_handler',
24
+ 'execute_scheduled_task',
25
+ 'schedule_task_for_later',
26
+ 'execute_scheduled_task_from_event'
27
+ ]
@@ -0,0 +1,229 @@
1
+ """
2
+ Декораторы для обработчиков событий и временных задач
3
+ """
4
+
5
+ import asyncio
6
+ import logging
7
+ from typing import Callable, Any, Dict, Optional
8
+ from datetime import datetime, timedelta
9
+ from functools import wraps
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ # Глобальный реестр обработчиков событий
14
+ _event_handlers: Dict[str, Callable] = {}
15
+ _scheduled_tasks: Dict[str, Dict[str, Any]] = {}
16
+
17
+ def event_handler(event_type: str, description: str = ""):
18
+ """
19
+ Декоратор для регистрации обработчика события
20
+
21
+ Args:
22
+ event_type: Тип события (например, 'appointment_booking', 'phone_collection')
23
+ description: Описание что делает обработчик (для добавления в промпт)
24
+
25
+ Example:
26
+ @event_handler("appointment_booking", "Записывает пользователя на прием")
27
+ async def book_appointment(user_id: int, appointment_data: dict):
28
+ # Логика записи на прием
29
+ return {"status": "success", "appointment_id": "123"}
30
+ """
31
+ def decorator(func: Callable) -> Callable:
32
+ _event_handlers[event_type] = {
33
+ 'handler': func,
34
+ 'description': description,
35
+ 'name': func.__name__
36
+ }
37
+
38
+ logger.info(f"📝 Зарегистрирован обработчик события '{event_type}': {func.__name__}")
39
+
40
+ @wraps(func)
41
+ async def wrapper(*args, **kwargs):
42
+ try:
43
+ logger.info(f"🔧 Выполняем обработчик события '{event_type}'")
44
+ result = await func(*args, **kwargs)
45
+ logger.info(f"✅ Обработчик '{event_type}' выполнен успешно")
46
+ return result
47
+ except Exception as e:
48
+ logger.error(f"❌ Ошибка в обработчике '{event_type}': {e}")
49
+ raise
50
+
51
+ return wrapper
52
+ return decorator
53
+
54
+ def schedule_task(task_name: str, description: str = ""):
55
+ """
56
+ Декоратор для регистрации задачи, которую можно запланировать на время
57
+
58
+ Args:
59
+ task_name: Название задачи (например, 'send_reminder', 'follow_up')
60
+ description: Описание задачи (для добавления в промпт)
61
+
62
+ Example:
63
+ @schedule_task("send_reminder", "Отправляет напоминание пользователю")
64
+ async def send_reminder(user_id: int, message: str):
65
+ # Логика отправки напоминания
66
+ return {"status": "sent"}
67
+ """
68
+ def decorator(func: Callable) -> Callable:
69
+ _scheduled_tasks[task_name] = {
70
+ 'handler': func,
71
+ 'description': description,
72
+ 'name': func.__name__
73
+ }
74
+
75
+ logger.info(f"⏰ Зарегистрирована задача '{task_name}': {func.__name__}")
76
+
77
+ @wraps(func)
78
+ async def wrapper(*args, **kwargs):
79
+ try:
80
+ logger.info(f"⏰ Выполняем запланированную задачу '{task_name}'")
81
+ result = await func(*args, **kwargs)
82
+ logger.info(f"✅ Задача '{task_name}' выполнена успешно")
83
+ return result
84
+ except Exception as e:
85
+ logger.error(f"❌ Ошибка в задаче '{task_name}': {e}")
86
+ raise
87
+
88
+ return wrapper
89
+ return decorator
90
+
91
+ def get_event_handlers() -> Dict[str, Dict[str, Any]]:
92
+ """Возвращает все зарегистрированные обработчики событий"""
93
+ return _event_handlers.copy()
94
+
95
+ def get_scheduled_tasks() -> Dict[str, Dict[str, Any]]:
96
+ """Возвращает все зарегистрированные задачи"""
97
+ return _scheduled_tasks.copy()
98
+
99
+ def get_handlers_for_prompt() -> str:
100
+ """
101
+ Возвращает описание всех обработчиков для добавления в промпт
102
+ """
103
+ if not _event_handlers and not _scheduled_tasks:
104
+ return ""
105
+
106
+ prompt_parts = []
107
+
108
+ if _event_handlers:
109
+ prompt_parts.append("ДОСТУПНЫЕ ОБРАБОТЧИКИ СОБЫТИЙ:")
110
+ for event_type, handler_info in _event_handlers.items():
111
+ prompt_parts.append(f"- {event_type}: {handler_info['description']}")
112
+
113
+ if _scheduled_tasks:
114
+ prompt_parts.append("\nДОСТУПНЫЕ ЗАДАЧИ ДЛЯ ПЛАНИРОВАНИЯ:")
115
+ for task_name, task_info in _scheduled_tasks.items():
116
+ prompt_parts.append(f"- {task_name}: {task_info['description']}")
117
+
118
+ return "\n".join(prompt_parts)
119
+
120
+ async def execute_event_handler(event_type: str, *args, **kwargs) -> Any:
121
+ """Выполняет обработчик события по типу"""
122
+ if event_type not in _event_handlers:
123
+ raise ValueError(f"Обработчик события '{event_type}' не найден")
124
+
125
+ handler_info = _event_handlers[event_type]
126
+ return await handler_info['handler'](*args, **kwargs)
127
+
128
+ async def execute_scheduled_task(task_name: str, *args, **kwargs) -> Any:
129
+ """Выполняет запланированную задачу по имени"""
130
+ if task_name not in _scheduled_tasks:
131
+ raise ValueError(f"Задача '{task_name}' не найдена")
132
+
133
+ task_info = _scheduled_tasks[task_name]
134
+ return await task_info['handler'](*args, **kwargs)
135
+
136
+ async def schedule_task_for_later(task_name: str, delay_seconds: int, *args, **kwargs):
137
+ """
138
+ Планирует выполнение задачи через указанное время
139
+
140
+ Args:
141
+ task_name: Название задачи
142
+ delay_seconds: Задержка в секундах
143
+ *args, **kwargs: Аргументы для задачи
144
+ """
145
+ if task_name not in _scheduled_tasks:
146
+ raise ValueError(f"Задача '{task_name}' не найдена")
147
+
148
+ logger.info(f"⏰ Планируем задачу '{task_name}' через {delay_seconds} секунд")
149
+
150
+ async def delayed_task():
151
+ await asyncio.sleep(delay_seconds)
152
+ await execute_scheduled_task(task_name, *args, **kwargs)
153
+
154
+ # Запускаем задачу в фоне
155
+ asyncio.create_task(delayed_task())
156
+
157
+ return {
158
+ "status": "scheduled",
159
+ "task_name": task_name,
160
+ "delay_seconds": delay_seconds,
161
+ "scheduled_at": datetime.now().isoformat()
162
+ }
163
+
164
+ async def execute_scheduled_task_from_event(user_id: int, task_name: str, event_info: str):
165
+ """
166
+ Выполняет запланированную задачу на основе события от ИИ
167
+
168
+ Args:
169
+ user_id: ID пользователя
170
+ task_name: Название задачи
171
+ event_info: Информация от ИИ (содержит время и сообщение)
172
+ """
173
+ if task_name not in _scheduled_tasks:
174
+ raise ValueError(f"Задача '{task_name}' не найдена")
175
+
176
+ # Парсим event_info для извлечения времени и сообщения
177
+ # Формат: "через 2 часа: напомнить о приеме"
178
+ try:
179
+ if ":" in event_info:
180
+ time_part, message = event_info.split(":", 1)
181
+ time_part = time_part.strip()
182
+ message = message.strip()
183
+ else:
184
+ time_part = event_info
185
+ message = "Напоминание"
186
+
187
+ # Парсим время
188
+ delay_seconds = _parse_time_to_seconds(time_part)
189
+
190
+ # Планируем задачу
191
+ result = await schedule_task_for_later(task_name, delay_seconds, user_id, message)
192
+
193
+ return result
194
+
195
+ except Exception as e:
196
+ logger.error(f"Ошибка парсинга времени из event_info '{event_info}': {e}")
197
+ # Fallback - планируем через 1 час
198
+ return await schedule_task_for_later(task_name, 3600, user_id, event_info)
199
+
200
+ def _parse_time_to_seconds(time_str: str) -> int:
201
+ """
202
+ Парсит строку времени в секунды
203
+ Поддерживает форматы:
204
+ - "через 2 часа"
205
+ - "через 30 минут"
206
+ - "через 1 день"
207
+ - "через 2 часа 30 минут"
208
+ """
209
+ import re
210
+
211
+ time_str = time_str.lower().strip()
212
+
213
+ # Ищем часы
214
+ hours_match = re.search(r'(\d+)\s*час', time_str)
215
+ hours = int(hours_match.group(1)) if hours_match else 0
216
+
217
+ # Ищем минуты
218
+ minutes_match = re.search(r'(\d+)\s*минут', time_str)
219
+ minutes = int(minutes_match.group(1)) if minutes_match else 0
220
+
221
+ # Ищем дни
222
+ days_match = re.search(r'(\d+)\s*дн', time_str)
223
+ days = int(days_match.group(1)) if days_match else 0
224
+
225
+ # Конвертируем в секунды
226
+ total_seconds = (days * 24 * 3600) + (hours * 3600) + (minutes * 60)
227
+
228
+ # Минимум 1 минута
229
+ return max(total_seconds, 60)
@@ -0,0 +1,83 @@
1
+ """
2
+ Интеграции с существующими файлами проекта
3
+ """
4
+
5
+ # Импортируем существующие классы из корня проекта
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ # Добавляем корень проекта в путь для импорта существующих файлов
10
+ project_root = Path(__file__).parent.parent.parent.parent
11
+ if str(project_root) not in sys.path:
12
+ sys.path.insert(0, str(project_root))
13
+
14
+ try:
15
+ from openai_client import OpenAIClient
16
+ from supabase_client import SupabaseClient
17
+ from config import Config
18
+ from conversation_manager import ConversationManager
19
+ from admin_manager import AdminManager
20
+ from prompt_loader import PromptLoader
21
+ from bot_utils import send_message, parse_ai_response, process_events
22
+ from handlers import router, setup_handlers
23
+ from admin_logic import setup_admin_handlers
24
+ from bot_utils import setup_utils_handlers
25
+ except ImportError as e:
26
+ # Если файлы не найдены, создаем заглушки
27
+ print(f"⚠️ Предупреждение: не удалось импортировать существующие файлы: {e}")
28
+
29
+ class OpenAIClient:
30
+ def __init__(self, *args, **kwargs):
31
+ raise NotImplementedError("OpenAIClient не найден. Убедитесь, что openai_client.py существует в корне проекта")
32
+
33
+ class SupabaseClient:
34
+ def __init__(self, *args, **kwargs):
35
+ raise NotImplementedError("SupabaseClient не найден. Убедитесь, что supabase_client.py существует в корне проекта")
36
+
37
+ class Config:
38
+ def __init__(self, *args, **kwargs):
39
+ raise NotImplementedError("Config не найден. Убедитесь, что config.py существует в корне проекта")
40
+
41
+ class ConversationManager:
42
+ def __init__(self, *args, **kwargs):
43
+ raise NotImplementedError("ConversationManager не найден. Убедитесь, что conversation_manager.py существует в корне проекта")
44
+
45
+ class AdminManager:
46
+ def __init__(self, *args, **kwargs):
47
+ raise NotImplementedError("AdminManager не найден. Убедитесь, что admin_manager.py существует в корне проекта")
48
+
49
+ class PromptLoader:
50
+ def __init__(self, *args, **kwargs):
51
+ raise NotImplementedError("PromptLoader не найден. Убедитесь, что prompt_loader.py существует в корне проекта")
52
+
53
+ # Заглушки для функций
54
+ def send_message(*args, **kwargs):
55
+ raise NotImplementedError("send_message не найден. Убедитесь, что bot_utils.py существует в корне проекта")
56
+
57
+ def parse_ai_response(*args, **kwargs):
58
+ raise NotImplementedError("parse_ai_response не найден. Убедитесь, что bot_utils.py существует в корне проекта")
59
+
60
+ def process_events(*args, **kwargs):
61
+ raise NotImplementedError("process_events не найден. Убедитесь, что bot_utils.py существует в корне проекта")
62
+
63
+ # Заглушки для роутера
64
+ router = None
65
+ setup_handlers = None
66
+ setup_admin_handlers = None
67
+ setup_utils_handlers = None
68
+
69
+ __all__ = [
70
+ 'OpenAIClient',
71
+ 'SupabaseClient',
72
+ 'Config',
73
+ 'ConversationManager',
74
+ 'AdminManager',
75
+ 'PromptLoader',
76
+ 'send_message',
77
+ 'parse_ai_response',
78
+ 'process_events',
79
+ 'router',
80
+ 'setup_handlers',
81
+ 'setup_admin_handlers',
82
+ 'setup_utils_handlers'
83
+ ]