تخطَّ إلى المحتوى

دليل المطوّر لـ Python SDK

مجموعة أدوات تطوير البرامج (⁨SDK⁩) الخاصة بـ ⁨NextPDF⁩ لـ ⁨Python⁩ هي عميل خفيف ومُحدَّد الأنواع لنقطة نهاية ⁨NextPDF Connect.⁩ يتولّى تطبيقك التحقّق من صحّة مدخلات صيغة المستندات المحمولة (⁨PDF⁩)، ومعالجة بيانات الاعتماد، وسياسة التزامن. وتتولّى الـ ⁨SDK⁩ بناء الطلب، والنقل، وتحديد أنواع الاستجابة. حافِظ على وضوح هذا الفاصل: اقرأ ملف ⁨PDF⁩ بأمان، واختر عميلاً، واستدعِ طريقة ast التي تحتاجها، وعالِج العطل المحدّد.

استخدِم هذا الدليل عند بناء خدمات الاستخراج، أو مهام الدفعات باستخدام ⁨asyncio⁩، أو أدوات وكلاء الذكاء الاصطناعي (⁨AI⁩)، أو سير عمل سطر الأوامر حول الـ ⁨SDK.⁩ يفترض الدليل أنّك قرأت النظرة العامة والبدء السريع، وأنّ لديك ⁨Python 3.10⁩ أو أحدث ونقطة نهاية ⁨NextPDF Connect.⁩

الطبقةيملكهاالمسؤوليةما لا يُوضع هنا
مصدر الإدخالالتطبيقخوِّل المُستدعي بالصلاحية، وتحقّق من صحّة مصدر ملف ⁨PDF⁩، واختر سياسة الاستخراج.محدِّد موقع المورد المُوحّد (⁨URL⁩) لنقطة النهاية أو قيم بيانات الاعتماد النصّية.
إنشاء العميلالتطبيقاقرأ base_url وapi_key من بيئة التشغيل أو من مدير أسرار.الأسرار المكتوبة مباشرةً في الشيفرة.
NextPDF / AsyncNextPDF⁨SDK⁩يبني الطلب، ويتصل بـ ⁨Connect⁩، ويُرجِع نماذج ⁨Pydantic⁩ مُحدَّدة الأنواع.منطق المجال أو سياسة التخزين.
مساحة أسماء طرق ast⁨SDK⁩يربط استدعاء الطريقة بنقطة نهاية ⁨Connect⁩ ويحلّل الاستجابة.سياسة إعادة المحاولة أو التراجع التدريجي خارج ما تُهيّئه.
نقطة نهاية ⁨NextPDF Connect⁩النشرتُشغّل الاستخراج وتفرض المصادقة والحصص والترخيص.تفويض صلاحية التطبيق.

لا تنفّذ الـ ⁨SDK⁩ مطلقاً التعرّف الضوئي على الحروف (⁨OCR⁩). إذا كان ملف ⁨PDF⁩ ممسوحاً ضوئياً أو مقتصراً على الصور، فشغِّل ⁨OCR⁩ قبل الاستخراج. عامِل تلك الخطوة بوصفها شأناً يخصّ التطبيق خارج هذا الفاصل.

المرحلةالسلوكإجراء المطوّر
إنشاء العميليجري التحقّق من صحّة base_url وapi_key؛ وأيّ قيمة فارغة منهما تُطلِق ValueError.اقرأهما كليهما من بيئة التشغيل؛ ولا تكتبهما مباشرةً في الشيفرة مطلقاً.
إنشاء الواجهة الخلفيةتفتح الواجهة الخلفية البعيدة اتصالاً من مجمّع الاتصالات إلى ⁨Connect.⁩أعِد استخدام عميل واحد بين الاستدعاءات بدلاً من إنشاء عميل لكلّ طلب.
استدعاء الطريقةتُسلسِل طريقة ast الطلب، وترسل بايتات ⁨PDF⁩، وتحلّل الاستجابة إلى نموذج ⁨Pydantic.⁩مرِّر bytes التي جرى التحقّق من صحّتها مسبقاً.
ربط الأخطاءتربط الـ ⁨SDK⁩ حالات بروتوكول نقل النصوص الفائقة (⁨HTTP⁩) غير الناجحة بفئات فرعية محدّدة من الاستثناءات.التقِط أكثر الفئات تحديداً أوّلاً.
الإيقافتُحرّر AsyncNextPDF.close() مجمّع الاتصالات؛ ويستدعيها مدير السياق غير المتزامن نيابةً عنك.استخدِم async with أو استدعِ close() داخل كتلة finally.
المسارالغرض
app/pdf/clients.pyيبني عميل NextPDF أو AsyncNextPDF مُهيّأً ويخزّنه مؤقتاً.
app/pdf/extraction.pyطبقة تغليف على مستوى التطبيق حول استدعاءات طريقة ast.
app/pdf/validation.pyالتحقّق من صحّة مصدر ⁨PDF⁩، وحدود الحجم، وفحوص المحتوى.
tests/pdf/اختبارات الاستخراج، وأوضاع الأعطال، وتجميع الدفعات غير المتزامن.

