smart-bot-factory 0.1.1__py3-none-any.whl → 0.1.3__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/__init__.py +51 -0
- smart_bot_factory/admin/__init__.py +16 -0
- smart_bot_factory/admin/admin_logic.py +430 -0
- smart_bot_factory/admin/admin_manager.py +141 -0
- smart_bot_factory/admin/admin_migration.sql +136 -0
- smart_bot_factory/admin/admin_tester.py +151 -0
- smart_bot_factory/admin/timeout_checker.py +499 -0
- smart_bot_factory/analytics/__init__.py +7 -0
- smart_bot_factory/analytics/analytics_manager.py +355 -0
- smart_bot_factory/cli.py +642 -0
- smart_bot_factory/config.py +235 -0
- smart_bot_factory/configs/growthmed-helper/env_example.txt +1 -0
- smart_bot_factory/configs/growthmed-helper/prompts/1sales_context.txt +9 -0
- smart_bot_factory/configs/growthmed-helper/prompts/2product_info.txt +582 -0
- smart_bot_factory/configs/growthmed-helper/prompts/3objection_handling.txt +66 -0
- smart_bot_factory/configs/growthmed-helper/prompts/final_instructions.txt +232 -0
- smart_bot_factory/configs/growthmed-helper/prompts/help_message.txt +28 -0
- smart_bot_factory/configs/growthmed-helper/prompts/welcome_message.txt +7 -0
- smart_bot_factory/configs/growthmed-helper/welcome_file/welcome_file_msg.txt +16 -0
- smart_bot_factory/configs/growthmed-helper/welcome_file//342/225/250/320/267/342/225/250/342/225/241/342/225/250/342/225/221 /342/225/250/342/225/227/342/225/250/342/225/225/342/225/244/320/221/342/225/244/320/222 /342/225/250/342/224/220/342/225/250/342/225/233 152/342/225/250/320/264/342/225/250/320/247 /342/225/250/342/225/225 323/342/225/250/320/264/342/225/250/320/247 /342/225/250/342/224/244/342/225/250/342/225/227/342/225/244/320/237 /342/225/250/342/225/235/342/225/250/342/225/241/342/225/250/342/224/244/342/225/250/342/225/225/342/225/244/320/226/342/225/250/342/225/225/342/225/250/342/225/234/342/225/244/320/233.pdf +0 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +16 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +582 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +66 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +212 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +28 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +8 -0
- smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +818 -0
- smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +32 -0
- smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +35 -0
- smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +66 -0
- smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +108 -0
- smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +46 -0
- smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +16 -0
- smart_bot_factory/configs/growthmed-october-24/welcome_file//342/225/250/320/267/342/225/250/342/225/241/342/225/250/342/225/221 /342/225/250/342/225/227/342/225/250/342/225/225/342/225/244/320/221/342/225/244/320/222 /342/225/250/342/224/220/342/225/250/342/225/233 152/342/225/250/320/264/342/225/250/320/247 /342/225/250/342/225/225 323/342/225/250/320/264/342/225/250/320/247 /342/225/250/342/224/244/342/225/250/342/225/227/342/225/244/320/237 /342/225/250/342/225/235/342/225/250/342/225/241/342/225/250/342/224/244/342/225/250/342/225/225/342/225/244/320/226/342/225/250/342/225/225/342/225/250/342/225/234/342/225/244/320/233.pdf +0 -0
- smart_bot_factory/core/__init__.py +22 -0
- smart_bot_factory/core/bot_utils.py +693 -0
- smart_bot_factory/core/conversation_manager.py +536 -0
- smart_bot_factory/core/decorators.py +229 -0
- smart_bot_factory/core/message_sender.py +249 -0
- smart_bot_factory/core/states.py +14 -0
- smart_bot_factory/creation/__init__.py +8 -0
- smart_bot_factory/creation/bot_builder.py +329 -0
- smart_bot_factory/creation/bot_testing.py +986 -0
- smart_bot_factory/database/database_structure.sql +57 -0
- smart_bot_factory/database/schema.sql +1094 -0
- smart_bot_factory/handlers/handlers.py +583 -0
- smart_bot_factory/integrations/__init__.py +9 -0
- smart_bot_factory/integrations/openai_client.py +435 -0
- smart_bot_factory/integrations/supabase_client.py +592 -0
- smart_bot_factory/setup_checker.py +476 -0
- smart_bot_factory/utils/__init__.py +9 -0
- smart_bot_factory/utils/debug_routing.py +103 -0
- smart_bot_factory/utils/prompt_loader.py +427 -0
- smart_bot_factory/uv.lock +2004 -0
- smart_bot_factory-0.1.3.dist-info/METADATA +126 -0
- smart_bot_factory-0.1.3.dist-info/RECORD +59 -0
- smart_bot_factory-0.1.3.dist-info/licenses/LICENSE +24 -0
- smart_bot_factory-0.1.1.dist-info/METADATA +0 -31
- smart_bot_factory-0.1.1.dist-info/RECORD +0 -4
- {smart_bot_factory-0.1.1.dist-info → smart_bot_factory-0.1.3.dist-info}/WHEEL +0 -0
- {smart_bot_factory-0.1.1.dist-info → smart_bot_factory-0.1.3.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Модуль для проверки настройки Telegram Sales Bot v2.0 (с админской системой)
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
import sys
|
|
8
|
+
import os
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Dict, Any, Optional, List, Tuple
|
|
11
|
+
|
|
12
|
+
from .config import Config
|
|
13
|
+
from .integrations.supabase_client import SupabaseClient
|
|
14
|
+
from .integrations.openai_client import OpenAIClient
|
|
15
|
+
from .utils.prompt_loader import PromptLoader
|
|
16
|
+
from .admin.admin_manager import AdminManager
|
|
17
|
+
from .core.conversation_manager import ConversationManager
|
|
18
|
+
from .analytics.analytics_manager import AnalyticsManager
|
|
19
|
+
from .core.bot_utils import parse_ai_response
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
def setup_bot_environment(bot_name: str = "growthmed-october-24") -> Optional[Path]:
|
|
24
|
+
"""
|
|
25
|
+
Настраивает окружение для указанного бота с автоопределением BOT_ID
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
bot_name: Имя бота для настройки
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Optional[Path]: Путь к корневой директории проекта, если настройка успешна, None в случае ошибки
|
|
32
|
+
"""
|
|
33
|
+
root_dir = Path(os.getcwd()) # Используем текущую директорию как корневую
|
|
34
|
+
config_dir = root_dir / 'bots' / bot_name
|
|
35
|
+
|
|
36
|
+
if not config_dir.exists():
|
|
37
|
+
logger.error(f"❌ Папка конфигурации не найдена: {config_dir}")
|
|
38
|
+
logger.info(f" Доступные боты:")
|
|
39
|
+
bots_dir = root_dir / 'bots'
|
|
40
|
+
if bots_dir.exists():
|
|
41
|
+
for bot_dir in bots_dir.iterdir():
|
|
42
|
+
if bot_dir.is_dir():
|
|
43
|
+
logger.info(f" - {bot_dir.name}")
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
# Устанавливаем BOT_ID из имени бота
|
|
47
|
+
os.environ['BOT_ID'] = bot_name
|
|
48
|
+
logger.info(f"🤖 Автоматически установлен BOT_ID: {bot_name}")
|
|
49
|
+
|
|
50
|
+
# Загружаем .env из конфигурации бота
|
|
51
|
+
env_file = config_dir / '.env'
|
|
52
|
+
if env_file.exists():
|
|
53
|
+
logger.info(f"🔧 Загружаем .env из: {env_file}")
|
|
54
|
+
from dotenv import load_dotenv
|
|
55
|
+
load_dotenv(env_file)
|
|
56
|
+
else:
|
|
57
|
+
logger.error(f"❌ Файл .env не найден: {env_file}")
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
# Меняем рабочую директорию
|
|
61
|
+
os.chdir(str(config_dir))
|
|
62
|
+
logger.info(f"📁 Рабочая директория: {config_dir}")
|
|
63
|
+
|
|
64
|
+
return root_dir
|
|
65
|
+
|
|
66
|
+
async def check_config() -> Optional[Config]:
|
|
67
|
+
"""Проверяем конфигурацию с новыми админскими настройками"""
|
|
68
|
+
try:
|
|
69
|
+
config = Config()
|
|
70
|
+
|
|
71
|
+
logger.info("✅ Конфигурация загружена успешно")
|
|
72
|
+
logger.info(f"📋 Сводка конфигурации:")
|
|
73
|
+
|
|
74
|
+
summary = config.get_summary()
|
|
75
|
+
for key, value in summary.items():
|
|
76
|
+
logger.info(f" • {key}: {value}")
|
|
77
|
+
|
|
78
|
+
# Проверяем админские настройки
|
|
79
|
+
logger.info(f"\n👑 Админские настройки:")
|
|
80
|
+
logger.info(f" • Админов настроено: {len(config.ADMIN_TELEGRAM_IDS)}")
|
|
81
|
+
if config.ADMIN_TELEGRAM_IDS:
|
|
82
|
+
logger.info(f" • ID админов: {config.ADMIN_TELEGRAM_IDS}")
|
|
83
|
+
logger.info(f" • Таймаут сессий: {config.ADMIN_SESSION_TIMEOUT_MINUTES} мин")
|
|
84
|
+
logger.info(f" • Режим отладки: {'Включен' if config.DEBUG_MODE else 'Выключен'}")
|
|
85
|
+
|
|
86
|
+
return config
|
|
87
|
+
except Exception as e:
|
|
88
|
+
logger.error(f"❌ Ошибка конфигурации: {e}")
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
async def check_supabase(config: Config) -> bool:
|
|
92
|
+
"""Проверяем подключение к Supabase и новые таблицы"""
|
|
93
|
+
try:
|
|
94
|
+
client = SupabaseClient(config.SUPABASE_URL, config.SUPABASE_KEY)
|
|
95
|
+
await client.initialize()
|
|
96
|
+
|
|
97
|
+
# Пробуем выполнить простой запрос к основной таблице
|
|
98
|
+
response = client.client.table('sales_users').select('id').limit(1).execute()
|
|
99
|
+
logger.info("✅ Supabase подключение успешно")
|
|
100
|
+
|
|
101
|
+
# Проверяем новые таблицы админской системы
|
|
102
|
+
admin_tables = [
|
|
103
|
+
'sales_admins',
|
|
104
|
+
'admin_user_conversations',
|
|
105
|
+
'session_events'
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
logger.info("🔍 Проверка админских таблиц:")
|
|
109
|
+
for table in admin_tables:
|
|
110
|
+
try:
|
|
111
|
+
response = client.client.table(table).select('*').limit(1).execute()
|
|
112
|
+
logger.info(f" ✅ {table}")
|
|
113
|
+
except Exception as e:
|
|
114
|
+
logger.error(f" ❌ {table}: {e}")
|
|
115
|
+
|
|
116
|
+
# Проверяем новые колонки
|
|
117
|
+
logger.info("🔍 Проверка новых колонок:")
|
|
118
|
+
try:
|
|
119
|
+
response = client.client.table('sales_chat_sessions').select(
|
|
120
|
+
'current_stage', 'lead_quality_score'
|
|
121
|
+
).limit(1).execute()
|
|
122
|
+
logger.info(" ✅ sales_chat_sessions: current_stage, lead_quality_score")
|
|
123
|
+
except Exception as e:
|
|
124
|
+
logger.error(f" ❌ sales_chat_sessions новые колонки: {e}")
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
response = client.client.table('sales_messages').select('ai_metadata').limit(1).execute()
|
|
128
|
+
logger.info(" ✅ sales_messages: ai_metadata")
|
|
129
|
+
except Exception as e:
|
|
130
|
+
logger.error(f" ❌ sales_messages.ai_metadata: {e}")
|
|
131
|
+
|
|
132
|
+
return True
|
|
133
|
+
except Exception as e:
|
|
134
|
+
logger.error(f"❌ Ошибка Supabase: {e}")
|
|
135
|
+
return False
|
|
136
|
+
|
|
137
|
+
async def check_openai(config: Config) -> bool:
|
|
138
|
+
"""Проверяем OpenAI API"""
|
|
139
|
+
try:
|
|
140
|
+
client = OpenAIClient(
|
|
141
|
+
config.OPENAI_API_KEY,
|
|
142
|
+
config.OPENAI_MODEL,
|
|
143
|
+
config.OPENAI_MAX_TOKENS,
|
|
144
|
+
config.OPENAI_TEMPERATURE
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
health = await client.check_api_health()
|
|
148
|
+
|
|
149
|
+
if health:
|
|
150
|
+
logger.info("✅ OpenAI API доступен")
|
|
151
|
+
|
|
152
|
+
# Получаем список доступных моделей
|
|
153
|
+
models = await client.get_available_models()
|
|
154
|
+
if config.OPENAI_MODEL in models:
|
|
155
|
+
logger.info(f"✅ Модель {config.OPENAI_MODEL} доступна")
|
|
156
|
+
else:
|
|
157
|
+
logger.warning(f"⚠️ Модель {config.OPENAI_MODEL} не найдена в доступных")
|
|
158
|
+
logger.info(f" Доступные модели: {models[:5]}...")
|
|
159
|
+
|
|
160
|
+
return health
|
|
161
|
+
except Exception as e:
|
|
162
|
+
logger.error(f"❌ Ошибка OpenAI: {e}")
|
|
163
|
+
return False
|
|
164
|
+
|
|
165
|
+
async def check_prompts(config: Config) -> bool:
|
|
166
|
+
"""Проверяем промпты с новыми JSON инструкциями"""
|
|
167
|
+
try:
|
|
168
|
+
loader = PromptLoader(
|
|
169
|
+
prompts_dir=config.PROMT_FILES_DIR,
|
|
170
|
+
prompt_files=config.PROMPT_FILES
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Проверяем доступность файлов
|
|
174
|
+
validation = await loader.validate_prompts()
|
|
175
|
+
|
|
176
|
+
logger.info(f"📝 Статус промптов:")
|
|
177
|
+
for filename, status in validation.items():
|
|
178
|
+
status_icon = "✅" if status else "❌"
|
|
179
|
+
logger.info(f" {status_icon} {filename}")
|
|
180
|
+
|
|
181
|
+
# Пробуем загрузить системный промпт
|
|
182
|
+
if any(validation.values()):
|
|
183
|
+
system_prompt = await loader.load_system_prompt()
|
|
184
|
+
logger.info(f"✅ Системный промпт загружен ({len(system_prompt)} символов)")
|
|
185
|
+
|
|
186
|
+
# Проверяем наличие JSON инструкций
|
|
187
|
+
if "JSON МЕТАДАННЫМ" in system_prompt:
|
|
188
|
+
logger.info("✅ JSON инструкции включены в системный промпт")
|
|
189
|
+
else:
|
|
190
|
+
logger.warning("⚠️ JSON инструкции не найдены в системном промпте")
|
|
191
|
+
|
|
192
|
+
if '"этап":' in system_prompt:
|
|
193
|
+
logger.info("✅ Примеры JSON найдены в промпте")
|
|
194
|
+
else:
|
|
195
|
+
logger.warning("⚠️ Примеры JSON не найдены в промпте")
|
|
196
|
+
|
|
197
|
+
# Проверяем приветственное сообщение
|
|
198
|
+
welcome_message = await loader.load_welcome_message()
|
|
199
|
+
logger.info(f"✅ Приветственное сообщение загружено ({len(welcome_message)} символов)")
|
|
200
|
+
|
|
201
|
+
# Проверяем справочное сообщение
|
|
202
|
+
help_message = await loader.load_help_message()
|
|
203
|
+
logger.info(f"✅ Справочное сообщение загружено ({len(help_message)} символов)")
|
|
204
|
+
|
|
205
|
+
return True
|
|
206
|
+
else:
|
|
207
|
+
logger.error("❌ Не удалось загрузить ни одного промпта")
|
|
208
|
+
return False
|
|
209
|
+
|
|
210
|
+
except Exception as e:
|
|
211
|
+
logger.error(f"❌ Ошибка загрузки промптов: {e}")
|
|
212
|
+
return False
|
|
213
|
+
|
|
214
|
+
async def check_admin_system(config: Config) -> bool:
|
|
215
|
+
"""Проверяем админскую систему"""
|
|
216
|
+
try:
|
|
217
|
+
logger.info("👑 Проверка админской системы...")
|
|
218
|
+
|
|
219
|
+
if not config.ADMIN_TELEGRAM_IDS:
|
|
220
|
+
logger.warning("⚠️ Админы не настроены (ADMIN_TELEGRAM_IDS пуст)")
|
|
221
|
+
return False
|
|
222
|
+
|
|
223
|
+
# Проверяем AdminManager
|
|
224
|
+
supabase_client = SupabaseClient(config.SUPABASE_URL, config.SUPABASE_KEY)
|
|
225
|
+
await supabase_client.initialize()
|
|
226
|
+
|
|
227
|
+
admin_manager = AdminManager(config, supabase_client)
|
|
228
|
+
logger.info(f"✅ AdminManager инициализирован ({len(admin_manager.admin_ids)} админов)")
|
|
229
|
+
|
|
230
|
+
# Проверяем ConversationManager
|
|
231
|
+
conversation_manager = ConversationManager(supabase_client, admin_manager)
|
|
232
|
+
logger.info("✅ ConversationManager инициализирован")
|
|
233
|
+
|
|
234
|
+
# Проверяем AnalyticsManager
|
|
235
|
+
analytics_manager = AnalyticsManager(supabase_client)
|
|
236
|
+
|
|
237
|
+
# Тестируем получение статистики
|
|
238
|
+
funnel_stats = await analytics_manager.get_funnel_stats(1)
|
|
239
|
+
logger.info("✅ AnalyticsManager работает")
|
|
240
|
+
|
|
241
|
+
logger.info("✅ Админская система готова к работе")
|
|
242
|
+
return True
|
|
243
|
+
|
|
244
|
+
except Exception as e:
|
|
245
|
+
logger.error(f"❌ Ошибка админской системы: {e}")
|
|
246
|
+
return False
|
|
247
|
+
|
|
248
|
+
async def check_json_parsing() -> bool:
|
|
249
|
+
"""Проверяем парсинг JSON метаданных"""
|
|
250
|
+
try:
|
|
251
|
+
logger.info("🧪 Проверка парсинга JSON...")
|
|
252
|
+
|
|
253
|
+
# Тестовые случаи
|
|
254
|
+
test_response = '''Отлично! Записал ваш номер телефона.
|
|
255
|
+
|
|
256
|
+
{
|
|
257
|
+
"этап": "contacts",
|
|
258
|
+
"качество": 9,
|
|
259
|
+
"события": [
|
|
260
|
+
{
|
|
261
|
+
"тип": "телефон",
|
|
262
|
+
"инфо": "Иван Петров +79219603144"
|
|
263
|
+
}
|
|
264
|
+
]
|
|
265
|
+
}'''
|
|
266
|
+
|
|
267
|
+
response_text, metadata = parse_ai_response(test_response)
|
|
268
|
+
|
|
269
|
+
if metadata:
|
|
270
|
+
logger.info("✅ JSON успешно распарсен")
|
|
271
|
+
logger.info(f" Этап: {metadata.get('этап')}")
|
|
272
|
+
logger.info(f" Качество: {metadata.get('качество')}")
|
|
273
|
+
logger.info(f" События: {len(metadata.get('события', []))}")
|
|
274
|
+
return True
|
|
275
|
+
else:
|
|
276
|
+
logger.error("❌ Не удалось распарсить JSON")
|
|
277
|
+
return False
|
|
278
|
+
|
|
279
|
+
except Exception as e:
|
|
280
|
+
logger.error(f"❌ Ошибка парсинга JSON: {e}")
|
|
281
|
+
return False
|
|
282
|
+
|
|
283
|
+
async def check_database_structure() -> bool:
|
|
284
|
+
"""Проверяем структуру базы данных"""
|
|
285
|
+
try:
|
|
286
|
+
logger.info("📊 Проверка структуры БД...")
|
|
287
|
+
|
|
288
|
+
# Проверяем наличие SQL файлов
|
|
289
|
+
root_dir = Path(os.getcwd())
|
|
290
|
+
sql_files = [
|
|
291
|
+
("database_structure.sql", "smart_bot_factory/database/database_structure.sql"),
|
|
292
|
+
("admin_migration.sql", "smart_bot_factory/admin/admin_migration.sql")
|
|
293
|
+
]
|
|
294
|
+
|
|
295
|
+
for sql_name, sql_path in sql_files:
|
|
296
|
+
full_path = root_dir / sql_path
|
|
297
|
+
if full_path.exists():
|
|
298
|
+
logger.info(f"✅ {sql_name} найден: {sql_path}")
|
|
299
|
+
else:
|
|
300
|
+
logger.error(f"❌ {sql_name} не найден: {sql_path}")
|
|
301
|
+
|
|
302
|
+
logger.info("ℹ️ Для проверки таблиц в БД запустите SQL скрипты в Supabase")
|
|
303
|
+
return True
|
|
304
|
+
|
|
305
|
+
except Exception as e:
|
|
306
|
+
logger.error(f"❌ Ошибка проверки БД: {e}")
|
|
307
|
+
return False
|
|
308
|
+
|
|
309
|
+
async def check_environment() -> None:
|
|
310
|
+
"""Проверяем окружение"""
|
|
311
|
+
logger.info("🔧 Проверка окружения...")
|
|
312
|
+
|
|
313
|
+
# Проверяем Python зависимости
|
|
314
|
+
dependencies = [
|
|
315
|
+
('aiogram', 'aiogram'),
|
|
316
|
+
('supabase', 'supabase'),
|
|
317
|
+
('openai', 'openai'),
|
|
318
|
+
('python-dotenv', 'dotenv'),
|
|
319
|
+
('aiofiles', 'aiofiles')
|
|
320
|
+
]
|
|
321
|
+
|
|
322
|
+
for dep_name, import_name in dependencies:
|
|
323
|
+
try:
|
|
324
|
+
if import_name == 'aiogram':
|
|
325
|
+
import aiogram
|
|
326
|
+
logger.info(f"✅ {dep_name} {aiogram.__version__}")
|
|
327
|
+
elif import_name == 'openai':
|
|
328
|
+
import openai
|
|
329
|
+
logger.info(f"✅ {dep_name} {openai.version.VERSION}")
|
|
330
|
+
else:
|
|
331
|
+
__import__(import_name)
|
|
332
|
+
logger.info(f"✅ {dep_name} установлен")
|
|
333
|
+
except ImportError:
|
|
334
|
+
logger.error(f"❌ {dep_name} не установлен")
|
|
335
|
+
|
|
336
|
+
async def run_quick_test() -> bool:
|
|
337
|
+
"""Быстрый тест основного функционала"""
|
|
338
|
+
try:
|
|
339
|
+
logger.info("⚡ Быстрый тест компонентов...")
|
|
340
|
+
|
|
341
|
+
config = Config()
|
|
342
|
+
|
|
343
|
+
if config.ADMIN_TELEGRAM_IDS:
|
|
344
|
+
logger.info(f"✅ {len(config.ADMIN_TELEGRAM_IDS)} админов настроено")
|
|
345
|
+
else:
|
|
346
|
+
logger.warning("⚠️ Админы не настроены")
|
|
347
|
+
|
|
348
|
+
# Тест парсинга JSON
|
|
349
|
+
await check_json_parsing()
|
|
350
|
+
|
|
351
|
+
return True
|
|
352
|
+
|
|
353
|
+
except Exception as e:
|
|
354
|
+
logger.error(f"❌ Ошибка быстрого теста: {e}")
|
|
355
|
+
return False
|
|
356
|
+
|
|
357
|
+
async def check_setup(bot_name: str = "growthmed-october-24") -> bool:
|
|
358
|
+
"""
|
|
359
|
+
Проверяет настройку бота
|
|
360
|
+
|
|
361
|
+
Args:
|
|
362
|
+
bot_name: Имя бота для проверки
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
bool: True если все критические проверки пройдены, False если есть критические ошибки
|
|
366
|
+
"""
|
|
367
|
+
logger.info(f"🚀 Проверка настройки Telegram Sales Bot v2.0: {bot_name}")
|
|
368
|
+
logger.info(f"🤖 Bot ID будет автоопределен как: {bot_name}\n")
|
|
369
|
+
|
|
370
|
+
# Настраиваем окружение для бота (автоматически устанавливает BOT_ID)
|
|
371
|
+
config_dir = setup_bot_environment(bot_name)
|
|
372
|
+
if not config_dir:
|
|
373
|
+
return False
|
|
374
|
+
|
|
375
|
+
# Проверяем окружение
|
|
376
|
+
await check_environment()
|
|
377
|
+
logger.info("")
|
|
378
|
+
|
|
379
|
+
# Проверяем конфигурацию
|
|
380
|
+
config = await check_config()
|
|
381
|
+
if not config:
|
|
382
|
+
logger.error("\n❌ Невозможно продолжить без правильной конфигурации")
|
|
383
|
+
return False
|
|
384
|
+
logger.info("")
|
|
385
|
+
|
|
386
|
+
# Основные проверки
|
|
387
|
+
checks: List[Tuple[str, bool]] = []
|
|
388
|
+
for name, check_coro in [
|
|
389
|
+
("База данных", check_database_structure()),
|
|
390
|
+
("Supabase", check_supabase(config)),
|
|
391
|
+
("OpenAI", check_openai(config)),
|
|
392
|
+
("Промпты", check_prompts(config)),
|
|
393
|
+
("Админская система", check_admin_system(config)),
|
|
394
|
+
("JSON парсинг", check_json_parsing()),
|
|
395
|
+
("Быстрый тест", run_quick_test())
|
|
396
|
+
]:
|
|
397
|
+
logger.info(f"\n🔍 Проверка: {name}")
|
|
398
|
+
result = await check_coro
|
|
399
|
+
checks.append((name, result))
|
|
400
|
+
|
|
401
|
+
# Итоговый результат
|
|
402
|
+
logger.info(f"\n{'='*60}")
|
|
403
|
+
logger.info(f"📋 ИТОГОВЫЙ ОТЧЕТ для {bot_name}:")
|
|
404
|
+
|
|
405
|
+
all_passed = True
|
|
406
|
+
critical_failed = False
|
|
407
|
+
|
|
408
|
+
# Критические компоненты
|
|
409
|
+
critical_checks = ["Supabase", "OpenAI", "Промпты"]
|
|
410
|
+
|
|
411
|
+
for name, passed in checks:
|
|
412
|
+
if name in critical_checks:
|
|
413
|
+
status = "✅ ПРОЙДЕНА" if passed else "❌ КРИТИЧЕСКАЯ ОШИБКА"
|
|
414
|
+
if not passed:
|
|
415
|
+
critical_failed = True
|
|
416
|
+
else:
|
|
417
|
+
status = "✅ ПРОЙДЕНА" if passed else "⚠️ ПРЕДУПРЕЖДЕНИЕ"
|
|
418
|
+
|
|
419
|
+
logger.info(f" {name}: {status}")
|
|
420
|
+
if not passed:
|
|
421
|
+
all_passed = False
|
|
422
|
+
|
|
423
|
+
passed_count = sum(1 for _, passed in checks if passed)
|
|
424
|
+
logger.info(f"\n📊 Результат: {passed_count}/{len(checks)} проверок пройдено")
|
|
425
|
+
|
|
426
|
+
if critical_failed:
|
|
427
|
+
logger.error("\n🚨 КРИТИЧЕСКИЕ ОШИБКИ! Бот не может быть запущен.")
|
|
428
|
+
logger.error(" Исправьте критические ошибки перед запуском.")
|
|
429
|
+
elif all_passed:
|
|
430
|
+
logger.info("\n🎉 Все проверки пройдены! Бот готов к запуску.")
|
|
431
|
+
logger.info(f" Запустите: python {bot_name}.py")
|
|
432
|
+
if config.ADMIN_TELEGRAM_IDS:
|
|
433
|
+
logger.info(f" 👑 Админский доступ настроен для: {config.ADMIN_TELEGRAM_IDS}")
|
|
434
|
+
else:
|
|
435
|
+
logger.warning("\n⚠️ Есть предупреждения, но бот может работать.")
|
|
436
|
+
logger.warning(" Рекомендуется исправить предупреждения для полного функционала.")
|
|
437
|
+
|
|
438
|
+
if config and config.DEBUG_MODE:
|
|
439
|
+
logger.warning("\n🐛 РЕЖИМ ОТЛАДКИ ВКЛЮЧЕН - JSON будет показываться пользователям")
|
|
440
|
+
|
|
441
|
+
logger.info(f"{'='*60}")
|
|
442
|
+
|
|
443
|
+
return not critical_failed
|
|
444
|
+
|
|
445
|
+
def main():
|
|
446
|
+
"""Точка входа для запуска из командной строки"""
|
|
447
|
+
# Настройка логирования
|
|
448
|
+
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
|
449
|
+
|
|
450
|
+
logger.info("🔍 Утилита проверки настройки бота")
|
|
451
|
+
logger.info("Использование:")
|
|
452
|
+
logger.info(" python -m smart_bot_factory.setup_checker [bot_name]")
|
|
453
|
+
logger.info(" python -m smart_bot_factory.setup_checker growthmed-october-24")
|
|
454
|
+
logger.info("")
|
|
455
|
+
|
|
456
|
+
if len(sys.argv) > 1 and sys.argv[1] in ['-h', '--help', 'help']:
|
|
457
|
+
return
|
|
458
|
+
|
|
459
|
+
# Определяем какого бота проверять
|
|
460
|
+
bot_name = "growthmed-october-24" # по умолчанию
|
|
461
|
+
if len(sys.argv) > 1:
|
|
462
|
+
bot_name = sys.argv[1]
|
|
463
|
+
|
|
464
|
+
try:
|
|
465
|
+
success = asyncio.run(check_setup(bot_name))
|
|
466
|
+
if not success:
|
|
467
|
+
sys.exit(1)
|
|
468
|
+
except KeyboardInterrupt:
|
|
469
|
+
logger.info("\n⏹️ Прервано пользователем")
|
|
470
|
+
except Exception as e:
|
|
471
|
+
logger.error(f"\n💥 Критическая ошибка: {e}")
|
|
472
|
+
logger.exception("Стек ошибки:")
|
|
473
|
+
sys.exit(1)
|
|
474
|
+
|
|
475
|
+
if __name__ == "__main__":
|
|
476
|
+
main()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utils модули smart_bot_factory
|
|
3
|
+
"""
|
|
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
|
+
|
|
9
|
+
__all__ = ['SupabaseClient', 'PromptLoader', 'setup_debug_handlers']
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# debug_routing.py - Утилиты для отладки маршрутизации сообщений
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from aiogram import Router
|
|
5
|
+
from aiogram.types import Message
|
|
6
|
+
from aiogram.fsm.context import FSMContext
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
# Создаем роутер для отладочных обработчиков
|
|
11
|
+
debug_router = Router()
|
|
12
|
+
|
|
13
|
+
def setup_debug_handlers(dp):
|
|
14
|
+
"""Настройка отладочных обработчиков"""
|
|
15
|
+
dp.include_router(debug_router)
|
|
16
|
+
|
|
17
|
+
# Функция для получения глобальных переменных
|
|
18
|
+
def get_global_var(var_name):
|
|
19
|
+
"""Получает глобальную переменную из модуля debug_routing"""
|
|
20
|
+
import sys
|
|
21
|
+
current_module = sys.modules[__name__]
|
|
22
|
+
return getattr(current_module, var_name, None)
|
|
23
|
+
|
|
24
|
+
async def debug_user_state(message: Message, state: FSMContext, context: str):
|
|
25
|
+
"""Отладочная функция для логирования состояния пользователя"""
|
|
26
|
+
conversation_manager = get_global_var('conversation_manager')
|
|
27
|
+
supabase_client = get_global_var('supabase_client')
|
|
28
|
+
|
|
29
|
+
user_id = message.from_user.id
|
|
30
|
+
current_state = await state.get_state()
|
|
31
|
+
state_data = await state.get_data()
|
|
32
|
+
|
|
33
|
+
logger.info(f"🔍 DEBUG [{context}] User {user_id}:")
|
|
34
|
+
logger.info(f" 📊 FSM State: {current_state}")
|
|
35
|
+
logger.info(f" 📦 State Data: {list(state_data.keys())}")
|
|
36
|
+
logger.info(f" 💬 Message: '{message.text[:50]}...'")
|
|
37
|
+
|
|
38
|
+
# Проверяем диалог с админом в БД
|
|
39
|
+
conversation = await conversation_manager.is_user_in_admin_chat(user_id)
|
|
40
|
+
logger.info(f" 🗃️ Admin Chat in DB: {'✅' if conversation else '❌'}")
|
|
41
|
+
|
|
42
|
+
if conversation:
|
|
43
|
+
logger.info(f" 👑 Admin ID: {conversation['admin_id']}")
|
|
44
|
+
logger.info(f" 🆔 Conversation ID: {conversation['id']}")
|
|
45
|
+
|
|
46
|
+
# Проверяем активную сессию
|
|
47
|
+
session_info = await supabase_client.get_active_session(user_id)
|
|
48
|
+
logger.info(f" 🎯 Active Session: {'✅' if session_info else '❌'}")
|
|
49
|
+
|
|
50
|
+
if session_info:
|
|
51
|
+
logger.info(f" 📝 Session ID: {session_info['id']}")
|
|
52
|
+
|
|
53
|
+
logger.info(f" {'='*50}")
|
|
54
|
+
|
|
55
|
+
async def debug_admin_conversation_creation(admin_id: int, user_id: int):
|
|
56
|
+
"""Отладка создания диалога админа с пользователем"""
|
|
57
|
+
supabase_client = get_global_var('supabase_client')
|
|
58
|
+
|
|
59
|
+
logger.info(f"🔍 DEBUG CONVERSATION CREATION:")
|
|
60
|
+
logger.info(f" 👑 Admin: {admin_id}")
|
|
61
|
+
logger.info(f" 👤 User: {user_id}")
|
|
62
|
+
|
|
63
|
+
# Проверяем активную сессию пользователя ДО создания диалога
|
|
64
|
+
session_info = await supabase_client.get_active_session(user_id)
|
|
65
|
+
logger.info(f" 🎯 User has active session: {'✅' if session_info else '❌'}")
|
|
66
|
+
|
|
67
|
+
if session_info:
|
|
68
|
+
logger.info(f" 📝 Session ID: {session_info['id']}")
|
|
69
|
+
logger.info(f" 📅 Session created: {session_info['created_at']}")
|
|
70
|
+
|
|
71
|
+
# Проверяем существующие диалоги пользователя
|
|
72
|
+
try:
|
|
73
|
+
existing = supabase_client.client.table('admin_user_conversations').select(
|
|
74
|
+
'*'
|
|
75
|
+
).eq('user_id', user_id).eq('status', 'active').execute()
|
|
76
|
+
|
|
77
|
+
logger.info(f" 💬 Existing active conversations: {len(existing.data)}")
|
|
78
|
+
for conv in existing.data:
|
|
79
|
+
logger.info(f" - ID: {conv['id']}, Admin: {conv['admin_id']}")
|
|
80
|
+
except Exception as e:
|
|
81
|
+
logger.error(f" ❌ Error checking existing conversations: {e}")
|
|
82
|
+
|
|
83
|
+
async def test_message_routing(user_id: int, test_message: str):
|
|
84
|
+
"""Тестирует маршрутизацию сообщения без отправки через Telegram"""
|
|
85
|
+
conversation_manager = get_global_var('conversation_manager')
|
|
86
|
+
|
|
87
|
+
logger.info(f"🧪 TESTING MESSAGE ROUTING:")
|
|
88
|
+
logger.info(f" 👤 User: {user_id}")
|
|
89
|
+
logger.info(f" 💬 Message: '{test_message}'")
|
|
90
|
+
|
|
91
|
+
# Проверяем есть ли диалог с админом
|
|
92
|
+
conversation = await conversation_manager.is_user_in_admin_chat(user_id)
|
|
93
|
+
logger.info(f" 🗃️ Admin conversation exists: {'✅' if conversation else '❌'}")
|
|
94
|
+
|
|
95
|
+
if conversation:
|
|
96
|
+
logger.info(f" 👑 Admin: {conversation['admin_id']}")
|
|
97
|
+
logger.info(f" 🆔 Conv ID: {conversation['id']}")
|
|
98
|
+
logger.info(f" 📅 Started: {conversation['started_at']}")
|
|
99
|
+
|
|
100
|
+
# Тестируем должен ли этот пользователь быть в admin_chat
|
|
101
|
+
return "admin_chat"
|
|
102
|
+
else:
|
|
103
|
+
return "bot_chat"
|