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)