أبقِ التحقّق من صحّة ⁨PDF⁩ مفصولاً عن الاستخراج. لا تمرِّر إلى طبقة الاستخراج إلا البايتات المُصرَّح بها والتي جرى فحص حجمها، واعتمِد مع ذلك على نقطة النهاية للدفاع المتعمّق.

import os
from nextpdf import NextPDF
def build_client() -> NextPDF:
"""Construct a synchronous client from environment configuration.
Raises:
KeyError: When a required environment variable is missing.
"""
base_url = os.environ["NEXTPDF_BASE_URL"]
api_key = os.environ["NEXTPDF_API_KEY"]
return NextPDF(base_url=base_url, api_key=api_key)

استخدِم عميل NextPDF المتزامن للنصوص البرمجية، ومهام الدفعات، ودفاتر الملاحظات. تحقّق من صحّة الإدخال قبل استدعاء الـ ⁨SDK⁩، وعالِج الأعطال المحدّدة التي قد يطلقها الاستدعاء.

from pathlib import Path
from nextpdf import (
NextPDF,
CitedTextBlock,
NextPDFAPIError,
NextPDFError,
QuotaExceededError,
)
MAX_PDF_BYTES = 100 * 1024 * 1024 # Reject documents above 100 MiB for the in-memory path.
def read_pdf(path: Path) -> bytes:
"""Read and validate a PDF from disk.
Raises:
ValueError: When the file is missing, empty, oversized, or not a PDF.
"""
if not path.is_file():
raise ValueError(f"Not a file: {path}")
data = path.read_bytes()
if not data:
raise ValueError("PDF is empty")
if len(data) > MAX_PDF_BYTES:
raise ValueError("PDF exceeds the configured size limit; use the CLI streaming path")
if not data.startswith(b"%PDF-"):
raise ValueError("File does not look like a PDF")
return data
def extract_text(client: NextPDF, path: Path) -> list[CitedTextBlock]:
"""Extract cited text blocks, handling the most specific failures first."""
pdf_bytes = read_pdf(path)
try:
return client.ast.extract_cited_text(pdf_bytes)
except QuotaExceededError as error:
raise RuntimeError(f"Quota exceeded; retry after {error.retry_after}s") from error
except NextPDFAPIError as error:
raise RuntimeError(f"API error {error.status_code}: {error}") from error
except NextPDFError as error:
raise RuntimeError(f"SDK error: {error}") from error

يأخذ عنصر النتيجة الواحد هذا الشكل:

block = blocks[0]
print(block.text) # the extracted text
print(block.citation.page_index) # 0-based page index
print(block.citation.confidence) # 0.0 - 1.0

نمط العمل غير المتزامن وتجميع الدفعات

قسم بعنوان «نمط العمل غير المتزامن وتجميع الدفعات»

استخدِم عميل AsyncNextPDF غير المتزامن داخل بيئات تشغيل ⁨asyncio⁩ مثل ⁨FastAPI.⁩ أنشِئ عميلاً واحداً بوصفه مدير سياق غير متزامن وشارِكه بين الاستدعاءات التي تعمل بالتزامن؛ ولا تفتح عميلاً لكلّ مستند. اضبط التزامن باستخدام إشارة سيمافور كي تراعي حصّة نقطة النهاية.

