@@ -484,26 +484,26 @@ def extract_text(
484484 parser : str = "pymupdf" ,
485485 ocr_fallback : bool = False ,
486486 ocr_backend : str = "none" ,
487+ parser_options : dict | None = None ,
488+ ocr_options : dict | None = None ,
487489) -> str :
488490 """Extract all text from a PDF as a single string.
489491
490492 Args:
491493 pdf_path: Path to the PDF file.
492- parser: Text extraction backend.
493- "pymupdf" — markdown via pymupdf4llm (default)
494- "tables" — PyMuPDF table detection → TSV
495- "pdfplumber" — layout-preserving spatial extraction
496- "tabula" — tabula-py table extraction → TSV (requires Java)
494+ parser: Text extraction backend — see ``PARSERS`` registry.
497495 ocr_fallback: Deprecated. Use ``ocr_backend="tesseract"`` instead.
498496 ocr_backend: OCR fallback when text layer is empty/short.
499- "none" — no OCR (default)
500- "tesseract" — local pytesseract (requires tesseract binary)
501- "mistral" — Mistral OCR API (requires MISTRAL_API_KEY)
497+ parser_options: Extra kwargs passed to the parser callable.
498+ ocr_options: Extra kwargs passed to the OCR callable.
502499
503500 Returns:
504501 Extracted text as a single string.
505502 """
506- pages = extract_text_pages (pdf_path , parser , ocr_fallback , ocr_backend )
503+ pages = extract_text_pages (
504+ pdf_path , parser , ocr_fallback , ocr_backend ,
505+ parser_options = parser_options , ocr_options = ocr_options ,
506+ )
507507 return "\n \n " .join (pages )
508508
509509
@@ -512,6 +512,8 @@ def extract_text_pages(
512512 parser : str = "pymupdf" ,
513513 ocr_fallback : bool = False ,
514514 ocr_backend : str = "none" ,
515+ parser_options : dict | None = None ,
516+ ocr_options : dict | None = None ,
515517) -> list [str ]:
516518 """Extract text from each page of a PDF separately.
517519
@@ -521,11 +523,15 @@ def extract_text_pages(
521523 ocr_fallback: Deprecated. Use ``ocr_backend="tesseract"`` instead.
522524 ocr_backend: OCR fallback when text layer is empty/short —
523525 see ``OCR_BACKENDS`` registry.
526+ parser_options: Extra kwargs passed to the parser callable.
527+ ocr_options: Extra kwargs passed to the OCR callable.
524528
525529 Returns:
526530 List of strings, one per page.
527531 """
528532 ocr_backend = _resolve_ocr_backend (ocr_fallback , ocr_backend )
533+ _p_opts = parser_options or {}
534+ _o_opts = ocr_options or {}
529535
530536 fn = PARSERS .get (parser )
531537 if fn is None :
@@ -550,9 +556,9 @@ def extract_text_pages(
550556 f"extract_async() or "
551557 f"extract_pages_async() instead."
552558 )
553- pages = asyncio .run (fn (pdf_path ))
559+ pages = asyncio .run (fn (pdf_path , ** _p_opts ))
554560 else :
555- pages = fn (pdf_path )
561+ pages = fn (pdf_path , ** _p_opts )
556562
557563 # Apply OCR fallback to pages with insufficient text
558564 if ocr_backend != "none" :
@@ -561,7 +567,10 @@ def extract_text_pages(
561567 if len (text .strip ()) < OCR_THRESHOLD :
562568 if doc is None :
563569 doc = fitz .open (pdf_path )
564- pages [i ] = _ocr_page (doc [i ], ocr_backend , pdf_path )
570+ pages [i ] = _ocr_page (
571+ doc [i ], ocr_backend , pdf_path ,
572+ ** _o_opts ,
573+ )
565574
566575 return pages
567576
@@ -599,13 +608,15 @@ def _ocr_page_tesseract(page) -> str:
599608def _ocr_page (
600609 page , ocr_backend : str = "tesseract" ,
601610 pdf_path : str | None = None ,
611+ ** ocr_options ,
602612) -> str :
603613 """OCR a single fitz page.
604614
605615 Args:
606616 page: A fitz page object.
607617 ocr_backend: OCR backend — see ``OCR_BACKENDS`` registry.
608618 pdf_path: Path to the source PDF (used by Mistral OCR).
619+ **ocr_options: Extra kwargs passed to the OCR callable.
609620
610621 Returns:
611622 Extracted text from the page.
@@ -627,8 +638,8 @@ def _ocr_page(
627638 f"Use extract_async() or "
628639 f"extract_pages_async() instead."
629640 )
630- return asyncio .run (fn (page ))
631- return fn (page )
641+ return asyncio .run (fn (page , ** ocr_options ))
642+ return fn (page , ** ocr_options )
632643
633644
634645def _ocr_full (doc , pdf_path : str , ocr_backend : str ) -> str :
@@ -831,6 +842,8 @@ async def extract_async(
831842 llm_backend : str | None = None ,
832843 text : str | None = None ,
833844 parse_fn = None ,
845+ parser_options : dict | None = None ,
846+ ocr_options : dict | None = None ,
834847) -> BaseModel :
835848 """Extract structured data from a single PDF.
836849
@@ -852,6 +865,7 @@ async def extract_async(
852865 Returns:
853866 Populated Pydantic model instance.
854867 """
868+ _p_opts = parser_options or {}
855869 mgr = get_manager ()
856870 if text is None :
857871 if parse_fn is not None :
@@ -866,13 +880,14 @@ async def extract_async(
866880 parser_fn
867881 ):
868882 pages = await mgr .run (
869- parser_fn , pdf_path ,
883+ parser_fn , pdf_path , ** _p_opts ,
870884 )
871885 text = "\n \n " .join (pages )
872886 else :
873887 text = await mgr .run_cpu (
874888 extract_text , pdf_path , parser ,
875889 ocr_fallback , ocr_backend ,
890+ _p_opts , ocr_options ,
876891 )
877892 if len (text ) > TEXT_WARN_THRESHOLD :
878893 warnings .warn (
@@ -945,6 +960,8 @@ def extract(
945960 ocr_fallback : bool = False ,
946961 ocr_backend : str = "none" ,
947962 llm_backend : str | None = None ,
963+ parser_options : dict | None = None ,
964+ ocr_options : dict | None = None ,
948965) -> BaseModel :
949966 """Sync wrapper around ``extract_async``. See that function for args."""
950967 return asyncio .run (
@@ -953,6 +970,7 @@ def extract(
953970 model = model , api_key = api_key , instructions = instructions ,
954971 parser = parser , ocr_fallback = ocr_fallback ,
955972 ocr_backend = ocr_backend , llm_backend = llm_backend ,
973+ parser_options = parser_options , ocr_options = ocr_options ,
956974 )
957975 )
958976
@@ -1132,6 +1150,8 @@ async def extract_pages_async(
11321150 page_range : str | None = None ,
11331151 parse_multiplier : int = 5 ,
11341152 parse_fn = None ,
1153+ parser_options : dict | None = None ,
1154+ ocr_options : dict | None = None ,
11351155) -> list [dict ]:
11361156 """Split a PDF into page chunks and extract each concurrently.
11371157
@@ -1162,6 +1182,8 @@ async def extract_pages_async(
11621182 parse_fn: Optional async callable(pdf_path, page_index, parser,
11631183 ocr_backend) -> str. When provided, replaces local
11641184 page-level text extraction (no ProcessPoolExecutor used).
1185+ parser_options: Extra kwargs passed to the parser callable.
1186+ ocr_options: Extra kwargs passed to the OCR callable.
11651187
11661188 Returns:
11671189 List of result dicts (with _page and optionally _error).
@@ -1175,6 +1197,8 @@ async def extract_pages_async(
11751197 stacklevel = 2 ,
11761198 )
11771199
1200+ _p_opts = parser_options or {}
1201+
11781202 # Resolve parser from registry
11791203 parser_fn = PARSERS .get (parser )
11801204 if parser_fn is None :
@@ -1210,11 +1234,11 @@ async def extract_pages_async(
12101234 try :
12111235 if parser_is_async :
12121236 h_pages = await mgr .run (
1213- parser_fn , h_path ,
1237+ parser_fn , h_path , ** _p_opts ,
12141238 )
12151239 else :
12161240 h_pages = await mgr .run_cpu (
1217- parser_fn , h_path ,
1241+ parser_fn , h_path , ** _p_opts ,
12181242 )
12191243 header_text = "\n \n " .join (h_pages )
12201244 finally :
@@ -1270,11 +1294,11 @@ async def _parse_chunk(idx_slice):
12701294 try :
12711295 if parser_is_async :
12721296 pages = await mgr .run (
1273- parser_fn , chunk_path ,
1297+ parser_fn , chunk_path , ** _p_opts ,
12741298 )
12751299 else :
12761300 pages = await mgr .run_cpu (
1277- parser_fn , chunk_path ,
1301+ parser_fn , chunk_path , ** _p_opts ,
12781302 )
12791303 return "\n \n " .join (pages )
12801304 finally :
@@ -1441,6 +1465,8 @@ async def extract_batch(
14411465 ocr_backend : str = "none" ,
14421466 llm_backend : str | None = None ,
14431467 parse_fn = None ,
1468+ parser_options : dict | None = None ,
1469+ ocr_options : dict | None = None ,
14441470) -> list [dict ]:
14451471 """Extract from multiple PDFs concurrently.
14461472
@@ -1460,11 +1486,14 @@ async def extract_batch(
14601486 parse_fn: Optional async callable(pdf_path, parser,
14611487 ocr_backend) -> str. When provided, replaces local
14621488 text extraction.
1489+ parser_options: Extra kwargs passed to the parser callable.
1490+ ocr_options: Extra kwargs passed to the OCR callable.
14631491
14641492 Returns:
14651493 List of result dicts (with _source_file and optionally
14661494 _error).
14671495 """
1496+ _p_opts = parser_options or {}
14681497 mgr = get_manager ()
14691498 mgr .configure (api_limit = concurrency )
14701499 client = _make_client (model , api_key , llm_backend )
@@ -1484,13 +1513,14 @@ async def _process(path: str):
14841513 )
14851514 elif parser_is_async :
14861515 pages = await mgr .run (
1487- parser_fn , path ,
1516+ parser_fn , path , ** _p_opts ,
14881517 )
14891518 text = "\n \n " .join (pages )
14901519 else :
14911520 text = await mgr .run_cpu (
14921521 extract_text , path , parser ,
14931522 ocr_fallback , ocr_backend ,
1523+ _p_opts , ocr_options ,
14941524 )
14951525 async with mgr .api ():
14961526 result = (
0 commit comments