Überblick über das Python-SDK
Überblick über das Python-SDK
Abschnitt betitelt „Überblick über das Python-SDK“Das NextPDF Python-SDK ist für Python-Anwendungen gedacht, die PDF-Extraktion mit Provenance benötigen. Es liefert strukturierte Blöcke mit Zitatankern wie Seitenindex, Konfidenz, optionalen Bounding-Boxen und semantischen Knotenkennungen, sofern das Quell-PDF diese Struktur bereitstellt.
Verwenden Sie das SDK, wenn Ihre Pipeline Fragen beantworten muss wie „Von welcher Seite stammt dieser Text?“, „Welche Tabelle stützt diesen Wert?“ oder „Was hat sich zwischen diesen beiden PDFs geändert?“, ohne die PDF-Extraktion als anonymen Klartext zu behandeln.
Was es bietet
Abschnitt betitelt „Was es bietet“- Einen synchronen
NextPDF-Client für Skripte, Batch-Jobs und Notebooks. - Einen asynchronen
AsyncNextPDF-Client fürasyncio, FastAPI und andere asynchrone Laufzeiten. - Eine
nextpdf-Befehlszeilenschnittstelle (CLI) für die einmalige Extraktion aus einem Dateipfad oder aus der Standardeingabe, mit Ausgabe auf die Standardausgabe oder in eine Datei. - Einen optionalen Model Context Protocol-Server (MCP), über den KI-Agenten PDF-Extraktionswerkzeuge direkt aufrufen können.
- Ein Remote-Backend für den produktiven Einsatz mit NextPDF Connect.
- Ein lokales Backend für die Offline-Extraktion ohne Server, ausschließlich als Bibliothek, über
pypdf.
Backend-Auswahl
Abschnitt betitelt „Backend-Auswahl“Das Remote-Backend sendet PDF-Bytes an einen NextPDF Connect-Server. Das ist der empfohlene Weg für die Produktion, weil er Extraktionsverhalten, Authentifizierung, Kontingente und Betriebssteuerung zentralisiert.
Das lokale Backend läuft im Python-Prozess und liest PDFs über pypdf. Es ist für die Offline-Entwicklung und getaggte PDFs nützlich, kann jedoch keine präzisen Bounding-Boxen liefern und nutzt für untaggte PDFs eine heuristische Extraktion auf Absatzebene. Das lokale Backend steht nur als Bibliothek zur Verfügung: Sie verwenden es, indem Sie AsyncNextPDF ein LocalBackend übergeben. Die nextpdf-CLI und der MCP-Server können es nicht nutzen. Siehe Matrix der Backend-Auswahl für den vollständigen Vergleich.
Einschränkungen
Abschnitt betitelt „Einschränkungen“Das SDK führt keine optische Zeichenerkennung (OCR) durch. Gescannte PDFs oder reine Bild-PDFs benötigen einen OCR-Schritt, bevor NextPDF eingebetteten Text extrahieren kann. Komplexe Layouts, überlappender Text und ungewöhnliche PDF-Erzeuger können die Extraktionsqualität ebenfalls verringern.
Die nextpdf-CLI kann nur remote genutzt werden und ist keine Streaming-Schnittstelle. Jeder Befehl liest das gesamte PDF in den Speicher (aus einem Dateipfad oder aus der Standardeingabe), sendet es an einen NextPDF Connect-Server, baut das vollständige Ergebnis im Speicher auf und serialisiert es dann in einem einzigen Schreibvorgang. Sie können diese Ausgabe mit --output (oder -o) in eine Datei oder auf die Standardausgabe umleiten, das Ergebnis wird jedoch vollständig gepuffert und nicht schrittweise erzeugt. Die CLI kann das lokale pypdf-Backend nicht nutzen.
Einen Client wählen: synchron oder asynchron
Abschnitt betitelt „Einen Client wählen: synchron oder asynchron“Beide Clients verwenden denselben ast-Methoden-Namespace und geben dieselben Pydantic-Modelle zurück. Der Unterschied liegt im Nebenläufigkeitsmodell.
| Ihr Kontext | Verwenden Sie | Warum |
|---|---|---|
| Skripte und Batch-Jobs | NextPDF (synchron) | Linearer Kontrollfluss; keine Event-Loop zu verwalten. |
| Jupyter-Notebooks | NextPDF (synchron) | run_sync erkennt die laufende Event-Loop und leitet Aufrufe an einen Worker-Thread weiter, sodass blockierende Aufrufe innerhalb von Zellen funktionieren. |
Die nextpdf-CLI | NextPDF (synchron, intern) | Die CLI erstellt für Sie einen synchronen Client. |
asyncio-Dienste | AsyncNextPDF | Natives await; keine Thread-Übergabe. |
| FastAPI, Starlette, ASGI | AsyncNextPDF | Verwendet die Event-Loop der Anfrage und denselben Verbindungspool. |
| Hochgradig nebenläufiges Fan-out | AsyncNextPDF | Führen Sie viele Extraktionen nebenläufig mit asyncio.gather über einen gepoolten Client aus. |
NextPDF umschließt ein internes AsyncNextPDF und führt jeden Aufruf über run_sync aus. Innerhalb einer laufenden Event-Loop (zum Beispiel in einem Notebook) leitet run_sync die Coroutine an einen Thread mit einem einzelnen Worker und eigener Loop weiter, sodass Sie nicht auf den Fehler eines verschachtelten asyncio.run stoßen. Rufen Sie in einem asyncio- oder ASGI-Dienst AsyncNextPDF direkt auf, statt bei jedem Aufruf den Aufwand dieser Thread-Übergabe zu tragen.
Der asynchrone Client besitzt einen httpx.AsyncClient für das Connection-Pooling; verwenden Sie daher eine einzige AsyncNextPDF-Instanz wieder und schließen Sie sie einmalig. Der synchrone NextPDF-Client stellt keine close()-Methode bereit. Bevorzugen Sie für langlebige asynchrone Workloads AsyncNextPDF und verwalten Sie seinen Lebenszyklus explizit (siehe Produktives Betriebsmodell).
Matrix der Backend-Auswahl
Abschnitt betitelt „Matrix der Backend-Auswahl“Ein Backend implementiert das PdfBackend-Protokoll. Das Remote-Backend (RemoteBackend) wird automatisch ausgewählt, wenn Sie base_url und api_key übergeben. Das lokale Backend (LocalBackend) muss explizit über den backend=-Parameter von AsyncNextPDF bereitgestellt werden; es wird nicht aus dem Top-Level-Paket nextpdf exportiert und ist weder über die CLI noch über den MCP-Server erreichbar.
| Fähigkeit | Remote (RemoteBackend) | Lokal (LocalBackend) |
|---|---|---|
| Ausgewählt durch | base_url + api_key | AsyncNextPDF(backend=LocalBackend(...)) |
| Netzwerk | NextPDF Connect über HyperText Transfer Protocol Secure (HTTPS) | Keines; läuft im Prozess |
| Authentifizierung, Kontingente, Messung | Auf dem Server zentralisiert | Keine |
| Beobachtbarkeit und Betriebssteuerung | Serverseitig | Keine |
| Extraktion aus getaggten PDFs (StructTree) | Ja | Ja |
| Extraktion aus untaggten PDFs | Server-Engine | Heuristische Absatztrennung, Konfidenz 0.5 |
| Bounding-Boxen | Ja (wenn der Server sie bereitstellt) | Nein (bbox ist None) |
| Tabellenextraktion aus untaggten PDFs | Server-Engine | Gibt keine Tabellen zurück |
| Über CLI / MCP-Server erreichbar | Ja | Nein (nur als Bibliothek) |
| Empfohlen für | Produktion | Offline-Entwicklung, Tests mit getaggten PDFs |
Verwenden Sie das Remote-Backend für die Produktion: Es ist der einzige Weg, der Ihnen zentralisierte Authentifizierung, Kontingent-Durchsetzung, Messung und Beobachtbarkeit bietet. Verwenden Sie das lokale Backend für die Offline-Entwicklung und Tests mit getaggten PDFs und akzeptieren Sie dabei heuristische Ergebnisse, keine Bounding-Boxen und keine Tabellen bei untaggter Eingabe.
"""Inject the local backend for offline, library-only extraction."""
from nextpdf import AsyncNextPDFfrom nextpdf.backends.local import LocalBackend
async def extract_offline(pdf_bytes: bytes) -> None: """Extract cited text without a NextPDF Connect server.""" async with AsyncNextPDF(backend=LocalBackend()) as client: blocks = await client.ast.extract_cited_text(pdf_bytes) for block in blocks: # Heuristic blocks on untagged PDFs report confidence 0.5. print(block.citation.confidence, block.text)Produktives Betriebsmodell
Abschnitt betitelt „Produktives Betriebsmodell“In der Produktion betreiben Sie das Remote-Backend gegen NextPDF Connect. Die folgenden Muster decken Client-Wiederverwendung, Fehlerbehandlung, Wiederholungen, Kontingentbehandlung und Zeitüberschreitungen ab. Jedes hier verwendete Symbol existiert im SDK; das SDK wiederholt Aufrufe nicht für Sie, daher liegt die Wiederholungsschleife in Ihrer Verantwortung.
Den Client wiederverwenden und Verbindungen poolen
Abschnitt betitelt „Den Client wiederverwenden und Verbindungen poolen“RemoteBackend hält einen einzigen persistenten httpx.AsyncClient für das Connection-Pooling. Erstellen Sie AsyncNextPDF einmal, verwenden Sie die Instanz anfrageübergreifend und schließen Sie sie beim Herunterfahren. Erstellen Sie keinen Client pro Anfrage.
"""Reuse one pooled async client for the lifetime of the process."""
import asyncioimport osfrom pathlib import Path
from nextpdf import AsyncNextPDF
async def main() -> None: """Run several extractions over a single pooled client.""" base_url = os.environ["NEXTPDF_BASE_URL"] # Treat the API key as a secret; read it from the environment, never hard-code it. api_key = os.environ["NEXTPDF_API_KEY"]
async with AsyncNextPDF(base_url=base_url, api_key=api_key) as client: pdf_paths = (Path("a.pdf"), Path("b.pdf"), Path("c.pdf")) tasks = [ client.ast.get_document_ast(path.read_bytes()) for path in pdf_paths ] documents = await asyncio.gather(*tasks) for document in documents: print(document.page_count, document.estimated_tokens)
if __name__ == "__main__": asyncio.run(main())Der asynchrone Kontextmanager ruft beim Verlassen close() auf und schließt damit den zugrunde liegenden Transport. Ohne Kontextmanager rufen Sie selbst await client.close() auf.
Fehler mit der Ausnahmehierarchie behandeln
Abschnitt betitelt „Fehler mit der Ausnahmehierarchie behandeln“Das SDK verwendet eine typisierte Ausnahmehierarchie. Alle Fehler leiten sich von NextPDFError ab; Fehler auf HTTP-Ebene leiten sich von NextPDFAPIError ab und tragen einen status_code. Fangen Sie die konkreten Typen ab, auf die Sie reagieren können, und fallen Sie ansonsten auf den Basistyp zurück.
| Ausnahme | Wird geworfen, wenn | Schlüsselattribute |
|---|---|---|
NextPDFError | Basistyp für jeden SDK-Fehler | status_code |
NextPDFAPIError | Der Server meldet einen HTTP-Fehler | status_code, error_code |
NextPDFLicenseError | HTTP 402; die Funktion erfordert eine höhere Server-Stufe | status_code (402) |
QuotaExceededError | HTTP 429; Ratenbegrenzung oder Kontingent überschritten | retry_after |
AstNoStructTreeError | HTTP 422; untaggtes PDF bei deaktiviertem Heuristik-Modus | status_code (422) |
AstBuildTimeoutError | HTTP 504; der AST-Aufbau überschreitet das Zeitlimit | status_code (504) |
"""Map SDK exceptions to caller-facing outcomes."""
from nextpdf import ( AstBuildTimeoutError, AstNoStructTreeError, AsyncNextPDF, NextPDFAPIError, NextPDFError, NextPDFLicenseError, QuotaExceededError,)
async def safe_extract(client: AsyncNextPDF, pdf_bytes: bytes) -> str: """Extract text, translating known failures into a stable status string.""" try: blocks = await client.ast.extract_cited_text(pdf_bytes) except QuotaExceededError as exc: # exc.retry_after holds the server Retry-After value in seconds, or None. return f"rate-limited; retry after {exc.retry_after}s" except NextPDFLicenseError: return "feature requires a higher server tier" except AstNoStructTreeError: return "untagged PDF; enable heuristic mode or use a tagged PDF" except AstBuildTimeoutError: return "build timed out; reduce the page range" except NextPDFAPIError as exc: return f"server error (status {exc.status_code})" except NextPDFError: return "extraction failed" return "\n".join(block.text for block in blocks)Vorübergehende Fehler mit Backoff wiederholen
Abschnitt betitelt „Vorübergehende Fehler mit Backoff wiederholen“Das SDK wiederholt Aufrufe nicht automatisch. Umschließen Sie Aufrufe mit einer eigenen Schleife, die bei vorübergehenden HTTP-Fehlern wiederholt und den Server-Wert Retry-After berücksichtigt, den QuotaExceededError als retry_after bereitstellt (eine ganze Zahl von Sekunden oder None). Verwenden Sie für andere vorübergehende Statuscodes ein exponentielles Backoff und wiederholen Sie NextPDFLicenseError nicht.
"""Retry transient failures with exponential backoff and Retry-After support."""
import asynciofrom collections.abc import Awaitable, Callablefrom typing import TypeVar
from nextpdf import NextPDFAPIError, QuotaExceededError
_RETRYABLE_STATUS = frozenset({500, 502, 503, 504})
_T = TypeVar("_T")
async def with_retry( coro_factory: Callable[[], Awaitable[_T]], *, max_attempts: int = 4,) -> _T: """Call coro_factory() with bounded retries on transient server errors.
Args: coro_factory: A zero-argument callable returning a fresh awaitable. max_attempts: Maximum number of attempts before giving up.
Returns: The awaited result of the first successful attempt.
Raises: NextPDFAPIError: When all attempts fail or the error is not retryable. """ delay = 1.0 for attempt in range(1, max_attempts + 1): try: return await coro_factory() except QuotaExceededError as exc: if attempt == max_attempts: raise await asyncio.sleep(exc.retry_after if exc.retry_after is not None else delay) delay *= 2.0 except NextPDFAPIError as exc: if attempt == max_attempts or exc.status_code not in _RETRYABLE_STATUS: raise await asyncio.sleep(delay) delay *= 2.0 raise RuntimeError("unreachable")Kontingente, Ratenbegrenzungen und Zeitüberschreitungen verwalten
Abschnitt betitelt „Kontingente, Ratenbegrenzungen und Zeitüberschreitungen verwalten“Die Durchsetzung von Kontingenten und Ratenbegrenzungen erfolgt auf dem Server. Bei HTTP 429 wirft das SDK QuotaExceededError und parst den Retry-After-Header in retry_after. Das Remote-Backend gibt bei Render-Antworten außerdem X-RateLimit-*-Header aus, sodass Sie proaktiv drosseln können, bevor Sie an eine harte Grenze stoßen.
Für Anfrage-Zeitüberschreitungen gilt ein fester Standardwert von 60 Sekunden insgesamt mit einem Verbindungs-Timeout von 10 Sekunden (httpx.Timeout(60.0, connect=10.0)). Um lange AST-Aufbauten zu begrenzen, schränken Sie die Arbeit lieber mit page_range_start, page_range_end oder token_budget ein, statt sich allein auf das Timeout zu verlassen; ein zu langer Aufbau gibt AstBuildTimeoutError zurück (HTTP 504).
Beispielarchitekturen
Abschnitt betitelt „Beispielarchitekturen“Batch-Job
Abschnitt betitelt „Batch-Job“Ein Batch-Worker liest PDFs, extrahiert zitierten Text und schreibt strukturierte Ausgaben. Verwenden Sie einen einzigen gepoolten Client, begrenzen Sie die Nebenläufigkeit mit einem Semaphor und wenden Sie den obigen Wiederholungs-Helfer an.
"""Batch-extract a directory of PDFs over one pooled async client."""
import asyncioimport osfrom pathlib import Path
from nextpdf import AsyncNextPDF
async def run_batch(input_dir: Path, concurrency: int = 8) -> None: """Extract cited text for every PDF in input_dir, bounded by concurrency.""" semaphore = asyncio.Semaphore(concurrency)
async def worker(client: AsyncNextPDF, path: Path) -> None: async with semaphore: blocks = await client.ast.extract_cited_text(path.read_bytes()) out = path.with_suffix(".txt") out.write_text("\n".join(b.text for b in blocks), encoding="utf-8")
async with AsyncNextPDF( base_url=os.environ["NEXTPDF_BASE_URL"], api_key=os.environ["NEXTPDF_API_KEY"], ) as client: await asyncio.gather(*(worker(client, p) for p in input_dir.glob("*.pdf")))Webdienst
Abschnitt betitelt „Webdienst“Ein FastAPI-Dienst teilt sich über die gesamte Lebensdauer der Anwendung hinweg eine einzige AsyncNextPDF-Instanz, sodass jede Anfrage den Verbindungspool wiederverwendet. Lesen Sie die Zugangsdaten aus der Umgebung und behandeln Sie den API-Schlüssel als Geheimnis.
"""FastAPI service that shares one pooled NextPDF client across requests."""
import osfrom contextlib import asynccontextmanager
from fastapi import FastAPI, UploadFile
from nextpdf import AsyncNextPDF
@asynccontextmanagerasync def lifespan(app: FastAPI): """Create the pooled client on startup and close it on shutdown.""" app.state.client = AsyncNextPDF( base_url=os.environ["NEXTPDF_BASE_URL"], api_key=os.environ["NEXTPDF_API_KEY"], ) try: yield finally: await app.state.client.close()
app = FastAPI(lifespan=lifespan)
@app.post("/extract")async def extract(file: UploadFile) -> dict[str, list[str]]: """Return cited text blocks for an uploaded PDF.""" pdf_bytes = await file.read() blocks = await app.state.client.ast.extract_cited_text(pdf_bytes) return {"text": [block.text for block in blocks]}Agent-Werkzeug
Abschnitt betitelt „Agent-Werkzeug“Betreiben Sie für KI-Agenten den MCP-Server. Er stellt PDF-Werkzeuge (zum Beispiel nextpdf_extract_text, nextpdf_extract_tables, nextpdf_get_ast, nextpdf_info, nextpdf_search, nextpdf_get_outline, nextpdf_diff und nextpdf_health) über Standardeingabe/-ausgabe bereit. Der Server liest NEXTPDF_BASE_URL und NEXTPDF_API_KEY aus der Umgebung und nutzt daher das Remote-Backend; wie die CLI kann er das lokale Backend nicht nutzen. Installieren Sie das optionale Extra und führen Sie das Modul aus.
pip install "nextpdf[mcp]"python -m nextpdf.mcpWeitere Informationen finden Sie unter Python MCP-Server für die Schritt-für-Schritt-Anleitung zur Agent-Integration, Python-CLI für die Nutzung im Terminal und Python API-Referenz für die vollständige Client-, Modell- und Ausnahme-API.