From 958865c397a876c2b04431ee4c98166fc297f9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Thu, 18 Jun 2026 09:23:09 +0400 Subject: [PATCH] =?UTF-8?q?v3.3.0:=20=D1=87=D0=B0=D1=82=20=D1=81=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=D0=B2=D0=BE=D1=80=D0=BE=D0=BC=20=E2=80=94=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B4=D0=B0=D1=82=D1=8C=20=D0=B2=D0=BE=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=81=20=D0=BF=D0=BE=20spec=5Frows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/app.py | 3 ++- site/routes/llm.py | 59 +++++++++++++++++++++++++++++++++++++++-- site/templates/llm.html | 56 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 3 deletions(-) diff --git a/site/app.py b/site/app.py index acc2542..9db4b42 100644 --- a/site/app.py +++ b/site/app.py @@ -13,7 +13,7 @@ from api import api_bp from routes.main import index from routes.parse import parse from routes.misc import health, logs -from routes.llm import process as llm_process +from routes.llm import process as llm_process, chat as llm_chat load_dotenv() @@ -47,6 +47,7 @@ class ContractsApp: # LLM: страница + SSE-извлечение self.app.add_url_rule("/llm", "llm_page", lambda: __import__('flask').render_template('llm.html')) self.app.add_url_rule("/llm/process/", "llm_process", llm_process) + self.app.add_url_rule("/llm/chat/", "llm_chat", llm_chat, methods=["POST"]) # Служебные self.app.add_url_rule("/health", "health", health) diff --git a/site/routes/llm.py b/site/routes/llm.py index ed44645..8d51be5 100644 --- a/site/routes/llm.py +++ b/site/routes/llm.py @@ -1,13 +1,14 @@ -"""routes/llm.py — LLM-извлечение + сравнение: один SSE-поток.""" +"""routes/llm.py — LLM-извлечение + сравнение + чат.""" import json as _json import time as _time -from flask import Response +from flask import Response, request, jsonify import db import extractor import differ +import llm_client def process(cid): @@ -137,3 +138,57 @@ def process(cid): yield f"data: {_json.dumps({'type': 'done', 'total_time_s': total_time, 'all_changes': all_changes})}\n\n" return Response(generate(), mimetype="text/event-stream") + + +def chat(cid): + """ + POST /llm/chat/ — задать вопрос по договору. + + Тело: {"question": "..."} + Контекст: все строки spec_rows этого договора. + Ответ: {"answer": "..."} + """ + data = request.get_json(silent=True) or {} + question = data.get("question", "").strip() + if not question: + return jsonify({"error": "Введите вопрос"}), 400 + + # ── Собрать контекст: все строки спецификации ────────── + rows_res, _ = db.query( + "SELECT s.type, s.number, d.filename, sr.row_num, sr.name, sr.price, sr.qty, sr.sum, sr.date_start " + "FROM spec_rows sr " + "JOIN supplements s ON sr.supplement_id = s.id " + "JOIN documents d ON s.document_id = d.id " + "WHERE s.contract_id = %s ORDER BY s.created_at, sr.row_num", + (cid,), + ) + if not rows_res or not rows_res["rows"]: + return jsonify({"answer": "Нет извлечённых данных. Сначала запустите сравнение."}) + + # Форматируем контекст + lines = [] + for r in rows_res["rows"]: + row = dict(zip(rows_res["columns"], r)) + lines.append( + f"[{row['filename']}] строка {row['row_num']}: {row['name']} | " + f"цена={row['price']} | объём={row['qty']} | сумма={row['sum']} | начало={row['date_start']}" + ) + context = "\n".join(lines) + + # ── Промпт ────────────────────────────────────────────── + prompt = f"""Ты — анализатор договоров облачного провайдера. У тебя есть извлечённые строки спецификации услуг. + +ДАННЫЕ: +{context} + +ВОПРОС ПОЛЬЗОВАТЕЛЯ: +{question} + +Ответь кратко и по делу, опираясь ТОЛЬКО на данные выше. Если данных недостаточно — скажи об этом.""" + + # ── Вызов LLM ─────────────────────────────────────────── + result = llm_client.ask(prompt, max_tokens=1000) + if "error" in result: + return jsonify({"answer": f"Ошибка LLM: {result['error']}"}) + + return jsonify({"answer": result.get("text", "Нет ответа")}) diff --git a/site/templates/llm.html b/site/templates/llm.html index 6ea1d3e..87216ea 100644 --- a/site/templates/llm.html +++ b/site/templates/llm.html @@ -104,6 +104,21 @@
+ + +