smart-bot-factory 0.1.9__py3-none-any.whl → 0.2.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.

Potentially problematic release.


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

@@ -1,5 +1,5 @@
1
1
  """
2
- Роутер для Smart Bot Factory - аналог aiogram Router
2
+ EventRouter для Smart Bot Factory - роутер для событий, задач и глобальных обработчиков
3
3
  """
4
4
 
5
5
  from typing import Dict, Any, Callable, Union
@@ -7,7 +7,7 @@ import logging
7
7
 
8
8
  logger = logging.getLogger(__name__)
9
9
 
10
- class Router:
10
+ class EventRouter:
11
11
  """
12
12
  Роутер для организации обработчиков событий, задач и глобальных обработчиков
13
13
  """
@@ -19,7 +19,7 @@ class Router:
19
19
  Args:
20
20
  name: Имя роутера для логирования
21
21
  """
22
- self.name = name or f"Router_{id(self)}"
22
+ self.name = name or f"EventRouter_{id(self)}"
23
23
  self._event_handlers: Dict[str, Dict[str, Any]] = {}
24
24
  self._scheduled_tasks: Dict[str, Dict[str, Any]] = {}
25
25
  self._global_handlers: Dict[str, Dict[str, Any]] = {}
@@ -183,12 +183,12 @@ class Router:
183
183
  all_handlers.update(self._global_handlers)
184
184
  return all_handlers
185
185
 
186
- def include_router(self, router: 'Router'):
186
+ def include_router(self, router: 'EventRouter'):
187
187
  """
188
188
  Включает другой роутер в текущий
189
189
 
190
190
  Args:
191
- router: Роутер для включения
191
+ router: EventRouter для включения
192
192
  """
193
193
  # Добавляем обработчики событий
194
194
  for event_type, handler_info in router.get_event_handlers().items():
@@ -211,4 +211,4 @@ class Router:
211
211
  logger.info(f"🔗 Роутер {self.name}: включен роутер {router.name}")
212
212
 
213
213
  def __repr__(self):
214
- return f"Router(name='{self.name}', events={len(self._event_handlers)}, tasks={len(self._scheduled_tasks)}, globals={len(self._global_handlers)})"
214
+ return f"EventRouter(name='{self.name}', events={len(self._event_handlers)}, tasks={len(self._scheduled_tasks)}, globals={len(self._global_handlers)})"
@@ -4,17 +4,17 @@
4
4
 
5
5
  from typing import Dict, List, Any, Optional
6
6
  import logging
7
- from .router import Router
7
+ from .router import EventRouter
8
8
 
9
9
  logger = logging.getLogger(__name__)
10
10
 
11
11
  class RouterManager:
12
12
  """
13
- Менеджер для управления роутерами и их обработчиками
13
+ Менеджер для управления роутерами событий и их обработчиками
14
14
  """
15
15
 
16
16
  def __init__(self):
17
- self._routers: List[Router] = []
17
+ self._routers: List[EventRouter] = []
18
18
  self._combined_handlers: Dict[str, Dict[str, Any]] = {
19
19
  'event_handlers': {},
20
20
  'scheduled_tasks': {},
@@ -23,12 +23,12 @@ class RouterManager:
23
23
 
24
24
  logger.info("🔄 Создан менеджер роутеров")
25
25
 
26
- def register_router(self, router: Router):
26
+ def register_router(self, router: EventRouter):
27
27
  """
28
- Регистрирует роутер в менеджере
28
+ Регистрирует роутер событий в менеджере
29
29
 
30
30
  Args:
31
- router: Роутер для регистрации
31
+ router: EventRouter для регистрации
32
32
  """
33
33
  if router not in self._routers:
34
34
  self._routers.append(router)
@@ -37,12 +37,12 @@ class RouterManager:
37
37
  else:
38
38
  logger.warning(f"⚠️ Роутер {router.name} уже зарегистрирован")
39
39
 
40
- def unregister_router(self, router: Router):
40
+ def unregister_router(self, router: EventRouter):
41
41
  """
42
- Отменяет регистрацию роутера
42
+ Отменяет регистрацию роутера событий
43
43
 
44
44
  Args:
