diff --git a/convert-service/app.py b/convert-service/app.py index 62a2209..85d907f 100644 --- a/convert-service/app.py +++ b/convert-service/app.py @@ -1,20 +1,85 @@ #!/usr/bin/env python3 -"""LibreOffice converter — Flask HTTP service. POST .doc → .docx.""" +"""LibreOffice converter — Flask HTTP service. .doc → .docx with UI + API.""" import subprocess, tempfile, os -from flask import Flask, request, send_file +from flask import Flask, request, send_file, render_template_string app = Flask(__name__) -@app.route("/convert", methods=["POST"]) -def convert(): - if "file" not in request.files: - return {"ok": False, "error": "no file"}, 400 +HTML = """ + + + + +Конвертер .doc → .docx + + + +

📄 Конвертер .doc → .docx

+

LibreOffice в headless-режиме. Поддерживает .doc, .rtf, .odt.

+
+ API: POST /convert с multipart/form-data, поле file.
+ Ответ: файл .docx или {"ok":false,"error":"..."}.
+ Health: GET /health{"ok":true} +
+
+

Конвертировать файл

+
+ + +
+
+ + +""" - f = request.files["file"] +def _convert_file(f): + """Convert one file to .docx, return (bytes, download_name) or raise.""" with tempfile.NamedTemporaryFile(suffix=".doc", delete=False) as tmp: f.save(tmp) doc_path = tmp.name - tmpdir = tempfile.mkdtemp() try: subprocess.run( @@ -23,15 +88,9 @@ def convert(): ) docx_files = [x for x in os.listdir(tmpdir) if x.endswith(".docx")] if not docx_files: - return {"ok": False, "error": "conversion produced no .docx"}, 500 - return send_file(os.path.join(tmpdir, docx_files[0]), - mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document", - as_attachment=True, - download_name=os.path.splitext(f.filename)[0] + ".docx") - except subprocess.TimeoutExpired: - return {"ok": False, "error": "conversion timeout"}, 500 - except subprocess.CalledProcessError as e: - return {"ok": False, "error": f"libreoffice: {e.stderr.decode() if e.stderr else 'unknown'}"}, 500 + raise ValueError("conversion produced no .docx") + with open(os.path.join(tmpdir, docx_files[0]), "rb") as out: + return out.read(), os.path.splitext(f.filename)[0] + ".docx" finally: if os.path.exists(doc_path): os.unlink(doc_path) @@ -39,9 +98,37 @@ def convert(): os.unlink(os.path.join(tmpdir, x)) os.rmdir(tmpdir) +@app.route("/", methods=["GET"]) +def index(): + return render_template_string(HTML) + +@app.route("/convert", methods=["POST"]) +def convert(): + if "file" not in request.files: + return {"ok": False, "error": "no file"}, 400 + f = request.files["file"] + if not f.filename: + return {"ok": False, "error": "empty filename"}, 400 + try: + data, name = _convert_file(f) + return send_file( + io.BytesIO(data), + mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document", + as_attachment=True, + download_name=name, + ) + except subprocess.TimeoutExpired: + return {"ok": False, "error": "conversion timeout"}, 500 + except subprocess.CalledProcessError as e: + err = e.stderr.decode() if e.stderr else "unknown" + return {"ok": False, "error": f"libreoffice: {err}"}, 500 + except ValueError as e: + return {"ok": False, "error": str(e)}, 500 + @app.route("/health", methods=["GET"]) def health(): return {"ok": True} if __name__ == "__main__": + import io app.run(host="0.0.0.0", port=5000)