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.
- smart_bot_factory/core/router.py +6 -6
- smart_bot_factory/core/router_manager.py +11 -11
- smart_bot_factory/core/telegram_router.py +58 -0
- smart_bot_factory/creation/bot_builder.py +100 -6
- smart_bot_factory/handlers/handlers.py +17 -0
- smart_bot_factory/router/__init__.py +4 -2
- {smart_bot_factory-0.1.9.dist-info → smart_bot_factory-0.2.1.dist-info}/METADATA +210 -23
- {smart_bot_factory-0.1.9.dist-info → smart_bot_factory-0.2.1.dist-info}/RECORD +11 -10
- {smart_bot_factory-0.1.9.dist-info → smart_bot_factory-0.2.1.dist-info}/WHEEL +0 -0
- {smart_bot_factory-0.1.9.dist-info → smart_bot_factory-0.2.1.dist-info}/entry_points.txt +0 -0
- {smart_bot_factory-0.1.9.dist-info → smart_bot_factory-0.2.1.dist-info}/licenses/LICENSE +0 -0
smart_bot_factory/core/router.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
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
|
|
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"
|
|
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: '
|
|
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"
|
|
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
|
|
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[
|
|
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:
|
|
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:
|
|
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[
|
|
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
|
|
5
|
+
from ..core.router import EventRouter
|
|
6
|
+
from ..core.telegram_router import TelegramRouter
|
|
6
7
|
|
|
7
8
|
__all__ = [
|
|
8
|
-
'
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
535
|
+
main_router = EventRouter("main")
|
|
429
536
|
|
|
430
537
|
# handlers/admin.py
|
|
431
|
-
admin_router =
|
|
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
|
-
|
|
443
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
|
|
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=
|
|
32
|
-
smart_bot_factory/core/router_manager.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
51
|
-
smart_bot_factory-0.1.
|
|
52
|
-
smart_bot_factory-0.1.
|
|
53
|
-
smart_bot_factory-0.1.
|
|
54
|
-
smart_bot_factory-0.1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|