smart-bot-factory 0.1.5__tar.gz → 0.1.6__tar.gz
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-0.1.5 → smart_bot_factory-0.1.6}/CLIENTS_USAGE.md +1 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/PKG-INFO +1 -1
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/ROUTER_ARCHITECTURE.md +1 -0
- smart_bot_factory-0.1.5/valera.py → smart_bot_factory-0.1.6/best-valera.py +9 -7
- {smart_bot_factory-0.1.5/smart_bot_factory/configs/growthmed-october-24 → smart_bot_factory-0.1.6/bots/best-valera}/prompts/final_instructions.txt +4 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/example_usage.py +69 -69
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/pyproject.toml +1 -1
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/cli.py +28 -33
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/core/bot_utils.py +28 -55
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/core/decorators.py +25 -41
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/core/message_sender.py +0 -5
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/core/router.py +2 -1
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/core/router_manager.py +1 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/creation/bot_builder.py +9 -27
- smart_bot_factory-0.1.6/smart_bot_factory/event/__init__.py +12 -0
- smart_bot_factory-0.1.6/smart_bot_factory/message/__init__.py +12 -0
- smart_bot_factory-0.1.6/smart_bot_factory/router/__init__.py +9 -0
- smart_bot_factory-0.1.6/smart_bot_factory/supabase/__init__.py +7 -0
- smart_bot_factory-0.1.6/smart_bot_factory/supabase/example_usage.py +1 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/uv.lock +1 -1
- smart_bot_factory-0.1.5/smart_bot_factory/analytics/__init__.py +0 -7
- smart_bot_factory-0.1.5/smart_bot_factory/clients/__init__.py +0 -33
- smart_bot_factory-0.1.5/smart_bot_factory/core/__init__.py +0 -43
- smart_bot_factory-0.1.5/smart_bot_factory/core/globals.py +0 -68
- smart_bot_factory-0.1.5/smart_bot_factory/integrations/__init__.py +0 -10
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/.github/ISSUE_TEMPLATE//342/234/250-/320/267/320/260/320/277/321/200/320/276/321/201-/321/204/321/203/320/275/320/272/321/206/320/270/320/270.md" +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/.github/ISSUE_TEMPLATE//360/237/220/233-/320/261/320/260/320/263-/321/200/320/265/320/277/320/276/321/200/321/202.md" +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/.github/workflows/ci.yml +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/.github/workflows/publish-private.yml +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/.github/workflows/publish.yml +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/.gitignore +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/.python-version +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/Dockerfile +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/LICENSE +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/README.md +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/bot_testing.py +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/bots/best-valera}/prompts/1sales_context.txt +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/bots/best-valera}/prompts/2product_info.txt +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/bots/best-valera}/prompts/3objection_handling.txt +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/bots/best-valera}/prompts/help_message.txt +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/bots/best-valera}/prompts/welcome_message.txt +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/bots/best-valera}/tests/quick_scenarios.yaml +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/bots/best-valera}/tests/realistic_scenarios.yaml +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/bots/best-valera}/tests/scenario_examples.yaml +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/bots/best-valera}/welcome_files/welcome_file_msg.txt +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/bots/best-valera}/welcome_files//320/247/320/265/320/272 /320/273/320/270/321/201/321/202 /320/277/320/276 152/320/244/320/227 /320/270 323/320/244/320/227 /320/264/320/273/321/217 /320/274/320/265/320/264/320/270/321/206/320/270/320/275/321/213.pdf" +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/configs/valera/cats//320/224/320/276/320/263/320/276/320/262/320/276/321/200.pdf" +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/configs/valera/cats//320/272/320/276/320/275/320/270.jpg" +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/configs/valera/cats//320/272/320/276/321/202.jpg" +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/configs/valera/cats//320/273/320/265/321/201.jpg" +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/configs/valera/tests/fixes_elina.yaml +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/configs/valera/welcome_file//320/247/320/265/320/272 /320/273/320/270/321/201/321/202 /320/277/320/276 152/320/244/320/227 /320/270 323/320/244/320/227 /320/264/320/273/321/217 /320/274/320/265/320/264/320/270/321/206/320/270/320/275/321/213.pdf" +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/create_tag.sh +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/docker-compose.yml +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/env.example +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/requirements.txt +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/save_backup.sh +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/save_fixes.sh +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/__init__.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/admin/__init__.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/admin/admin_logic.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/admin/admin_manager.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/admin/admin_migration.sql +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/admin/admin_tester.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/admin/timeout_checker.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/analytics/analytics_manager.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/config.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +0 -0
- {smart_bot_factory-0.1.5/bots/valera → smart_bot_factory-0.1.6/smart_bot_factory/configs/growthmed-october-24}/prompts/final_instructions.txt +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/configs/growthmed-october-24/welcome_file//320/247/320/265/320/272 /320/273/320/270/321/201/321/202 /320/277/320/276 152/320/244/320/227 /320/270 323/320/244/320/227 /320/264/320/273/321/217 /320/274/320/265/320/264/320/270/321/206/320/270/320/275/321/213.pdf" +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/core/conversation_manager.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/core/states.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/creation/__init__.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/creation/bot_testing.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/database/database_structure.sql +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/database/schema.sql +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/handlers/handlers.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/integrations/openai_client.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/integrations/supabase_client.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/setup_checker.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/utils/__init__.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/utils/debug_routing.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/utils/prompt_loader.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/utm_link_generator.py +0 -0
- {smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/system_prompt_example.txt +0 -0
|
@@ -71,3 +71,4 @@ async def send_mass_notification(message_text: str):
|
|
|
71
71
|
- Клиенты доступны только после запуска бота через `BotBuilder`
|
|
72
72
|
- Все клиенты типизированы для полной поддержки автозаполнения
|
|
73
73
|
- Остальные глобальные переменные (config, admin_manager и т.д.) недоступны пользователю
|
|
74
|
+
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
|
-
Бот valera - создан с помощью Smart Bot Factory
|
|
3
|
+
Бот best-valera - создан с помощью Smart Bot Factory
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import asyncio
|
|
7
7
|
|
|
8
|
-
from smart_bot_factory.
|
|
9
|
-
from smart_bot_factory.
|
|
10
|
-
from smart_bot_factory.
|
|
8
|
+
from smart_bot_factory.router import Router
|
|
9
|
+
from smart_bot_factory.message import send_message_by_human, send_message_to_users_by_stage
|
|
10
|
+
from smart_bot_factory.supabase import SupabaseClient
|
|
11
11
|
from smart_bot_factory.creation import BotBuilder
|
|
12
12
|
|
|
13
13
|
# Создаем роутер для всех обработчиков
|
|
14
|
-
router = Router("valera_handlers")
|
|
14
|
+
router = Router("best-valera_handlers")
|
|
15
|
+
|
|
16
|
+
supabase_client = SupabaseClient("best-valera")
|
|
15
17
|
|
|
16
18
|
# =============================================================================
|
|
17
19
|
# ОБРАБОТЧИКИ СОБЫТИЙ
|
|
18
20
|
# =============================================================================
|
|
19
21
|
|
|
20
|
-
@router.event_handler("
|
|
22
|
+
@router.event_handler("имя")
|
|
21
23
|
async def handle_example_event(user_id: int, event_data: str):
|
|
22
24
|
"""Пример обработчика события"""
|
|
23
25
|
# Отправляем подтверждение пользователю
|
|
@@ -116,7 +118,7 @@ async def main():
|
|
|
116
118
|
"""Основная функция запуска бота"""
|
|
117
119
|
try:
|
|
118
120
|
# Создаем и собираем бота
|
|
119
|
-
bot_builder = BotBuilder("valera")
|
|
121
|
+
bot_builder = BotBuilder("best-valera")
|
|
120
122
|
|
|
121
123
|
# Регистрируем роутер ПЕРЕД сборкой, чтобы обработчики были доступны
|
|
122
124
|
bot_builder.register_router(router)
|
|
@@ -128,6 +128,8 @@ id этапа бери из stages
|
|
|
128
128
|
<stage id="introduction">
|
|
129
129
|
на данном этапе выясни его имя, а также кем он работает и профиль его компании. после этого переходи к этапу consult.
|
|
130
130
|
если он уже в первом сообщении дал эту информацию - не переспрашивай.
|
|
131
|
+
|
|
132
|
+
Когда узнаешь имя пользователя, добавь событие тип='имя', в инфо добавь имя пользователя
|
|
131
133
|
</stage>
|
|
132
134
|
|
|
133
135
|
<stage id="consult">
|
|
@@ -135,6 +137,8 @@ id этапа бери из stages
|
|
|
135
137
|
если видишь, что особо вопросов больше не осталось переходи на этап offer.
|
|
136
138
|
будь краток, пиши по делу и только ключевую информацию. избегай длинных сообщений.
|
|
137
139
|
НЕ надо в первом же сообщении вываливать инфомацию из FAQ, пиши покороче.d
|
|
140
|
+
|
|
141
|
+
Если пользователь просит перевсти на консультацию добавь событие - тип=mass_notification запусти через минуту
|
|
138
142
|
</stage>
|
|
139
143
|
|
|
140
144
|
<stage id="offer">
|
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Пример использования простого импорта компонентов бота
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from smart_bot_factory.core import global_handler
|
|
7
|
-
from smart_bot_factory.clients import supabase_client, openai_client
|
|
8
|
-
|
|
9
|
-
# Теперь можно просто использовать импортированные переменные
|
|
10
|
-
async def example_function():
|
|
11
|
-
"""Пример функции с использованием импортированных компонентов"""
|
|
12
|
-
|
|
13
|
-
# Проверяем доступность
|
|
14
|
-
if not supabase_client:
|
|
15
|
-
print("Supabase клиент не доступен")
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
if not openai_client:
|
|
19
|
-
print("OpenAI клиент не доступен")
|
|
20
|
-
return
|
|
21
|
-
|
|
22
|
-
# Используем напрямую - теперь автозаполнение работает!
|
|
23
|
-
try:
|
|
24
|
-
# Получаем пользователей из БД с учетом bot_id
|
|
25
|
-
# IDE теперь знает тип supabase_client и предлагает методы
|
|
26
|
-
users = supabase_client.client.table('sales_users').select('*').eq('bot_id', supabase_client.bot_id).execute()
|
|
27
|
-
print(f"Найдено пользователей: {len(users.data)}")
|
|
28
|
-
|
|
29
|
-
# Пример использования OpenAI клиента
|
|
30
|
-
# IDE знает тип openai_client и предлагает методы
|
|
31
|
-
print("OpenAI клиент доступен для использования")
|
|
32
|
-
|
|
33
|
-
except Exception as e:
|
|
34
|
-
print(f"Ошибка: {e}")
|
|
35
|
-
|
|
36
|
-
# Пример глобального обработчика с простым импортом
|
|
37
|
-
@global_handler("example_notification")
|
|
38
|
-
async def send_example_notification(message_text: str):
|
|
39
|
-
"""Пример глобального обработчика с простым импортом"""
|
|
40
|
-
|
|
41
|
-
# Просто используем импортированный supabase_client
|
|
42
|
-
if not supabase_client:
|
|
43
|
-
return {"status": "error", "message": "Supabase клиент не найден"}
|
|
44
|
-
|
|
45
|
-
try:
|
|
46
|
-
# Получаем всех пользователей с учетом bot_id
|
|
47
|
-
users_response = supabase_client.client.table('sales_users').select('telegram_id').eq('bot_id', supabase_client.bot_id).execute()
|
|
48
|
-
|
|
49
|
-
if not users_response.data:
|
|
50
|
-
return {"status": "no_users", "message": "Пользователи не найдены"}
|
|
51
|
-
|
|
52
|
-
# Отправляем сообщения (пример)
|
|
53
|
-
sent_count = 0
|
|
54
|
-
for user in users_response.data:
|
|
55
|
-
# Здесь была бы отправка сообщения
|
|
56
|
-
sent_count += 1
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
"status": "completed",
|
|
60
|
-
"sent_count": sent_count,
|
|
61
|
-
"message": f"Отправлено {sent_count} сообщений"
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
except Exception as e:
|
|
65
|
-
return {"status": "error", "message": str(e)}
|
|
66
|
-
|
|
67
|
-
if __name__ == "__main__":
|
|
68
|
-
import asyncio
|
|
69
|
-
asyncio.run(example_function())
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Пример использования простого импорта компонентов бота
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from smart_bot_factory.core import global_handler
|
|
7
|
+
from smart_bot_factory.clients import supabase_client, openai_client
|
|
8
|
+
|
|
9
|
+
# Теперь можно просто использовать импортированные переменные
|
|
10
|
+
async def example_function():
|
|
11
|
+
"""Пример функции с использованием импортированных компонентов"""
|
|
12
|
+
|
|
13
|
+
# Проверяем доступность
|
|
14
|
+
if not supabase_client:
|
|
15
|
+
print("Supabase клиент не доступен")
|
|
16
|
+
return
|
|
17
|
+
|
|
18
|
+
if not openai_client:
|
|
19
|
+
print("OpenAI клиент не доступен")
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
# Используем напрямую - теперь автозаполнение работает!
|
|
23
|
+
try:
|
|
24
|
+
# Получаем пользователей из БД с учетом bot_id
|
|
25
|
+
# IDE теперь знает тип supabase_client и предлагает методы
|
|
26
|
+
users = supabase_client.client.table('sales_users').select('*').eq('bot_id', supabase_client.bot_id).execute()
|
|
27
|
+
print(f"Найдено пользователей: {len(users.data)}")
|
|
28
|
+
|
|
29
|
+
# Пример использования OpenAI клиента
|
|
30
|
+
# IDE знает тип openai_client и предлагает методы
|
|
31
|
+
print("OpenAI клиент доступен для использования")
|
|
32
|
+
|
|
33
|
+
except Exception as e:
|
|
34
|
+
print(f"Ошибка: {e}")
|
|
35
|
+
|
|
36
|
+
# Пример глобального обработчика с простым импортом
|
|
37
|
+
@global_handler("example_notification")
|
|
38
|
+
async def send_example_notification(message_text: str):
|
|
39
|
+
"""Пример глобального обработчика с простым импортом"""
|
|
40
|
+
|
|
41
|
+
# Просто используем импортированный supabase_client
|
|
42
|
+
if not supabase_client:
|
|
43
|
+
return {"status": "error", "message": "Supabase клиент не найден"}
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
# Получаем всех пользователей с учетом bot_id
|
|
47
|
+
users_response = supabase_client.client.table('sales_users').select('telegram_id').eq('bot_id', supabase_client.bot_id).execute()
|
|
48
|
+
|
|
49
|
+
if not users_response.data:
|
|
50
|
+
return {"status": "no_users", "message": "Пользователи не найдены"}
|
|
51
|
+
|
|
52
|
+
# Отправляем сообщения (пример)
|
|
53
|
+
sent_count = 0
|
|
54
|
+
for user in users_response.data:
|
|
55
|
+
# Здесь была бы отправка сообщения
|
|
56
|
+
sent_count += 1
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
"status": "completed",
|
|
60
|
+
"sent_count": sent_count,
|
|
61
|
+
"message": f"Отправлено {sent_count} сообщений"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
except Exception as e:
|
|
65
|
+
return {"status": "error", "message": str(e)}
|
|
66
|
+
|
|
67
|
+
if __name__ == "__main__":
|
|
68
|
+
import asyncio
|
|
69
|
+
asyncio.run(example_function())
|
|
@@ -35,9 +35,9 @@ def list():
|
|
|
35
35
|
click.echo("🤖 Нет доступных ботов")
|
|
36
36
|
return
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
click.echo("🤖 Доступные боты:")
|
|
39
|
+
for bot in sorted(bots):
|
|
40
|
+
click.echo(f" 📱 {bot}")
|
|
41
41
|
|
|
42
42
|
@cli.command()
|
|
43
43
|
@click.argument("bot_id")
|
|
@@ -191,8 +191,8 @@ def prompts(bot_id: str, list_prompts: bool = False, edit_prompt: str = None, ad
|
|
|
191
191
|
if not prompts_dir.exists():
|
|
192
192
|
raise click.ClickException(f"Папка промптов не найдена для бота {bot_id}")
|
|
193
193
|
|
|
194
|
-
if list_prompts:
|
|
195
|
-
# Показываем список промптов
|
|
194
|
+
if list_prompts or (not edit_prompt and not add_prompt):
|
|
195
|
+
# Показываем список промптов (по умолчанию или с флагом --list)
|
|
196
196
|
prompt_files = [f.name for f in prompts_dir.glob("*.txt")]
|
|
197
197
|
|
|
198
198
|
if not prompt_files:
|
|
@@ -202,6 +202,13 @@ def prompts(bot_id: str, list_prompts: bool = False, edit_prompt: str = None, ad
|
|
|
202
202
|
click.echo(f"📝 Промпты бота {bot_id}:")
|
|
203
203
|
for prompt_file in sorted(prompt_files):
|
|
204
204
|
click.echo(f" 📄 {prompt_file[:-4]}")
|
|
205
|
+
|
|
206
|
+
# Показываем справку только если не указан флаг --list
|
|
207
|
+
if not list_prompts:
|
|
208
|
+
click.echo()
|
|
209
|
+
click.echo("Использование:")
|
|
210
|
+
click.echo(" sbf prompts <bot_id> --edit <prompt_name> # Редактировать промпт")
|
|
211
|
+
click.echo(" sbf prompts <bot_id> --add <prompt_name> # Добавить новый промпт")
|
|
205
212
|
|
|
206
213
|
elif edit_prompt:
|
|
207
214
|
# Редактируем промпт
|
|
@@ -231,12 +238,6 @@ def prompts(bot_id: str, list_prompts: bool = False, edit_prompt: str = None, ad
|
|
|
231
238
|
click.echo(f"📝 Создаем новый промпт {add_prompt}...")
|
|
232
239
|
subprocess.run([editor, str(prompt_file)], check=True)
|
|
233
240
|
|
|
234
|
-
else:
|
|
235
|
-
# Показываем справку
|
|
236
|
-
click.echo("📖 Использование:")
|
|
237
|
-
click.echo(" 📋 sbf prompts <bot_id> --list # Показать список промптов")
|
|
238
|
-
click.echo(" ✏️ sbf prompts <bot_id> --edit <prompt_name> # Редактировать промпт")
|
|
239
|
-
click.echo(" ➕ sbf prompts <bot_id> --add <prompt_name> # Добавить новый промпт")
|
|
240
241
|
|
|
241
242
|
except subprocess.CalledProcessError as e:
|
|
242
243
|
click.echo(f"❌ Ошибка при открытии редактора: {e}", err=True)
|
|
@@ -259,21 +260,21 @@ def rm(bot_id: str, force: bool = False):
|
|
|
259
260
|
# Проверяем существование бота
|
|
260
261
|
bot_path = PROJECT_ROOT / Path("bots") / bot_id
|
|
261
262
|
if not bot_path.exists():
|
|
262
|
-
raise click.ClickException(f"Бот {bot_id} не найден в папке bots/")
|
|
263
|
+
raise click.ClickException(f"🤖 Бот {bot_id} не найден в папке bots/")
|
|
263
264
|
|
|
264
265
|
# Проверяем наличие основного файла бота в корневой директории
|
|
265
266
|
bot_file = Path(f"{bot_id}.py")
|
|
266
267
|
if not bot_file.exists():
|
|
267
|
-
raise click.ClickException(f"Файл {bot_id}.py не найден в корневой директории")
|
|
268
|
+
raise click.ClickException(f"📄 Файл {bot_id}.py не найден в корневой директории")
|
|
268
269
|
|
|
269
270
|
# Показываем что будет удалено
|
|
270
271
|
click.echo("🗑️ Будет удалено:")
|
|
271
|
-
click.echo(f"
|
|
272
|
-
click.echo(f"
|
|
272
|
+
click.echo(f" 📄 Файл запускалки: {bot_file}")
|
|
273
|
+
click.echo(f" 📁 Папка бота: {bot_path}")
|
|
273
274
|
|
|
274
275
|
# Запрашиваем подтверждение если не указан --force
|
|
275
276
|
if not force:
|
|
276
|
-
if not click.confirm(f"
|
|
277
|
+
if not click.confirm(f"⚠️ Вы уверены, что хотите удалить бота {bot_id}?"):
|
|
277
278
|
click.echo("❌ Удаление отменено")
|
|
278
279
|
return
|
|
279
280
|
|
|
@@ -288,7 +289,7 @@ def rm(bot_id: str, force: bool = False):
|
|
|
288
289
|
shutil.rmtree(bot_path)
|
|
289
290
|
click.echo(f"✅ Папка {bot_path} удалена")
|
|
290
291
|
|
|
291
|
-
click.echo(f"
|
|
292
|
+
click.echo(f"🎉 Бот {bot_id} полностью удален")
|
|
292
293
|
|
|
293
294
|
except Exception as e:
|
|
294
295
|
click.echo(f"❌ Ошибка при удалении бота: {e}", err=True)
|
|
@@ -318,8 +319,8 @@ def copy(source_bot_id: str, new_bot_id: str, force: bool = False):
|
|
|
318
319
|
|
|
319
320
|
if new_bot_path.exists() or new_bot_file.exists():
|
|
320
321
|
if not force:
|
|
321
|
-
if not click.confirm(f"
|
|
322
|
-
click.echo("
|
|
322
|
+
if not click.confirm(f"Бот {new_bot_id} уже существует. Перезаписать?"):
|
|
323
|
+
click.echo("Копирование отменено")
|
|
323
324
|
return
|
|
324
325
|
else:
|
|
325
326
|
click.echo(f"⚠️ Перезаписываем существующего бота {new_bot_id}")
|
|
@@ -414,14 +415,16 @@ def create_bot_template(bot_id: str) -> str:
|
|
|
414
415
|
|
|
415
416
|
import asyncio
|
|
416
417
|
|
|
417
|
-
from smart_bot_factory.
|
|
418
|
-
from smart_bot_factory.
|
|
419
|
-
from smart_bot_factory.
|
|
418
|
+
from smart_bot_factory.router import Router
|
|
419
|
+
from smart_bot_factory.message import send_message_by_human
|
|
420
|
+
from smart_bot_factory.supabase import SupabaseClient
|
|
420
421
|
from smart_bot_factory.creation import BotBuilder
|
|
421
422
|
|
|
422
423
|
# Создаем роутер для всех обработчиков
|
|
423
424
|
router = Router("{bot_id}_handlers")
|
|
424
425
|
|
|
426
|
+
supabase_client = SupabaseClient("{bot_id}")
|
|
427
|
+
|
|
425
428
|
# =============================================================================
|
|
426
429
|
# ОБРАБОТЧИКИ СОБЫТИЙ
|
|
427
430
|
# =============================================================================
|
|
@@ -677,18 +680,10 @@ def copy_bot_template(source_bot_id: str, new_bot_id: str):
|
|
|
677
680
|
new_bot_file.write_text(content, encoding='utf-8')
|
|
678
681
|
click.echo(f" 📄 Файл запускалки скопирован: {new_bot_id}.py")
|
|
679
682
|
|
|
680
|
-
#
|
|
681
|
-
source_env = source_dir / ".env"
|
|
683
|
+
# Создаем шаблон .env файла (НЕ копируем существующий)
|
|
682
684
|
new_env = new_dir / ".env"
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
shutil.copy2(source_env, new_env)
|
|
686
|
-
|
|
687
|
-
# Заменяем BOT_ID в .env
|
|
688
|
-
env_content = new_env.read_text(encoding='utf-8')
|
|
689
|
-
env_content = env_content.replace(f'BOT_ID={source_bot_id}', f'BOT_ID={new_bot_id}')
|
|
690
|
-
new_env.write_text(env_content, encoding='utf-8')
|
|
691
|
-
click.echo(f" ⚙️ .env файл скопирован и обновлен")
|
|
685
|
+
new_env.write_text(create_env_template(new_bot_id), encoding='utf-8')
|
|
686
|
+
click.echo(f" ⚙️ Создан шаблон .env файла")
|
|
692
687
|
|
|
693
688
|
# Копируем промпты
|
|
694
689
|
source_prompts = source_dir / "prompts"
|
|
@@ -31,45 +31,6 @@ def get_global_var(var_name):
|
|
|
31
31
|
|
|
32
32
|
logger = logging.getLogger(__name__)
|
|
33
33
|
|
|
34
|
-
def parse_time_expression(time_text: str) -> int:
|
|
35
|
-
"""
|
|
36
|
-
Парсит временные выражения и возвращает количество секунд
|
|
37
|
-
|
|
38
|
-
Поддерживаемые форматы:
|
|
39
|
-
- "30" -> 30 секунд (основной формат)
|
|
40
|
-
- "Запуск через 30 секунд" -> 30 секунд
|
|
41
|
-
- "через 5 минут" -> 300 секунд
|
|
42
|
-
- "через 1 час" -> 3600 секунд
|
|
43
|
-
- "через 2 часа" -> 7200 секунд
|
|
44
|
-
"""
|
|
45
|
-
# Сначала пробуем простое число (основной формат)
|
|
46
|
-
try:
|
|
47
|
-
return int(time_text)
|
|
48
|
-
except ValueError:
|
|
49
|
-
pass
|
|
50
|
-
|
|
51
|
-
# Убираем лишние символы и приводим к нижнему регистру
|
|
52
|
-
text = re.sub(r'[^\w\s\d]', '', time_text.lower())
|
|
53
|
-
|
|
54
|
-
# Ищем числа в тексте
|
|
55
|
-
numbers = re.findall(r'\d+', text)
|
|
56
|
-
if not numbers:
|
|
57
|
-
raise ValueError(f"Не найдено число в выражении: {time_text}")
|
|
58
|
-
|
|
59
|
-
number = int(numbers[0])
|
|
60
|
-
|
|
61
|
-
# Определяем единицу времени
|
|
62
|
-
if 'секунд' in text:
|
|
63
|
-
return number
|
|
64
|
-
elif 'минут' in text:
|
|
65
|
-
return number * 60
|
|
66
|
-
elif 'час' in text:
|
|
67
|
-
return number * 3600
|
|
68
|
-
elif 'день' in text or 'дней' in text:
|
|
69
|
-
return number * 86400
|
|
70
|
-
else:
|
|
71
|
-
# По умолчанию считаем секундами
|
|
72
|
-
return number
|
|
73
34
|
|
|
74
35
|
# Создаем роутер для общих команд
|
|
75
36
|
utils_router = Router()
|
|
@@ -244,10 +205,12 @@ async def process_events(session_id: str, events: list, user_id: int):
|
|
|
244
205
|
event_handlers = router_manager.get_event_handlers()
|
|
245
206
|
scheduled_tasks = router_manager.get_scheduled_tasks()
|
|
246
207
|
global_handlers = router_manager.get_global_handlers()
|
|
208
|
+
logger.debug(f"🔍 RouterManager найден: {len(global_handlers)} глобальных обработчиков")
|
|
247
209
|
else:
|
|
248
210
|
event_handlers = _event_handlers
|
|
249
211
|
scheduled_tasks = _scheduled_tasks
|
|
250
212
|
global_handlers = _global_handlers
|
|
213
|
+
logger.warning("⚠️ RouterManager не найден, используем старые декораторы")
|
|
251
214
|
|
|
252
215
|
# Сначала пробуем как обычное событие
|
|
253
216
|
if event_type in event_handlers:
|
|
@@ -266,49 +229,59 @@ async def process_events(session_id: str, events: list, user_id: int):
|
|
|
266
229
|
# Если не user_event, пробуем как запланированную задачу
|
|
267
230
|
elif event_type in scheduled_tasks:
|
|
268
231
|
try:
|
|
269
|
-
|
|
232
|
+
# Извлекаем время из event_info (AI должен передавать число секунд)
|
|
233
|
+
try:
|
|
234
|
+
delay_seconds = int(event_info)
|
|
235
|
+
except ValueError:
|
|
236
|
+
# Если не число, используем значение по умолчанию
|
|
237
|
+
delay_seconds = 3600
|
|
238
|
+
logger.warning(f" ⚠️ Не удалось извлечь время из '{event_info}', используем 3600с")
|
|
239
|
+
|
|
270
240
|
logger.info(f" ⏰ Сохраняем как scheduled_task: '{event_type}' через {delay_seconds}с")
|
|
271
241
|
result = await schedule_task_for_later_with_db(event_type, user_id, event_info, delay_seconds, session_id)
|
|
272
242
|
event_id = result['event_id']
|
|
273
243
|
should_notify = result.get('notify', False)
|
|
274
244
|
logger.info(f" 💾 Задача сохранена в БД: {event_id}")
|
|
275
245
|
|
|
276
|
-
except
|
|
246
|
+
except Exception as e:
|
|
277
247
|
if "once_only=True" in str(e):
|
|
278
248
|
logger.info(f" 🔄 Задача '{event_type}' уже запланирована, пропускаем")
|
|
279
249
|
continue
|
|
280
250
|
else:
|
|
281
|
-
logger.error(f" ❌ Ошибка
|
|
282
|
-
|
|
283
|
-
result = await schedule_task_for_later_with_db(event_type, user_id, event_info, 3600, session_id)
|
|
284
|
-
event_id = result['event_id']
|
|
285
|
-
should_notify = result.get('notify', False)
|
|
286
|
-
logger.info(f" ⏰ Задача сохранена с fallback временем (1 час): {event_id}")
|
|
251
|
+
logger.error(f" ❌ Ошибка планирования scheduled_task '{event_type}': {e}")
|
|
252
|
+
continue
|
|
287
253
|
|
|
288
254
|
# Если не scheduled_task, пробуем как глобальный обработчик
|
|
289
255
|
elif event_type in global_handlers:
|
|
290
256
|
try:
|
|
291
|
-
|
|
257
|
+
# Извлекаем время из event_info (AI должен передавать число секунд)
|
|
258
|
+
try:
|
|
259
|
+
delay_seconds = int(event_info)
|
|
260
|
+
except ValueError:
|
|
261
|
+
# Если не число, используем значение по умолчанию
|
|
262
|
+
delay_seconds = 3600
|
|
263
|
+
logger.warning(f" ⚠️ Не удалось извлечь время из '{event_info}', используем 3600с")
|
|
264
|
+
|
|
292
265
|
logger.info(f" 🌍 Сохраняем как global_handler: '{event_type}' через {delay_seconds}с")
|
|
293
266
|
result = await schedule_global_handler_for_later_with_db(event_type, delay_seconds, event_info)
|
|
294
267
|
event_id = result['event_id']
|
|
295
268
|
should_notify = result.get('notify', False)
|
|
296
269
|
logger.info(f" 💾 Глобальное событие сохранено в БД: {event_id}")
|
|
297
270
|
|
|
298
|
-
except
|
|
271
|
+
except Exception as e:
|
|
299
272
|
if "once_only=True" in str(e):
|
|
300
273
|
logger.info(f" 🔄 Глобальное событие '{event_type}' уже запланировано, пропускаем")
|
|
301
274
|
continue
|
|
302
275
|
else:
|
|
303
|
-
logger.error(f" ❌ Ошибка
|
|
304
|
-
|
|
305
|
-
result = await schedule_global_handler_for_later_with_db(event_type, 3600, event_info)
|
|
306
|
-
event_id = result['event_id']
|
|
307
|
-
should_notify = result.get('notify', False)
|
|
308
|
-
logger.info(f" 🌍 Глобальное событие сохранено с fallback временем (1 час): {event_id}")
|
|
276
|
+
logger.error(f" ❌ Ошибка планирования global_handler '{event_type}': {e}")
|
|
277
|
+
continue
|
|
309
278
|
|
|
310
279
|
else:
|
|
311
280
|
logger.warning(f" ⚠️ Обработчик '{event_type}' не найден среди зарегистрированных")
|
|
281
|
+
logger.debug(f" 🔍 Доступные обработчики:")
|
|
282
|
+
logger.debug(f" - event_handlers: {list(event_handlers.keys())}")
|
|
283
|
+
logger.debug(f" - scheduled_tasks: {list(scheduled_tasks.keys())}")
|
|
284
|
+
logger.debug(f" - global_handlers: {list(global_handlers.keys())}")
|
|
312
285
|
|
|
313
286
|
# Выполняем немедленные события
|
|
314
287
|
if should_execute_immediately and event_id:
|
|
@@ -292,18 +292,16 @@ async def execute_scheduled_task(task_name: str, user_id: int, user_data: str) -
|
|
|
292
292
|
|
|
293
293
|
async def execute_global_handler(handler_type: str, *args, **kwargs) -> Any:
|
|
294
294
|
"""Выполняет глобальный обработчик по типу"""
|
|
295
|
-
|
|
296
|
-
if
|
|
297
|
-
global_handlers =
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
return await handler_info['handler'](*args, **kwargs)
|
|
295
|
+
router_manager = get_router_manager()
|
|
296
|
+
if router_manager:
|
|
297
|
+
global_handlers = router_manager.get_global_handlers()
|
|
298
|
+
else:
|
|
299
|
+
global_handlers = _global_handlers
|
|
301
300
|
|
|
302
|
-
|
|
303
|
-
if handler_type not in _global_handlers:
|
|
301
|
+
if handler_type not in global_handlers:
|
|
304
302
|
raise ValueError(f"Глобальный обработчик '{handler_type}' не найден")
|
|
305
303
|
|
|
306
|
-
handler_info =
|
|
304
|
+
handler_info = global_handlers[handler_type]
|
|
307
305
|
return await handler_info['handler'](*args, **kwargs)
|
|
308
306
|
|
|
309
307
|
async def schedule_task_for_later(task_name: str, delay_seconds: int, user_id: int, user_data: str):
|
|
@@ -461,12 +459,7 @@ async def save_immediate_event(
|
|
|
461
459
|
raise RuntimeError("Supabase клиент не инициализирован")
|
|
462
460
|
|
|
463
461
|
# Проверяем, нужно ли предотвращать дублирование
|
|
464
|
-
|
|
465
|
-
if _router_manager:
|
|
466
|
-
event_handlers = _router_manager.get_event_handlers()
|
|
467
|
-
event_handler_info = event_handlers.get(event_type, {})
|
|
468
|
-
else:
|
|
469
|
-
event_handler_info = _event_handlers.get(event_type, {})
|
|
462
|
+
event_handler_info = _event_handlers.get(event_type, {})
|
|
470
463
|
once_only = event_handler_info.get('once_only', True)
|
|
471
464
|
|
|
472
465
|
if once_only:
|
|
@@ -510,12 +503,7 @@ async def save_scheduled_task(
|
|
|
510
503
|
raise RuntimeError("Supabase клиент не инициализирован")
|
|
511
504
|
|
|
512
505
|
# Проверяем, нужно ли предотвращать дублирование
|
|
513
|
-
|
|
514
|
-
if _router_manager:
|
|
515
|
-
scheduled_tasks = _router_manager.get_scheduled_tasks()
|
|
516
|
-
task_info = scheduled_tasks.get(task_name, {})
|
|
517
|
-
else:
|
|
518
|
-
task_info = _scheduled_tasks.get(task_name, {})
|
|
506
|
+
task_info = _scheduled_tasks.get(task_name, {})
|
|
519
507
|
once_only = task_info.get('once_only', True)
|
|
520
508
|
|
|
521
509
|
if once_only:
|
|
@@ -559,12 +547,13 @@ async def save_global_event(
|
|
|
559
547
|
raise RuntimeError("Supabase клиент не инициализирован")
|
|
560
548
|
|
|
561
549
|
# Проверяем, нужно ли предотвращать дублирование
|
|
562
|
-
|
|
563
|
-
if
|
|
564
|
-
global_handlers =
|
|
565
|
-
handler_info = global_handlers.get(handler_type, {})
|
|
550
|
+
router_manager = get_router_manager()
|
|
551
|
+
if router_manager:
|
|
552
|
+
global_handlers = router_manager.get_global_handlers()
|
|
566
553
|
else:
|
|
567
|
-
|
|
554
|
+
global_handlers = _global_handlers
|
|
555
|
+
|
|
556
|
+
handler_info = global_handlers.get(handler_type, {})
|
|
568
557
|
once_only = handler_info.get('once_only', True)
|
|
569
558
|
|
|
570
559
|
if once_only:
|
|
@@ -714,14 +703,8 @@ async def process_scheduled_event(event: Dict):
|
|
|
714
703
|
async def schedule_task_for_later_with_db(task_name: str, user_id: int, user_data: str, delay_seconds: int, session_id: str = None):
|
|
715
704
|
"""Планирует выполнение задачи через указанное время с сохранением в БД"""
|
|
716
705
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
scheduled_tasks = _router_manager.get_scheduled_tasks()
|
|
720
|
-
if task_name not in scheduled_tasks:
|
|
721
|
-
raise ValueError(f"Задача '{task_name}' не найдена")
|
|
722
|
-
else:
|
|
723
|
-
if task_name not in _scheduled_tasks:
|
|
724
|
-
raise ValueError(f"Задача '{task_name}' не найдена")
|
|
706
|
+
if task_name not in _scheduled_tasks:
|
|
707
|
+
raise ValueError(f"Задача '{task_name}' не найдена")
|
|
725
708
|
|
|
726
709
|
logger.info(f"⏰ Планируем задачу '{task_name}' через {delay_seconds} секунд")
|
|
727
710
|
|
|
@@ -782,14 +765,15 @@ async def schedule_task_for_later_with_db(task_name: str, user_id: int, user_dat
|
|
|
782
765
|
async def schedule_global_handler_for_later_with_db(handler_type: str, delay_seconds: int, handler_data: str):
|
|
783
766
|
"""Планирует выполнение глобального обработчика через указанное время с сохранением в БД"""
|
|
784
767
|
|
|
785
|
-
# Проверяем через
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
raise ValueError(f"Глобальный обработчик '{handler_type}' не найден")
|
|
768
|
+
# Проверяем обработчик через RouterManager или fallback к старым декораторам
|
|
769
|
+
router_manager = get_router_manager()
|
|
770
|
+
if router_manager:
|
|
771
|
+
global_handlers = router_manager.get_global_handlers()
|
|
790
772
|
else:
|
|
791
|
-
|
|
792
|
-
|
|
773
|
+
global_handlers = _global_handlers
|
|
774
|
+
|
|
775
|
+
if handler_type not in global_handlers:
|
|
776
|
+
raise ValueError(f"Глобальный обработчик '{handler_type}' не найден")
|
|
793
777
|
|
|
794
778
|
logger.info(f"🌍 Планируем глобальный обработчик '{handler_type}' через {delay_seconds} секунд")
|
|
795
779
|
|
{smart_bot_factory-0.1.5 → smart_bot_factory-0.1.6}/smart_bot_factory/core/message_sender.py
RENAMED
|
@@ -29,11 +29,6 @@ async def send_message_by_ai(
|
|
|
29
29
|
try:
|
|
30
30
|
# Импортируем необходимые компоненты
|
|
31
31
|
from .bot_utils import parse_ai_response, process_events
|
|
32
|
-
from ..config import Config
|
|
33
|
-
from ..integrations.openai_client import OpenAIClient
|
|
34
|
-
from ..integrations.supabase_client import SupabaseClient
|
|
35
|
-
from ..utils.prompt_loader import PromptLoader
|
|
36
|
-
from aiogram import Bot
|
|
37
32
|
|
|
38
33
|
# Получаем компоненты из глобального контекста
|
|
39
34
|
from ..handlers.handlers import get_global_var
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Роутер для Smart Bot Factory - аналог aiogram Router
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from typing import Dict,
|
|
5
|
+
from typing import Dict, Any, Callable
|
|
6
6
|
import logging
|
|
7
7
|
|
|
8
8
|
logger = logging.getLogger(__name__)
|
|
@@ -170,3 +170,4 @@ class Router:
|
|
|
170
170
|
|
|
171
171
|
def __repr__(self):
|
|
172
172
|
return f"Router(name='{self.name}', events={len(self._event_handlers)}, tasks={len(self._scheduled_tasks)}, globals={len(self._global_handlers)})"
|
|
173
|
+
|