45
- router: Роутер для отмены регистрации
45
+ router: EventRouter для отмены регистрации
46
46
  """
47
47
  if router in self._routers:
48
48
  self._routers.remove(router)
@@ -150,8 +150,8 @@ class RouterManager:
150
150
 
151
151
  return "\n".join(prompt_parts)
152
152
 
153
- def get_router_by_name(self, name: str) -> Optional[Router]:
154
- """Получает роутер по имени"""
153
+ def get_router_by_name(self, name: str) -> Optional[EventRouter]:
154
+ """Получает роутер событий по имени"""
155
155
  for router in self._routers:
156
156
  if router.name == name:
157
157
  return router
@@ -0,0 +1,58 @@
1
+ """
2
+ TelegramRouter - обертка над aiogram Router для обработки Telegram сообщений
3
+ """
4
+
5
+ from typing import Any
6
+ import logging
7
+ from aiogram import Router as AiogramRouter
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class TelegramRouter:
13
+ """
14
+ Обертка над aiogram Router для единообразного API библиотеки
15
+ Позволяет регистрировать обработчики команд, сообщений и callback'ов
16
+ """
17
+
18
+ def __init__(self, name: str = None):
19
+ """
20
+ Инициализация Telegram роутера
21
+
22
+ Args:
23
+ name: Имя роутера для логирования
24
+ """
25
+ self.name = name or f"TelegramRouter_{id(self)}"
26
+ self._router = AiogramRouter(name=self.name)
27
+
28
+ logger.info(f"📱 Создан TelegramRouter: {self.name}")
29
+
30
+ @property
31
+ def router(self) -> AiogramRouter:
32
+ """
33
+ Возвращает внутренний aiogram Router
34
+
35
+ Используйте этот роутер для прямой работы с aiogram API:
36
+
37
+ Example:
38
+ telegram_router = TelegramRouter("my_router")
39
+
40
+ # Регистрация команды
41
+ @telegram_router.router.message(Command("start"))
42
+ async def start_handler(message: Message):
43
+ await message.answer("Hello!")
44
+
45
+ # Регистрация callback
46
+ @telegram_router.router.callback_query(F.data.startswith("buy_"))
47
+ async def buy_handler(callback: CallbackQuery):
48
+ await callback.answer("Покупка...")
49
+ """
50
+ return self._router
51
+
52
+ def get_aiogram_router(self) -> AiogramRouter:
53
+ """Получает внутренний aiogram Router (алиас для .router)"""
54
+ return self._router
55
+
56
+ def __repr__(self):
57
+ return f"TelegramRouter(name='{self.name}')"
58
+
@@ -5,7 +5,7 @@
5
5
  import os
6
6
  import logging
7
7
  from pathlib import Path
8
- from typing import Optional, Dict, Any
8
+ from typing import Optional, Dict, Any, List
9
9
 
10
10
  from ..config import Config
11
11
  from ..integrations.openai_client import OpenAIClient
@@ -45,6 +45,8 @@ class BotBuilder:
45
45
  self.analytics_manager: Optional[AnalyticsManager] = None
46
46
  self.prompt_loader: Optional[PromptLoader] = None
47
47
  self.router_manager: Optional[RouterManager] = None
48
+ self._telegram_routers: List = [] # Список Telegram роутеров
49
+ self._start_handlers: List = [] # Список обработчиков on_start
48
50
 
49
51
  # Флаги инициализации
50
52
  self._initialized = False
@@ -258,10 +260,10 @@ class BotBuilder:
258
260
 
259
261
  def register_router(self, router):
260
262
  """
261
- Регистрирует роутер в менеджере роутеров
263
+ Регистрирует роутер событий в менеджере роутеров
262
264
 
263
265
  Args:
