smart-bot-factory 1.1.1__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.
Files changed (73) hide show
  1. smart_bot_factory/__init__.py +3 -0
  2. smart_bot_factory/admin/__init__.py +18 -0
  3. smart_bot_factory/admin/admin_events.py +1223 -0
  4. smart_bot_factory/admin/admin_logic.py +553 -0
  5. smart_bot_factory/admin/admin_manager.py +156 -0
  6. smart_bot_factory/admin/admin_tester.py +157 -0
  7. smart_bot_factory/admin/timeout_checker.py +547 -0
  8. smart_bot_factory/aiogram_calendar/__init__.py +14 -0
  9. smart_bot_factory/aiogram_calendar/common.py +64 -0
  10. smart_bot_factory/aiogram_calendar/dialog_calendar.py +259 -0
  11. smart_bot_factory/aiogram_calendar/schemas.py +99 -0
  12. smart_bot_factory/aiogram_calendar/simple_calendar.py +224 -0
  13. smart_bot_factory/analytics/analytics_manager.py +414 -0
  14. smart_bot_factory/cli.py +806 -0
  15. smart_bot_factory/config.py +258 -0
  16. smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +16 -0
  17. smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +582 -0
  18. smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +66 -0
  19. smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +212 -0
  20. smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +28 -0
  21. smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +8 -0
  22. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +818 -0
  23. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +32 -0
  24. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +35 -0
  25. smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +133 -0
  26. smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +108 -0
  27. smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +46 -0
  28. smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +16 -0
  29. 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
  30. smart_bot_factory/core/bot_utils.py +1108 -0
  31. smart_bot_factory/core/conversation_manager.py +653 -0
  32. smart_bot_factory/core/decorators.py +2464 -0
  33. smart_bot_factory/core/message_sender.py +729 -0
  34. smart_bot_factory/core/router.py +347 -0
  35. smart_bot_factory/core/router_manager.py +218 -0
  36. smart_bot_factory/core/states.py +27 -0
  37. smart_bot_factory/creation/__init__.py +7 -0
  38. smart_bot_factory/creation/bot_builder.py +1093 -0
  39. smart_bot_factory/creation/bot_testing.py +1122 -0
  40. smart_bot_factory/dashboard/__init__.py +3 -0
  41. smart_bot_factory/event/__init__.py +7 -0
  42. smart_bot_factory/handlers/handlers.py +2013 -0
  43. smart_bot_factory/integrations/langchain_openai.py +542 -0
  44. smart_bot_factory/integrations/openai_client.py +513 -0
  45. smart_bot_factory/integrations/supabase_client.py +1678 -0
  46. smart_bot_factory/memory/__init__.py +8 -0
  47. smart_bot_factory/memory/memory_manager.py +299 -0
  48. smart_bot_factory/memory/static_memory.py +214 -0
  49. smart_bot_factory/message/__init__.py +56 -0
  50. smart_bot_factory/rag/__init__.py +5 -0
  51. smart_bot_factory/rag/decorators.py +29 -0
  52. smart_bot_factory/rag/router.py +54 -0
  53. smart_bot_factory/rag/templates/__init__.py +3 -0
  54. smart_bot_factory/rag/templates/create_table.sql +7 -0
  55. smart_bot_factory/rag/templates/create_table_and_function_template.py +94 -0
  56. smart_bot_factory/rag/templates/match_function.sql +61 -0
  57. smart_bot_factory/rag/templates/match_services_template.py +82 -0
  58. smart_bot_factory/rag/vectorstore.py +449 -0
  59. smart_bot_factory/router/__init__.py +10 -0
  60. smart_bot_factory/setup_checker.py +512 -0
  61. smart_bot_factory/supabase/__init__.py +7 -0
  62. smart_bot_factory/supabase/client.py +631 -0
  63. smart_bot_factory/utils/__init__.py +11 -0
  64. smart_bot_factory/utils/debug_routing.py +114 -0
  65. smart_bot_factory/utils/prompt_loader.py +529 -0
  66. smart_bot_factory/utils/tool_router.py +68 -0
  67. smart_bot_factory/utils/user_prompt_loader.py +55 -0
  68. smart_bot_factory/utm_link_generator.py +123 -0
  69. smart_bot_factory-1.1.1.dist-info/METADATA +1135 -0
  70. smart_bot_factory-1.1.1.dist-info/RECORD +73 -0
  71. smart_bot_factory-1.1.1.dist-info/WHEEL +4 -0
  72. smart_bot_factory-1.1.1.dist-info/entry_points.txt +2 -0
  73. smart_bot_factory-1.1.1.dist-info/licenses/LICENSE +24 -0
