#!/usr/bin/env python3 """LibreOffice converter — Flask HTTP service. .doc → .docx with UI + API.""" import subprocess, tempfile, os from flask import Flask, request, send_file, render_template_string app = Flask(__name__) 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}

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

""" 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( ["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: 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) for x in os.listdir(tmpdir): 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)