fix: DrHider via VM — managed Flask proxies, VM does LLM-NER obfuscation
Deploy contracts-flask / validate (push) Successful in 0s
Deploy contracts-flask / validate (push) Successful in 0s
This commit is contained in:
@@ -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
@@ -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():
|
||||||
|
|||||||
Reference in New Issue
Block a user