@@ -0,0 +1,553 @@
1
+ # Исправленный admin_logic.py с правильной обработкой диалогов
2
+
3
+ import logging
4
+
5
+ from aiogram import F, Router
6
+ from aiogram.filters import Command, StateFilter
7
+ from aiogram.fsm.context import FSMContext
8
+ from aiogram.types import (CallbackQuery, InlineKeyboardButton,
9
+ InlineKeyboardMarkup, Message)
10
+
11
+ # Импортируем состояния
12
+ from ..core.states import AdminStates
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # Создаем роутер для админских обработчиков
17
+ admin_router = Router()
18
+
19
+
20
+ def setup_admin_handlers(dp):
21
+ """Настройка админских обработчиков"""
22
+ dp.include_router(admin_router)
23
+
24
+
25
+ @admin_router.message(Command(commands=["отмена", "cancel"]))
26
+ async def cancel_handler(message: Message, state: FSMContext):
27
+ """Отмена текущего действия и очистка state"""
28
+ from ..handlers.handlers import get_global_var
29
+
30
+ admin_manager = get_global_var("admin_manager")
31
+
32
+ # Получаем текущий state
33
+ current_state = await state.get_state()
34
+
35
+ # Очищаем временные файлы если это создание события
36
+ if current_state and current_state.startswith("AdminStates:create_event"):
37
+ from .admin_events import cleanup_temp_files
38
+
39
+ await cleanup_temp_files(state)
40
+
41
+ # Очищаем state
42
+ await state.clear()
43
+
44
+ if current_state:
45
+ logger.info(
46
+ f"State очищен для пользователя {message.from_user.id}: {current_state}"
47
+ )
48
+
49
+ # Если это админ, возвращаем в админ режим
50
+ if admin_manager.is_admin(message.from_user.id):
51
+ await state.set_state(AdminStates.admin_mode)
52
+ await message.answer(
53
+ "✅ Текущее действие отменено\n"
54
+ "Вы вернулись в админ режим\n\n"
55
+ "Используйте /admin для просмотра доступных команд",
56
+ parse_mode="Markdown",
57
+ )
58
+ else:
59
+ await message.answer(
60
+ "✅ Текущее действие отменено\n\n"
61
+ "Используйте /start для начала работы",
62
+ parse_mode="Markdown",
63
+ )
64
+ else:
65
+ await message.answer(
66
+ "ℹ️ Нет активных действий для отмены", parse_mode="Markdown"
67
+ )
68
+
69
+
70
+ async def admin_start_handler(message: Message, state: FSMContext):
71
+ """Обработчик /start для админов в режиме администратора"""
72
+ from ..handlers.handlers import get_global_var
73
+
74
+ admin_manager = get_global_var("admin_manager")
75
+
76
+ await state.set_state(AdminStates.admin_mode)
77
+
78
+ admin_status = admin_manager.get_admin_mode_text(message.from_user.id)
79
+
80
+ # Основное меню админа
81
+ keyboard = InlineKeyboardMarkup(
82
+ inline_keyboard=[
83
+ [InlineKeyboardButton(text="📊 Статистика", callback_data="admin_stats")],
84
+ [
85
+ InlineKeyboardButton(
86
+ text="💬 Активные чаты", callback_data="admin_active_chats"
87
+ )
88
+ ],
89
+ [
90
+ InlineKeyboardButton(
91
+ text="🔄 Режим польз.", callback_data="admin_toggle_mode"
92
+ )
93
+ ],
94
+ ]
95
+ )
96
+
97
+ welcome_text = f"""
98
+ {admin_status}
99
+
100
+ 🎛️ **Панель администратора**
101
+
102
+ Доступные команды:
103
+ • `/стат` - статистика воронки
104
+ • `/история user_id` - история пользователя
105
+ • `/чат user_id` - начать диалог
106
+ • `/чаты` - активные диалоги
107
+ • `/стоп` - завершить диалог
108
+ • `/админ` - переключить режим
109
+ • `/отмена` - отменить текущее действие
110
+
111
+ 📅 **Управление событиями:**
112
+ • `/создать_событие` - создать новое событие
113
+ • `/список_событий` - список активных событий
114
+ • `/удалить_событие название` - отменить событие
115
+ """
116
+
117
+ await message.answer(welcome_text, reply_markup=keyboard, parse_mode="Markdown")
118
+
119
+
120
+ @admin_router.message(Command(commands=["стат", "stats"]))
121
+ async def admin_stats_handler(message: Message, state: FSMContext):
122
+ """Статистика воронки"""
123
+ from ..handlers.handlers import get_global_var
124
+
125
+ admin_manager = get_global_var("admin_manager")
126
+ analytics_manager = get_global_var("analytics_manager")
127
+
128
+ if not admin_manager.is_admin(message.from_user.id):
129
+ return
130
+
131
+ try:
132
+ # Получаем статистику
133
+ funnel_stats = await analytics_manager.get_funnel_stats(7)
134
+ events_stats = await analytics_manager.get_events_stats(7)
135
+
136
+ # Форматируем ответ
137
+ funnel_text = analytics_manager.format_funnel_stats(funnel_stats)
138
+ events_text = analytics_manager.format_events_stats(events_stats)
139
+
140
+ full_text = f"{funnel_text}\n\n{events_text}"
141
+
142
+ await message.answer(full_text)
143
+
144
+ except Exception as e:
145
+ logger.error(f"Ошибка получения статистики: {e}")
146
+ await message.answer("❌ Ошибка получения статистики")
147
+
148
+
149
+ @admin_router.message(Command(commands=["история", "history"]))
150
+ async def admin_history_handler(message: Message, state: FSMContext):
151
+ """История пользователя"""
152
+ from ..handlers.handlers import get_global_var
153
+
154
+ admin_manager = get_global_var("admin_manager")
155
+ analytics_manager = get_global_var("analytics_manager")
156
+
157
+ if not admin_manager.is_admin(message.from_user.id):
158
+ return
159
+
160
+ try:
161
+ parts = message.text.split()
162
+ if len(parts) < 2:
163
+ await message.answer("Укажите ID пользователя: /история 123456789")
164
+ return
165
+
166
+ user_id = int(parts[1])
167
+
168
+ # Получаем историю (та же функция что использует кнопка)
169
+ journey = await analytics_manager.get_user_journey(user_id)
170
+
171
+ if not journey:
172
+ await message.answer(f"❌ У пользователя {user_id} нет активной сессии")
173
+ return
174
+
175
+ # Используем ту же функцию форматирования что и кнопка
176
+ history_text = analytics_manager.format_user_journey(user_id, journey)
177
+
178
+ await message.answer(history_text)
179
+
180
+ except ValueError:
181
+ await message.answer("❌ Неверный формат ID пользователя")
182
+ except Exception as e:
183
+ logger.error(f"Ошибка получения истории: {e}")
184
+ await message.answer("❌ Ошибка получения истории")
185
+
186
+
187
+ @admin_router.message(Command(commands=["чат", "chat"]))
188
+ async def admin_chat_handler(message: Message, state: FSMContext):
189
+ """Начать диалог с пользователем"""
190
+ from ..handlers.handlers import get_global_var
191
+
192
+ admin_manager = get_global_var("admin_manager")
193
+ supabase_client = get_global_var("supabase_client")
194
+ conversation_manager = get_global_var("conversation_manager")
195
+
196
+ if not admin_manager.is_admin(message.from_user.id):
197
+ return
198
+
199
+ try:
200
+ # Парсим user_id из команды
201
+ parts = message.text.split()
202
+ if len(parts) < 2:
203
+ await message.answer("Укажите ID пользователя: /чат 123456789")
204
+ return
205
+
206
+ user_id = int(parts[1])
207
+ admin_id = message.from_user.id
208
+
209
+ logger.info(
210
+ f"👑 Админ {admin_id} хочет начать диалог с пользователем {user_id}"
211
+ )
212
+
213
+ # Проверяем, есть ли активная сессия у пользователя
214
+ session_info = await supabase_client.get_active_session(user_id)
215
+ if not session_info:
216
+ await message.answer(f"❌ У пользователя {user_id} нет активной сессии")
217
+ logger.warning(f"❌ У пользователя {user_id} нет активной сессии")
218
+ return
219
+
220
+ logger.info(
221
+ f"✅ У пользователя {user_id} есть активная сессия: {session_info['id']}"
222
+ )
223
+
224
+ # Начинаем диалог
225
+ logger.info("🚀 Запускаем создание диалога...")
226
+ success = await conversation_manager.start_admin_conversation(admin_id, user_id)
227
+
228
+ if success:
229
+ # ✅ ИСПРАВЛЕНИЕ: Правильно переключаем состояние админа
230
+ await state.set_state(AdminStates.in_conversation)
231
+ await state.update_data(conversation_user_id=user_id)
232
+
233
+ await message.answer(
234
+ f"✅ Диалог с пользователем {user_id} начат\n💬 Ваши сообщения будут переданы пользователю\n⏹️ Используйте /стоп для завершения"
235
+ )
236
+ logger.info(
237
+ "✅ Диалог успешно создан, админ переключен в состояние in_conversation"
238
+ )
239
+ else:
240
+ await message.answer(
241
+ f"❌ Не удалось начать диалог с пользователем {user_id}"
242
+ )
243
+ logger.error("❌ Не удалось создать диалог")
244
+
245
+ except ValueError:
246
+ await message.answer("❌ Неверный формат ID пользователя")
247
+ logger.error(f"❌ Неверный формат ID пользователя: {message.text}")
248
+ except Exception as e:
249
+ logger.error(f"❌ Ошибка начала диалога: {e}")
250
+ await message.answer("❌ Ошибка начала диалога")
251
+
252
+
253
+ @admin_router.message(Command(commands=["чаты", "chats"]))
254
+ async def admin_active_chats_command(message: Message, state: FSMContext):
255
+ """Показать активные диалоги админов"""
256
+ from ..handlers.handlers import get_global_var
257
+
258
+ admin_manager = get_global_var("admin_manager")
259
+ conversation_manager = get_global_var("conversation_manager")
260
+
261
+ if not admin_manager.is_admin(message.from_user.id):
262
+ return
263
+
264
+ try:
265
+ conversations = await conversation_manager.get_active_conversations()
266
+ formatted_text = conversation_manager.format_active_conversations(conversations)
267
+
268
+ # ✅ ИСПРАВЛЕНИЕ: Убираем parse_mode='Markdown' чтобы избежать ошибок парсинга
269
+ await message.answer(formatted_text)
270
+
271
+ except Exception as e:
272
+ logger.error(f"Ошибка получения активных чатов: {e}")
273
+ await message.answer("❌ Ошибка получения активных диалогов")
274
+
275
+
276
+ @admin_router.message(Command(commands=["стоп", "stop"]))
277
+ async def admin_stop_handler(message: Message, state: FSMContext):
278
+ """Завершить диалог"""
279
+ from ..handlers.handlers import get_global_var
280
+
281
+ admin_manager = get_global_var("admin_manager")
282
+ conversation_manager = get_global_var("conversation_manager")
283
+
284
+ if not admin_manager.is_admin(message.from_user.id):
285
+ return
286
+
287
+ try:
288
+ admin_id = message.from_user.id
289
+
290
+ # Проверяем есть ли активный диалог
291
+ conversation = await conversation_manager.get_admin_active_conversation(
292
+ admin_id
293
+ )
294
+
295
+ if conversation:
296
+ user_id = conversation["user_id"]
297
+ logger.info(
298
+ f"🛑 Завершаем диалог админа {admin_id} с пользователем {user_id}"
299
+ )
300
+
301
+ success = await conversation_manager.end_admin_conversation(admin_id)
302
+
303
+ if success:
304
+ # ✅ ИСПРАВЛЕНИЕ: Правильно переключаем состояние обратно
305
+ await state.set_state(AdminStates.admin_mode)
306
+ await state.update_data(conversation_user_id=None)
307
+
308
+ await message.answer(f"✅ Диалог с пользователем {user_id} завершен")
309
+ logger.info("✅ Диалог завершен, админ переключен в admin_mode")
310
+ else:
311
+ await message.answer("❌ Ошибка завершения диалога")
312
+ else:
313
+ await message.answer("❌ Нет активного диалога")
314
+ logger.info(f"❌ У админа {admin_id} нет активного диалога")
315
+
316
+ except Exception as e:
317
+ logger.error(f"Ошибка завершения диалога: {e}")
318
+ await message.answer("❌ Ошибка завершения диалога")
319
+
320
+
321
+ @admin_router.message(Command(commands=["админ", "admin"]))
322
+ async def admin_toggle_handler(message: Message, state: FSMContext):
323
+ """Переключение режима админа"""
324
+ from ..handlers.handlers import get_global_var
325
+
326
+ admin_manager = get_global_var("admin_manager")
327
+
328
+ if not admin_manager.is_admin(message.from_user.id):
329
+ return
330
+
331
+ new_mode = admin_manager.toggle_admin_mode(message.from_user.id)
332
+
333
+ if new_mode:
334
+ # Переключились в режим админа
335
+ await admin_start_handler(message, state)
336
+ else:
337
+ # Переключились в режим пользователя
338
+ await state.clear()
339
+ await message.answer(
340
+ "🔄 Переключен в режим пользователя\nНапишите /start для начала диалога"
341
+ )
342
+
343
+
344
+ @admin_router.message(Command("debug_chat"))
345
+ async def debug_chat_handler(message: Message, state: FSMContext):
346
+ """Отладка диалогов админов"""
347
+ from ..handlers.handlers import get_global_var
348
+
349
+ admin_manager = get_global_var("admin_manager")
350
+ conversation_manager = get_global_var("conversation_manager")
351
+ supabase_client = get_global_var("supabase_client")
352
+
353
+ if not admin_manager.is_admin(message.from_user.id):
354
+ return
355
+
356
+ parts = message.text.split()
357
+ if len(parts) < 2:
358
+ await message.answer("Использование: /debug_chat USER_ID")
359
+ return
360
+
361
+ try:
362
+ user_id = int(parts[1])
363
+
364
+ # 1. Проверяем запись в БД
365
+ conversation = await conversation_manager.is_user_in_admin_chat(user_id)
366
+
367
+ debug_info = [
368
+ f"🔍 ОТЛАДКА ДИАЛОГА С {user_id}",
369
+ "",
370
+ f"📊 Диалог в БД: {'✅' if conversation else '❌'}",
371
+ ]
372
+
373
+ if conversation:
374
+ debug_info.extend(
375
+ [
376
+ f"👑 Админ: {conversation['admin_id']}",
377
+ f"🕐 Начат: {conversation['started_at']}",
378
+ ]
379
+ )
380
+
381
+ # 2. Проверяем активную сессию пользователя
382
+ session_info = await supabase_client.get_active_session(user_id)
383
+ debug_info.append(f"🎯 Активная сессия: {'✅' if session_info else '❌'}")
384
+
385
+ if session_info:
386
+ debug_info.append(f"📝 ID сессии: {session_info['id']}")
387
+
388
+ # 3. Проверяем состояние пользователя (если он онлайн)
389
+ debug_info.append("")
390
+ debug_info.append(
391
+ "ℹ️ Для проверки состояния пользователь должен написать что-то"
392
+ )
393
+
394
+ await message.answer("\n".join(debug_info))
395
+
396
+ except Exception as e:
397
+ await message.answer(f"❌ Ошибка: {e}")
398
+ logger.error(f"Ошибка отладки: {e}")
399
+
400
+
401
+ @admin_router.callback_query(F.data.startswith("admin_"))
402
+ async def admin_callback_handler(callback: CallbackQuery, state: FSMContext):
403
+ """Обработчик callback кнопок админов"""
404
+ from ..handlers.handlers import get_global_var
405
+
406
+ admin_manager = get_global_var("admin_manager")
407
+ analytics_manager = get_global_var("analytics_manager")
408
+ conversation_manager = get_global_var("conversation_manager")
409
+
410
+ if not admin_manager.is_admin(callback.from_user.id):
411
+ await callback.answer("Нет доступа")
412
+ return
413
+
414
+ data = callback.data
415
+
416
+ try:
417
+ if data == "admin_stats":
418
+ # Показываем статистику
419
+ funnel_stats = await analytics_manager.get_funnel_stats(7)
420
+ events_stats = await analytics_manager.get_events_stats(7)
421
+
422
+ funnel_text = analytics_manager.format_funnel_stats(funnel_stats)
423
+ events_text = analytics_manager.format_events_stats(events_stats)
424
+
425
+ await callback.message.answer(f"{funnel_text}\n\n{events_text}")
426
+
427
+ elif data == "admin_toggle_mode":
428
+ # Переключаем режим
429
+ new_mode = admin_manager.toggle_admin_mode(callback.from_user.id)
430
+ mode_text = "администратор" if new_mode else "пользователь"
431
+ await callback.answer(f"Режим переключен: {mode_text}")
432
+
433
+ if not new_mode:
434
+ await state.clear()
435
+ await callback.message.answer("🔄 Теперь вы в режиме пользователя")
436
+
437
+ elif data == "admin_active_chats":
438
+ # Показываем активные диалоги
439
+ conversations = await conversation_manager.get_active_conversations()
440
+ formatted_text = conversation_manager.format_active_conversations(
441
+ conversations
442
+ )
443
+
444
+ # ✅ ИСПРАВЛЕНИЕ: Убираем parse_mode='Markdown'
445
+ await callback.message.answer(formatted_text)
446
+
447
+ elif data.startswith("admin_history_"):
448
+ user_id = int(data.split("_")[2])
449
+ journey = await analytics_manager.get_user_journey(user_id)
450
+ history_text = analytics_manager.format_user_journey(user_id, journey)
451
+ await callback.message.answer(history_text)
452
+
453
+ elif data.startswith("admin_end_"):
454
+ user_id = int(data.split("_")[2])
455
+
456
+ # Проверяем есть ли активный диалог
457
+ conversation = await conversation_manager.get_admin_active_conversation(
458
+ callback.from_user.id
459
+ )
460
+
461
+ if conversation and conversation["user_id"] == user_id:
462
+ await conversation_manager.end_admin_conversation(callback.from_user.id)
463
+
464
+ # ✅ ИСПРАВЛЕНИЕ: Правильно переключаем состояние
465
+ await state.set_state(AdminStates.admin_mode)
466
+ await state.update_data(conversation_user_id=None)
467
+
468
+ await callback.answer("Диалог завершен")
469
+ await callback.message.answer(
470
+ f"✅ Диалог с пользователем {user_id} завершен"
471
+ )
472
+ logger.info(
473
+ "✅ Диалог завершен через кнопку, админ переключен в admin_mode"
474
+ )
475
+ else:
476
+ await callback.answer("Диалог не найден")
477
+
478
+ elif data.startswith("admin_chat_"):
479
+ user_id = int(data.split("_")[2])
480
+ admin_id = callback.from_user.id
481
+
482
+ success = await conversation_manager.start_admin_conversation(
483
+ admin_id, user_id
484
+ )
485
+ if success:
486
+ # ✅ ИСПРАВЛЕНИЕ: Правильно переключаем состояние
487
+ await state.set_state(AdminStates.in_conversation)
488
+ await state.update_data(conversation_user_id=user_id)
489
+
490
+ await callback.answer("Диалог начат")
491
+ await callback.message.answer(
492
+ f"✅ Диалог с пользователем {user_id} начат"
493
+ )
494
+ logger.info(
495
+ "✅ Диалог начат через кнопку, админ переключен в in_conversation"
496
+ )
497
+ else:
498
+ await callback.answer("Не удалось начать диалог")
499
+
500
+ await callback.answer()
501
+
502
+ except Exception as e:
503
+ logger.error(f"Ошибка обработки callback {data}: {e}")
504
+ await callback.answer("Ошибка")
505
+
506
+
507
+ @admin_router.message(
508
+ StateFilter(AdminStates.admin_mode, AdminStates.in_conversation),
509
+ F.text,
510
+ lambda message: not message.text.startswith("/"),
511
+ )
512
+ async def admin_message_handler(message: Message, state: FSMContext):
513
+ """Обработчик сообщений админов"""
514
+ from ..handlers.handlers import get_global_var
515
+
516
+ admin_manager = get_global_var("admin_manager")
517
+ conversation_manager = get_global_var("conversation_manager")
518
+
519
+ if not admin_manager.is_admin(message.from_user.id):
520
+ return
521
+
522
+ try:
523
+ logger.info(
524
+ f"👑 Получено сообщение от админа {message.from_user.id}: '{message.text}'"
525
+ )
526
+
527
+ # Пытаемся обработать как админское сообщение
528
+ handled = await conversation_manager.route_admin_message(message, state)
529
+
530
+ if handled:
531
+ logger.info("✅ Сообщение админа обработано и переслано пользователю")
532
+ else:
533
+ # Не админское сообщение - показываем справку
534
+ logger.info("❌ Сообщение админа не обработано, показываем справку")
535
+ await message.answer(
536
+ """
537
+ 👑 **Режим администратора**
538
+
539
+ Доступные команды:
540
+ • `/стат` - статистика воронки
541
+ • `/история user_id` - история пользователя
542
+ • `/чат user_id` - начать диалог
543
+ • `/стоп` - завершить диалог
544
+ • `/админ` - переключить режим
545
+
546
+ 💡 Если вы в диалоге с пользователем, просто напишите сообщение - оно будет переслано пользователю.
547
+ """,
548
+ parse_mode="Markdown",
549
+ )
550
+
551
+ except Exception as e:
552
+ logger.error(f"Ошибка обработки сообщения админа: {e}")
553
+ await message.answer("❌ Ошибка обработки команды")