Przejdź do głównej zawartości

Przegląd SDK dla języka Python

SDK NextPDF dla języka Python jest przeznaczony dla aplikacji w Pythonie, które potrzebują ekstrakcji z Portable Document Format (PDF) wraz z informacją o pochodzeniu. Zwraca bloki strukturalne z kotwicami cytowań: indeksem strony, poziomem pewności, opcjonalnymi prostokątami ograniczającymi oraz identyfikatorami węzłów semantycznych, gdy źródłowy plik PDF udostępnia taką strukturę.

Używaj SDK, gdy potok musi odpowiadać na pytania w rodzaju „Z której strony pochodzi ten tekst?”, „Która tabela potwierdza tę wartość?” albo „Co się zmieniło między tymi dwoma plikami PDF?”, bez sprowadzania ekstrakcji z plików PDF do anonimowego zwykłego tekstu.

  • Synchroniczny klient NextPDF do skryptów, zadań wsadowych i notatników.
  • Asynchroniczny klient AsyncNextPDF do asyncio, FastAPI i innych środowisk asynchronicznych.
  • Interfejs wiersza poleceń (CLI) nextpdf do jednorazowej ekstrakcji z podanej ścieżki pliku lub z wejścia standardowego, z zapisem do wyjścia standardowego albo do pliku.
  • Opcjonalny serwer Model Context Protocol (MCP), dzięki któremu agenci sztucznej inteligencji (AI) mogą bezpośrednio wywoływać narzędzia do ekstrakcji z plików PDF.
  • Zdalny backend produkcyjny oparty na NextPDF Connect.
  • Lokalny backend do ekstrakcji offline, wyłącznie bibliotecznej, za pośrednictwem pypdf.

Zdalny backend wysyła bajty pliku PDF na serwer NextPDF Connect. To zalecana ścieżka produkcyjna, ponieważ centralizuje sposób ekstrakcji, uwierzytelnianie, limity oraz mechanizmy kontroli operacyjnej.

Lokalny backend działa w procesie Pythona i odczytuje pliki PDF za pośrednictwem pypdf. Przydaje się do prac programistycznych offline oraz do plików PDF ze znacznikami, ale nie może dostarczać precyzyjnych prostokątów ograniczających i stosuje heurystyczną ekstrakcję na poziomie akapitów dla plików PDF bez znaczników. Lokalny backend jest wyłącznie biblioteczny: aby go użyć, wstrzyknij LocalBackend do AsyncNextPDF. Interfejs CLI nextpdf oraz serwer MCP nie mogą go używać. Pełne porównanie znajduje się w sekcji Macierz wyboru backendu.

SDK nie wykonuje optycznego rozpoznawania znaków (OCR). Zeskanowane pliki PDF albo pliki PDF zawierające wyłącznie obrazy wymagają etapu OCR, zanim NextPDF będzie mógł wyekstrahować osadzony tekst. Złożone układy, nakładający się tekst oraz nietypowe generatory plików PDF również mogą obniżyć jakość ekstrakcji.

Interfejs CLI nextpdf działa wyłącznie zdalnie i nie obsługuje strumieniowania. Każde polecenie wczytuje cały plik PDF do pamięci (ze ścieżki pliku lub z wejścia standardowego), wysyła go na serwer NextPDF Connect, buduje kompletny wynik w pamięci i serializuje go jednym zapisem. Wynik możesz przekierować do pliku za pomocą --output (lub -o) albo do wyjścia standardowego, ale jest on w pełni buforowany, a nie generowany przyrostowo. Interfejs CLI nie może używać lokalnego backendu pypdf.

Klient synchroniczny i asynchroniczny współdzielą tę samą przestrzeń nazw metod ast do operacji na abstrakcyjnym drzewie składniowym (AST) i zwracają te same modele Pydantic. Różnią się tylko modelem współbieżności.

Twój kontekstUżyjDlaczego
Skrypty i zadania wsadoweNextPDF (synchroniczny)Liniowy przepływ sterowania; brak pętli zdarzeń do zarządzania.
Notatniki JupyterNextPDF (synchroniczny)run_sync wykrywa działającą pętlę zdarzeń i deleguje wykonanie do wątku roboczego, dzięki czemu wywołania blokujące działają wewnątrz komórek.
Interfejs CLI nextpdfNextPDF (synchroniczny, wewnętrzny)Interfejs CLI buduje za Ciebie klienta synchronicznego.
Usługi asyncioAsyncNextPDFNatywne await; brak przekazywania między wątkami.
FastAPI, Starlette, Asynchronous Server Gateway Interface (ASGI)AsyncNextPDFWspółdzieli pętlę zdarzeń obsługującą żądanie oraz tę samą pulę połączeń.
Rozdzielanie zadań przy wysokiej współbieżnościAsyncNextPDFUruchamiaj wiele ekstrakcji współbieżnie za pomocą asyncio.gather na jednym kliencie z puli połączeń.

