Przegląd SDK dla języka Python
Przegląd SDK dla języka Python
Dział zatytułowany „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.
Co zapewnia
Dział zatytułowany „Co zapewnia”- Synchroniczny klient
NextPDFdo skryptów, zadań wsadowych i notatników. - Asynchroniczny klient
AsyncNextPDFdoasyncio, FastAPI i innych środowisk asynchronicznych. - Interfejs wiersza poleceń (CLI)
nextpdfdo 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.
Wybór backendu
Dział zatytułowany „Wybór backendu”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.
Ograniczenia
Dział zatytułowany „Ograniczenia”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.
Wybór klienta: synchroniczny czy asynchroniczny
Dział zatytułowany „Wybór klienta: synchroniczny czy asynchroniczny”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 kontekst | Użyj | Dlaczego |
|---|---|---|
| Skrypty i zadania wsadowe | NextPDF (synchroniczny) | Liniowy przepływ sterowania; brak pętli zdarzeń do zarządzania. |
| Notatniki Jupyter | NextPDF (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 nextpdf | NextPDF (synchroniczny, wewnętrzny) | Interfejs CLI buduje za Ciebie klienta synchronicznego. |
Usługi asyncio | AsyncNextPDF | Natywne await; brak przekazywania między wątkami. |
| FastAPI, Starlette, Asynchronous Server Gateway Interface (ASGI) | AsyncNextPDF | Współdzieli pętlę zdarzeń obsługującą żądanie oraz tę samą pulę połączeń. |
| Rozdzielanie zadań przy wysokiej współbieżności | AsyncNextPDF | Uruchamiaj 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).
Macierz wyboru backendu
Dział zatytułowany „Macierz wyboru backendu”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.
| Funkcja | Zdalny (RemoteBackend) | Lokalny (LocalBackend) |
|---|---|---|
| Wybierany przez | base_url + api_key | AsyncNextPDF(backend=LocalBackend(...)) |
| Sieć | NextPDF Connect przez Hypertext Transfer Protocol Secure (HTTPS) | Brak; działa w procesie |
| Uwierzytelnianie, limity, pomiar zużycia | Scentralizowane na serwerze | Brak |
| Obserwowalność i mechanizmy kontroli operacyjnej | Po stronie serwera | Brak |
| Ekstrakcja z plików PDF ze znacznikami (StructTree) | Tak | Tak |
| Ekstrakcja z plików PDF bez znaczników | Silnik serwera | Heurystyczny podział na akapity, pewność 0.5 |
| Prostokąty ograniczające | Tak (gdy serwer je dostarcza) | Nie (bbox ma wartość None) |
| Ekstrakcja tabel z plików PDF bez znaczników | Silnik serwera | Nie zwraca tabel |
| Dostępny z interfejsu CLI / serwera MCP | Tak | Nie (wyłącznie biblioteczny) |
| Zalecany do | Produkcja | Prace 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 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)Produkcyjny model operacyjny
Dział zatytułowany „Produkcyjny model operacyjny”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.
Używaj ponownie klienta i puli połączeń
Dział zatytułowany „Używaj ponownie klienta i puli połączeń”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 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())Asynchroniczny menedżer kontekstu wywołuje close() przy wyjściu, co zamyka transport bazowy. Bez menedżera kontekstu wywołaj await client.close() samodzielnie.
Obsługuj błędy za pomocą hierarchii wyjątków
Dział zatytułowany „Obsługuj błędy za pomocą hierarchii wyjątków”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ątek | Zgłaszany, gdy | Kluczowe atrybuty |
|---|---|---|
NextPDFError | Typ bazowy wszystkich błędów SDK | status_code |
NextPDFAPIError | Każdy błąd HTTP z serwera | status_code, error_code |
NextPDFLicenseError | HTTP 402; funkcja wymaga wyższego poziomu serwera | status_code (402) |
QuotaExceededError | HTTP 429; przekroczono limit szybkości lub limit zużycia | retry_after |
AstNoStructTreeError | HTTP 422; plik PDF bez znaczników z wyłączonym trybem heurystycznym | status_code (422) |
AstBuildTimeoutError | HTTP 504; upłynął limit czasu budowania AST | 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)Ponawiaj przejściowe awarie z opóźnieniem
Dział zatytułowany „Ponawiaj przejściowe awarie z opóźnieniem”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 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")Zarządzaj limitami zużycia, szybkości i czasu
Dział zatytułowany „Zarządzaj limitami zużycia, szybkości i czasu”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).
Przykładowe architektury
Dział zatytułowany „Przykładowe architektury”Zadanie wsadowe
Dział zatytułowany „Zadanie wsadowe”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 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")))Usługa sieciowa
Dział zatytułowany „Usługa sieciowa”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 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]}Narzędzie agenta
Dział zatytułowany „Narzędzie agenta”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ł.
pip install "nextpdf[mcp]"python -m nextpdf.mcpZobacz 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.