Small HTTP server that converts a hand-drawn diagram image into standalone LaTeX/TikZ using an LLM, then compiles it with pdflatex and renders a PNG preview via ImageMagick. https://lab.phc.dm.unipi.it/diagram-to-tikz/
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
Antonio De Lucreziis 7dbab98466 feat: add fork functionality to create a copy of a run 5 months ago
examples initial prototype 5 months ago
public feat: enhance security features and improve user interface in LaTeX diagram tool 5 months ago
templates feat: add fork functionality to create a copy of a run 5 months ago
.gitignore initial prototype 5 months ago
.python-version initial prototype 5 months ago
Dockerfile feat: enhance security features and improve user interface in LaTeX diagram tool 5 months ago
README.md fix: update image references from 'preview.png' to 'diagram.png' in README and HTML template 5 months ago
docker-compose.yaml feat: enhance security features and improve user interface in LaTeX diagram tool 5 months ago
main.py feat: add fork functionality to create a copy of a run 5 months ago
pyproject.toml refactor: rename project from latex-diagram-to-tikz to diagram-to-tikz 5 months ago
uv.lock refactor: rename project from latex-diagram-to-tikz to diagram-to-tikz 5 months ago

README.md

diagram-to-tikz

Small HTTP server that converts a hand-drawn diagram image into standalone LaTeX/TikZ using an LLM, then compiles it with pdflatex and renders a PNG preview via ImageMagick (magick).

Prerequisites

  • System tools:

    • pdflatex (TeX Live)

    • magick (ImageMagick)

    • pdf2svg

Install (uv)

From this folder:

uv sync

Configure LLM

This project uses LiteLLM with Google Gemini models.

Set credentials (common case):

export GOOGLE_API_KEY="..."

Defaults (comma-separated fallback order):

  • LLM_MODELS=gemini/gemini-3-pro-preview,gemini/gemini-3-flash-preview,gemini/gemini-flash-latest
  • EDIT_MODELS=gemini/gemini-3-flash-preview,gemini/gemini-flash-latest

Override if you want:

export LLM_MODELS="gemini/gemini-3-flash-preview"
export EDIT_MODELS="gemini/gemini-3-flash-preview"

Run

Option A: run via Python entrypoint

uv run python main.py
uv run uvicorn main:app --reload

Open:

Docker

Single-stage python:3.12-slim + uv with cached dependency layer. BuildKit is required for cache mounts.

Build locally:

docker build -t diagram-to-tikz .

Run with Docker

docker run -it --rm -p 8000:8000 \
    -e GOOGLE_API_KEY="your-google-api-key" \
    -e LLM_MODELS="gemini/gemini-3-pro-preview,gemini/gemini-3-flash-preview,gemini/gemini-flash-latest" \
    -e EDIT_MODELS="gemini/gemini-3-flash-preview,gemini/gemini-flash-latest" \
    -e BASE_PATH="/" \
    -v $(pwd)/runs:/app/runs \
    diagram-to-tikz \
    uv run uvicorn main:app --host 0.0.0.0 --port 8000

Run with Docker Compose

Run with Compose (persists runs/ to the host):

services:
    app:
        build: .
        ports:
            - "8000:8000"
        environment:
            GOOGLE_API_KEY: "your-google-api-key"
            LLM_MODELS: "gemini/gemini-3-pro-preview,gemini/gemini-3-flash-preview,gemini/gemini-flash-latest"
            EDIT_MODELS: "gemini/gemini-3-flash-preview,gemini/gemini-flash-latest"
            BASE_PATH: "/"
            LOG_LEVEL: "INFO"
            CONVERT_DAILY_LIMIT: "5"
            EDIT_DAILY_LIMIT: "10"
            PDFLATEX_TIMEOUT_SECONDS: "10"
            HOST: "0.0.0.0"
            PORT: "8000"
            RELOAD: "0"
        volumes:
            - ./runs:/app/runs
        command: uv run uvicorn main:app --host 0.0.0.0 --port 8000

Then start it:

docker compose up --build

Outputs

Each request creates a folder under runs/<run_id>/ containing:

  • original.* (your upload)
  • diagram.tex
  • diagram.pdf (if LaTeX compilation succeeded)
  • diagram.png (if ImageMagick rendering succeeded)
  • run.log.txt (all logs: LLM + pdflatex + magick)