fix: DrHider via VM — managed Flask proxies, VM does LLM-NER obfuscation
Deploy contracts-flask / validate (push) Successful in 0s

This commit is contained in:
2026-06-29 14:39:47 +04:00
parent e407696f6b
commit 853af0ff2f
2 changed files with 61 additions and 34 deletions
+40
View File
@@ -86,6 +86,8 @@ class Handler(BaseHTTPRequestHandler):
self._handle_api_prompts_delete() self._handle_api_prompts_delete()
elif self.path == "/api/sync": elif self.path == "/api/sync":
self._handle_api_sync() self._handle_api_sync()
elif self.path == "/api/drhider":
self._handle_drhider()
else: else:
self.send_error(404) self.send_error(404)
@@ -210,6 +212,44 @@ class Handler(BaseHTTPRequestHandler):
execute("DELETE FROM contracts WHERE id NOT IN (SELECT DISTINCT contract_id FROM supplements)") execute("DELETE FROM contracts WHERE id NOT IN (SELECT DISTINCT contract_id FROM supplements)")
self._json({"ok": True, "deleted": deleted}) self._json({"ok": True, "deleted": deleted})
# ── POST /api/drhider ────────────────────────────────────────────────
def _handle_drhider(self):
"""Обфускация: multipart files → LLM-NER → ZIP."""
from services.drhider import obfuscate_files
from services.llm_client import HttpxLLMClient
from services.upload import parse_multipart
length = int(self.headers.get("Content-Length", 0))
raw = self.rfile.read(length)
ctype = self.headers.get("Content-Type", "")
files = parse_multipart(raw, ctype)
if not files:
self._json({"ok": False, "error": "Нет файлов"}, 400)
return
file_list = [(f.filename, f.content, f.content_type) for f in files]
try:
llm = HttpxLLMClient(
os.environ.get("LLM_API_URL", "https://api.aillm.ru/v1/chat/completions"),
os.environ.get("LLM_API_KEY", ""),
os.environ.get("LLM_MODEL", "gpt-oss-120b")
)
zip_data, _csv = obfuscate_files(file_list, llm_client=llm)
self.send_response(200)
self.send_header("Content-Type", "application/zip")
self.send_header("Content-Disposition", 'attachment; filename="drhider_output.zip"')
self.send_header("Content-Length", str(len(zip_data)))
self.end_headers()
self.wfile.write(zip_data)
except Exception as e:
import traceback
traceback.print_exc()
self._json({"ok": False, "error": str(e)}, 500)
# ── /api/groups ?batch=X ───────────────────────────────────────────── # ── /api/groups ?batch=X ─────────────────────────────────────────────
def _handle_api_groups(self, parsed): def _handle_api_groups(self, parsed):
+19 -32
View File
@@ -110,51 +110,38 @@ def drhider():
@app.route("/api/drhider", methods=["POST"]) @app.route("/api/drhider", methods=["POST"])
def api_drhider(): def api_drhider():
"""Обфускация: файлы → ZIP с обезличенными копиями + mapping.csv.""" """Обфускация: файлы → VM (LLM-NER) → ZIP."""
import io import httpx
import zipfile
from flask import send_file from flask import send_file
uploaded = request.files.getlist("files") uploaded = request.files.getlist("files")
if not uploaded: if not uploaded:
return jsonify({"ok": False, "error": "Нет файлов"}), 400 return jsonify({"ok": False, "error": "Нет файлов"}), 400
files = [] # Отправляем файлы на VM
try:
files_data = []
for f in uploaded: for f in uploaded:
if not f.filename: if f.filename:
continue files_data.append(("files", (f.filename, f.read(), f.content_type or "")))
content = f.read()
files.append((f.filename, content, f.content_type or ""))
if not files:
return jsonify({"ok": False, "error": "Нет файлов"}), 400
with httpx.Client(timeout=300) as client:
resp = client.post(f"{VM_API}/api/drhider", files=files_data)
resp.raise_for_status()
except httpx.HTTPStatusError as e:
try: try:
from services.drhider import obfuscate_files detail = e.response.json().get("error", str(e))
llm = None
if LLM_KEY:
try:
from services.llm_client import HttpxLLMClient
llm = HttpxLLMClient(LLM_URL, LLM_KEY, LLM_MODEL)
except Exception: except Exception:
pass detail = str(e)
return jsonify({"ok": False, "error": detail}), 500
zip_data, csv_data = obfuscate_files(files, llm_client=llm)
buf = io.BytesIO()
buf.write(zip_data)
buf.seek(0)
return send_file(
buf,
mimetype="application/zip",
as_attachment=True,
download_name="drhider_output.zip"
)
except Exception as e: except Exception as e:
return jsonify({"ok": False, "error": str(e)}), 500 return jsonify({"ok": False, "error": str(e)}), 500
import io
buf = io.BytesIO(resp.content)
buf.seek(0)
return send_file(buf, mimetype="application/zip", as_attachment=True, download_name="drhider_output.zip")
@app.route("/health") @app.route("/health")
def health(): def health():