NextPDF opakowuje wewnętrzny AsyncNextPDF i wykonuje każde wywołanie przez run_sync. W działającej pętli zdarzeń, takiej jak w notatniku, run_sync deleguje korutynę do pojedynczego wątku roboczego z własną pętlą, dzięki czemu nie napotkasz błędu zagnieżdżonego asyncio.run. W usłudze asyncio lub ASGI wywołuj AsyncNextPDF bezpośrednio, zamiast dokładać koszt przekazywania między wątkami przy każdym wywołaniu.

Klient asynchroniczny posiada httpx.AsyncClient, który obsługuje pulę połączeń, dlatego używaj ponownie jednej instancji AsyncNextPDF i zamykaj ją raz. Synchroniczny klient NextPDF nie udostępnia metody close(). Do długotrwałych obciążeń asynchronicznych wybieraj AsyncNextPDF i jawnie zarządzaj jego cyklem życia (zobacz Produkcyjny model operacyjny).

Backend implementuje protokół Pdfbackend. Zdalny backend (Remotebackend) jest wybierany automatycznie, gdy podasz base_url oraz api_key. Lokalny backend (Localbackend) musisz wstrzyknąć jawnie przez parametr backend= klasy AsyncNextPDF; nie jest eksportowany z pakietu najwyższego poziomu nextpdf i nie jest dostępny z interfejsu CLI ani z serwera MCP.

FunkcjaZdalny (RemoteBackend)Lokalny (LocalBackend)
Wybierany przezbase_url + api_keyAsyncNextPDF(backend=LocalBackend(...))
SiećNextPDF Connect przez Hypertext Transfer Protocol Secure (HTTPS)Brak; działa w procesie
Uwierzytelnianie, limity, pomiar zużyciaScentralizowane na serwerzeBrak
Obserwowalność i mechanizmy kontroli operacyjnejPo stronie serweraBrak
Ekstrakcja z plików PDF ze znacznikami (StructTree)TakTak
Ekstrakcja z plików PDF bez znacznikówSilnik serweraHeurystyczny podział na akapity, pewność 0.5
Prostokąty ograniczająceTak (gdy serwer je dostarcza)Nie (bbox ma wartość None)
Ekstrakcja tabel z plików PDF bez znacznikówSilnik serweraNie zwraca tabel
Dostępny z interfejsu CLI / serwera MCPTakNie (wyłącznie biblioteczny)
Zalecany doProdukcjaPrace programistyczne offline, testy na plikach PDF ze znacznikami

Używaj zdalnego backendu w środowisku produkcyjnym, ponieważ jest to jedyna ścieżka ze scentralizowanym uwierzytelnianiem, egzekwowaniem limitów, pomiarem zużycia i obserwowalnością. Używaj lokalnego backendu do prac programistycznych offline i do testów na plikach PDF ze znacznikami, godząc się na wyniki heurystyczne, brak prostokątów ograniczających i brak tabel dla danych wejściowych bez znaczników.

"""Inject the local backend for offline, library-only extraction."""
from nextpdf import AsyncNextPDF
from 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)

W środowisku produkcyjnym używaj zdalnego backendu z NextPDF Connect. Poniższe wzorce obejmują ponowne użycie klienta, obsługę błędów, ponawianie prób, obsługę limitów oraz limity czasu. Każdy użyty tu symbol istnieje w SDK. SDK nie ponawia prób automatycznie, więc musisz zapewnić pętlę ponawiania.

RemoteBackend utrzymuje jeden trwały httpx.AsyncClient na potrzeby puli połączeń. Utwórz AsyncNextPDF jednokrotnie, współdziel go między żądaniami i zamknij podczas zamykania aplikacji. Nie twórz klienta dla każdego żądania.

"""Reuse one pooled async client for the lifetime of the process."""
import asyncio
import os
from 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())

Asynchroniczny menedżer kontekstu wywołuje close() przy wyjściu, co zamyka transport bazowy. Bez menedżera kontekstu wywołaj await client.close() samodzielnie.

