commit 8b0e93bf694977bb4cf1e1e04ea322b0b5fc3b06 Author: Carlos Date: Thu May 28 11:53:52 2026 +0000 feat: initial commit — markitdown converter diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e271f8a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM python:3.12-slim + +WORKDIR /app + +# System deps for markitdown (PDF, DOCX, etc.) +RUN apt-get update && apt-get install -y --no-install-recommends \ + libmagic1 \ + && rm -rf /var/lib/apt/lists/* + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 8000 +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..138745a --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,12 @@ +services: + markitdown: + build: . + container_name: markitdown + restart: unless-stopped + networks: + - web-net + +networks: + web-net: + external: true + name: web_web-net \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..e7042a7 --- /dev/null +++ b/main.py @@ -0,0 +1,70 @@ +from fastapi import FastAPI, UploadFile, File, Request +from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse +from fastapi.templating import Jinja2Templates +from fastapi.staticfiles import StaticFiles +from markitdown import MarkItDown +from markitdown._stream_info import StreamInfo +import io, os, mimetypes + +app = FastAPI(title="MarkItDown Converter") +templates = Jinja2Templates(directory="templates") + +# markitdown supports: PDF, DOCX, PPTX, XLSX, HTML, CSV, JSON, XML, +# images (with OCR via LLM), audio, ZIP, EPUB, YouTube URLs, Wikipedia, etc. +ALLOWED_EXTENSIONS = { + ".pdf", ".docx", ".doc", ".pptx", ".ppt", ".xlsx", ".xls", + ".html", ".htm", ".csv", ".json", ".xml", ".epub", + ".txt", ".md", ".rst", ".zip", ".msg", + ".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", + ".mp3", ".wav", ".m4a", +} + +MAX_SIZE_MB = 50 + + +@app.get("/", response_class=HTMLResponse) +async def index(request: Request): + return templates.TemplateResponse("index.html", {"request": request}) + + +@app.post("/convert") +async def convert(file: UploadFile = File(...)): + # Validate extension + _, ext = os.path.splitext(file.filename or "") + ext = ext.lower() + if ext not in ALLOWED_EXTENSIONS: + return JSONResponse( + {"error": f"Unsupported file type: '{ext}'. Supported: {', '.join(sorted(ALLOWED_EXTENSIONS))}"}, + status_code=400 + ) + + # Read into memory + data = await file.read() + size_mb = len(data) / (1024 * 1024) + if size_mb > MAX_SIZE_MB: + return JSONResponse( + {"error": f"File too large ({size_mb:.1f} MB). Max: {MAX_SIZE_MB} MB"}, + status_code=413 + ) + + try: + md = MarkItDown() + stream = io.BytesIO(data) + mime = mimetypes.types_map.get(ext, "application/octet-stream") + result = md.convert_stream( + stream, + stream_info=StreamInfo( + mimetype=mime, + extension=ext, + filename=file.filename, + ) + ) + markdown_text = result.text_content or "" + return JSONResponse({ + "markdown": markdown_text, + "filename": file.filename, + "size_kb": round(len(data) / 1024, 1), + "chars": len(markdown_text), + }) + except Exception as e: + return JSONResponse({"error": f"Conversion failed: {str(e)}"}, status_code=500) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..173d001 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +fastapi==0.115.0 +uvicorn[standard]==0.30.6 +python-multipart==0.0.9 +markitdown[all]==0.1.1 +jinja2==3.1.4 \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..bc220ec --- /dev/null +++ b/templates/index.html @@ -0,0 +1,604 @@ + + + + + +MarkItDown · carloselugo.com + + + + + + + + + +
+
+ +
+
// document converter
+
+

MarkItDown

+

Drop any document. Get clean Markdown. PDF, DOCX, PPTX, XLSX, HTML, and more.

+
+ +
+ +
+
+ INPUT + no file selected +
+
+ + +
+
📄
+
DROP FILE HERE
+
or click to browse
+
+ pdf + docx + pptx + xlsx + html + csv + epub + json + xml + + more +
+
+ + + +
+
📄
+
+
+
+ + +
+
+ + +
+
+ Converting... +
+ + +
+ +
+
+ + +
+
+ OUTPUT · MARKDOWN + +
+
+ +
+
+
MARKDOWN WILL APPEAR HERE
+
+ +
+
chars 0
+
lines 0
+
words 0
+
+ + + +
+ + + copied! +
+ +
+
+
+ + +
+
+

Supported Formats

+
+
+
DOCUMENTS
+
PDF
DOCX / DOC
PPTX / PPT
XLSX / XLS
EPUB
MSG (Outlook)
+
+
+
WEB / DATA
+
HTML / HTM
CSV
JSON
XML
RSS / Atom
Plain text
+
+
+
IMAGES
+
PNG
JPG / JPEG
GIF
WEBP
BMP
(OCR via AI)
+
+
+
AUDIO
+
MP3
WAV
M4A
(Transcription via AI)
+
+
+
ARCHIVES
+
ZIP
(converts each file inside)
+
+
+
+ +
+
+ + + + + + \ No newline at end of file