diff --git a/convert-service/Dockerfile b/convert-service/Dockerfile new file mode 100644 index 0000000..7024fd7 --- /dev/null +++ b/convert-service/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.12 + +RUN apt-get update && apt-get install -y --no-install-recommends libreoffice && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY app.py . + +EXPOSE 5000 + +CMD ["python3", "app.py"] diff --git a/convert-service/app.py b/convert-service/app.py new file mode 100644 index 0000000..62a2209 --- /dev/null +++ b/convert-service/app.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +"""LibreOffice converter — Flask HTTP service. POST .doc → .docx.""" +import subprocess, tempfile, os +from flask import Flask, request, send_file + +app = Flask(__name__) + +@app.route("/convert", methods=["POST"]) +def convert(): + if "file" not in request.files: + return {"ok": False, "error": "no file"}, 400 + + f = request.files["file"] + with tempfile.NamedTemporaryFile(suffix=".doc", delete=False) as tmp: + f.save(tmp) + doc_path = tmp.name + + tmpdir = tempfile.mkdtemp() + try: + subprocess.run( + ["libreoffice", "--headless", "--convert-to", "docx", "--outdir", tmpdir, doc_path], + timeout=120, capture_output=True, check=True + ) + 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 + finally: + if os.path.exists(doc_path): + os.unlink(doc_path) + for x in os.listdir(tmpdir): + os.unlink(os.path.join(tmpdir, x)) + os.rmdir(tmpdir) + +@app.route("/health", methods=["GET"]) +def health(): + return {"ok": True} + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000) diff --git a/convert-service/requirements.txt b/convert-service/requirements.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/convert-service/requirements.txt @@ -0,0 +1 @@ +flask