import asyncio
import os
from nextpdf import (
AsyncNextPDF,
ExtractCitedTablesResponse,
NextPDFError,
QuotaExceededError,
)
async def extract_tables_batch(
pdfs: list[bytes],
*,
max_concurrency: int = 4,
) -> list[ExtractCitedTablesResponse | None]:
"""Extract tables from many PDFs concurrently with one shared client.
Returns one response per input PDF, or None where extraction failed.
"""
base_url = os.environ["NEXTPDF_BASE_URL"]
api_key = os.environ["NEXTPDF_API_KEY"]
semaphore = asyncio.Semaphore(max_concurrency)
async with AsyncNextPDF(base_url=base_url, api_key=api_key) as client:
async def one(pdf_bytes: bytes) -> ExtractCitedTablesResponse | None:
async with semaphore:
try:
return await client.ast.extract_cited_tables(pdf_bytes)
except QuotaExceededError as error:
# Surface the backpressure signal; do not silently drop it.
raise RuntimeError(f"Quota exceeded; retry after {error.retry_after}s") from error
except NextPDFError:
return None
return await asyncio.gather(*(one(pdf) for pdf in pdfs))

لا تكتب كتلة except فارغة مطلقاً. عالِج العطل، أو حوّله إلى نتيجة مُعرّفة، أو أعِد إطلاقه.

نقطة الامتداداستخدِمها لـالقيد
AsyncNextPDF(backend=...)حقن واجهة خلفية مخصّصة أو محلّية في الاختبارات.يجب أن تستوفي الواجهة الخلفية بروتوكول PdfBackend.
وسيط api_versionتثبيت إصدار واجهة برمجة التطبيقات (⁨API⁩) لـ ⁨Connect.⁩القيمة الافتراضية هي v1؛ لا تُغيّرها إلّا عندما تدعم نقطة النهاية الإصدار المستهدف.
تهيئة بيئة التشغيلوفِّر NEXTPDF_BASE_URL وNEXTPDF_API_KEY لواجهة سطر الأوامر (⁨CLI⁩) وخادم بروتوكول سياق النموذج (⁨MCP⁩).عامِل المفتاح بوصفه سرّاً محصوراً في نطاق عبء العمل.
خادم ⁨MCP⁩ (python -m nextpdf.mcp)يُتيح أدوات الاستخراج للوكلاء القادرين على استخدام ⁨MCP.⁩يتطلّب الإضافة nextpdf[mcp] ونقطة نهاية خاضعة للتحكّم.
  1. ثبِّت الـ ⁨SDK⁩ باستخدام pip install nextpdf، أو استخدِم pip install nextpdf[mcp] لخادم الوكيل.
  2. اقرأ NEXTPDF_BASE_URL وNEXTPDF_API_KEY من بيئة التشغيل كي لا يدخل أيّ سرّ إلى نظام التحكّم بالمصدر.
  3. تحقّق من صحّة كلّ مصدر ⁨PDF⁩ من حيث الوجود والحجم وبايتات التوقيع السحري %PDF- قبل استدعاء الـ ⁨SDK.⁩
  4. أنشِئ عميلاً واحداً لكلّ عملية وأعِد استخدامه؛ وفي حالة ⁨asyncio⁩، أبقِه مفتوحاً بـ async with.
  5. استدعِ طريقة ast الأكثر تحديداً والملائمة للمهمّة: extract_cited_text() للنصوص النثرية، وextract_cited_tables() للجداول، وget_document_ast() فقط عندما تحتاج إلى الشجرة الكاملة.
  6. التقِط أكثر استثناء تحديداً يمكنك التصرّف إزاءه، ثمّ تراجَع إلى NextPDFError.
  7. للمستندات التي تتجاوز 100 ⁨MiB⁩، استخدِم مسار البثّ في الـ ⁨CLI⁩ بدلاً من تحميل المحتوى كله في الذاكرة.
  8. شغِّل ⁨mypy⁩ في الوضع الصارم وأضِف اختباراً لوضع عطل لكلّ استثناء تعالجه.