264
- router: Роутер для регистрации
266
+ router: EventRouter для регистрации
265
267
  """
266
268
  # Если RouterManager еще не инициализирован, создаем его
267
269
  if not self.router_manager:
@@ -270,10 +272,94 @@ class BotBuilder:
270
272
  logger.info(f"✅ Router Manager создан для регистрации роутера '{router.name}'")
271
273
 
272
274
  self.router_manager.register_router(router)
273
- logger.info(f"✅ Роутер '{router.name}' зарегистрирован в боте {self.bot_id}")
275
+ logger.info(f"✅ Роутер событий '{router.name}' зарегистрирован в боте {self.bot_id}")
276
+
277
+ def register_routers(self, *event_routers):
278
+ """
279
+ Регистрирует несколько роутеров событий одновременно
280
+
281
+ Args:
282
+ *event_routers: Произвольное количество EventRouter
283
+
284
+ Example:
285
+ bot_builder.register_routers(event_router1, event_router2, event_router3)
286
+ """
287
+ if not event_routers:
288
+ logger.warning("⚠️ register_routers вызван без аргументов")
289
+ return
290
+
291
+ for router in event_routers:
292
+ self.register_router(router)
293
+
294
+ logger.info(f"✅ Зарегистрировано {len(event_routers)} роутеров событий")
295
+
296
+ def register_telegram_router(self, telegram_router):
297
+ """
298
+ Регистрирует Telegram роутер для обработки команд и сообщений
299
+
300
+ Args:
301
+ telegram_router: TelegramRouter для регистрации
302
+ """
303
+ from ..core.telegram_router import TelegramRouter
304
+
305
+ if not isinstance(telegram_router, TelegramRouter):
306
+ raise TypeError(f"Ожидается TelegramRouter, получен {type(telegram_router)}")
307
+
308
+ self._telegram_routers.append(telegram_router)
309
+ logger.info(f"✅ Telegram роутер '{telegram_router.name}' зарегистрирован в боте {self.bot_id}")
310
+
311
+ def register_telegram_routers(self, *telegram_routers):
312
+ """
313
+ Регистрирует несколько Telegram роутеров одновременно
314
+
315
+ Args:
316
+ *telegram_routers: Произвольное количество TelegramRouter
317
+
318
+ Example:
319
+ bot_builder.register_telegram_routers(telegram_router1, telegram_router2)
320
+ """
321
+ if not telegram_routers:
322
+ logger.warning("⚠️ register_telegram_routers вызван без аргументов")
323
+ return
324
+
325
+ for router in telegram_routers:
326
+ self.register_telegram_router(router)
327
+
328
+ logger.info(f"✅ Зарегистрировано {len(telegram_routers)} Telegram роутеров")
329
+
330
+ def on_start(self, handler):
331
+ """
332
+ Регистрирует обработчик, который вызывается после стандартной логики /start
333
+
334
+ Обработчик получает доступ к:
335
+ - user_id: int - ID пользователя Telegram
336
+ - session_id: str - ID созданной сессии
337
+ - message: Message - Объект сообщения от aiogram
338
+ - state: FSMContext - Контекст состояния
339
+
340
+ Args:
341
+ handler: Async функция с сигнатурой:
342
+ async def handler(user_id: int, session_id: str, message: Message, state: FSMContext)
343
+
344
+ Example:
345
+ @bot_builder.on_start
346
+ async def my_start_handler(user_id, session_id, message, state):
347
+ keyboard = InlineKeyboardMarkup(...)
348
+ await message.answer("Выберите действие:", reply_markup=keyboard)
349
+ """
350
+ if not callable(handler):
351
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
352
+
353
+ self._start_handlers.append(handler)
354
+ logger.info(f"✅ Зарегистрирован обработчик on_start: {handler.__name__}")
355
+ return handler # Возвращаем handler для использования как декоратор
356
+
357
+ def get_start_handlers(self) -> List:
358
+ """Получает список обработчиков on_start"""
359
+ return self._start_handlers.copy()
274
360
 
275
361
  def get_router_manager(self) -> RouterManager:
276
- """Получает менеджер роутеров"""
362
+ """Получает менеджер роутеров событий"""
277
363
  return self.router_manager
278
364
 
279
365
  async def start(self):
@@ -320,6 +406,7 @@ class BotBuilder:
320
406
  handlers_module.admin_manager = self.admin_manager
321
407
  handlers_module.analytics_manager = self.analytics_manager
322
408
  handlers_module.conversation_manager = self.conversation_manager
409
+ handlers_module.start_handlers = self._start_handlers # Передаем обработчики on_start
323
410
  logger.info("✅ Глобальные переменные установлены в handlers")
324
411
  except Exception as e:
325
412
  logger.warning(f"⚠️ Не удалось установить глобальные переменные в handlers: {e}")
@@ -375,7 +462,14 @@ class BotBuilder:
375
462
  from ..admin.admin_logic import setup_admin_handlers
376
463
  from ..core.bot_utils import setup_utils_handlers
377
464
 
378
- # Настраиваем обработчики запросов
465
+ # Подключаем пользовательские Telegram роутеры ПЕРВЫМИ (высший приоритет)
466
+ if self._telegram_routers:
467
+ logger.info(f"🔗 Подключаем {len(self._telegram_routers)} пользовательских Telegram роутеров")
468
+ for telegram_router in self._telegram_routers:
469
+ dp.include_router(telegram_router.get_aiogram_router())
470
+ logger.info(f"✅ Подключен Telegram роутер: {telegram_router.name}")
471
+
472
+ # Настраиваем стандартные обработчики (меньший приоритет)
379
473
  setup_utils_handlers(dp) # Утилитарные команды (/status, /help)
380
474
  setup_admin_handlers(dp) # Админские команды (/админ, /стат, /чат)
381
475
  setup_handlers(dp) # Основные пользовательские обработчики
@@ -277,6 +277,23 @@ async def user_start_handler(message: Message, state: FSMContext):
277
277
 
278
278
  logging.info(f"✅ Приветственное сообщение успешно сохранено в БД для сессии {session_id}")
279
279
 
280
+ # ВЫЗЫВАЕМ ПОЛЬЗОВАТЕЛЬСКИЕ ОБРАБОТЧИКИ on_start
281
+ start_handlers = get_global_var('start_handlers')
282
+ if start_handlers:
283
+ logger.info(f"🔔 Вызов {len(start_handlers)} пользовательских обработчиков on_start")
284
+ for handler in start_handlers:
285
+ try:
286
+ await handler(
287
+ user_id=message.from_user.id,
288
+ session_id=session_id,
289
+ message=message,
290
+ state=state
291
+ )
292
+ logger.info(f"✅ Обработчик on_start '{handler.__name__}' выполнен успешно")
293
+ except Exception as handler_error:
294
+ logger.error(f"❌ Ошибка в обработчике on_start '{handler.__name__}': {handler_error}")
295
+ # Продолжаем выполнение остальных обработчиков
296
+
280
297
  except Exception as e:
281
298
  logger.error(f"Ошибка при обработке user /start: {e}")
282
299
  await send_message(message, "Произошла ошибка при инициализации. Попробуйте позже.")
@@ -2,8 +2,10 @@
2
2
  Router модули smart_bot_factory
3
3
  """
