diff --git a/handlers/admin.py b/handlers/admin.py
index 48ad006..dce5398 100644
--- a/handlers/admin.py
+++ b/handlers/admin.py
@@ -58,104 +58,8 @@ async def process_swarm_task(message: Message, state: FSMContext):
# ... (код остается прежним)
pass
-# =============================================================================
-# ЮРИДИЧЕСКИЙ ПОМОЩНИК (NotebookLM)
-# =============================================================================
+# (Устаревший блок NotebookLM перенесен в специализированный модуль handlers/legal_advisor.py)
-@router.message(Command('jurist'))
-@router.message(F.text == '⚖️ Юрист (ЖК РФ)')
-@admin_only
-async def cmd_jurist(message: Message, state: FSMContext):
- """Активация юридического помощника"""
- await message.answer(
- "⚖️ ЮРИДИЧЕСКИЙ ПОМОЩНИК (ЖК РФ)\n\n"
- "Напишите ваш вопрос для анализа на основе судебных дел и ЖК РФ.\n\n"
- "Я проанализирую ваш запрос через NotebookLM.",
- parse_mode='HTML'
- )
- await state.set_state(JuristState.waiting_for_question)
-
-@router.callback_query(F.data == 'admin_jurist')
-@admin_callback_only
-async def cb_admin_jurist(callback: CallbackQuery, state: FSMContext):
- """Callback-активация юридического помощника"""
- await callback.answer()
- await callback.message.answer(
- "⚖️ ЮРИДИЧЕСКИЙ ПОМОЩНИК (ЖК РФ)\n\n"
- "Напишите ваш вопрос для анализа на основе судебных дел и ЖК РФ.\n\n"
- "Я проанализирую ваш запрос через NotebookLM.",
- parse_mode='HTML'
- )
- await state.set_state(JuristState.waiting_for_question)
-
-@router.message(JuristState.waiting_for_question)
-@admin_only
-async def process_jurist_question(message: Message, state: FSMContext):
- """Обработка вопроса к юристу через NotebookLM"""
- status_msg = await message.answer(
- "⏳ Отправляю запрос в NotebookLM, анализирую судебные материалы и законы (это займет около 10-15 секунд)...",
- parse_mode='HTML'
- )
-
- import asyncio
- import os
-
- # Динамический поиск бинарника nlm
- nlm_bin = "nlm"
- for p in ["/app/bin/nlm", "/usr/local/bin/nlm", os.path.expanduser("~/.local/bin/nlm"), "/home/matrixhasyou/.local/bin/nlm"]:
- if os.path.exists(p):
- nlm_bin = p
- break
-
- cmd = [
- nlm_bin, "query", "notebook",
- "00ed7d92-1ab2-4159-ac72-1d0c4be21377",
- message.text
- ]
- env = os.environ.copy()
-
- try:
- proc = await asyncio.create_subprocess_exec(
- *cmd,
- stdout=asyncio.subprocess.PIPE,
- stderr=asyncio.subprocess.PIPE,
- env=env
- )
- stdout, stderr = await proc.communicate()
-
- output = stdout.decode('utf-8').strip()
- error = stderr.decode('utf-8').strip()
-
- # Убираем предупреждения о новой версии из вывода nlm
- if "Update available:" in output:
- output = output.split("Update available:")[0].strip()
-
- if proc.returncode == 0:
- import html
- import re
-
- # Заменяем
,
,
на переносы строк
- clean_output = output.replace("
", "\n").replace("
", "\n").replace("
", "\n")
- # Экранируем спецсимволы для parse_mode='HTML'
- safe_output = html.escape(clean_output)
- # Форматируем **жирный** текст -> жирный
- safe_output = re.sub(r'\*\*(.*?)\*\*', r'\1', safe_output, flags=re.DOTALL)
- # Форматируем [ссылка](url) -> \1
- safe_output = re.sub(r'\[(.*?)\]\((.*?)\)', r'\1', safe_output, flags=re.DOTALL)
-
- if len(safe_output) > 4000:
- parts = [safe_output[i:i+4000] for i in range(0, len(safe_output), 4000)]
- await status_msg.edit_text(f"⚖️ Анализ NotebookLM (часть 1):\n\n{parts[0]}", parse_mode='HTML')
- for part in parts[1:]:
- await message.answer(part, parse_mode='HTML')
- else:
- await status_msg.edit_text(f"⚖️ Анализ NotebookLM:\n\n{safe_output}", parse_mode='HTML')
- else:
- await status_msg.edit_text(f"❌ Ошибка запроса к NotebookLM:\n{error or output}")
- except Exception as e:
- await status_msg.edit_text(f"❌ Внутренняя ошибка бота: {str(e)}")
- finally:
- await state.clear()
@router.message(F.text & ~F.text.startswith('/') & F.chat.type == 'private')
diff --git a/handlers/legal_advisor.py b/handlers/legal_advisor.py
index c36946d..74ce5eb 100644
--- a/handlers/legal_advisor.py
+++ b/handlers/legal_advisor.py
@@ -77,11 +77,46 @@ async def determine_user_role(user_id: int) -> str:
# === КОМАНДЫ АКТИВАЦИИ ===
-@router.message(Command("юрист", "jurist", "вопрос", "help_law"))
-@router.message(F.text == "⚖️ Юрист (ЖК РФ)")
-async def cmd_legal_advisor(message: Message, state: FSMContext):
+@router.message(Command("jurist", "юрист", "вопрос", "help_law"))
+@router.message(F.text.casefold().in_(["/юрист", "/jurist", "/вопрос", "юрист", "⚖️ юрист (жк рф)"]))
+@router.message(F.text.casefold().startswith(("/юрист", "/jurist")))
+async def cmd_legal_advisor(message: Message, state: FSMContext, bot: Bot):
role = await determine_user_role(message.from_user.id)
+ # Проверяем, не задал ли пользователь вопрос прямо в команде: /юрист Какой срок ответа?
+ parts = (message.text or "").split(maxsplit=1)
+ if len(parts) > 1 and parts[0].casefold() in ("/юрист", "/jurist", "/вопрос"):
+ inline_question = parts[1].strip()
+ if len(inline_question) > 3:
+ status_msg = await message.answer("⏳ Анализирую нормативную базу дома...", parse_mode='HTML')
+ result = await legal_engine.query(prompt=inline_question, role=role)
+ await status_msg.delete()
+ if result.get("success"):
+ header = f"⚖️ Юридический ответ ({result.get('latency_sec')} сек):"
+ await send_split_message(message, header, result["text"])
+ else:
+ await message.answer(f"❌ Ошибка: {result.get('text')}", parse_mode='HTML')
+ return
+
+ role_desc = {
+ "admin": "👑 Режим Стратегического Аналитика (Администратор)",
+ "lawyer": "⚖️ Режим Судебного Юриста (Совет дома / Активист)",
+ "resident": "🏡 Соседский Юридический Помощник"
+ }.get(role, "🏡 Юридический Помощник")
+
+ text = (
+ f"{role_desc}\n\n"
+ "Задайте ваш вопрос по ЖКХ, протечкам, тарифам, собраниям или спорам с управляющей компанией.\n\n"
+ "🎙 Вы можете написать текст или отправить голосовое сообщение!\n"
+ "Я проанализирую обращение по базе законов РФ и материалам дома."
+ )
+ await message.answer(text, parse_mode='HTML')
+ await state.set_state(LegalQuestionState.waiting_for_question)
+
+@router.callback_query(F.data.in_(["admin_jurist", "jurist_ai", "main_jurist"]))
+async def cb_legal_advisor(callback: CallbackQuery, state: FSMContext):
+ await callback.answer()
+ role = await determine_user_role(callback.from_user.id)
role_desc = {
"admin": "👑 Режим Стратегического Аналитика (Администратор)",
"lawyer": "⚖️ Режим Судебного Юриста (Совет дома / Активист)",
@@ -94,7 +129,7 @@ async def cmd_legal_advisor(message: Message, state: FSMContext):
"🎙 Вы можете написать текст или отправить голосовое сообщение!\n"
"Я проанализирую обращение по базе законов РФ и судебным материалам дома."
)
- await message.answer(text, parse_mode='HTML')
+ await callback.message.answer(text, parse_mode='HTML')
await state.set_state(LegalQuestionState.waiting_for_question)
# === ОБРАБОТКА ТЕКСТОВЫХ ВОПРОСОВ ===
diff --git a/keyboards/inline.py b/keyboards/inline.py
index a03301a..dc488b6 100644
--- a/keyboards/inline.py
+++ b/keyboards/inline.py
@@ -15,6 +15,9 @@ def get_main_menu(verified: bool = False, is_ig: bool = False, is_admin: bool =
# СТРОКА 1: БАЗА (ВСЕГДА ТУТ)
builder.row(
InlineKeyboardButton(text='📞 Телефоны', callback_data='phones'),
+ InlineKeyboardButton(text='⚖️ Юрист (ЖК РФ)', callback_data='main_jurist')
+ )
+ builder.row(
InlineKeyboardButton(text='🏢 О доме', callback_data='about_house')
)
diff --git a/main.py b/main.py
index d3c4426..6ad6378 100644
--- a/main.py
+++ b/main.py
@@ -49,6 +49,18 @@ async def on_startup(bot: Bot):
await init_db()
scheduler = Scheduler(bot)
scheduler.start()
+ try:
+ from aiogram.types import BotCommand
+ await bot.set_my_commands([
+ BotCommand(command="start", description="Главное меню дома"),
+ BotCommand(command="jurist", description="⚖️ Юрист & Разбор ЖК РФ"),
+ BotCommand(command="admin", description="🛡️ Админ-панель"),
+ BotCommand(command="phones", description="📞 Экстренные телефоны"),
+ BotCommand(command="help", description="❓ Помощь и навигация")
+ ])
+ except Exception as e:
+ logger.warning(f"Failed to set bot commands: {e}")
+
try:
await bot.send_message(ADMIN_USER_ID, '✅ LKM37 CORE v4.3 АКТИВИРОВАН')
await send_domovoy_alert("Сервис запущен", "Домовой МКД успешно запущен в автономном коммунальном режиме.")
@@ -59,7 +71,12 @@ async def main():
bot = get_bot()
dp = Dispatcher(storage=MemoryStorage())
- # Регистрация роутеров МКД
+ # Регистрация роутеров МКД (Юрист в наивысшем приоритете)
+ from handlers.legal_advisor import router as legal_advisor_router
+ from handlers.smart_broadcast import router as smart_broadcast_router
+ from handlers.digest import router as digest_router
+
+ dp.include_router(legal_advisor_router)
dp.include_router(admin_router)
dp.include_router(users_router)
@@ -69,18 +86,12 @@ async def main():
antispam_router, ratelimit_router, schedule_router, ads_router,
payments_router, multicount_router, topics_router, toxicity_router,
profile_history_router, achievements_router, thanks_router,
- events_router, initiative_group_router, mutual_aid_router
+ events_router, initiative_group_router, mutual_aid_router,
+ smart_broadcast_router, digest_router
]
for r in other_routers:
dp.include_router(r)
-
- from handlers.smart_broadcast import router as smart_broadcast_router
- from handlers.digest import router as digest_router
- from handlers.legal_advisor import router as legal_advisor_router
- dp.include_router(legal_advisor_router)
- dp.include_router(smart_broadcast_router)
- dp.include_router(digest_router)
dp.startup.register(on_startup)