SDK zgłasza typowaną hierarchię wyjątków. Wszystkie błędy dziedziczą po NextPDFError; awarie na poziomie protokołu Hypertext Transfer Protocol (HTTP) dziedziczą po NextPDFAPIError i zawierają status_code. Przechwytuj konkretne typy, na które możesz zareagować, a typ bazowy obsłuż jako zabezpieczenie.

WyjątekZgłaszany, gdyKluczowe atrybuty
NextPDFErrorTyp bazowy wszystkich błędów SDKstatus_code
NextPDFAPIErrorKażdy błąd HTTP z serwerastatus_code, error_code
NextPDFLicenseErrorHTTP 402; funkcja wymaga wyższego poziomu serwerastatus_code (402)
QuotaExceededErrorHTTP 429; przekroczono limit szybkości lub limit zużyciaretry_after
AstNoStructTreeErrorHTTP 422; plik PDF bez znaczników z wyłączonym trybem heurystycznymstatus_code (422)
AstBuildTimeoutErrorHTTP 504; upłynął limit czasu budowania ASTstatus_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)

SDK nie ponawia prób automatycznie. Opakuj wywołania własną pętlą, która ponawia próby po przejściowych awariach HTTP i respektuje wartość Retry-After zwróconą przez serwer, którą QuotaExceededError udostępnia jako retry_after (liczbę całkowitą sekund lub None). Dla pozostałych przejściowych statusów stosuj wykładnicze odczekiwanie i nie ponawiaj NextPDFLicenseError.

"""Retry transient failures with exponential backoff and Retry-After support."""
import asyncio
from collections.abc import Awaitable, Callable
from 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")

Egzekwowanie limitów zużycia i ograniczeń szybkości odbywa się na serwerze. Przy HTTP 429 zestaw SDK zgłasza QuotaExceededError i parsuje nagłówek Retry-After do retry_after. Zdalny backend udostępnia także nagłówki X-RateLimit-* w odpowiedziach renderowania, dzięki czemu możesz proaktywnie ograniczać tempo, zanim osiągniesz twardy limit.

Żądania korzystają ze stałego domyślnego limitu czasu wynoszącego łącznie 60 sekund, z 10-sekundowym limitem czasu połączenia (httpx.Timeout(60.0, connect=10.0)). Aby ograniczyć długie budowanie AST, zawęź zakres pracy za pomocą page_range_start, page_range_end lub token_budget, zamiast polegać wyłącznie na limicie czasu; zbyt długie budowanie zwraca AstBuildTimeoutError (HTTP 504).

Zadanie wsadowe odczytuje pliki PDF, ekstrahuje cytowany tekst i zapisuje ustrukturyzowane wyjście. Używaj ponownie jednego klienta z puli połączeń, ogranicz współbieżność za pomocą semafora i zastosuj opisaną wyżej funkcję pomocniczą do ponawiania prób.

"""Batch-extract a directory of PDFs over one pooled async client."""
import asyncio
import os
from 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")))

Usługa FastAPI współdzieli jeden AsyncNextPDF między żądaniami przez cały czas życia aplikacji, dzięki czemu każde żądanie ponownie używa puli połączeń. Odczytuj poświadczenia ze środowiska i traktuj klucz API jako tajny.

"""FastAPI service that shares one pooled NextPDF client across requests."""
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI, UploadFile
from nextpdf import AsyncNextPDF
@asynccontextmanager
async 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]}

Dla agentów AI uruchom serwer MCP. Udostępnia narzędzia do plików PDF (na przykład nextpdf_extract_text, nextpdf_extract_tables, nextpdf_get_ast, nextpdf_info, nextpdf_search, nextpdf_get_outline, nextpdf_diff oraz nextpdf_health) przez wejście i wyjście standardowe. Serwer odczytuje NEXTPDF_BASE_URL oraz NEXTPDF_API_KEY ze środowiska, więc korzysta ze zdalnego backendu; podobnie jak interfejs CLI, nie może używać lokalnego backendu. Zainstaluj opcjonalny dodatek i uruchom moduł.

Okno terminala
pip install "nextpdf[mcp]"
python -m nextpdf.mcp

Zobacz Serwer MCP dla języka Python, aby przeprowadzić integrację z agentem, Interfejs CLI dla języka Python, aby poznać sposób użycia w terminalu, oraz Dokumentację API dla języka Python, aby zapoznać się z pełnym zestawem klientów, modeli i wyjątków.