fix(legal): японский минимализм в ответах юриста (убраны самоназвания, титулы, плашки источников и задержек)

This commit is contained in:
Admin 2026-10-13 14:20:04 +04:00
parent 8cb5ee7036
commit b582a579aa
2 changed files with 30 additions and 56 deletions

View file

@ -124,22 +124,16 @@ async def cmd_legal_advisor(message: Message, state: FSMContext, bot: Bot):
result = await legal_engine.query(prompt=inline_question, role=role) result = await legal_engine.query(prompt=inline_question, role=role)
await status_msg.delete() await status_msg.delete()
if result.get("success"): if result.get("success"):
header = f"⚖️ <b>Юридический ответ ({result.get('latency_sec')} сек):</b>" header = "⚖️ <b>Юридический ответ:</b>"
await send_split_message(message, header, result["text"]) await send_split_message(message, header, result["text"])
else: else:
await message.answer(f"❌ <b>Ошибка:</b> {result.get('text')}", parse_mode='HTML') await message.answer(f"❌ <b>Ошибка:</b> {result.get('text')}", parse_mode='HTML')
return return
role_desc = {
"admin": "👑 <b>Режим Стратегического Аналитика (Администратор)</b>",
"lawyer": "⚖️ <b>Режим Судебного Юриста (Совет дома / Активист)</b>",
}.get(role, "🏡 <b>Юридический Помощник</b>")
text = ( text = (
f"{role_desc}\n\n" "⚖️ <b>Юридический помощник (ЖК РФ)</b>\n\n"
"Задайте ваш вопрос по ЖКХ, протечкам, тарифам, собраниям или спорам с управляющей компанией.\n\n" "Напишите ваш вопрос (текстом или отправьте голосовое сообщение).\n"
"🎙 <b>Вы можете написать текст или отправить голосовое сообщение!</b>\n" "<i>Ответ формируется по нормам законодательства РФ и судебной практике.</i>"
"<i>Я проанализирую обращение по базе законов РФ и материалам дома.</i>"
) )
await message.answer(text, parse_mode='HTML') await message.answer(text, parse_mode='HTML')
await state.set_state(LegalQuestionState.waiting_for_question) await state.set_state(LegalQuestionState.waiting_for_question)
@ -157,16 +151,10 @@ async def cb_legal_advisor(callback: CallbackQuery, state: FSMContext):
) )
return return
role_desc = {
"admin": "👑 <b>Режим Стратегического Аналитика (Администратор)</b>",
"lawyer": "⚖️ <b>Режим Судебного Юриста (Совет дома / Активист)</b>",
}.get(role, "🏡 <b>Юридический Помощник</b>")
text = ( text = (
f"{role_desc}\n\n" "⚖️ <b>Юридический помощник (ЖК РФ)</b>\n\n"
"Задайте ваш вопрос по ЖКХ, протечкам, тарифам, собраниям или спорам с управляющей компанией.\n\n" "Напишите ваш вопрос (текстом или отправьте голосовое сообщение).\n"
"🎙 <b>Вы можете написать текст или отправить голосовое сообщение!</b>\n" "<i>Ответ формируется по нормам законодательства РФ и судебной практике.</i>"
"<i>Я проанализирую обращение по базе законов РФ и судебным материалам дома.</i>"
) )
await callback.message.answer(text, parse_mode='HTML') await callback.message.answer(text, parse_mode='HTML')
await state.set_state(LegalQuestionState.waiting_for_question) await state.set_state(LegalQuestionState.waiting_for_question)
@ -189,7 +177,7 @@ async def process_text_legal_question(message: Message, state: FSMContext, bot:
question = message.text question = message.text
status_msg = await message.answer( status_msg = await message.answer(
"⏳ <i>Анализирую нормативную базу и материалы дома (1–3 сек)...</i>", "⏳ <i>Анализирую нормы законодательства РФ...</i>",
parse_mode='HTML' parse_mode='HTML'
) )
@ -207,7 +195,7 @@ async def process_text_legal_question(message: Message, state: FSMContext, bot:
try: try:
await bot.send_message( await bot.send_message(
chat_id=user_id, chat_id=user_id,
text=f"⚖️ <b>Ответ на ваш вопрос из чата дома:</b>\n\n{format_telegram_html(result['text'])}", text=f"⚖️ <b>Юридический ответ:</b>\n\n{format_telegram_html(result['text'])}",
parse_mode='HTML' parse_mode='HTML'
) )
await message.reply( await message.reply(
@ -221,7 +209,7 @@ async def process_text_legal_question(message: Message, state: FSMContext, bot:
) )
else: else:
# В личном диалоге отвечаем напрямую # В личном диалоге отвечаем напрямую
header = f"⚖️ <b>Юридический ответ ({result.get('latency_sec')} сек):</b>" header = "⚖️ <b>Юридический ответ:</b>"
await send_split_message(message, header, result["text"]) await send_split_message(message, header, result["text"])
await state.clear() await state.clear()
@ -243,7 +231,7 @@ async def process_voice_legal_question(message: Message, state: FSMContext, bot:
return return
status_msg = await message.answer( status_msg = await message.answer(
"🎙 <i>Слушаю голосовое сообщение и сопоставляю с законами РФ...</i>", "🎙 <i>Анализирую голосовое обращение по нормам законодательства...</i>",
parse_mode='HTML' parse_mode='HTML'
) )
@ -260,10 +248,10 @@ async def process_voice_legal_question(message: Message, state: FSMContext, bot:
await status_msg.delete() await status_msg.delete()
if not result.get("success"): if not result.get("success"):
await message.answer(f"❌ <b>Ошибка распознавания:</b> {result.get('text')}", parse_mode='HTML') await message.answer(f"❌ <b>Ошибка:</b> {result.get('text')}", parse_mode='HTML')
return return
header = f"🎙 <b>Голосовой разбор ({result.get('latency_sec')} сек):</b>" header = "⚖️ <b>Юридический ответ:</b>"
await send_split_message(message, header, result["text"]) await send_split_message(message, header, result["text"])
except Exception as e: except Exception as e:

View file

@ -41,35 +41,23 @@ class AILegalEngine:
def get_role_instructions(self, role: str) -> str: def get_role_instructions(self, role: str) -> str:
if role == "resident": if role == "resident":
return ( return (
"РОЛЬ ДЛЯ ОТВЕТА: 'Соседский помощник для жильца'.\n" "СТИЛЬ ОТВЕТА: Спокойный, понятный, без бюрократического канцелярита.\n"
"СТИЛЬ: Спокойный, уважительный, без сложного бюрократического языка и канцелярита.\n"
"ТРЕБОВАНИЯ:\n" "ТРЕБОВАНИЯ:\n"
"1. Объясни ситуацию простыми словами за 2-3 коротких абзаца.\n" "1. Суть ситуации простыми словами (1-2 абзаца).\n"
"2. Дай пошаговый житейский совет (Шаг 1, Шаг 2, Шаг 3).\n" "2. Пошаговый порядок действий (Шаг 1, Шаг 2, Шаг 3).\n"
"3. Укажи, кто несет ответственность (УК, застройщик, водоканал, совет дома).\n" "3. Кто несет ответственность (УК, застройщик, поставщик ресурсов, совет дома).\n"
"4. Если нужно подать заявление — приведи краткий текст (3-4 строки), который жилец может скопировать и отправить в УК." "4. Образец краткого заявления при необходимости."
) )
elif role == "lawyer": else:
return ( return (
"РОЛЬ ДЛЯ ОТВЕТА: 'Профессиональный юрист по жилищному праву и защите прав потребителей'.\n" "СТИЛЬ ОТВЕТА: Сугубо юридический, строгий, аргументированный.\n"
"СТИЛЬ: Строгий, юридически выверенный, аргументированный.\n"
"ТРЕБОВАНИЯ:\n" "ТРЕБОВАНИЯ:\n"
"1. Четкая правовая квалификация действий/бездействия лиц.\n" "1. Правовая квалификация ситуации со ссылками на статьи нормативных актов РФ (ЖК РФ, ГК РФ, 59-ФЗ, ЗоЗПП, ПП РФ № 354, ПП РФ № 491, Госстрой № 170, СанПиН).\n"
"2. Прямые ссылки на статьи законов (ЖК РФ, ГК РФ, 59-ФЗ, ПП РФ № 354, ПП РФ № 491, Госстрой № 170, СанПиН 2.1.3684-21).\n" "2. Оценка рисков, перспектив в надзорных органах и суде.\n"
"3. Оценка перспектив в суде или надзорных органах (ГЖИ, Прокуратура, Роспотребнадзор).\n" "3. Четкий алгоритм действий (досудебная претензия, жалоба в ГЖИ / прокуратуру, иск).\n"
"4. Готовый проект претензии / жалобы с правовой мотивировкой." "4. Готовый образец мотивировочной части претензии или заявления при необходимости."
) )
elif role == "admin": return "Отвечай строго по существу."
return (
"РОЛЬ ДЛЯ ОТВЕТА: 'Главный аналитик Совета Дома и стратег судебных процессов'.\n"
"СТИЛЬ: Стратегический, системный, аналитический.\n"
"ТРЕБОВАНИЯ:\n"
"1. Полный расклад с точки зрения системной выгоды для всего дома.\n"
"2. Выявление уловок УК, скрытых манипуляций со сметами, протоколами ОСС или объемами коммунальных ресурсов.\n"
"3. Сравнение с прецедентами и судебной практикой Ульяновского областного суда и Верховного Суда РФ.\n"
"4. Стратегия принуждения госорганов к исполнению служебных обязанностей по 59-ФЗ и Приказу ГП № 45."
)
return "Отвечай вежливо и по делу."
async def _query_rest_api(self, prompt: str, system_instruction: str, model: str, audio_path: str = None) -> str: async def _query_rest_api(self, prompt: str, system_instruction: str, model: str, audio_path: str = None) -> str:
"""Прямой асинхронный REST запрос к Google Gemini API.""" """Прямой асинхронный REST запрос к Google Gemini API."""
@ -208,8 +196,11 @@ class AILegalEngine:
} }
system_instruction = ( system_instruction = (
"Ты — интеллектуальный юридический щит 10-подъездного многоквартирного дома по адресу: г. Ульяновск, пр-кт Ленинского Комсомола, д. 37 (МКД ЛенКом 37).\n" "Ты — профессиональный юридический консультант по жилищному праву РФ (ЖК РФ, ГК РФ, защита прав потребителей в сфере ЖКХ).\n"
"Дом ведет системную юридическую защиту прав собственников против нарушений управляющей компании, бездействия надзорных органов и фальсификаций.\n" "ЖЕСТКИЕ ПРАВИЛА ОФОРМЛЕНИЯ:\n"
"1. КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО писать любые самопрезентации, самоназвания, титулы, приветствия или регалии (никаких 'Я — аналитик', 'Главный стратег', 'Юридический щит', 'Здравствуйте', 'Я помогу вам').\n"
"2. Ответ начинать СТРОГО сразу по существу вопроса.\n"
"3. Полный минимализм: только факты, правовые нормы, статьи законов и пошаговый алгоритм действий. Без рекламной шелухи и упоминания технологий/моделей.\n"
f"{self.get_role_instructions(role)}" f"{self.get_role_instructions(role)}"
) )
@ -224,11 +215,6 @@ class AILegalEngine:
) )
latency = (datetime.now() - start_time).total_seconds() latency = (datetime.now() - start_time).total_seconds()
# Если для админа не сработал блокнот, честно добавляем статус
if role == "admin" and not audio_path:
prefix = "📚 <b>[Источник: База законов РФ / Резервный шлюз Gemini]</b>\n<i>(Сессия NotebookLM требует обновления куков)</i>\n\n"
reply_text = prefix + reply_text
return { return {
"success": True, "success": True,