fix(legal): NotebookLM priority query, fix model name to gemini-2.5-flash fallback
This commit is contained in:
parent
0aac30187b
commit
0dcea20739
1 changed files with 61 additions and 5 deletions
|
|
@ -23,7 +23,7 @@ class AILegalEngine:
|
||||||
self.api_key = raw_key.strip("\"'") if raw_key else ""
|
self.api_key = raw_key.strip("\"'") if raw_key else ""
|
||||||
self.client = None
|
self.client = None
|
||||||
self.model_name = "gemini-2.5-flash"
|
self.model_name = "gemini-2.5-flash"
|
||||||
self.deep_model_name = "gemini-2.5-pro"
|
self.deep_model_name = "gemini-2.5-flash"
|
||||||
self._init_sdk_client()
|
self._init_sdk_client()
|
||||||
|
|
||||||
def _init_sdk_client(self):
|
def _init_sdk_client(self):
|
||||||
|
|
@ -111,8 +111,60 @@ class AILegalEngine:
|
||||||
data = await resp.json()
|
data = await resp.json()
|
||||||
return data["candidates"][0]["content"]["parts"][0]["text"]
|
return data["candidates"][0]["content"]["parts"][0]["text"]
|
||||||
|
|
||||||
|
async def query_notebooklm(self, prompt: str) -> dict:
|
||||||
|
"""Прямой запрос к блокноту NotebookLM «Разбор ответов строго по ЖК РФ»."""
|
||||||
|
notebook_id = os.getenv("NOTEBOOKLM_ID", "00ed7d92-1ab2-4159-ac72-1d0c4be21377")
|
||||||
|
nlm_bins = ["/home/matrixhasyou/.local/bin/nlm", "/usr/local/bin/nlm", "nlm"]
|
||||||
|
nlm_bin = next((b for b in nlm_bins if os.path.exists(b)), "nlm")
|
||||||
|
|
||||||
|
cmd = [
|
||||||
|
nlm_bin, "query", "notebook",
|
||||||
|
notebook_id,
|
||||||
|
prompt
|
||||||
|
]
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["SSL_CERT_FILE"] = "/etc/ssl/certs/ca-certificates.crt"
|
||||||
|
|
||||||
|
try:
|
||||||
|
proc = await asyncio.create_subprocess_exec(
|
||||||
|
*cmd,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE,
|
||||||
|
env=env
|
||||||
|
)
|
||||||
|
stdout, stderr = await proc.communicate()
|
||||||
|
out_str = stdout.decode('utf-8', errors='ignore').strip()
|
||||||
|
err_str = stderr.decode('utf-8', errors='ignore').strip()
|
||||||
|
|
||||||
|
if proc.returncode == 0 and out_str and "Authentication Error" not in out_str and "ConnectError" not in out_str:
|
||||||
|
# Очистка предупреждений об апдейте nlm
|
||||||
|
if "Update available:" in out_str:
|
||||||
|
out_str = out_str.split("Update available:")[0].strip()
|
||||||
|
return {"success": True, "text": out_str, "source": "notebooklm"}
|
||||||
|
else:
|
||||||
|
return {"success": False, "error": err_str or out_str, "source": "notebooklm"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"success": False, "error": str(e), "source": "notebooklm"}
|
||||||
|
|
||||||
async def query(self, prompt: str, role: str = "resident", audio_path: str = None) -> dict:
|
async def query(self, prompt: str, role: str = "resident", audio_path: str = None) -> dict:
|
||||||
"""Основной метод запроса к юридическому ядру."""
|
"""Основной метод запроса: NotebookLM (первый приоритет) -> Gemini (fallback)."""
|
||||||
|
start_time = datetime.now()
|
||||||
|
|
||||||
|
# Если вопрос от Админа и нет аудио — пробуем NotebookLM в первую очередь!
|
||||||
|
if role in ("admin", "lawyer") and not audio_path and prompt:
|
||||||
|
nlm_res = await self.query_notebooklm(prompt)
|
||||||
|
if nlm_res.get("success"):
|
||||||
|
latency = (datetime.now() - start_time).total_seconds()
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"text": nlm_res["text"],
|
||||||
|
"answer": nlm_res["text"],
|
||||||
|
"role": role,
|
||||||
|
"latency_sec": round(latency, 2),
|
||||||
|
"model": "NotebookLM: Разбор ответов строго по ЖК РФ"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Резервный контур через Gemini API (если сессия блокнота требует продления или жилец)
|
||||||
if not self.api_key:
|
if not self.api_key:
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"success": False,
|
||||||
|
|
@ -121,17 +173,15 @@ class AILegalEngine:
|
||||||
"latency_sec": 0.0
|
"latency_sec": 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
start_time = datetime.now()
|
|
||||||
system_instruction = (
|
system_instruction = (
|
||||||
"Ты — интеллектуальный юридический щит 10-подъездного многоквартирного дома по адресу: г. Ульяновск, пр-кт Ленинского Комсомола, д. 37 (МКД ЛенКом 37).\n"
|
"Ты — интеллектуальный юридический щит 10-подъездного многоквартирного дома по адресу: г. Ульяновск, пр-кт Ленинского Комсомола, д. 37 (МКД ЛенКом 37).\n"
|
||||||
"Дом ведет системную юридическую защиту прав собственников против нарушений управляющей компании, бездействия надзорных органов и фальсификаций.\n"
|
"Дом ведет системную юридическую защиту прав собственников против нарушений управляющей компании, бездействия надзорных органов и фальсификаций.\n"
|
||||||
f"{self.get_role_instructions(role)}"
|
f"{self.get_role_instructions(role)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
model_to_use = self.deep_model_name if role in ("lawyer", "admin") else self.model_name
|
model_to_use = self.model_name
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Используем прямой REST (наивысшая надежность без конфликтов библиотек)
|
|
||||||
reply_text = await self._query_rest_api(
|
reply_text = await self._query_rest_api(
|
||||||
prompt=prompt,
|
prompt=prompt,
|
||||||
system_instruction=system_instruction,
|
system_instruction=system_instruction,
|
||||||
|
|
@ -140,6 +190,12 @@ 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,
|
||||||
"text": reply_text.strip(),
|
"text": reply_text.strip(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue