smart-bot-factory 0.1.2__py3-none-any.whl → 0.1.4__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.

Files changed (61) hide show
  1. smart_bot_factory/__init__.py +33 -0
  2. smart_bot_factory/admin/__init__.py +16 -0
  3. smart_bot_factory/admin/admin_logic.py +430 -0
  4. smart_bot_factory/admin/admin_manager.py +141 -0
  5. smart_bot_factory/admin/admin_migration.sql +136 -0
  6. smart_bot_factory/admin/admin_tester.py +151 -0
  7. smart_bot_factory/admin/timeout_checker.py +499 -0
  8. smart_bot_factory/analytics/__init__.py +7 -0
  9. smart_bot_factory/analytics/analytics_manager.py +355 -0
  10. smart_bot_factory/cli.py +768 -0
  11. smart_bot_factory/config.py +235 -0
  12. smart_bot_factory/configs/growthmed-helper/env_example.txt +1 -0
  13. smart_bot_factory/configs/growthmed-helper/prompts/1sales_context.txt +9 -0
  14. smart_bot_factory/configs/growthmed-helper/prompts/2product_info.txt +582 -0
  15. smart_bot_factory/configs/growthmed-helper/prompts/3objection_handling.txt +66 -0
  16. smart_bot_factory/configs/growthmed-helper/prompts/final_instructions.txt +232 -0
  17. smart_bot_factory/configs/growthmed-helper/prompts/help_message.txt +28 -0
  18. smart_bot_factory/configs/growthmed-helper/prompts/welcome_message.txt +7 -0
  19. smart_bot_factory/configs/growthmed-helper/welcome_file/welcome_file_msg.txt +16 -0
  20. 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
  21. smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +16 -0
  22. smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +582 -0
  23. smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +66 -0
  24. smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +212 -0
  25. smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +28 -0
  26. smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +8 -0
  27. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +818 -0
  28. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +32 -0
  29. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +35 -0
  30. smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +66 -0
  31. smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +108 -0
  32. smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +46 -0
  33. smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +16 -0
  34. 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
  35. smart_bot_factory/core/__init__.py +22 -0
  36. smart_bot_factory/core/bot_utils.py +703 -0
  37. smart_bot_factory/core/conversation_manager.py +536 -0
  38. smart_bot_factory/core/decorators.py +230 -0
  39. smart_bot_factory/core/message_sender.py +249 -0
  40. smart_bot_factory/core/states.py +14 -0
  41. smart_bot_factory/creation/__init__.py +8 -0
  42. smart_bot_factory/creation/bot_builder.py +329 -0
  43. smart_bot_factory/creation/bot_testing.py +986 -0
  44. smart_bot_factory/database/database_structure.sql +57 -0
  45. smart_bot_factory/database/schema.sql +1094 -0
  46. smart_bot_factory/handlers/handlers.py +583 -0
  47. smart_bot_factory/integrations/__init__.py +9 -0
  48. smart_bot_factory/integrations/openai_client.py +435 -0
  49. smart_bot_factory/integrations/supabase_client.py +592 -0
  50. smart_bot_factory/setup_checker.py +476 -0
  51. smart_bot_factory/utils/__init__.py +9 -0
  52. smart_bot_factory/utils/debug_routing.py +103 -0
  53. smart_bot_factory/utils/prompt_loader.py +427 -0
  54. smart_bot_factory/utm_link_generator.py +106 -0
  55. smart_bot_factory-0.1.4.dist-info/METADATA +126 -0
  56. smart_bot_factory-0.1.4.dist-info/RECORD +59 -0
  57. smart_bot_factory-0.1.4.dist-info/licenses/LICENSE +24 -0
  58. smart_bot_factory-0.1.2.dist-info/METADATA +0 -31
  59. smart_bot_factory-0.1.2.dist-info/RECORD +0 -4
  60. {smart_bot_factory-0.1.2.dist-info → smart_bot_factory-0.1.4.dist-info}/WHEEL +0 -0
  61. {smart_bot_factory-0.1.2.dist-info → smart_bot_factory-0.1.4.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"