\usepackage{openai}

PDF LaTeX avec OpenAI via Function Calling

Définissez un outil compile_latex et laissez GPT-4o l'appeler automatiquement. FormaTeX se charge de la compilation : vous obtenez un PDF sans écrire vous-même la moindre ligne de LaTeX.

\section{Définition de la fonction}

Définition de la fonction pour la compilation LaTeX

Déclarez un outil compile_latex dans le tableau tools. GPT-4o l'appellera lorsque l'utilisateur demandera un PDF, en transmettant le source LaTeX complet, le moteur et le nom de fichier souhaité sous forme d'arguments structurés.

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"],
            },
        },
    }
]

Bien rédiger les descriptions d'outils

Le champ description est lu par GPT-4o pour décider quand appeler la fonction. Précisez qu'elle doit être appelée chaque fois que l'utilisateur veut un PDF compilé, et pas seulement lorsqu'il mentionne LaTeX par son nom.

\section{Exemple complet}

Exemple complet de chat et de compilation

Le flux complet en deux tours : GPT-4o reçoit le message de l'utilisateur, appelle compile_latex avec le source LaTeX généré, puis résume le résultat. Le PDF est enregistré sur disque une fois le premier tour terminé.

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/api/v1/compile"

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={
            "X-API-Key": FORMATEX_API_KEY,
            "Content-Type": "application/json",
        },
        json={
            "latex": 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}

Considérations sur le streaming

Lorsque le streaming est activé, les arguments des appels d'outils arrivent par morceaux et doivent être assemblés avant l'exécution. L'exemple ci-dessous montre comment accumuler les fragments d'appels d'outils reçus en streaming et les exécuter une fois le flux terminé.

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}")

Quand utiliser le streaming

Activez le streaming sur le premier tour pour afficher GPT-4o en train d'écrire le LaTeX en temps réel. Cela améliore la latence perçue pour les utilisateurs qui attendent des documents longs.

La compilation est toujours synchrone

Le point de terminaison de compilation FormaTeX n'est pas diffusé en streaming : il renvoie le PDF complet une fois la compilation terminée. La latence typique est inférieure à 3 secondes.

\end{openai}

Générez des PDF avec GPT-4o + FormaTeX

Obtenez une clé API FormaTeX, copiez l'exemple complet ci-dessus et livrez en quelques minutes des PDF générés par l'IA depuis le function calling d'OpenAI.