diff --git a/handlers/legal_advisor.py b/handlers/legal_advisor.py
index ad7048c..2d57fa9 100644
--- a/handlers/legal_advisor.py
+++ b/handlers/legal_advisor.py
@@ -78,12 +78,24 @@ async def send_split_message(message: Message, header: str, body: str):
part_header = f"(Продолжение {idx}/{len(chunks)}):\n\n"
part_text = f"{part_header}{format_telegram_html(chunk)}"
+ # Прикрепляем инлайн-кнопки только к последней части ответа
+ reply_markup = get_legal_nav_keyboard() if idx == len(chunks) else None
try:
- await message.answer(part_text, parse_mode='HTML')
+ await message.answer(part_text, parse_mode='HTML', reply_markup=reply_markup)
except Exception as e:
log.warning(f"HTML send failed ({e}), falling back to plain text")
plain_header = header if idx == 1 else f"(Продолжение {idx}/{len(chunks)}):"
- await message.answer(f"{plain_header}\n\n{chunk}")
+ await message.answer(f"{plain_header}\n\n{chunk}", reply_markup=reply_markup)
+
+def get_legal_nav_keyboard() -> InlineKeyboardMarkup:
+ """Инлайн-кнопки навигации после ответа юриста."""
+ kb = [
+ [
+ InlineKeyboardButton(text="📝 Задать следующий вопрос", callback_data="jurist_ask_next"),
+ InlineKeyboardButton(text="🚪 Выход из режима юриста", callback_data="jurist_exit")
+ ]
+ ]
+ return InlineKeyboardMarkup(inline_keyboard=kb)
async def determine_user_role(user_id: int) -> str:
"""Определяет роль пользователя в системе."""
@@ -120,12 +132,13 @@ async def cmd_legal_advisor(message: Message, state: FSMContext, bot: Bot):
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')
+ 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 = "⚖️ Юридический ответ:"
await send_split_message(message, header, result["text"])
+ await state.set_state(LegalQuestionState.waiting_for_question)
else:
await message.answer(f"❌ Ошибка: {result.get('text')}", parse_mode='HTML')
return
@@ -159,6 +172,60 @@ async def cb_legal_advisor(callback: CallbackQuery, state: FSMContext):
await callback.message.answer(text, parse_mode='HTML')
await state.set_state(LegalQuestionState.waiting_for_question)
+# === КНОПКИ НАВИГАЦИИ ПОСЛЕ ОТВЕТА ЮРИСТА ===
+
+@router.callback_query(F.data == "jurist_ask_next")
+async def cb_jurist_ask_next(callback: CallbackQuery, state: FSMContext):
+ """Пользователь хочет задать следующий вопрос юристу"""
+ await callback.answer()
+ role = await determine_user_role(callback.from_user.id)
+ if role not in ("admin", "lawyer"):
+ await callback.message.answer("🔒 Доступ ограничен.", parse_mode='HTML')
+ await state.clear()
+ return
+
+ await state.set_state(LegalQuestionState.waiting_for_question)
+ await callback.message.answer(
+ "⚖️ Режим юриста активен.\n\n"
+ "Напишите ваш следующий вопрос или отправьте голосовое сообщение:",
+ parse_mode='HTML'
+ )
+
+@router.callback_query(F.data == "jurist_exit")
+async def cb_jurist_exit(callback: CallbackQuery, state: FSMContext):
+ """Выход из режима юриста с возвратом в главное меню"""
+ await callback.answer("Режим юриста завершён")
+ await state.clear()
+
+ user_id = callback.from_user.id
+ try:
+ from keyboards.inline import get_main_menu
+ from database.models import InitiativeGroup
+ import config
+
+ async with AsyncSessionLocal() as session:
+ stmt = select(User).where(User.user_id == user_id)
+ user = (await session.execute(stmt)).scalar_one_or_none()
+ ig_stmt = select(InitiativeGroup).where(InitiativeGroup.user_id == user_id, InitiativeGroup.is_active == True)
+ is_ig = (await session.execute(ig_stmt)).scalar_one_or_none() is not None
+
+ is_admin = (user.is_admin if user else False) or (user_id == config.ADMIN_USER_ID)
+ is_verified = user.verified if user else False
+
+ await callback.message.answer(
+ "🚪 Вы вышли из режима юриста.\n\nГлавное меню:",
+ reply_markup=get_main_menu(
+ verified=is_verified,
+ is_ig=is_ig,
+ is_admin=is_admin,
+ is_superadmin=(user_id == config.ADMIN_USER_ID)
+ ),
+ parse_mode='HTML'
+ )
+ except Exception as e:
+ log.warning(f"Failed to show main menu on jurist exit: {e}")
+ await callback.message.answer("🚪 Вы вышли из режима юриста.", parse_mode='HTML')
+
# === ОБРАБОТКА ТЕКСТОВЫХ ВОПРОСОВ ===
@router.message(LegalQuestionState.waiting_for_question, F.text)
@@ -186,7 +253,6 @@ async def process_text_legal_question(message: Message, state: FSMContext, bot:
if not result.get("success"):
await message.answer(f"❌ Ошибка: {result.get('text')}", parse_mode='HTML')
- await state.clear()
return
# Защита от спама: если вопрос задан в групповом чате
@@ -196,7 +262,8 @@ async def process_text_legal_question(message: Message, state: FSMContext, bot:
await bot.send_message(
chat_id=user_id,
text=f"⚖️ Юридический ответ:\n\n{format_telegram_html(result['text'])}",
- parse_mode='HTML'
+ parse_mode='HTML',
+ reply_markup=get_legal_nav_keyboard()
)
await message.reply(
"💬 Ответ сформирован и отправлен вам в личные сообщения с ботом, чтобы не перегружать общий чат дома.",
@@ -212,7 +279,8 @@ async def process_text_legal_question(message: Message, state: FSMContext, bot:
header = "⚖️ Юридический ответ:"
await send_split_message(message, header, result["text"])
- await state.clear()
+ # Оставляем состояние активным, чтобы жилец мог сразу задать следующий вопрос без клика
+ await state.set_state(LegalQuestionState.waiting_for_question)
# === ОБРАБОТКА ГОЛОСОВЫХ ВОПРОСОВ (НАТИВНОЕ МУЛЬТИМОДАЛЬНОЕ РАСПОЗНАВАНИЕ) ===
@@ -253,6 +321,7 @@ async def process_voice_legal_question(message: Message, state: FSMContext, bot:
header = "⚖️ Юридический ответ:"
await send_split_message(message, header, result["text"])
+ await state.set_state(LegalQuestionState.waiting_for_question)
except Exception as e:
log.error(f"Voice processing error: {e}")
@@ -262,4 +331,3 @@ async def process_voice_legal_question(message: Message, state: FSMContext, bot:
if voice_file_path and os.path.exists(voice_file_path):
try: os.unlink(voice_file_path)
except: pass
- await state.clear()