code: def get_text_blocks(
      doc,
      tess_lang: str,
      spell_lang: Optional[str],
      max_pages: Optional[int] = None,
      parallel: int = settings.OCR_PARALLEL_WORKERS,
  ):
      all_blocks = []
      toc = doc.get_toc()
      ocr_pages = 0
      ocr_failed = 0
      ocr_success = 0
      # This is a thread because most of the work happens in a separate process (tesseract)
      range_end = len(doc)
      no_text = len(naive_get_text(doc).strip()) == 0
      if max_pages:
          range_end = min(max_pages, len(doc))
      with ThreadPoolExecutor(max_workers=parallel) as pool:
          args_list = [
              (doc, pnum, tess_lang, spell_lang, no_text)
              for pnum in range(range_end)
          ]
          if parallel == 1:
              func = map
          else:
              func = pool.map
          results = func(lambda a: convert_single_page(*a), args_list)
  
          for result in results:
              page_obj, ocr_stats = result
              all_blocks.append(page_obj)
              ocr_pages += ocr_stats["ocr_pages"]
              ocr_failed += ocr_stats["ocr_failed"]
              ocr_success += ocr_stats["ocr_success"]
  
      return (
          all_blocks,
          toc,
          {
              "ocr_pages": ocr_pages,
              "ocr_failed": ocr_failed,
              "ocr_success": ocr_success,
          },
      )
  
file_path: pdf-to-markdown/marker/extract_text.py
imports: import os
  from typing import Tuple, List, Optional
  from spellchecker import SpellChecker
  from marker.bbox import correct_rotation
  from marker.ocr.page import ocr_entire_page
  from marker.ocr.utils import detect_bad_ocr, font_flags_decomposer
  from marker.settings import settings
  from marker.schema import Span, Line, Block, Page
  from concurrent.futures import ThreadPoolExecutor
label_desc: Use image node_id 4 for calling a global function with example usage: get_text_blocks(doc, tess_lang, spell_lang, max_pages, parallel) and returns: all_blocks,  toc,  dict