smart-bot-factory 0.2.4__py3-none-any.whl → 0.2.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of smart-bot-factory might be problematic. Click here for more details.
- smart_bot_factory/creation/bot_builder.py +65 -4
- smart_bot_factory/handlers/handlers.py +14 -1
- smart_bot_factory/supabase/client.py +3 -12
- smart_bot_factory/utils/__init__.py +5 -4
- smart_bot_factory/utils/user_prompt_loader.py +56 -0
- {smart_bot_factory-0.2.4.dist-info → smart_bot_factory-0.2.6.dist-info}/METADATA +1 -1
- {smart_bot_factory-0.2.4.dist-info → smart_bot_factory-0.2.6.dist-info}/RECORD +10 -9
- {smart_bot_factory-0.2.4.dist-info → smart_bot_factory-0.2.6.dist-info}/WHEEL +0 -0
- {smart_bot_factory-0.2.4.dist-info → smart_bot_factory-0.2.6.dist-info}/entry_points.txt +0 -0
- {smart_bot_factory-0.2.4.dist-info → smart_bot_factory-0.2.6.dist-info}/licenses/LICENSE +0 -0
|
@@ -52,8 +52,12 @@ class BotBuilder:
|
|
|
52
52
|
self._message_validators: List = [] # Валидация ДО обработки
|
|
53
53
|
self._prompt_enrichers: List = [] # Обогащение системного промпта
|
|
54
54
|
self._context_enrichers: List = [] # Обогащение контекста для AI
|
|
55
|
+
self._response_processors: List = [] # Обработка ответа AI
|
|
55
56
|
self._send_filters: List = [] # Фильтры перед отправкой пользователю
|
|
56
57
|
|
|
58
|
+
# Кастомный PromptLoader
|
|
59
|
+
self._custom_prompt_loader = None
|
|
60
|
+
|
|
57
61
|
# Флаги инициализации
|
|
58
62
|
self._initialized = False
|
|
59
63
|
|
|
@@ -174,10 +178,16 @@ class BotBuilder:
|
|
|
174
178
|
else:
|
|
175
179
|
logger.info(f"✅ Router Manager уже был создан ранее")
|
|
176
180
|
|
|
177
|
-
# Prompt Loader
|
|
178
|
-
self.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
+
# Prompt Loader (используем кастомный если установлен)
|
|
182
|
+
if self._custom_prompt_loader:
|
|
183
|
+
self.prompt_loader = self._custom_prompt_loader
|
|
184
|
+
logger.info(f"✅ Используется кастомный Prompt Loader: {type(self.prompt_loader).__name__}")
|
|
185
|
+
else:
|
|
186
|
+
self.prompt_loader = PromptLoader(
|
|
187
|
+
prompts_dir=self.config.PROMT_FILES_DIR
|
|
188
|
+
)
|
|
189
|
+
logger.info(f"✅ Используется стандартный Prompt Loader")
|
|
190
|
+
|
|
181
191
|
await self.prompt_loader.validate_prompts()
|
|
182
192
|
logger.info(f"✅ Prompt Loader инициализирован")
|
|
183
193
|
|
|
@@ -364,6 +374,34 @@ class BotBuilder:
|
|
|
364
374
|
"""Получает список обработчиков on_start"""
|
|
365
375
|
return self._start_handlers.copy()
|
|
366
376
|
|
|
377
|
+
def set_prompt_loader(self, prompt_loader):
|
|
378
|
+
"""
|
|
379
|
+
Устанавливает кастомный PromptLoader
|
|
380
|
+
|
|
381
|
+
Должен быть вызван ДО build()
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
prompt_loader: Экземпляр PromptLoader или его наследника (например UserPromptLoader)
|
|
385
|
+
|
|
386
|
+
Example:
|
|
387
|
+
from smart_bot_factory.utils import UserPromptLoader
|
|
388
|
+
|
|
389
|
+
# Использовать UserPromptLoader с автопоиском prompts_dir
|
|
390
|
+
custom_loader = UserPromptLoader("my-bot")
|
|
391
|
+
bot_builder.set_prompt_loader(custom_loader)
|
|
392
|
+
|
|
393
|
+
# Или кастомный наследник
|
|
394
|
+
class MyPromptLoader(UserPromptLoader):
|
|
395
|
+
def __init__(self, bot_id):
|
|
396
|
+
super().__init__(bot_id)
|
|
397
|
+
self.extra_file = self.prompts_dir / 'extra.txt'
|
|
398
|
+
|
|
399
|
+
my_loader = MyPromptLoader("my-bot")
|
|
400
|
+
bot_builder.set_prompt_loader(my_loader)
|
|
401
|
+
"""
|
|
402
|
+
self._custom_prompt_loader = prompt_loader
|
|
403
|
+
logger.info(f"✅ Установлен кастомный PromptLoader: {type(prompt_loader).__name__}")
|
|
404
|
+
|
|
367
405
|
# ========== ХУКИ ДЛЯ КАСТОМИЗАЦИИ ОБРАБОТКИ СООБЩЕНИЙ ==========
|
|
368
406
|
|
|
369
407
|
def validate_message(self, handler):
|
|
@@ -437,6 +475,28 @@ class BotBuilder:
|
|
|
437
475
|
logger.info(f"✅ Зарегистрирован обогатитель контекста: {handler.__name__}")
|
|
438
476
|
return handler
|
|
439
477
|
|
|
478
|
+
def process_response(self, handler):
|
|
479
|
+
"""
|
|
480
|
+
Регистрирует обработчик ответа AI (ПОСЛЕ получения ответа)
|
|
481
|
+
|
|
482
|
+
Args:
|
|
483
|
+
handler: async def(response_text: str, ai_metadata: dict, user_id: int) -> tuple[str, dict]
|
|
484
|
+
|
|
485
|
+
Example:
|
|
486
|
+
@bot_builder.process_response
|
|
487
|
+
async def modify_response(response_text, ai_metadata, user_id):
|
|
488
|
+
# Модифицируем ответ
|
|
489
|
+
if "цена" in response_text.lower():
|
|
490
|
+
response_text += "\\n\\n💰 Актуальные цены на сайте"
|
|
491
|
+
return response_text, ai_metadata
|
|
492
|
+
"""
|
|
493
|
+
if not callable(handler):
|
|
494
|
+
raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
|
|
495
|
+
|
|
496
|
+
self._response_processors.append(handler)
|
|
497
|
+
logger.info(f"✅ Зарегистрирован обработчик ответа: {handler.__name__}")
|
|
498
|
+
return handler
|
|
499
|
+
|
|
440
500
|
def filter_send(self, handler):
|
|
441
501
|
"""
|
|
442
502
|
Регистрирует фильтр отправки (может блокировать отправку пользователю)
|
|
@@ -466,6 +526,7 @@ class BotBuilder:
|
|
|
466
526
|
'validators': self._message_validators.copy(),
|
|
467
527
|
'prompt_enrichers': self._prompt_enrichers.copy(),
|
|
468
528
|
'context_enrichers': self._context_enrichers.copy(),
|
|
529
|
+
'response_processors': self._response_processors.copy(),
|
|
469
530
|
'send_filters': self._send_filters.copy()
|
|
470
531
|
}
|
|
471
532
|
|
|
@@ -624,6 +624,19 @@ async def process_user_message(message: Message, state: FSMContext, session_id:
|
|
|
624
624
|
|
|
625
625
|
logger.info(f"✅ Финальный текст для отправки: {len(response_text)} символов")
|
|
626
626
|
|
|
627
|
+
# ============ ХУК 4: ОБРАБОТКА ОТВЕТА ============
|
|
628
|
+
response_processors = message_hooks.get('response_processors', [])
|
|
629
|
+
for processor in response_processors:
|
|
630
|
+
try:
|
|
631
|
+
response_text, ai_metadata = await processor(
|
|
632
|
+
response_text,
|
|
633
|
+
ai_metadata,
|
|
634
|
+
message.from_user.id
|
|
635
|
+
)
|
|
636
|
+
logger.info(f"✅ Ответ обработан '{processor.__name__}'")
|
|
637
|
+
except Exception as e:
|
|
638
|
+
logger.error(f"❌ Ошибка в обработчике ответа '{processor.__name__}': {e}")
|
|
639
|
+
|
|
627
640
|
# Обновляем этап сессии и качество лида
|
|
628
641
|
if ai_metadata:
|
|
629
642
|
logger.info("🔍 Анализ метаданных от ИИ:")
|
|
@@ -732,7 +745,7 @@ async def process_user_message(message: Message, state: FSMContext, session_id:
|
|
|
732
745
|
|
|
733
746
|
logger.info(f"📱 Отправляем пользователю: {len(final_response)} символов")
|
|
734
747
|
|
|
735
|
-
# ============ ХУК
|
|
748
|
+
# ============ ХУК 5: ФИЛЬТРЫ ОТПРАВКИ ============
|
|
736
749
|
send_filters = message_hooks.get('send_filters', [])
|
|
737
750
|
for filter_func in send_filters:
|
|
738
751
|
try:
|
|
@@ -32,10 +32,10 @@ class SupabaseClient:
|
|
|
32
32
|
# Автоматически загружаем настройки из .env
|
|
33
33
|
self._load_env_config()
|
|
34
34
|
|
|
35
|
-
# Инициализируем клиент
|
|
36
|
-
self.client
|
|
35
|
+
# Инициализируем клиент СИНХРОННО прямо в __init__
|
|
36
|
+
self.client = create_client(self.url, self.key)
|
|
37
37
|
|
|
38
|
-
logger.info(f"
|
|
38
|
+
logger.info(f"✅ SupabaseClient инициализирован для bot_id: {self.bot_id}")
|
|
39
39
|
|
|
40
40
|
def _load_env_config(self):
|
|
41
41
|
"""Загружает конфигурацию из .env файла"""
|
|
@@ -80,15 +80,6 @@ class SupabaseClient:
|
|
|
80
80
|
logger.error(f" Искали в: {bot_env_path}")
|
|
81
81
|
return None
|
|
82
82
|
|
|
83
|
-
async def initialize(self):
|
|
84
|
-
"""Инициализация клиента Supabase"""
|
|
85
|
-
try:
|
|
86
|
-
self.client = create_client(self.url, self.key)
|
|
87
|
-
logger.info(f"✅ Supabase client инициализирован{f' для bot_id: {self.bot_id}' if self.bot_id else ''}")
|
|
88
|
-
except Exception as e:
|
|
89
|
-
logger.error(f"❌ Ошибка инициализации Supabase client: {e}")
|
|
90
|
-
raise
|
|
91
|
-
|
|
92
83
|
# =============================================================================
|
|
93
84
|
# МЕТОДЫ ДЛЯ РАБОТЫ С ПОЛЬЗОВАТЕЛЯМИ
|
|
94
85
|
# =============================================================================
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
Utils модули smart_bot_factory
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from ..integrations.supabase_client import SupabaseClient
|
|
6
|
-
from ..utils.prompt_loader import PromptLoader
|
|
7
|
-
from ..utils.debug_routing import setup_debug_handlers
|
|
8
5
|
|
|
9
|
-
|
|
6
|
+
from .user_prompt_loader import UserPromptLoader
|
|
7
|
+
|
|
8
|
+
__all__ = [ # Базовый класс (для библиотеки)
|
|
9
|
+
'UserPromptLoader', # Для пользователей (автопоиск prompts_dir)
|
|
10
|
+
]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
UserPromptLoader - упрощенный PromptLoader для пользователей библиотеки
|
|
3
|
+
с автоматическим поиском prompts_dir от корня проекта
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from .prompt_loader import PromptLoader
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class UserPromptLoader(PromptLoader):
|
|
14
|
+
"""
|
|
15
|
+
PromptLoader для пользователей библиотеки с автоматическим поиском prompts_dir
|
|
16
|
+
|
|
17
|
+
Автоматически находит папку prompts для указанного бота от корня проекта
|
|
18
|
+
Наследуется от базового PromptLoader - все методы доступны
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, bot_id: str, prompts_subdir: str = "prompts"):
|
|
22
|
+
"""
|
|
23
|
+
Инициализация загрузчика промптов с автоматическим поиском
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
bot_id: Идентификатор бота
|
|
27
|
+
prompts_subdir: Подпапка с промптами (по умолчанию "prompts")
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
# Автоматически найдет bots/my-bot/prompts
|
|
31
|
+
loader = UserPromptLoader("my-bot")
|
|
32
|
+
|
|
33
|
+
# Или кастомную подпапку
|
|
34
|
+
loader = UserPromptLoader("my-bot", "custom_prompts")
|
|
35
|
+
|
|
36
|
+
# Наследование для кастомизации
|
|
37
|
+
class MyLoader(UserPromptLoader):
|
|
38
|
+
def __init__(self, bot_id):
|
|
39
|
+
super().__init__(bot_id)
|
|
40
|
+
# Добавить свою логику
|
|
41
|
+
self.extra_file = self.prompts_dir / 'extra.txt'
|
|
42
|
+
"""
|
|
43
|
+
from project_root_finder import root
|
|
44
|
+
|
|
45
|
+
# Автоматически определяем путь к промптам
|
|
46
|
+
prompts_dir = root / "bots" / bot_id / prompts_subdir
|
|
47
|
+
|
|
48
|
+
if not prompts_dir.exists():
|
|
49
|
+
logger.warning(f"⚠️ Папка промптов не найдена: {prompts_dir}")
|
|
50
|
+
logger.warning(f" Создайте папку или проверьте bot_id")
|
|
51
|
+
|
|
52
|
+
# Вызываем базовую инициализацию
|
|
53
|
+
super().__init__(str(prompts_dir))
|
|
54
|
+
|
|
55
|
+
logger.info(f"✅ UserPromptLoader создан для bot_id '{bot_id}': {prompts_dir}")
|
|
56
|
+
|
|
@@ -33,23 +33,24 @@ smart_bot_factory/core/router_manager.py,sha256=dUwesog-oHk1U2EDdS8p0e4MTSkwtx5_
|
|
|
33
33
|
smart_bot_factory/core/states.py,sha256=AOc19_yAsDW_8md-2oiowjBhuW3bwcsmMxszCXWZZTQ,355
|
|
34
34
|
smart_bot_factory/core/telegram_router.py,sha256=LcPLOd87Y4Y4YN6TBXVAtmpSp8gAK2otgMI4YS5f5tk,2091
|
|
35
35
|
smart_bot_factory/creation/__init__.py,sha256=IgDk8GDS3pg7Pw_Et41J33ZmeZIU5dRwQdTmYKXfJfE,128
|
|
36
|
-
smart_bot_factory/creation/bot_builder.py,sha256=
|
|
36
|
+
smart_bot_factory/creation/bot_builder.py,sha256=Fud-E3J-S7IEjWBfFhRu4YXnJZHbNHG33zqgGk_Cy8I,35585
|
|
37
37
|
smart_bot_factory/creation/bot_testing.py,sha256=JDWXyJfZmbgo-DLdAPk8Sd9FiehtHHa4sLD17lBrTOc,55669
|
|
38
38
|
smart_bot_factory/event/__init__.py,sha256=hPL449RULIOB-OXv1ZbGNiHctAYaOMUqhSWGPrDHYBM,212
|
|
39
|
-
smart_bot_factory/handlers/handlers.py,sha256=
|
|
39
|
+
smart_bot_factory/handlers/handlers.py,sha256=jtCf8XiJD3pIjcd7vqT8uG8Q-qiHd1W-ZLZiVPK8YR4,41458
|
|
40
40
|
smart_bot_factory/integrations/openai_client.py,sha256=aMcDrKO0GEx3ZSVEOGDeDtFCDWSXs6biUfgrbRK8yTU,23180
|
|
41
41
|
smart_bot_factory/integrations/supabase_client.py,sha256=AfALLZdDYeMWHLJw6POTGiBd-sH3i03oT6tT7m9C28I,44644
|
|
42
42
|
smart_bot_factory/message/__init__.py,sha256=8XWEEl3J0l1xDeEPmXPwFbHbnQelGApCwnicUkcBbOg,391
|
|
43
43
|
smart_bot_factory/router/__init__.py,sha256=QrfO5u8H2uVzWGMtBvNKunsJAv7UrKtvt2f_D5xSFWE,270
|
|
44
44
|
smart_bot_factory/supabase/__init__.py,sha256=XmZP6yM9ffERM5ddAWyJnrNzEhCYtMu3AcjVCi1rOf8,179
|
|
45
|
-
smart_bot_factory/supabase/client.py,sha256=
|
|
45
|
+
smart_bot_factory/supabase/client.py,sha256=lWIzfOgoSvU7xPhYLoJtM5GnbWdoWsvHcRFC22sFBMU,25637
|
|
46
46
|
smart_bot_factory/table/database_structure.sql,sha256=26gFtMC2jdQGQF7Zb_F4Br56rMd4hUDTk9FkNZYneLo,2789
|
|
47
47
|
smart_bot_factory/table/schema.sql,sha256=-6kOmA9QnSkUtmGI2iQRbTvbdiqOhEOQcuz1lJn79mU,28059
|
|
48
|
-
smart_bot_factory/utils/__init__.py,sha256=
|
|
48
|
+
smart_bot_factory/utils/__init__.py,sha256=UhsJXEHfrIK8h1AHsroHSwAriijk-LvnqLyvgzi2VYs,273
|
|
49
49
|
smart_bot_factory/utils/debug_routing.py,sha256=BOoDhKBg7UXe5uHQxRk3TSfPfLPOFqt0N7lAo6kjCOo,4719
|
|
50
50
|
smart_bot_factory/utils/prompt_loader.py,sha256=JSn7CsWnToSbHYtURdeuZn7ectyDqQGrPGHN2ixIGkw,19930
|
|
51
|
-
smart_bot_factory
|
|
52
|
-
smart_bot_factory-0.2.
|
|
53
|
-
smart_bot_factory-0.2.
|
|
54
|
-
smart_bot_factory-0.2.
|
|
55
|
-
smart_bot_factory-0.2.
|
|
51
|
+
smart_bot_factory/utils/user_prompt_loader.py,sha256=dk6P0X_3UcNqxjRtuIvb0LcPrp03zIIsstZwdmeCPaE,2519
|
|
52
|
+
smart_bot_factory-0.2.6.dist-info/METADATA,sha256=HFUAtOVAOW7_sf2S5Bsqx6WQVTRsb4NSkMy_vqQeUQ0,28224
|
|
53
|
+
smart_bot_factory-0.2.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
54
|
+
smart_bot_factory-0.2.6.dist-info/entry_points.txt,sha256=ybKEAI0WSb7WoRiey7QE-HHfn88UGV7nxLDxXq7b7SU,50
|
|
55
|
+
smart_bot_factory-0.2.6.dist-info/licenses/LICENSE,sha256=OrK3cwdUTzNzIhJvSPtJaVMoYIyC_sSx5EFE_FDMvGs,1092
|
|
56
|
+
smart_bot_factory-0.2.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|