code: def match_predictions_to_boxes(
      encodings, predictions, metadata, sample_lengths, layoutlm_model
  ) -> List[List[BlockType]]:
      assert len(encodings) == len(predictions) == sum(sample_lengths)
      assert len(metadata) == len(sample_lengths)
  
      page_start = 0
      page_block_types = []
      for pnum, sample_length in enumerate(sample_lengths):
          # Page has no blocks
          if sample_length == 0:
              page_block_types.append([])
              continue
  
          page_data = metadata[pnum]
          page_end = min(page_start + sample_length, len(predictions))
          page_predictions = predictions[page_start:page_end]
          page_encodings = encodings[page_start:page_end]
          token_boxes = [e["bbox"] for e in page_encodings]
          offset_mapping = [e["offset_mapping"] for e in page_encodings]
          pwidth = page_data["pwidth"]
          pheight = page_data["pheight"]
          boxes = page_data["original_bbox"]
  
          predicted_block_types = []
  
          for i in range(len(token_boxes)):
              assert len(token_boxes[i]) == len(page_predictions[i])
  
          for i, (pred, box, mapped) in enumerate(
              zip(page_predictions, token_boxes, offset_mapping)
          ):
              box = box.tolist()
              is_subword = np.array(mapped)[:, 0] != 0
              overlap_adjust = 0
              if i > 0:
                  overlap_adjust = (
                      1
                      + settings.LAYOUT_CHUNK_OVERLAP
                      - sum(
                          is_subword[
                              : 1 + settings.LAYOUT_CHUNK_OVERLAP
                          ]
                      )
                  )
  
              prov_predictions, prov_boxes = get_provisional_boxes(
                  pred, box, is_subword, overlap_adjust
              )
  
              for prov_box, prov_prediction in zip(
                  prov_boxes, prov_predictions
              ):
                  if prov_box == [0, 0, 0, 0]:
                      continue
                  block_type = BlockType(
                      block_type=layoutlm_model.config.id2label[
                          prov_prediction
                      ],
                      bbox=prov_box,
                  )
  
                  # Sometimes blocks will cross chunks, unclear why
                  if (
                      len(predicted_block_types) == 0
                      or prov_box != predicted_block_types[-1].bbox
                  ):
                      predicted_block_types.append(block_type)
  
          # Align bboxes
          # This will search both lists to find matching bboxes
          # This will align both sets of bboxes by index
          # If there are duplicate bboxes, it may result in issues
          aligned_blocks = []
          for i in range(len(boxes)):
              unnorm_box = unnormalize_box(boxes[i], pwidth, pheight)
              appended = False
              for j in range(len(predicted_block_types)):
                  if boxes[i] == predicted_block_types[j].bbox:
                      predicted_block_types[j].bbox = unnorm_box
                      aligned_blocks.append(predicted_block_types[j])
                      appended = True
                      break
              if not appended:
                  aligned_blocks.append(
                      BlockType(block_type="Text", bbox=unnorm_box)
                  )
          page_block_types.append(aligned_blocks)
          page_start += sample_length
      return page_block_types
  
imports: from concurrent.futures import ThreadPoolExecutor
  from typing import List
  from transformers import LayoutLMv3ForTokenClassification
  from marker.bbox import unnormalize_box
  from transformers.models.layoutlmv3.image_processing_layoutlmv3 import normalize_box
  import io
  from PIL import Image
  from transformers import LayoutLMv3Processor
  import numpy
  from marker.settings import settings
  from marker.schema import Page, BlockType
  import torch
  from math import isclose
label_desc: Use image node_id 7 for calling a global function with example usage: match_predictions_to_boxes(encodings, predictions, metadata, sample_lengths, layoutlm_model) and returns: page_block_types