smart-bot-factory 0.1.8__py3-none-any.whl → 0.2.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.
- smart_bot_factory/core/decorators.py +1 -1
- 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 +67 -6
- smart_bot_factory/integrations/supabase_client.py +8 -18
- smart_bot_factory/router/__init__.py +4 -2
- smart_bot_factory-0.2.0.dist-info/METADATA +789 -0
- {smart_bot_factory-0.1.8.dist-info → smart_bot_factory-0.2.0.dist-info}/RECORD +12 -11
- smart_bot_factory-0.1.8.dist-info/METADATA +0 -126
- {smart_bot_factory-0.1.8.dist-info → smart_bot_factory-0.2.0.dist-info}/WHEEL +0 -0
- {smart_bot_factory-0.1.8.dist-info → smart_bot_factory-0.2.0.dist-info}/entry_points.txt +0 -0
- {smart_bot_factory-0.1.8.dist-info → smart_bot_factory-0.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1153,7 +1153,7 @@ async def background_event_processor():
|
|
|
1153
1153
|
logger.error(f"❌ Ошибка обработки события {event['id']}: {e}")
|
|
1154
1154
|
await update_event_result(event['id'], 'failed', None, str(e))
|
|
1155
1155
|
|
|
1156
|
-
await asyncio.sleep(
|
|
1156
|
+
await asyncio.sleep(60)
|
|
1157
1157
|
|
|
1158
1158
|
except Exception as e:
|
|
1159
1159
|
logger.error(f"❌ Ошибка в фоновом процессоре: {e}")
|
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,7 @@ 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 роутеров
|
|
48
49
|
|
|
49
50
|
# Флаги инициализации
|
|
50
51
|
self._initialized = False
|
|
@@ -258,10 +259,10 @@ class BotBuilder:
|
|
|
258
259
|
|
|
259
260
|
def register_router(self, router):
|
|
260
261
|
"""
|
|
261
|
-
Регистрирует роутер в менеджере роутеров
|
|
262
|
+
Регистрирует роутер событий в менеджере роутеров
|
|
262
263
|
|
|
263
264
|
Args:
|
|
264
|
-
router:
|
|
265
|
+
router: EventRouter для регистрации
|
|
265
266
|
"""
|
|
266
267
|
# Если RouterManager еще не инициализирован, создаем его
|
|
267
268
|
if not self.router_manager:
|
|
@@ -270,10 +271,63 @@ class BotBuilder:
|
|
|
270
271
|
logger.info(f"✅ Router Manager создан для регистрации роутера '{router.name}'")
|
|
271
272
|
|
|
272
273
|
self.router_manager.register_router(router)
|
|
273
|
-
logger.info(f"✅ Роутер '{router.name}' зарегистрирован в боте {self.bot_id}")
|
|
274
|
+
logger.info(f"✅ Роутер событий '{router.name}' зарегистрирован в боте {self.bot_id}")
|
|
275
|
+
|
|
276
|
+
def register_routers(self, *event_routers):
|
|
277
|
+
"""
|
|
278
|
+
Регистрирует несколько роутеров событий одновременно
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
*event_routers: Произвольное количество EventRouter
|
|
282
|
+
|
|
283
|
+
Example:
|
|
284
|
+
bot_builder.register_routers(event_router1, event_router2, event_router3)
|
|
285
|
+
"""
|
|
286
|
+
if not event_routers:
|
|
287
|
+
logger.warning("⚠️ register_routers вызван без аргументов")
|
|
288
|
+
return
|
|
289
|
+
|
|
290
|
+
for router in event_routers:
|
|
291
|
+
self.register_router(router)
|
|
292
|
+
|
|
293
|
+
logger.info(f"✅ Зарегистрировано {len(event_routers)} роутеров событий")
|
|
294
|
+
|
|
295
|
+
def register_telegram_router(self, telegram_router):
|
|
296
|
+
"""
|
|
297
|
+
Регистрирует Telegram роутер для обработки команд и сообщений
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
telegram_router: TelegramRouter для регистрации
|
|
301
|
+
"""
|
|
302
|
+
from ..core.telegram_router import TelegramRouter
|
|
303
|
+
|
|
304
|
+
if not isinstance(telegram_router, TelegramRouter):
|
|
305
|
+
raise TypeError(f"Ожидается TelegramRouter, получен {type(telegram_router)}")
|
|
306
|
+
|
|
307
|
+
self._telegram_routers.append(telegram_router)
|
|
308
|
+
logger.info(f"✅ Telegram роутер '{telegram_router.name}' зарегистрирован в боте {self.bot_id}")
|
|
309
|
+
|
|
310
|
+
def register_telegram_routers(self, *telegram_routers):
|
|
311
|
+
"""
|
|
312
|
+
Регистрирует несколько Telegram роутеров одновременно
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
*telegram_routers: Произвольное количество TelegramRouter
|
|
316
|
+
|
|
317
|
+
Example:
|
|
318
|
+
bot_builder.register_telegram_routers(telegram_router1, telegram_router2)
|
|
319
|
+
"""
|
|
320
|
+
if not telegram_routers:
|
|
321
|
+
logger.warning("⚠️ register_telegram_routers вызван без аргументов")
|
|
322
|
+
return
|
|
323
|
+
|
|
324
|
+
for router in telegram_routers:
|
|
325
|
+
self.register_telegram_router(router)
|
|
326
|
+
|
|
327
|
+
logger.info(f"✅ Зарегистрировано {len(telegram_routers)} Telegram роутеров")
|
|
274
328
|
|
|
275
329
|
def get_router_manager(self) -> RouterManager:
|
|
276
|
-
"""Получает менеджер роутеров"""
|
|
330
|
+
"""Получает менеджер роутеров событий"""
|
|
277
331
|
return self.router_manager
|
|
278
332
|
|
|
279
333
|
async def start(self):
|
|
@@ -375,7 +429,14 @@ class BotBuilder:
|
|
|
375
429
|
from ..admin.admin_logic import setup_admin_handlers
|
|
376
430
|
from ..core.bot_utils import setup_utils_handlers
|
|
377
431
|
|
|
378
|
-
#
|
|
432
|
+
# Подключаем пользовательские Telegram роутеры ПЕРВЫМИ (высший приоритет)
|
|
433
|
+
if self._telegram_routers:
|
|
434
|
+
logger.info(f"🔗 Подключаем {len(self._telegram_routers)} пользовательских Telegram роутеров")
|
|
435
|
+
for telegram_router in self._telegram_routers:
|
|
436
|
+
dp.include_router(telegram_router.get_aiogram_router())
|
|
437
|
+
logger.info(f"✅ Подключен Telegram роутер: {telegram_router.name}")
|
|
438
|
+
|
|
439
|
+
# Настраиваем стандартные обработчики (меньший приоритет)
|
|
379
440
|
setup_utils_handlers(dp) # Утилитарные команды (/status, /help)
|
|
380
441
|
setup_admin_handlers(dp) # Админские команды (/админ, /стат, /чат)
|
|
381
442
|
setup_handlers(dp) # Основные пользовательские обработчики
|
|
@@ -805,31 +805,21 @@ class SupabaseClient:
|
|
|
805
805
|
return {}
|
|
806
806
|
|
|
807
807
|
async def get_user_last_message_info(self, user_id: int) -> Optional[Dict[str, Any]]:
|
|
808
|
-
"""Получает информацию о
|
|
808
|
+
"""Получает информацию о последней активности пользователя из сессии"""
|
|
809
809
|
try:
|
|
810
|
-
# Получаем
|
|
811
|
-
response = self.client.table('
|
|
812
|
-
'id', '
|
|
813
|
-
).eq('
|
|
810
|
+
# Получаем последнюю сессию пользователя
|
|
811
|
+
response = self.client.table('sales_chat_sessions').select(
|
|
812
|
+
'id', 'current_stage', 'created_at', 'updated_at'
|
|
813
|
+
).eq('user_id', user_id).order('updated_at', desc=True).limit(1).execute()
|
|
814
814
|
|
|
815
815
|
if not response.data:
|
|
816
816
|
return None
|
|
817
817
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
# Получаем информацию о сессии
|
|
821
|
-
session_response = self.client.table('sales_chat_sessions').select(
|
|
822
|
-
'id', 'current_stage', 'updated_at'
|
|
823
|
-
).eq('id', last_message['session_id']).execute()
|
|
824
|
-
|
|
825
|
-
if not session_response.data:
|
|
826
|
-
return None
|
|
827
|
-
|
|
828
|
-
session = session_response.data[0]
|
|
818
|
+
session = response.data[0]
|
|
829
819
|
|
|
830
820
|
return {
|
|
831
|
-
'last_message_at':
|
|
832
|
-
'session_id':
|
|
821
|
+
'last_message_at': session['updated_at'],
|
|
822
|
+
'session_id': session['id'],
|
|
833
823
|
'current_stage': session['current_stage'],
|
|
834
824
|
'session_updated_at': session['updated_at']
|
|
835
825
|
}
|
|
@@ -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
|
]
|
|
@@ -0,0 +1,789 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: smart-bot-factory
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Библиотека для создания умных чат-ботов
|
|
5
|
+
Author-email: Kopatych <kopatych@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: chatbot,cli,openai,supabase,telegram
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Framework :: AsyncIO
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Communications :: Chat
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: aiofiles>=23.0.0
|
|
24
|
+
Requires-Dist: aiogram>=3.4.1
|
|
25
|
+
Requires-Dist: click>=8.0.0
|
|
26
|
+
Requires-Dist: openai>=1.12.0
|
|
27
|
+
Requires-Dist: project-root-finder>=1.9
|
|
28
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
29
|
+
Requires-Dist: pytz>=2023.3
|
|
30
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
31
|
+
Requires-Dist: supabase>=2.3.4
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# Smart Bot Factory
|
|
35
|
+
|
|
36
|
+
Современная библиотека для создания умных чат-ботов на Python с использованием OpenAI, Telegram и Supabase.
|
|
37
|
+
|
|
38
|
+
## 🚀 Возможности
|
|
39
|
+
|
|
40
|
+
- **🤖 AI Integration** - Полная интеграция с OpenAI GPT для умных диалогов
|
|
41
|
+
- **📱 Telegram Bot API** - Поддержка через aiogram 3.x
|
|
42
|
+
- **💾 Supabase Backend** - Хранение данных, сессий и аналитики
|
|
43
|
+
- **🎯 Router System** - Модульная система обработчиков событий
|
|
44
|
+
- **⏰ Smart Scheduler** - Умное планирование задач с проверкой активности пользователей
|
|
45
|
+
- **🌍 Global Handlers** - Массовые рассылки и глобальные события
|
|
46
|
+
- **🧪 Testing Suite** - Встроенная система тестирования ботов
|
|
47
|
+
- **🛠️ CLI Tools** - Удобный интерфейс командной строки
|
|
48
|
+
- **👥 Admin Panel** - Система администрирования через Telegram
|
|
49
|
+
- **📊 Analytics** - Встроенная аналитика и отчеты
|
|
50
|
+
|
|
51
|
+
## 📦 Установка
|
|
52
|
+
|
|
53
|
+
### Системные требования
|
|
54
|
+
|
|
55
|
+
Перед установкой убедитесь, что у вас установлено:
|
|
56
|
+
|
|
57
|
+
- **Python 3.9+** (рекомендуется 3.11+)
|
|
58
|
+
- **pip** или **uv** для управления пакетами
|
|
59
|
+
- Доступ к интернету для установки зависимостей
|
|
60
|
+
|
|
61
|
+
### Из PyPI (рекомендуется)
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install smart_bot_factory
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### С помощью uv (современный менеджер пакетов)
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
uv add smart_bot_factory
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Из исходников (для разработки)
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Клонируйте репозиторий
|
|
77
|
+
git clone https://github.com/yourusername/chat-bots.git
|
|
78
|
+
cd chat-bots
|
|
79
|
+
|
|
80
|
+
# Установите зависимости через uv
|
|
81
|
+
uv sync
|
|
82
|
+
|
|
83
|
+
# Или через pip
|
|
84
|
+
pip install -e .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Установка определенной версии
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pip install smart_bot_factory==0.1.8
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Проверка установки
|
|
94
|
+
|
|
95
|
+
После установки проверьте доступность CLI:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
sbf --help
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Вы должны увидеть список доступных команд.
|
|
102
|
+
|
|
103
|
+
### Настройка внешних сервисов
|
|
104
|
+
|
|
105
|
+
Для работы бота вам понадобятся:
|
|
106
|
+
|
|
107
|
+
1. **Telegram Bot Token**
|
|
108
|
+
- Создайте бота через [@BotFather](https://t.me/botfather)
|
|
109
|
+
- Получите токен вида `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`
|
|
110
|
+
|
|
111
|
+
2. **OpenAI API Key**
|
|
112
|
+
- Зарегистрируйтесь на [platform.openai.com](https://platform.openai.com)
|
|
113
|
+
- Создайте API ключ в разделе API Keys
|
|
114
|
+
- Ключ имеет вид `sk-...`
|
|
115
|
+
|
|
116
|
+
3. **Supabase Project**
|
|
117
|
+
- Создайте проект на [supabase.com](https://supabase.com)
|
|
118
|
+
- Получите URL проекта и `anon` ключ в Project Settings → API
|
|
119
|
+
- Импортируйте SQL схему из `smart_bot_factory/database/schema.sql`
|
|
120
|
+
|
|
121
|
+
## ⚡ Быстрый старт
|
|
122
|
+
|
|
123
|
+
### 1. Создайте нового бота
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
sbf create my-bot
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Это создаст:
|
|
130
|
+
- 📁 `bots/my-bot/` - папка с конфигурацией бота
|
|
131
|
+
- 📄 `my-bot.py` - основной файл запуска
|
|
132
|
+
- ⚙️ `bots/my-bot/.env` - конфигурация окружения
|
|
133
|
+
- 📝 `bots/my-bot/prompts/` - промпты для AI
|
|
134
|
+
- 🧪 `bots/my-bot/tests/` - тестовые сценарии
|
|
135
|
+
|
|
136
|
+
### 2. Настройте переменные окружения
|
|
137
|
+
|
|
138
|
+
Отредактируйте `bots/my-bot/.env`:
|
|
139
|
+
|
|
140
|
+
```env
|
|
141
|
+
# Telegram
|
|
142
|
+
TELEGRAM_BOT_TOKEN=your_bot_token
|
|
143
|
+
|
|
144
|
+
# Supabase
|
|
145
|
+
SUPABASE_URL=https://your-project.supabase.co
|
|
146
|
+
SUPABASE_KEY=your_supabase_key
|
|
147
|
+
|
|
148
|
+
# OpenAI
|
|
149
|
+
OPENAI_API_KEY=sk-your-openai-key
|
|
150
|
+
OPENAI_MODEL=gpt-4o-mini
|
|
151
|
+
|
|
152
|
+
# Администраторы
|
|
153
|
+
ADMIN_TELEGRAM_IDS=123456789,987654321
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 3. Запустите бота
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
sbf run my-bot
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 📚 Архитектура
|
|
163
|
+
|
|
164
|
+
### Router System
|
|
165
|
+
|
|
166
|
+
Smart Bot Factory использует **два типа роутеров** для организации обработчиков:
|
|
167
|
+
|
|
168
|
+
1. **EventRouter** - для бизнес-логики (события, задачи, глобальные обработчики)
|
|
169
|
+
2. **TelegramRouter** - для Telegram команд, сообщений и callback'ов
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from smart_bot_factory.router import EventRouter, TelegramRouter
|
|
173
|
+
from smart_bot_factory.message import send_message_by_human
|
|
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
|
|
179
|
+
|
|
180
|
+
# EventRouter - для бизнес-логики
|
|
181
|
+
event_router = EventRouter("my_bot_events")
|
|
182
|
+
|
|
183
|
+
@event_router.event_handler("appointment_booking", notify=True)
|
|
184
|
+
async def handle_booking(user_id: int, event_data: str):
|
|
185
|
+
"""Обработчик записи на прием"""
|
|
186
|
+
await send_message_by_human(
|
|
187
|
+
user_id=user_id,
|
|
188
|
+
message_text=f"✅ Запись подтверждена! {event_data}"
|
|
189
|
+
)
|
|
190
|
+
return {"status": "success"}
|
|
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
|
+
|
|
205
|
+
# Запуск бота
|
|
206
|
+
async def main():
|
|
207
|
+
bot = BotBuilder("my-bot")
|
|
208
|
+
|
|
209
|
+
# Регистрируем роутеры (можно по одному или несколько сразу)
|
|
210
|
+
bot.register_routers(event_router) # EventRouter
|
|
211
|
+
bot.register_telegram_routers(telegram_router) # TelegramRouter
|
|
212
|
+
|
|
213
|
+
await bot.build()
|
|
214
|
+
await bot.start()
|
|
215
|
+
```
|
|
216
|
+
|
|
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 - Типы обработчиков событий
|
|
300
|
+
|
|
301
|
+
#### 1. Event Handlers - Обработчики событий
|
|
302
|
+
|
|
303
|
+
Немедленная обработка событий от AI:
|
|
304
|
+
|
|
305
|
+
```python
|
|
306
|
+
@router.event_handler("phone_collected", notify=True, once_only=True)
|
|
307
|
+
async def handle_phone(user_id: int, event_data: str):
|
|
308
|
+
"""Вызывается когда AI собирает номер телефона"""
|
|
309
|
+
# event_data содержит данные от AI
|
|
310
|
+
phone = parse_phone(event_data)
|
|
311
|
+
|
|
312
|
+
# Сохраняем в CRM
|
|
313
|
+
await save_to_crm(user_id, phone)
|
|
314
|
+
|
|
315
|
+
return {"status": "saved", "phone": phone}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Параметры:**
|
|
319
|
+
- `notify` - уведомлять админов (default: False)
|
|
320
|
+
- `once_only` - выполнить только один раз (default: True)
|
|
321
|
+
|
|
322
|
+
#### 2. Scheduled Tasks - Запланированные задачи
|
|
323
|
+
|
|
324
|
+
Задачи с отложенным выполнением для конкретного пользователя:
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
@router.schedule_task("send_reminder", delay="2h", smart_check=True)
|
|
328
|
+
async def send_reminder(user_id: int, reminder_text: str):
|
|
329
|
+
"""Отправит напоминание через 2 часа"""
|
|
330
|
+
await send_message_by_human(
|
|
331
|
+
user_id=user_id,
|
|
332
|
+
message_text=f"🔔 {reminder_text}"
|
|
333
|
+
)
|
|
334
|
+
return {"status": "sent"}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Параметры:**
|
|
338
|
+
- `delay` - задержка (обязательно): `"1h"`, `"30m"`, `"2h 15m"`, `3600`
|
|
339
|
+
- `smart_check` - умная проверка активности (default: True)
|
|
340
|
+
- `once_only` - выполнить только один раз (default: True)
|
|
341
|
+
- `event_type` - привязка к событию для напоминаний
|
|
342
|
+
|
|
343
|
+
**Smart Check:**
|
|
344
|
+
- Отменяет задачу если пользователь перешел на другой этап
|
|
345
|
+
- Переносит выполнение если пользователь был активен недавно
|
|
346
|
+
- Сохраняет session_id для точного отслеживания
|
|
347
|
+
|
|
348
|
+
#### 3. Global Handlers - Глобальные обработчики
|
|
349
|
+
|
|
350
|
+
Массовые действия для всех пользователей:
|
|
351
|
+
|
|
352
|
+
```python
|
|
353
|
+
@router.global_handler("mass_notification", delay="1h", notify=True)
|
|
354
|
+
async def send_announcement(announcement_text: str):
|
|
355
|
+
"""Отправит анонс всем пользователям через 1 час"""
|
|
356
|
+
from smart_bot_factory.message import send_message_to_users_by_stage
|
|
357
|
+
|
|
358
|
+
await send_message_to_users_by_stage(
|
|
359
|
+
stage="introduction",
|
|
360
|
+
message_text=announcement_text,
|
|
361
|
+
bot_id="my-bot"
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
return {"status": "completed"}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Параметры:**
|
|
368
|
+
- `delay` - задержка (обязательно)
|
|
369
|
+
- `notify` - уведомлять админов (default: False)
|
|
370
|
+
- `once_only` - выполнить только один раз (default: True)
|
|
371
|
+
|
|
372
|
+
### Event-Based Reminders
|
|
373
|
+
|
|
374
|
+
Напоминания о событиях за определенное время:
|
|
375
|
+
|
|
376
|
+
```python
|
|
377
|
+
# Сначала создаем обработчик события
|
|
378
|
+
@router.event_handler("appointment_booking")
|
|
379
|
+
async def handle_booking(user_id: int, event_data: str):
|
|
380
|
+
"""Сохраняет запись: имя, телефон, дата, время"""
|
|
381
|
+
return {"status": "saved", "data": event_data}
|
|
382
|
+
|
|
383
|
+
# Затем создаем напоминание
|
|
384
|
+
@router.schedule_task(
|
|
385
|
+
"appointment_reminder",
|
|
386
|
+
delay="2h",
|
|
387
|
+
event_type="appointment_booking" # Привязка к событию
|
|
388
|
+
)
|
|
389
|
+
async def remind_about_appointment(user_id: int, reminder_text: str):
|
|
390
|
+
"""Отправит напоминание за 2 часа до записи"""
|
|
391
|
+
await send_message_by_human(
|
|
392
|
+
user_id=user_id,
|
|
393
|
+
message_text=f"⏰ Напоминание о записи через 2 часа!"
|
|
394
|
+
)
|
|
395
|
+
return {"status": "sent"}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Система автоматически:
|
|
399
|
+
1. Извлечет дату/время из события `appointment_booking`
|
|
400
|
+
2. Вычислит время напоминания (за 2 часа до записи)
|
|
401
|
+
3. Запланирует отправку в правильное время
|
|
402
|
+
|
|
403
|
+
## 🛠️ CLI Команды
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
# Создание и управление ботами
|
|
407
|
+
sbf create <bot-id> # Создать нового бота
|
|
408
|
+
sbf create <bot-id> <template> # Создать из шаблона
|
|
409
|
+
sbf copy <source> <new-id> # Копировать существующего бота
|
|
410
|
+
sbf list # Показать всех ботов
|
|
411
|
+
sbf rm <bot-id> # Удалить бота
|
|
412
|
+
|
|
413
|
+
# Запуск
|
|
414
|
+
sbf run <bot-id> # Запустить бота
|
|
415
|
+
|
|
416
|
+
# Тестирование
|
|
417
|
+
sbf test <bot-id> # Запустить все тесты
|
|
418
|
+
sbf test <bot-id> --file quick_scenarios.yaml
|
|
419
|
+
sbf test <bot-id> -v # Подробный вывод
|
|
420
|
+
sbf test <bot-id> --max-concurrent 10
|
|
421
|
+
|
|
422
|
+
# Промпты
|
|
423
|
+
sbf prompts <bot-id> # Список промптов
|
|
424
|
+
sbf prompts <bot-id> --edit welcome_message
|
|
425
|
+
sbf prompts <bot-id> --add new_prompt
|
|
426
|
+
|
|
427
|
+
# Конфигурация
|
|
428
|
+
sbf config <bot-id> # Редактировать .env
|
|
429
|
+
sbf path # Показать путь к проекту
|
|
430
|
+
sbf link # Генератор UTM-ссылок
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## 📝 Система промптов
|
|
434
|
+
|
|
435
|
+
Промпты хранятся в `bots/<bot-id>/prompts/`:
|
|
436
|
+
|
|
437
|
+
- `welcome_message.txt` - Приветственное сообщение
|
|
438
|
+
- `help_message.txt` - Справка для пользователя
|
|
439
|
+
- `1sales_context.txt` - Контекст продаж
|
|
440
|
+
- `2product_info.txt` - Информация о продукте
|
|
441
|
+
- `3objection_handling.txt` - Работа с возражениями
|
|
442
|
+
- `final_instructions.txt` - Финальные инструкции для AI
|
|
443
|
+
|
|
444
|
+
AI автоматически получает доступ к зарегистрированным обработчикам через промпт.
|
|
445
|
+
|
|
446
|
+
## 🧪 Тестирование
|
|
447
|
+
|
|
448
|
+
Создайте тестовые сценарии в YAML:
|
|
449
|
+
|
|
450
|
+
```yaml
|
|
451
|
+
# bots/my-bot/tests/scenarios.yaml
|
|
452
|
+
scenarios:
|
|
453
|
+
- name: "Запись на прием"
|
|
454
|
+
steps:
|
|
455
|
+
- user: "Привет!"
|
|
456
|
+
expect_stage: "introduction"
|
|
457
|
+
|
|
458
|
+
- user: "Хочу записаться на прием"
|
|
459
|
+
expect_stage: "qualification"
|
|
460
|
+
expect_events:
|
|
461
|
+
- type: "appointment_request"
|
|
462
|
+
|
|
463
|
+
- user: "Меня зовут Иван, +79991234567, завтра в 15:00"
|
|
464
|
+
expect_events:
|
|
465
|
+
- type: "appointment_booking"
|
|
466
|
+
- type: "appointment_reminder" # Должно запланироваться
|
|
467
|
+
expect_quality: ">= 8"
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Запуск:
|
|
471
|
+
```bash
|
|
472
|
+
sbf test my-bot --file scenarios.yaml -v
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## 💬 Отправка сообщений
|
|
476
|
+
|
|
477
|
+
### Отправка пользователю
|
|
478
|
+
|
|
479
|
+
```python
|
|
480
|
+
from smart_bot_factory.message import send_message_by_human
|
|
481
|
+
|
|
482
|
+
await send_message_by_human(
|
|
483
|
+
user_id=123456789,
|
|
484
|
+
message_text="Привет! Это сообщение от системы",
|
|
485
|
+
session_id="optional-session-id"
|
|
486
|
+
)
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Массовая рассылка по этапу
|
|
490
|
+
|
|
491
|
+
```python
|
|
492
|
+
from smart_bot_factory.message import send_message_to_users_by_stage
|
|
493
|
+
|
|
494
|
+
await send_message_to_users_by_stage(
|
|
495
|
+
stage="introduction",
|
|
496
|
+
message_text="📢 Важное объявление!",
|
|
497
|
+
bot_id="my-bot"
|
|
498
|
+
)
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
## 🗄️ База данных
|
|
502
|
+
|
|
503
|
+
Smart Bot Factory использует Supabase со следующими таблицами:
|
|
504
|
+
|
|
505
|
+
- `sales_users` - Пользователи
|
|
506
|
+
- `sales_chat_sessions` - Сессии диалогов
|
|
507
|
+
- `sales_chat_messages` - История сообщений
|
|
508
|
+
- `scheduled_events` - Запланированные события и задачи
|
|
509
|
+
- `admin_sessions` - Сессии администраторов
|
|
510
|
+
|
|
511
|
+
SQL схема доступна в `smart_bot_factory/database/`.
|
|
512
|
+
|
|
513
|
+
## 👥 Система администрирования
|
|
514
|
+
|
|
515
|
+
Добавьте ID администраторов в `.env`:
|
|
516
|
+
|
|
517
|
+
```env
|
|
518
|
+
ADMIN_TELEGRAM_IDS=123456789,987654321
|
|
519
|
+
ADMIN_SESSION_TIMEOUT_MINUTES=30
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Админы получают:
|
|
523
|
+
- 📊 Статистику и аналитику
|
|
524
|
+
- 🔔 Уведомления о важных событиях (если `notify=True`)
|
|
525
|
+
- 🛠️ Доступ к специальным командам
|
|
526
|
+
|
|
527
|
+
## 🔧 Продвинутое использование
|
|
528
|
+
|
|
529
|
+
### Множественные роутеры
|
|
530
|
+
|
|
531
|
+
#### Регистрация нескольких EventRouter
|
|
532
|
+
|
|
533
|
+
```python
|
|
534
|
+
# handlers/main.py
|
|
535
|
+
main_router = EventRouter("main")
|
|
536
|
+
|
|
537
|
+
# handlers/admin.py
|
|
538
|
+
admin_router = EventRouter("admin")
|
|
539
|
+
|
|
540
|
+
# handlers/payments.py
|
|
541
|
+
payments_router = EventRouter("payments")
|
|
542
|
+
|
|
543
|
+
# app.py
|
|
544
|
+
bot = BotBuilder("my-bot")
|
|
545
|
+
|
|
546
|
+
# Можно по одному
|
|
547
|
+
bot.register_router(main_router)
|
|
548
|
+
bot.register_router(admin_router)
|
|
549
|
+
|
|
550
|
+
# Или все сразу
|
|
551
|
+
bot.register_routers(main_router, admin_router, payments_router)
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
#### Регистрация нескольких TelegramRouter
|
|
555
|
+
|
|
556
|
+
```python
|
|
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")
|
|
606
|
+
|
|
607
|
+
# Включаем роутер платежей в основной
|
|
608
|
+
main_router.include_router(payments_router)
|
|
609
|
+
|
|
610
|
+
bot.register_router(main_router)
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### Работа с клиентами
|
|
614
|
+
|
|
615
|
+
```python
|
|
616
|
+
from smart_bot_factory.supabase import SupabaseClient
|
|
617
|
+
|
|
618
|
+
# Создаем клиент для вашего бота
|
|
619
|
+
supabase = SupabaseClient("my-bot")
|
|
620
|
+
|
|
621
|
+
# Используем напрямую
|
|
622
|
+
users = supabase.client.table('sales_users').select('*').eq('bot_id', 'my-bot').execute()
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
## 📊 Структура проекта
|
|
626
|
+
|
|
627
|
+
```
|
|
628
|
+
my-project/
|
|
629
|
+
├── bots/ # Папка с ботами
|
|
630
|
+
│ ├── my-bot/
|
|
631
|
+
│ │ ├── .env # Конфигурация
|
|
632
|
+
│ │ ├── prompts/ # AI промпты
|
|
633
|
+
│ │ ├── tests/ # Тестовые сценарии
|
|
634
|
+
│ │ ├── files/ # Файлы бота
|
|
635
|
+
│ │ ├── welcome_files/ # Приветственные файлы
|
|
636
|
+
│ │ └── reports/ # Отчеты тестов
|
|
637
|
+
│ └── another-bot/
|
|
638
|
+
│ └── ...
|
|
639
|
+
├── my-bot.py # Основной файл запуска
|
|
640
|
+
├── another-bot.py
|
|
641
|
+
└── .env # Глобальная конфигурация (опционально)
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
## 🔄 Примеры
|
|
645
|
+
|
|
646
|
+
### Полный пример бота
|
|
647
|
+
|
|
648
|
+
```python
|
|
649
|
+
import asyncio
|
|
650
|
+
|
|
651
|
+
from smart_bot_factory.router import EventRouter, TelegramRouter
|
|
652
|
+
from smart_bot_factory.message import send_message_by_human, send_message_to_users_by_stage
|
|
653
|
+
from smart_bot_factory.supabase import SupabaseClient
|
|
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
|
|
659
|
+
|
|
660
|
+
# Инициализация
|
|
661
|
+
event_router = EventRouter("medical_bot_events")
|
|
662
|
+
telegram_router = TelegramRouter("medical_bot_telegram")
|
|
663
|
+
supabase_client = SupabaseClient("medical-bot")
|
|
664
|
+
|
|
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)
|
|
683
|
+
async def handle_appointment(user_id: int, event_data: str):
|
|
684
|
+
"""Обрабатывает запись на прием к врачу"""
|
|
685
|
+
# event_data: "имя: Иван, телефон: +79991234567, дата: 2025-10-15, время: 14:00"
|
|
686
|
+
|
|
687
|
+
await send_message_by_human(
|
|
688
|
+
user_id=user_id,
|
|
689
|
+
message_text="✅ Запись подтверждена! Ждем вас."
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
return {"status": "success", "data": event_data}
|
|
693
|
+
|
|
694
|
+
# Напоминание за 2 часа до приема (EventRouter)
|
|
695
|
+
@event_router.schedule_task(
|
|
696
|
+
"appointment_reminder",
|
|
697
|
+
delay="2h",
|
|
698
|
+
event_type="appointment_booking"
|
|
699
|
+
)
|
|
700
|
+
async def remind_before_appointment(user_id: int, reminder_text: str):
|
|
701
|
+
"""Напоминание о записи"""
|
|
702
|
+
await send_message_by_human(
|
|
703
|
+
user_id=user_id,
|
|
704
|
+
message_text="⏰ Напоминаем о вашей записи через 2 часа!"
|
|
705
|
+
)
|
|
706
|
+
return {"status": "sent"}
|
|
707
|
+
|
|
708
|
+
# Ночной дайджест для всех (EventRouter)
|
|
709
|
+
@event_router.global_handler("daily_digest", delay="24h")
|
|
710
|
+
async def send_daily_digest(digest_text: str):
|
|
711
|
+
"""Отправляет ежедневный дайджест всем активным пользователям"""
|
|
712
|
+
await send_message_to_users_by_stage(
|
|
713
|
+
stage="active",
|
|
714
|
+
message_text=f"📊 Дайджест дня:\n\n{digest_text}",
|
|
715
|
+
bot_id="medical-bot"
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
# Запуск
|
|
719
|
+
async def main():
|
|
720
|
+
bot = BotBuilder("medical-bot")
|
|
721
|
+
|
|
722
|
+
# Регистрируем роутеры
|
|
723
|
+
bot.register_routers(event_router) # EventRouter
|
|
724
|
+
bot.register_telegram_routers(telegram_router) # TelegramRouter
|
|
725
|
+
|
|
726
|
+
await bot.build()
|
|
727
|
+
await bot.start()
|
|
728
|
+
|
|
729
|
+
if __name__ == "__main__":
|
|
730
|
+
asyncio.run(main())
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
## 🐛 Отладка
|
|
734
|
+
|
|
735
|
+
Включите режим отладки в `.env`:
|
|
736
|
+
|
|
737
|
+
```env
|
|
738
|
+
DEBUG_MODE=true
|
|
739
|
+
LOG_LEVEL=DEBUG
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
Это покажет:
|
|
743
|
+
- JSON ответы от AI
|
|
744
|
+
- Детальные логи обработки
|
|
745
|
+
- Информацию о роутерах и обработчиках
|
|
746
|
+
|
|
747
|
+
## 📋 Требования
|
|
748
|
+
|
|
749
|
+
### Системные
|
|
750
|
+
- Python 3.9+ (рекомендуется 3.11+)
|
|
751
|
+
- pip или uv для управления пакетами
|
|
752
|
+
|
|
753
|
+
### Основные зависимости
|
|
754
|
+
- aiogram 3.4.1+ - Telegram Bot API
|
|
755
|
+
- supabase 2.3.4+ - База данных
|
|
756
|
+
- openai 1.12.0+ - AI модель
|
|
757
|
+
- click 8.0.0+ - CLI интерфейс
|
|
758
|
+
- python-dotenv 1.0.1+ - Управление переменными окружения
|
|
759
|
+
|
|
760
|
+
Все зависимости устанавливаются автоматически при установке библиотеки.
|
|
761
|
+
|
|
762
|
+
### Внешние сервисы
|
|
763
|
+
- Telegram Bot Token ([@BotFather](https://t.me/botfather))
|
|
764
|
+
- OpenAI API Key ([platform.openai.com](https://platform.openai.com))
|
|
765
|
+
- Supabase Project ([supabase.com](https://supabase.com))
|
|
766
|
+
|
|
767
|
+
Подробнее см. раздел [Установка](#-установка).
|
|
768
|
+
|
|
769
|
+
## 🤝 Вклад в проект
|
|
770
|
+
|
|
771
|
+
Мы приветствуем вклад в развитие проекта!
|
|
772
|
+
|
|
773
|
+
## 📄 Лицензия
|
|
774
|
+
|
|
775
|
+
MIT License - см. [LICENSE](LICENSE)
|
|
776
|
+
|
|
777
|
+
## 🔗 Полезные ссылки
|
|
778
|
+
|
|
779
|
+
- [Документация Supabase](https://supabase.com/docs)
|
|
780
|
+
- [Документация OpenAI](https://platform.openai.com/docs)
|
|
781
|
+
- [Документация aiogram](https://docs.aiogram.dev/)
|
|
782
|
+
|
|
783
|
+
## 💡 Поддержка
|
|
784
|
+
|
|
785
|
+
Если у вас возникли вопросы или проблемы, создайте issue в репозитории.
|
|
786
|
+
|
|
787
|
+
---
|
|
788
|
+
|
|
789
|
+
Сделано с ❤️ для создания умных ботов
|
|
@@ -26,29 +26,30 @@ smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt
|
|
|
26
26
|
smart_bot_factory/configs/growthmed-october-24/welcome_file/Чек лист по 152ФЗ и 323ФЗ для медицины.pdf,sha256=BiAiQHNnQXJPMsks9AeL6s0beEjRFkRMJLMlAn4WorA,5284954
|
|
27
27
|
smart_bot_factory/core/bot_utils.py,sha256=XmwQ31LOpE_Wudx4OO4tlnVwse3YagakwpgN2cZC5SQ,41085
|
|
28
28
|
smart_bot_factory/core/conversation_manager.py,sha256=eoHL7MCEz68DRvTVwRwZgf2PWwGv4T6J9D-I-thETi8,28289
|
|
29
|
-
smart_bot_factory/core/decorators.py,sha256=
|
|
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=xWgWRe4DV3PngiLoQlzm6AdhNvPqn3wOCwcgsIoh-QA,25220
|
|
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
41
|
smart_bot_factory/handlers/handlers.py,sha256=YH8xG0tDcb7uxZXI4socXURzc-y57_FEQ6GqTgYcM5Q,37603
|
|
41
42
|
smart_bot_factory/integrations/openai_client.py,sha256=aMcDrKO0GEx3ZSVEOGDeDtFCDWSXs6biUfgrbRK8yTU,23180
|
|
42
|
-
smart_bot_factory/integrations/supabase_client.py,sha256=
|
|
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.
|
|
51
|
-
smart_bot_factory-0.
|
|
52
|
-
smart_bot_factory-0.
|
|
53
|
-
smart_bot_factory-0.
|
|
54
|
-
smart_bot_factory-0.
|
|
51
|
+
smart_bot_factory-0.2.0.dist-info/METADATA,sha256=WEC38O2La8OlQpfCZWkXjhMU70VigduV0wIrferi2w0,28224
|
|
52
|
+
smart_bot_factory-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
53
|
+
smart_bot_factory-0.2.0.dist-info/entry_points.txt,sha256=ybKEAI0WSb7WoRiey7QE-HHfn88UGV7nxLDxXq7b7SU,50
|
|
54
|
+
smart_bot_factory-0.2.0.dist-info/licenses/LICENSE,sha256=OrK3cwdUTzNzIhJvSPtJaVMoYIyC_sSx5EFE_FDMvGs,1092
|
|
55
|
+
smart_bot_factory-0.2.0.dist-info/RECORD,,
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: smart-bot-factory
|
|
3
|
-
Version: 0.1.8
|
|
4
|
-
Summary: Библиотека для создания умных чат-ботов
|
|
5
|
-
Author-email: Kopatych <kopatych@example.com>
|
|
6
|
-
License: MIT
|
|
7
|
-
License-File: LICENSE
|
|
8
|
-
Keywords: chatbot,cli,openai,supabase,telegram
|
|
9
|
-
Classifier: Development Status :: 4 - Beta
|
|
10
|
-
Classifier: Environment :: Console
|
|
11
|
-
Classifier: Framework :: AsyncIO
|
|
12
|
-
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
-
Classifier: Operating System :: OS Independent
|
|
15
|
-
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
-
Classifier: Topic :: Communications :: Chat
|
|
21
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
-
Requires-Python: >=3.9
|
|
23
|
-
Requires-Dist: aiofiles>=23.0.0
|
|
24
|
-
Requires-Dist: aiogram>=3.4.1
|
|
25
|
-
Requires-Dist: click>=8.0.0
|
|
26
|
-
Requires-Dist: openai>=1.12.0
|
|
27
|
-
Requires-Dist: project-root-finder>=1.9
|
|
28
|
-
Requires-Dist: python-dotenv>=1.0.1
|
|
29
|
-
Requires-Dist: pytz>=2023.3
|
|
30
|
-
Requires-Dist: pyyaml>=6.0.2
|
|
31
|
-
Requires-Dist: supabase>=2.3.4
|
|
32
|
-
Description-Content-Type: text/markdown
|
|
33
|
-
|
|
34
|
-
# Smart Bot Factory
|
|
35
|
-
|
|
36
|
-
Библиотека для создания умных чат-ботов с использованием OpenAI, Telegram и Supabase.
|
|
37
|
-
|
|
38
|
-
## Установка
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
pip install smart-bot-factory
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Быстрый старт
|
|
45
|
-
|
|
46
|
-
1. Создайте нового бота:
|
|
47
|
-
```bash
|
|
48
|
-
sbf create my-bot
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
2. Настройте конфигурацию в `bots/my-bot/.env`
|
|
52
|
-
|
|
53
|
-
3. Запустите бота:
|
|
54
|
-
```bash
|
|
55
|
-
sbf run my-bot
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Возможности
|
|
59
|
-
|
|
60
|
-
- 🤖 Интеграция с OpenAI GPT для умных ответов
|
|
61
|
-
- 📱 Поддержка Telegram Bot API через aiogram
|
|
62
|
-
- 💾 Хранение данных в Supabase
|
|
63
|
-
- 🔄 Система событий и обработчиков
|
|
64
|
-
- ⏰ Планировщик задач
|
|
65
|
-
- 🧪 Встроенная система тестирования
|
|
66
|
-
- 📝 Управление промптами
|
|
67
|
-
- 🛠️ Удобный CLI интерфейс
|
|
68
|
-
|
|
69
|
-
## CLI команды
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
# Создать нового бота
|
|
73
|
-
sbf create my-bot
|
|
74
|
-
|
|
75
|
-
# Запустить бота
|
|
76
|
-
sbf run my-bot
|
|
77
|
-
|
|
78
|
-
# Показать список ботов
|
|
79
|
-
sbf list
|
|
80
|
-
|
|
81
|
-
# Управление промптами
|
|
82
|
-
sbf prompts my-bot --list
|
|
83
|
-
sbf prompts my-bot --edit welcome_message
|
|
84
|
-
sbf prompts my-bot --add new_prompt
|
|
85
|
-
|
|
86
|
-
# Запустить тесты
|
|
87
|
-
sbf test my-bot
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Пример использования
|
|
91
|
-
|
|
92
|
-
```python
|
|
93
|
-
from smart_bot_factory import BotBuilder, event_handler, schedule_task
|
|
94
|
-
|
|
95
|
-
# Обработчик события
|
|
96
|
-
@event_handler("book_appointment", "Запись на прием")
|
|
97
|
-
async def handle_booking(user_id: int, event_data: dict):
|
|
98
|
-
# Логика обработки записи на прием
|
|
99
|
-
return {"status": "success"}
|
|
100
|
-
|
|
101
|
-
# Запланированная задача
|
|
102
|
-
@schedule_task("send_reminder", "Отправка напоминания")
|
|
103
|
-
async def send_reminder(user_id: int, message: str):
|
|
104
|
-
# Логика отправки напоминания
|
|
105
|
-
return {"status": "sent"}
|
|
106
|
-
|
|
107
|
-
# Запуск бота
|
|
108
|
-
async def main():
|
|
109
|
-
bot = BotBuilder("my-bot")
|
|
110
|
-
await bot.build()
|
|
111
|
-
await bot.start()
|
|
112
|
-
|
|
113
|
-
if __name__ == "__main__":
|
|
114
|
-
asyncio.run(main())
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Требования
|
|
118
|
-
|
|
119
|
-
- Python 3.9+
|
|
120
|
-
- OpenAI API ключ
|
|
121
|
-
- Telegram Bot Token
|
|
122
|
-
- Supabase проект
|
|
123
|
-
|
|
124
|
-
## Лицензия
|
|
125
|
-
|
|
126
|
-
MIT
|
|
File without changes
|
|
File without changes
|
|
File without changes
|