العطلالاستثناءالاستجابة المُوصى بها
ملف ⁨PDF⁩ غير موسوم، والاستدلالات معطّلةAstNoStructTreeError (⁨HTTP 422⁩)فعِّل وضع الاستدلال على نقطة النهاية أو وفِّر ملف ⁨PDF⁩ موسوماً.
انتهاء مهلة البناء من جانب الخادمAstBuildTimeoutError (⁨HTTP 504⁩)قلِّص نطاق الصفحات وأعِد المحاولة.
فئة ترخيص مطلوبةNextPDFLicenseError (⁨HTTP 402⁩)رقِّ ترخيص الخادم أو تراجَع إلى ميزة مسموح بها.
حدّ المعدّل أو الحصّةQuotaExceededError (⁨HTTP 429⁩)انتظر retry_after ثانية، ثمّ أعِد المحاولة مع تراجع تدريجي.
خطأ ⁨HTTP⁩ آخرNextPDFAPIErrorافحص status_code وerror_code؛ وسجِّل خطأً مُعرّفاً وأظهِره.
أيّ خطأ في الـ ⁨SDK⁩NextPDFErrorخيار التراجع النهائي؛ لا تسمح بمروره مطلقاً بوصفه استثناءً غير معالَج.

تُبلِغ نقطة النهاية عن الأعطال باستخدام دلالات حالة ⁨HTTP⁩ المتوافقة مع طلب التعليقات (⁨RFC⁩) 9110 وبأجسام أخطاء قابلة للقراءة آلياً متوافقة مع ⁨RFC 9457.⁩ يحافظ كلّ استثناء على status_code الأصلي. اربط تلك الأعطال باستجابات الأخطاء الخاصّة بك بدلاً من تسريب تفاصيل النقل إلى المُستدعين.

الإعدادات الافتراضية الآمنة

قسم بعنوان «الإعدادات الافتراضية الآمنة»
الجانب المعنيالافتراضيمتى تتجاوزه
إصدار ⁨API⁩v1.لا تُغيّره إلّا عندما تدعم نقطة النهاية إصداراً أحدث.
التحقّق من أمان طبقة النقل (⁨TLS⁩)مُفعَّل؛ ولا يتوفّر أيّ مُبدِّل غير آمن.لا تُعطّله مطلقاً لحركة المرور الإنتاجية.
بيانات الاعتمادتُقرأ من بيئة التشغيل؛ ولا تُكتب مباشرةً في الشيفرة مطلقاً.استخدِم مدير أسرار في بيئة الإنتاج.
حدّ الحجم في الذاكرةارفض ملفات ⁨PDF⁩ التي تتجاوز 100 ⁨MiB⁩ على مسار العميل.اخفِضه في الخدمات متعدّدة المستأجرين؛ واستخدِم الـ ⁨CLI⁩ للملفات الأكبر.
التزامنمحدود بإشارة سيمافور في الدفعات غير المتزامنة.اضبطه وفقاً لحصّة نقطة النهاية، لا وفقاً لعدد أنوية المضيف.
التسجيلسجِّل اسم الملف والحجم والحالة والمدّة.لا تُسجِّل مطلقاً بايتات ⁨PDF⁩ أو مفتاح ⁨API.⁩
  • تؤكّد اختبارات الإنشاء أنّ base_url أو api_key الفارغ يُطلِق ValueError.
  • تغطّي اختبارات التحقّق المدخلات المفقودة والفارغة والمتجاوزة للحجم والتي ليست ⁨PDF.⁩
  • تؤكّد اختبارات الاستخراج أنواع النماذج المُرجَعة ووجود CitationAnchor في كلّ كتلة.
  • تغطّي اختبارات أوضاع الأعطال AstNoStructTreeError وAstBuildTimeoutError وNextPDFLicenseError وQuotaExceededError وNextPDFAPIError.
  • تؤكّد الاختبارات غير المتزامنة أنّ العميل يعمل بوصفه مدير سياق async with وأنّ التزامن يبقى ضمن الحدّ الذي تفرضه إشارة السيمافور.
  • تؤكّد اختبارات دورة الحياة أنّ close() تُحرّر طبقة النقل وأنّ استدعاءها مُتساوي الأثر عند التكرار.
  • احقن واجهة خلفية وهمية بـ AsyncNextPDF(backend=...) كي تعمل الاختبارات دون نقطة نهاية حيّة.