DocumentStudio (Python)

June 23, 2026 · View on GitHub

A bidirectional, Markdown-centric document converter — a Python library and CLI in the spirit of Microsoft's markitdown, but going both ways:

DirectionFormatsNotes
Reverse X → MarkdownPDF, Word, PPT, Excel, EPUB, HTML, CSV/TSV, JSON, ZIP, imageslike markitdown; can delegate to markitdown when installed
Forward Markdown → XHTML, PDF, Word (.docx), LaTeX, EPUB, Excel (.xlsx), texthigh-fidelity export — the part markitdown does not do
AI / VLMimage & scanned-PDF recognition, "smart cleanup"any OpenAI-compatible endpoint; vision model optional
AI assistantpolish, translate, summarise, expand, continue, grammar, formalise, titles, outline, fix-LaTeX, free-formone-shot ops on a document
Toolboxtable of contents, merge PDFs, extract imagesheadless, no browser
Templatesacademic, techdoc, minutes, readme, weekly, blogready-to-edit Markdown

The design mirrors markitdown's: a small core, a converter registry that's open for extension, and optional dependency extras so a minimal install still works.

Install

pip install docstudio                 # core: csv/tsv/json/html  +  md→html/latex/text
pip install "docstudio[office]"       # docx, pptx, xlsx, epub
pip install "docstudio[pdf]"          # PDF text extraction (pdfminer.six)
pip install "docstudio[ocr]"          # scanned-PDF / image OCR (PyMuPDF, pytesseract)
pip install "docstudio[llm]"          # AI cleanup + VLM (requests)
pip install "docstudio[markitdown]"   # reuse Microsoft markitdown for the reverse path
pip install "docstudio[all]"

For Markdown → PDF/DOCX/EPUB with the best fidelity, install pandoc plus a TeX engine (xelatex):

sudo apt install pandoc texlive-xetex texlive-latex-recommended fonts-noto-cjk

PDF also has two pure-Python backends as fallbacks: weasyprint (docstudio[pdf-weasy]) and headless-Chrome via playwright (docstudio[pdf-chrome], full KaTeX math).

Library

from docstudio import DocumentStudio
ds = DocumentStudio()                       # use_markitdown=True by default

# anything → Markdown
md = ds.to_markdown("report.pdf")
md = ds.to_markdown("slides.pptx")

# Markdown → anything (non-md inputs are auto-converted first)
ds.convert("paper.md",  to="pdf",   out="paper.pdf")
ds.convert("paper.md",  to="docx",  out="paper.docx")
ds.convert("scan.pdf",  to="docx",  out="scan.docx")   # PDF → md → docx
ds.convert("table.png", to="xlsx",  out="table.xlsx")  # image → md → xlsx

AI + Vision (VLM)

from docstudio import DocumentStudio
from docstudio.llm import LLM

llm = LLM(base_url="https://api.openai.com", api_key="sk-...",
          model="gpt-4o-mini", vlm_model="gpt-4o")

print(LLM.fetch_models("https://api.openai.com", "sk-..."))   # pick from the list

ds = DocumentStudio(llm=llm)
md = ds.to_markdown("photographed_table.jpg")   # recognised by the vision model
md = ds.to_markdown("scanned_book.pdf")         # page-by-page VLM when no text layer
md = llm.cleanup_markdown(rough_text)           # turn messy OCR into clean Markdown

AI assistant (operate on a document)

One-shot AI operations on Markdown/text — the AI Assistant from the web app. Needs an llm (any OpenAI-compatible endpoint).

from docstudio import DocumentStudio
from docstudio.llm import LLM

# any OpenAI-compatible endpoint — OpenAI, DeepSeek, vLLM, Ollama, a gateway…
# you choose base_url + model; nothing is hard-coded to a provider
ds = DocumentStudio(llm=LLM(base_url="https://api.openai.com",
                            api_key="sk-...", model="gpt-4o-mini"))

ds.assist(md, action="polish")     # 润色
ds.assist(md, action="to_en")      # 翻译成英文(to_zh 反之)
ds.assist(md, action="summary")    # 摘要
ds.assist(md, action="outline")    # 生成大纲
ds.assist(md, instruction="把所有表格改成要点列表")   # 自由指令

DocumentStudio.assist_actions()
# polish, to_en, to_zh, summary, expand, condense, continue,
# grammar, formal, titles, outline, fix_latex

Toolbox

ds.generate_toc(md)                              # insert a Markdown table of contents
ds.merge_pdfs(["a.pdf", "b.pdf"], "all.pdf")     # concatenate PDFs (needs pypdf)
ds.extract_images("report.pdf", "./imgs")        # pull embedded images out (PDF/DOCX/PPTX/EPUB)

Templates

Six ready-to-edit Markdown templates: academic, techdoc, minutes, readme, weekly, blog.

ds.templates()                # {slug: (title, description)}
body = ds.template("academic")

CLI

docstudio report.pdf                      # → report.md   (prints to stdout)
docstudio report.pdf -o out.md
cat report.pdf | docstudio                # stdin → stdout
docstudio paper.md --to pdf -o paper.pdf  # Markdown → anything
docstudio scan.pdf --to docx              # PDF → md → docx
docstudio photo.jpg --vlm-model gpt-4o --base-url https://api.openai.com --api-key sk-...
docstudio --list-formats

docstudio paper.md --toc -o paper.md                     # insert a table of contents
docstudio notes.md --assist polish --base-url https://api.openai.com --model gpt-4o-mini --api-key sk-... -o clean.md
docstudio notes.md --instruction "翻译成英文" --base-url https://api.openai.com --model gpt-4o-mini --api-key sk-... -o en.md
docstudio --merge a.pdf b.pdf -o all.pdf                 # merge PDFs
docstudio report.pdf --extract-images ./imgs             # pull out images
docstudio --template academic                            # print a template
docstudio --list-templates

Extending

Register your own converter — exactly how the built-ins are defined:

from docstudio.core import registry

@registry.ingester("rtf")
def rtf_to_md(source, ds=None, **opts):
    ...
    return markdown_text

@registry.exporter("rst")
def md_to_rst(md, out=None, ds=None, **opts):
    ...
    return out

Relationship to markitdown

markitdown is excellent at X → Markdown for LLM pipelines. DocumentStudio reuses it for that direction when present (use_markitdown=True), and adds the missing half: turning Markdown back into polished, human-facing PDF / Word / LaTeX / EPUB / Excel, plus a vision-model path for images and scanned PDFs.

MIT licensed.