FormaTeX

\usepackage{openai}

OpenAI LaTeX PDF via Function Calling

Define a compile_latex tool and let GPT-4o call it automatically. FormaTeX handles the compilation — you get a PDF without writing a single line of LaTeX yourself.

\section{Function Definition}

Function definition for LaTeX compilation

Declare a compile_latex tool in the tools array. GPT-4o will call it when the user requests a PDF — passing the complete LaTeX source, engine, and desired filename as structured arguments.

tool_definition.py
from openai import OpenAI

client = OpenAI(api_key="your-openai-key")

# Define the compile_latex function that GPT-4 can call
TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "compile_latex",
            "description": (
                "Compile a complete LaTeX document to PDF using the FormaTeX API. "
                "Call this whenever the user wants a PDF output of a LaTeX document. "
                "Returns a confirmation message with the output file path."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "source": {
                        "type": "string",
                        "description": (
                            "Complete LaTeX source code including \\documentclass, "
                            "preamble packages, and \\begin{document}...\\end{document}."
                        ),
                    },
                    "engine": {
                        "type": "string",
                        "enum": ["pdflatex", "xelatex", "lualatex", "latexmk"],
                        "description": "LaTeX engine. Use xelatex for Unicode/custom fonts.",
                    },
                    "output_filename": {
                        "type": "string",
                        "description": "Filename for the saved PDF (e.g. report.pdf).",
                    },
                },
                "required": ["source"],
            },
        },
    }
]

Writing good tool descriptions

The description field is read by GPT-4o to decide when to call the function. Be explicit that it should be called whenever the user wants a compiled PDF — not just when they mention LaTeX by name.

\section{Complete Example}

Complete chat + compile example

The full two-turn flow: GPT-4o receives the user message, calls compile_latex with generated LaTeX source, and then summarises the result. The PDF is saved to disk after the first turn completes.

openai_formatex.py
import json
import requests
from openai import OpenAI

openai_client = OpenAI(api_key="your-openai-key")
FORMATEX_API_KEY = "your-formatex-key"
FORMATEX_URL = "https://api.formatex.io/v1/compile/sync"

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "compile_latex",
            "description": "Compile LaTeX source to PDF via FormaTeX. Returns output file path.",
            "parameters": {
                "type": "object",
                "properties": {
                    "source": {"type": "string", "description": "Complete LaTeX source code."},
                    "engine": {
                        "type": "string",
                        "enum": ["pdflatex", "xelatex", "lualatex", "latexmk"],
                    },
                    "output_filename": {"type": "string"},
                },
                "required": ["source"],
            },
        },
    }
]

def call_compile_latex(args: dict) -> str:
    """Execute the compile_latex tool call."""
    response = requests.post(
        FORMATEX_URL,
        headers={
            "Authorization": f"Bearer {FORMATEX_API_KEY}",
            "Content-Type": "application/json",
        },
        json={
            "source": args["source"],
            "engine": args.get("engine", "pdflatex"),
        },
        timeout=30,
    )
    response.raise_for_status()

    filename = args.get("output_filename", "output.pdf")
    with open(filename, "wb") as f:
        f.write(response.content)
    return f"PDF compiled successfully and saved to {filename}"

def chat_and_compile(user_message: str) -> str:
    """Run a GPT-4o chat turn that can call compile_latex."""
    messages = [
        {
            "role": "system",
            "content": (
                "You are a LaTeX expert assistant. When the user asks for a PDF document, "
                "write complete, valid LaTeX source and call compile_latex to produce it."
            ),
        },
        {"role": "user", "content": user_message},
    ]

    # First turn — GPT-4o decides to call compile_latex
    response = openai_client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=TOOLS,
        tool_choice="auto",
    )
    msg = response.choices[0].message

    if not msg.tool_calls:
        return msg.content or ""

    # Execute all tool calls
    messages.append(msg)
    for tool_call in msg.tool_calls:
        args = json.loads(tool_call.function.arguments)
        result = call_compile_latex(args)
        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": result,
        })

    # Second turn — GPT-4o summarises the result
    final = openai_client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
    )
    return final.choices[0].message.content or ""


reply = chat_and_compile(
    "Create a one-page LaTeX CV for a software engineer and compile it to PDF."
)
print(reply)

\section{Streaming}

Streaming considerations

When streaming is enabled, tool call arguments arrive in chunks and must be assembled before execution. The example below shows how to accumulate streamed tool call fragments and execute them once the stream ends.

streaming_example.py
from openai import OpenAI
import json

client = OpenAI(api_key="your-openai-key")

# Stream the first turn to show GPT-4o "thinking" while it writes LaTeX.
# Tool calls are assembled from streamed chunks before execution.
stream = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "You are a LaTeX expert. Call compile_latex for PDFs."},
        {"role": "user", "content": "Write a beamer presentation on machine learning basics."},
    ],
    tools=TOOLS,
    tool_choice="auto",
    stream=True,
)

tool_call_chunks: dict[int, dict] = {}

for chunk in stream:
    delta = chunk.choices[0].delta

    # Accumulate streamed tool call arguments
    if delta.tool_calls:
        for tc in delta.tool_calls:
            idx = tc.index
            if idx not in tool_call_chunks:
                tool_call_chunks[idx] = {"id": "", "name": "", "arguments": ""}
            if tc.id:
                tool_call_chunks[idx]["id"] = tc.id
            if tc.function and tc.function.name:
                tool_call_chunks[idx]["name"] = tc.function.name
            if tc.function and tc.function.arguments:
                tool_call_chunks[idx]["arguments"] += tc.function.arguments

# Execute accumulated tool calls after stream finishes
for idx, tc in tool_call_chunks.items():
    args = json.loads(tc["arguments"])
    result = call_compile_latex(args)
    print(f"Tool call {idx}: {result}")

When to stream

Stream the first turn to show GPT-4o writing LaTeX in real time. This improves perceived latency for users waiting on long documents.

Compilation is always synchronous

The FormaTeX compile endpoint is not streamed — it returns the full PDF once compilation finishes. Typical latency is under 3 seconds.

\end{openai}

Generate PDFs with GPT-4o + FormaTeX

Get a FormaTeX API key, copy the complete example above, and ship AI-generated PDFs from OpenAI function calling in minutes.

One quick thing

We track anonymous usage — page views, feature usage, compilation events — to understand what works and what doesn't. No ads, no personal data, no third-party sharing.

Cookie policy