4
4
 
5
- from ..core.router import Router
5
+ from ..core.router import EventRouter
6
+ from ..core.telegram_router import TelegramRouter
6
7
 
7
8
  __all__ = [
8
- 'Router'
9
+ 'EventRouter', # Роутер для событий
10
+ 'TelegramRouter', # Роутер для Telegram
9
11
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smart-bot-factory
3
- Version: 0.1.9
3
+ Version: 0.2.1
4
4
  Summary: Библиотека для создания умных чат-ботов
5
5
  Author-email: Kopatych <kopatych@example.com>
6
6
  License: MIT
@@ -163,18 +163,24 @@ sbf run my-bot
163
163
 
164
164
  ### Router System
165
165
 
166
- Smart Bot Factory использует систему роутеров для организации обработчиков:
166
+ Smart Bot Factory использует **два типа роутеров** для организации обработчиков:
167
+
168
+ 1. **EventRouter** - для бизнес-логики (события, задачи, глобальные обработчики)
169
+ 2. **TelegramRouter** - для Telegram команд, сообщений и callback'ов
167
170
 
168
171
  ```python
169
- from smart_bot_factory.router import Router
172
+ from smart_bot_factory.router import EventRouter, TelegramRouter
170
173
  from smart_bot_factory.message import send_message_by_human
171
174
  from smart_bot_factory.creation import BotBuilder
175
+ from aiogram import F
176
+ from aiogram.filters import Command
177
+ from aiogram.types import Message
178
+ from aiogram.fsm.context import FSMContext
172
179
 
173
- # Создаем роутер
174
- router = Router("my_bot_handlers")
180
+ # EventRouter - для бизнес-логики
181
+ event_router = EventRouter("my_bot_events")
175
182
 
176
- # Регистрируем обработчики
177
- @router.event_handler("appointment_booking", notify=True)
183
+ @event_router.event_handler("appointment_booking", notify=True)
178
184
  async def handle_booking(user_id: int, event_data: str):
179
185
  """Обработчик записи на прием"""
180
186
  await send_message_by_human(
@@ -183,15 +189,114 @@ async def handle_booking(user_id: int, event_data: str):
183
189
  )
184
190
  return {"status": "success"}
185
191
 
192
+ # TelegramRouter - для Telegram команд и сообщений
193
+ telegram_router = TelegramRouter("my_bot_telegram")
194
+
195
+ @telegram_router.router.message(Command("price", "цена"))
196
+ async def handle_price(message: Message, state: FSMContext):
197
+ """Обработчик команды /price"""
198
+ await message.answer("💰 Наши цены...")
199
+
200
+ @telegram_router.router.message(F.text.contains("помощь"))
201
+ async def handle_help(message: Message, state: FSMContext):
202
+ """Обработчик запросов помощи"""
203
+ await message.answer("📖 Чем могу помочь?")
204
+
186
205
  # Запуск бота
187
206
  async def main():
188
207
  bot = BotBuilder("my-bot")
189
- bot.register_router(router)
208
+
209
+ # Регистрируем роутеры (можно по одному или несколько сразу)
210
+ bot.register_routers(event_router) # EventRouter
211
+ bot.register_telegram_routers(telegram_router) # TelegramRouter
212
+
190
213
  await bot.build()
191
214
  await bot.start()
192
215
  ```
193
216
 
194
- ### Типы обработчиков
217
+ ### TelegramRouter - Обработчики Telegram
218
+
219
+ **TelegramRouter** позволяет добавлять пользовательские команды и обработчики сообщений в Telegram бота, используя стандартный aiogram API:
220
+
221
+ #### Команды
222
+
223
+ ```python
224
+ from smart_bot_factory.router import TelegramRouter
225
+ from aiogram.filters import Command
226
+ from aiogram.types import Message
227
+ from aiogram.fsm.context import FSMContext
228
+
229
+ telegram_router = TelegramRouter("my_commands")
230
+
231
+ @telegram_router.router.message(Command("start", "старт"))
232
+ async def cmd_start(message: Message, state: FSMContext):
233
+ """Обработчик команды /start"""
234
+ await message.answer("👋 Привет!")
235
+
236
+ @telegram_router.router.message(Command("price"))
237
+ async def cmd_price(message: Message, state: FSMContext):
238
+ """Обработчик команды /price"""
239
+ await message.answer("💰 Цены:\n1. Базовый - 1000₽\n2. Премиум - 5000₽")
240
+ ```
241
+
242
+ #### Фильтры по тексту
243
+
244
+ ```python
245
+ from aiogram import F
246
+
247
+ @telegram_router.router.message(F.text.lower().contains("цена"))
248
+ async def handle_price_question(message: Message, state: FSMContext):
249
+ """Когда пользователь спрашивает о цене"""
250
+ await message.answer("💡 Используйте /price для просмотра цен")
251
+
252
+ @telegram_router.router.message(F.text.startswith("!"))
253
+ async def handle_commands(message: Message, state: FSMContext):
254
+ """Обработка кастомных команд с !"""
255
+ command = message.text[1:]
256
+ await message.answer(f"Выполняю команду: {command}")
257
+ ```
258
+
259
+ #### Callback Query
260
+
261
+ ```python
262
+ from aiogram.types import CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
263
+
264
+ @telegram_router.router.callback_query(F.data.startswith("buy_"))
265
+ async def handle_buy(callback: CallbackQuery, state: FSMContext):
266
+ """Обработка покупки"""
267
+ product_id = callback.data.split("_")[1]
268
+ await callback.answer("Оформляем...")
269
+ await callback.message.answer(f"✅ Товар {product_id} добавлен в корзину")
270
+
271
+ @telegram_router.router.message(Command("catalog"))
272
+ async def show_catalog(message: Message, state: FSMContext):
273
+ """Показывает каталог с кнопками"""
274
+ keyboard = InlineKeyboardMarkup(inline_keyboard=[
275
+ [InlineKeyboardButton(text="Купить товар 1", callback_data="buy_1")],
276
+ [InlineKeyboardButton(text="Купить товар 2", callback_data="buy_2")]
277
+ ])
278
+ await message.answer("🛍️ Каталог товаров:", reply_markup=keyboard)
279
+ ```
280
+
281
+ #### Регистрация нескольких роутеров
282
+
283
+ ```python
284
+ # Создаем несколько TelegramRouter для разных модулей
285
+ commands_router = TelegramRouter("commands")
286
+ admin_router = TelegramRouter("admin_commands")
287
+ callbacks_router = TelegramRouter("callbacks")
288
+
289
+ # Регистрируем все сразу
290
+ bot_builder.register_telegram_routers(
291
+ commands_router,
292
+ admin_router,
293
+ callbacks_router
294
+ )
295
+ ```
296
+
297
+ **Важно:** TelegramRouter - это обертка над aiogram Router, предоставляющая доступ к полному функционалу aiogram через свойство `.router`.
298
+
299
+ ### EventRouter - Типы обработчиков событий
195
300
 
196
301
  #### 1. Event Handlers - Обработчики событий
197
302
 
@@ -423,24 +528,81 @@ ADMIN_SESSION_TIMEOUT_MINUTES=30
423
528
 
424
529
  ### Множественные роутеры
425
530
 
531
+ #### Регистрация нескольких EventRouter
532
+
426
533
  ```python
427
534
  # handlers/main.py
428
- main_router = Router("main")
535
+ main_router = EventRouter("main")
429
536
 
430
537
  # handlers/admin.py
431
- admin_router = Router("admin")
538
+ admin_router = EventRouter("admin")
539
+
540
+ # handlers/payments.py
541
+ payments_router = EventRouter("payments")
432
542
 
433
543
  # app.py
434
544
  bot = BotBuilder("my-bot")
545
+
546
+ # Можно по одному
435
547
  bot.register_router(main_router)
436
548
  bot.register_router(admin_router)
549
+
550
+ # Или все сразу
551
+ bot.register_routers(main_router, admin_router, payments_router)
437
552
  ```
438
553
 
439
- ### Вложенные роутеры
554
+ #### Регистрация нескольких TelegramRouter
440
555
 
441
556
  ```python
442
- main_router = Router("main")
443
- payments_router = Router("payments")
557
+ # telegram/commands.py
558
+ commands_router = TelegramRouter("commands")
559
+
560
+ @commands_router.router.message(Command("start"))
561
+ async def start(message: Message, state: FSMContext):
562
+ await message.answer("Привет!")
563
+
564
+ # telegram/callbacks.py
565
+ callbacks_router = TelegramRouter("callbacks")
566
+
567
+ @callbacks_router.router.callback_query(F.data.startswith("action_"))
568
+ async def handle_action(callback: CallbackQuery, state: FSMContext):
569
+ await callback.answer("Выполнено!")
570
+
571
+ # app.py
572
+ bot = BotBuilder("my-bot")
573
+
574
+ # Регистрируем несколько Telegram роутеров сразу
575
+ bot.register_telegram_routers(commands_router, callbacks_router)
576
+ ```
577
+
578
+ #### Комбинирование EventRouter и TelegramRouter
579
+
580
+ ```python
581
+ # Создаем роутеры для разных целей
582
+ event_router = EventRouter("events")
583
+ telegram_router = TelegramRouter("telegram_handlers")
584
+
585
+ # EventRouter - бизнес-логика
586
+ @event_router.event_handler("payment_success")
587
+ async def handle_payment(user_id: int, event_data: str):
588
+ await send_message_by_human(user_id, "✅ Оплата получена!")
589
+ return {"status": "success"}
590
+
591
+ # TelegramRouter - пользовательские команды
592
+ @telegram_router.router.message(Command("balance"))
593
+ async def check_balance(message: Message, state: FSMContext):
594
+ await message.answer("💰 Ваш баланс: 1000₽")
595
+
596
+ # Регистрируем оба типа роутеров
597
+ bot_builder.register_routers(event_router)
598
+ bot_builder.register_telegram_routers(telegram_router)
599
+ ```
600
+
601
+ ### Вложенные роутеры (EventRouter)
602
+
603
+ ```python
604
+ main_router = EventRouter("main")
605
+ payments_router = EventRouter("payments")
444
606
 
445
607
  # Включаем роутер платежей в основной
446
608
  main_router.include_router(payments_router)
@@ -486,17 +648,38 @@ my-project/
486
648
  ```python
487
649
  import asyncio
488
650
 
489
- from smart_bot_factory.router import Router
651
+ from smart_bot_factory.router import EventRouter, TelegramRouter
490
652
  from smart_bot_factory.message import send_message_by_human, send_message_to_users_by_stage
491
653
  from smart_bot_factory.supabase import SupabaseClient
492
654
  from smart_bot_factory.creation import BotBuilder
655
+ from aiogram import F
656
+ from aiogram.filters import Command
657
+ from aiogram.types import Message
658
+ from aiogram.fsm.context import FSMContext
493
659
 
494
660
  # Инициализация
495
- router = Router("medical_bot")
661
+ event_router = EventRouter("medical_bot_events")
662
+ telegram_router = TelegramRouter("medical_bot_telegram")
496
663
  supabase_client = SupabaseClient("medical-bot")
497
664
 
498
- # Обработчик записи на прием
499
- @router.event_handler("appointment_booking", notify=True)
665
+ # Пользовательские команды (TelegramRouter)
666
+ @telegram_router.router.message(Command("appointment", "запись"))
667
+ async def cmd_appointment(message: Message, state: FSMContext):
668
+ """Команда для записи на прием"""
669
+ await message.answer(
670
+ "📅 Для записи на прием укажите:\n"
671
+ "- Ваше имя\n"
672
+ "- Телефон\n"
673
+ "- Желаемая дата и время"
674
+ )
675
+
676
+ @telegram_router.router.message(F.text.lower().contains("цена"))
677
+ async def handle_price_question(message: Message, state: FSMContext):
678
+ """Вопросы о ценах"""
679
+ await message.answer("💰 Используйте /appointment для записи и уточнения стоимости")
680
+
681
+ # Обработчик записи на прием (EventRouter)
682
+ @event_router.event_handler("appointment_booking", notify=True)
500
683
  async def handle_appointment(user_id: int, event_data: str):
501
684
  """Обрабатывает запись на прием к врачу"""
502
685
  # event_data: "имя: Иван, телефон: +79991234567, дата: 2025-10-15, время: 14:00"
@@ -508,8 +691,8 @@ async def handle_appointment(user_id: int, event_data: str):
508
691
 
509
692
  return {"status": "success", "data": event_data}
510
693
 
511
- # Напоминание за 2 часа до приема
512
- @router.schedule_task(
694
+ # Напоминание за 2 часа до приема (EventRouter)
695
+ @event_router.schedule_task(
513
696
  "appointment_reminder",
514
697
  delay="2h",
515
698
  event_type="appointment_booking"
@@ -522,8 +705,8 @@ async def remind_before_appointment(user_id: int, reminder_text: str):
522
705
  )
523
706
  return {"status": "sent"}
524
707
 
525
- # Ночной дайджест для всех
526
- @router.global_handler("daily_digest", delay="24h")
708
+ # Ночной дайджест для всех (EventRouter)
709
+ @event_router.global_handler("daily_digest", delay="24h")
527
710
  async def send_daily_digest(digest_text: str):
528
711
  """Отправляет ежедневный дайджест всем активным пользователям"""
529
712
  await send_message_to_users_by_stage(
@@ -535,7 +718,11 @@ async def send_daily_digest(digest_text: str):
535
718
  # Запуск
536
719
  async def main():
537
720
  bot = BotBuilder("medical-bot")
538
- bot.register_router(router)
721
+
722
+ # Регистрируем роутеры
723
+ bot.register_routers(event_router) # EventRouter
724
+ bot.register_telegram_routers(telegram_router) # TelegramRouter
725
+
539
726
  await bot.build()
540
727
  await bot.start()
541
728
 
@@ -28,27 +28,28 @@ smart_bot_factory/core/bot_utils.py,sha256=XmwQ31LOpE_Wudx4OO4tlnVwse3YagakwpgN2
28
28
  smart_bot_factory/core/conversation_manager.py,sha256=eoHL7MCEz68DRvTVwRwZgf2PWwGv4T6J9D-I-thETi8,28289
29
29
  smart_bot_factory/core/decorators.py,sha256=xQCtr5SOLqqmEzaxrDf_sfxWQouIG7riI6Sa_jqGlcg,68647
30
30
  smart_bot_factory/core/message_sender.py,sha256=7uZlMw7bdLb_2eokANUxyP4HomVQV7T2mrl4SBTfqNM,19134
31
- smart_bot_factory/core/router.py,sha256=Ly2Kj6T9stu2UmE__3CvMvN8Rl1Ipo-SrsbTsiPSssA,11469
32
- smart_bot_factory/core/router_manager.py,sha256=qncd57qhqXBV42FBEQ8Wl7aar8S7WZnfSC4EQ1BIr0w,9617
31
+ smart_bot_factory/core/router.py,sha256=o-AzLarBgYbXq7OeeXQEfa6XFqcAtLKqf5-3Do79Boo,11555
32
+ smart_bot_factory/core/router_manager.py,sha256=dUwesog-oHk1U2EDdS8p0e4MTSkwtx5_qXn6nrJ9l9I,9700
33
33
  smart_bot_factory/core/states.py,sha256=AOc19_yAsDW_8md-2oiowjBhuW3bwcsmMxszCXWZZTQ,355
34
+ smart_bot_factory/core/telegram_router.py,sha256=LcPLOd87Y4Y4YN6TBXVAtmpSp8gAK2otgMI4YS5f5tk,2091
34
35
  smart_bot_factory/creation/__init__.py,sha256=IgDk8GDS3pg7Pw_Et41J33ZmeZIU5dRwQdTmYKXfJfE,128
35
- smart_bot_factory/creation/bot_builder.py,sha256=c3maqY9qJBsRJO3kI4iko2oKf0JrjECUV_XRrImlgQQ,22169
36
+ smart_bot_factory/creation/bot_builder.py,sha256=RhnnZZhNvJC-nKTly5VvoxpXBucKFoXUl4e5gfBk7TI,27057
36
37
  smart_bot_factory/creation/bot_testing.py,sha256=JDWXyJfZmbgo-DLdAPk8Sd9FiehtHHa4sLD17lBrTOc,55669
37
38
  smart_bot_factory/database/database_structure.sql,sha256=26gFtMC2jdQGQF7Zb_F4Br56rMd4hUDTk9FkNZYneLo,2789
38
39
  smart_bot_factory/database/schema.sql,sha256=-6kOmA9QnSkUtmGI2iQRbTvbdiqOhEOQcuz1lJn79mU,28059
39
40
  smart_bot_factory/event/__init__.py,sha256=hPL449RULIOB-OXv1ZbGNiHctAYaOMUqhSWGPrDHYBM,212
40
- smart_bot_factory/handlers/handlers.py,sha256=YH8xG0tDcb7uxZXI4socXURzc-y57_FEQ6GqTgYcM5Q,37603
41
+ smart_bot_factory/handlers/handlers.py,sha256=1_0CAbedbmdSBeWPF9KR97RM6zNWPv56wR9EdrfPtdo,38630
41
42
  smart_bot_factory/integrations/openai_client.py,sha256=aMcDrKO0GEx3ZSVEOGDeDtFCDWSXs6biUfgrbRK8yTU,23180
42
43
  smart_bot_factory/integrations/supabase_client.py,sha256=AfALLZdDYeMWHLJw6POTGiBd-sH3i03oT6tT7m9C28I,44644
43
44
  smart_bot_factory/message/__init__.py,sha256=6QvjdfF99venyDB9udZv9WDNjIHJLNuaVhYdTK3a44A,282
44
- smart_bot_factory/router/__init__.py,sha256=fLXSXfa-MaI9ickXoqha3PqpjxunsNLyVNlHIoIbr1c,115
45
+ smart_bot_factory/router/__init__.py,sha256=QrfO5u8H2uVzWGMtBvNKunsJAv7UrKtvt2f_D5xSFWE,270
45
46
  smart_bot_factory/supabase/__init__.py,sha256=XmZP6yM9ffERM5ddAWyJnrNzEhCYtMu3AcjVCi1rOf8,179
46
47
  smart_bot_factory/supabase/client.py,sha256=8_-I3kxZQlKQElI4cTUjNGYcqlyIyEkSrUZaP0nfNNU,26044
47
48
  smart_bot_factory/utils/__init__.py,sha256=5zNjw491bj5VkOhoEAwh2hjmv8nldyDOTrG7pbGpz6A,285
48
49
  smart_bot_factory/utils/debug_routing.py,sha256=BOoDhKBg7UXe5uHQxRk3TSfPfLPOFqt0N7lAo6kjCOo,4719
49
50
  smart_bot_factory/utils/prompt_loader.py,sha256=JSn7CsWnToSbHYtURdeuZn7ectyDqQGrPGHN2ixIGkw,19930
50
- smart_bot_factory-0.1.9.dist-info/METADATA,sha256=ViqO05vBPd-Qz6kQ2imVmUqePKRGUaOeyBCGpxG4VUk,20494
51
- smart_bot_factory-0.1.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
52
- smart_bot_factory-0.1.9.dist-info/entry_points.txt,sha256=ybKEAI0WSb7WoRiey7QE-HHfn88UGV7nxLDxXq7b7SU,50
53
- smart_bot_factory-0.1.9.dist-info/licenses/LICENSE,sha256=OrK3cwdUTzNzIhJvSPtJaVMoYIyC_sSx5EFE_FDMvGs,1092
54
- smart_bot_factory-0.1.9.dist-info/RECORD,,
51
+ smart_bot_factory-0.2.1.dist-info/METADATA,sha256=wj1v5p2joJlA_u9LcfBFPFjPqBfxvFu1BxUE389uwDA,28224
52
+ smart_bot_factory-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
53
+ smart_bot_factory-0.2.1.dist-info/entry_points.txt,sha256=ybKEAI0WSb7WoRiey7QE-HHfn88UGV7nxLDxXq7b7SU,50
54
+ smart_bot_factory-0.2.1.dist-info/licenses/LICENSE,sha256=OrK3cwdUTzNzIhJvSPtJaVMoYIyC_sSx5EFE_FDMvGs,1092
55
+ smart_bot_factory-0.2.1.dist-info/RECORD,,