v1.0.118: ZIP upload — unzip on VM, add files to queue individually, flat structure only
This commit is contained in:
@@ -60,6 +60,8 @@ class Handler(BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
if self.path == "/llm-ops":
|
||||
self._handle_llm_ops()
|
||||
elif self.path == "/unzip-upload":
|
||||
self._handle_unzip_upload()
|
||||
else:
|
||||
self._handle_doc_convert()
|
||||
|
||||
@@ -275,6 +277,57 @@ class Handler(BaseHTTPRequestHandler):
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps({"error": str(e)}, ensure_ascii=False).encode())
|
||||
|
||||
def _handle_unzip_upload(self):
|
||||
"""Распаковать ZIP и загрузить каждый файл в Lucee. Только файлы из корня архива."""
|
||||
import zipfile, io
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
data = self.rfile.read(length)
|
||||
|
||||
results = []
|
||||
try:
|
||||
with zipfile.ZipFile(io.BytesIO(data)) as zf:
|
||||
for name in zf.namelist():
|
||||
# Только файлы из корня (без папок), пропускаем директории
|
||||
if name.endswith('/') or '/' in name:
|
||||
continue
|
||||
content = zf.read(name)
|
||||
ext = name.rsplit('.', 1)[-1].lower() if '.' in name else ''
|
||||
if ext not in ('docx', 'doc', 'pdf'):
|
||||
continue
|
||||
|
||||
# Загрузить в Lucee
|
||||
resp = httpx.post(
|
||||
f"{LUCEE_URL}/upload.cfm",
|
||||
data={"filename": name, "data": content},
|
||||
timeout=30
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
rj = resp.json()
|
||||
if rj.get("OK"):
|
||||
results.append({
|
||||
"filename": name,
|
||||
"doc_id": rj.get("DOC_ID", ""),
|
||||
"contract_id": rj.get("CONTRACT_ID", ""),
|
||||
"size": len(content),
|
||||
})
|
||||
else:
|
||||
results.append({"filename": name, "error": rj.get("ERROR", "upload failed")})
|
||||
else:
|
||||
results.append({"filename": name, "error": f"HTTP {resp.status_code}"})
|
||||
|
||||
except zipfile.BadZipFile:
|
||||
self.send_error(400, "not a valid ZIP file")
|
||||
return
|
||||
except Exception as e:
|
||||
self.send_error(500, str(e))
|
||||
return
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "application/json; charset=utf-8")
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps({"ok": True, "files": results}, ensure_ascii=False).encode())
|
||||
|
||||
def _handle_doc_convert(self):
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
data = self.rfile.read(length)
|
||||
|
||||
@@ -43,6 +43,15 @@ server {
|
||||
add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
|
||||
}
|
||||
|
||||
location /unzip-upload {
|
||||
add_header Access-Control-Allow-Origin "*";
|
||||
add_header Access-Control-Allow-Methods "POST, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "*";
|
||||
if ($request_method = OPTIONS) { return 200; }
|
||||
proxy_pass http://127.0.0.1:8766;
|
||||
client_max_body_size 100m;
|
||||
}
|
||||
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/contracts.kube5s.ru/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/contracts.kube5s.ru/privkey.pem; # managed by Certbot
|
||||
|
||||
Reference in New Issue
Block a user