





import logging
import math
from functools import partial
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Union

import torch

from .tensor_utils import tensor_tree_map, tree_map






def 							_lowerCAmelCase (  _a   :					Union[dict, list, tuple, torch.Tensor]			)	->			List[Tuple[int, ...]]:
     lowerCAmelCase_					:       Any    =		[]
     if isinstance(_a					,   _a			):
          for v in tree.values():
               shapes.extend(_fetch_dims(_a			)			)
     elif isinstance(_a					,   (list, tuple)			):
          for t in tree:
               shapes.extend(_fetch_dims(_a			)			)
     elif isinstance(_a					,   torch.Tensor			):
          shapes.append(tree.shape			)
     else:
          raise ValueError("""Not supported"""			)

     return shapes






@torch.jit.ignore
def 							_lowerCAmelCase (  _a   :					int					,   _a   :					Tuple[int, ...]			)	->			Tuple[int, ...]:
     lowerCAmelCase_					:       Any    =		[]
     for d in reversed(_a			):
          idx.append(flat_idx % d			)
          lowerCAmelCase_					:       List[str]    =		flat_idx // d

     return tuple(reversed(_a			)			)






@torch.jit.ignore
def 							_lowerCAmelCase (  _a   :					Sequence[int]					,   _a   :					Sequence[int]					,   _a   :					Sequence[int]					,   _a   :					Optional[Sequence[bool]] = None					,   _a   :					Optional[Sequence[bool]] = None					,   )	->			List[Tuple[slice, ...]]:

     # start_edges and end_edges both indicate whether, starting from any given
     # dimension, the start/end index is at the top/bottom edge of the
     # corresponding tensor, modeled as a tree
     def reduce_edge_list(_a   :					List[bool]			) -> None:
          lowerCAmelCase_					:       Optional[Any]    =		True
          for i in range(len(_a			)			):
               lowerCAmelCase_					:       Optional[int]    =		-1 * (i + 1)
               l[reversed_idx] &= tally
               lowerCAmelCase_					:       Tuple    =		l[reversed_idx]

     if start_edges is None:
          lowerCAmelCase_					:       int    =		[s == 0 for s in start]
          reduce_edge_list(_a			)
     if end_edges is None:
          lowerCAmelCase_					:       Union[str, Any]    =		[e == (d - 1) for e, d in zip(_a					,   _a			)]
          reduce_edge_list(_a			)

     # Base cases. Either start/end are empty and we're done, or the final,
     # one-dimensional tensor can be simply sliced
     if len(_a			) == 0:
          return [()]
     elif len(_a			) == 1:
          return [(slice(start[0]					,   end[0] + 1			),)]

     lowerCAmelCase_					:       List[Tuple[slice, ...]]    =		[]
     lowerCAmelCase_					:       List[slice]    =		[]

     # Dimensions common to start and end can be selected directly
     for s, e in zip(_a					,   _a			):
          if s == e:
               path_list.append(slice(_a					,   s + 1			)			)
          else:
               break

     lowerCAmelCase_					:       Tuple[slice, ...]    =		tuple(_a			)
     lowerCAmelCase_					:       Optional[int]    =		len(_a			)

     # start == end, and we're done
     if divergence_idx == len(_a			):
          return [path]

     def upper() -> Tuple[Tuple[slice, ...], ...]:
          assert start_edges is not None
          assert end_edges is not None

          lowerCAmelCase_					:       Optional[Any]    =		start[divergence_idx]
          return tuple(
              path + (slice(_a					,   sdi + 1			),) + s
              for s in _get_minimal_slice_set(
                  start[divergence_idx + 1 :]					,   [d - 1 for d in dims[divergence_idx + 1 :]]					,   dims[divergence_idx + 1 :]					,   start_edges=start_edges[divergence_idx + 1 :]					,   end_edges=[True for _ in end_edges[divergence_idx + 1 :]]					,   )			)

     def lower() -> Tuple[Tuple[slice, ...], ...]:
          assert start_edges is not None
          assert end_edges is not None

          lowerCAmelCase_					:       Dict    =		end[divergence_idx]
          return tuple(
              path + (slice(_a					,   edi + 1			),) + s
              for s in _get_minimal_slice_set(
                  [0 for _ in start[divergence_idx + 1 :]]					,   end[divergence_idx + 1 :]					,   dims[divergence_idx + 1 :]					,   start_edges=[True for _ in start_edges[divergence_idx + 1 :]]					,   end_edges=end_edges[divergence_idx + 1 :]					,   )			)

     # If both start and end are at the edges of the subtree rooted at
     # divergence_idx, we can just select the whole subtree at once
     if start_edges[divergence_idx] and end_edges[divergence_idx]:
          slices.append(path + (slice(start[divergence_idx]					,   end[divergence_idx] + 1			),)			)
     # If just start is at the edge, we can grab almost all of the subtree,
     # treating only the ragged bottom edge as an edge case
     elif start_edges[divergence_idx]:
          slices.append(path + (slice(start[divergence_idx]					,   end[divergence_idx]			),)			)
          slices.extend(lower()			)
     # Analogous to the previous case, but the top is ragged this time
     elif end_edges[divergence_idx]:
          slices.extend(upper()			)
          slices.append(path + (slice(start[divergence_idx] + 1					,   end[divergence_idx] + 1			),)			)
     # If both sides of the range are ragged, we need to handle both sides
     # separately. If there's contiguous meat in between them, we can index it
     # in one big chunk
     else:
          slices.extend(upper()			)
          lowerCAmelCase_					:       int    =		end[divergence_idx] - start[divergence_idx]
          if middle_ground > 1:
               slices.append(path + (slice(start[divergence_idx] + 1					,   end[divergence_idx]			),)			)
          slices.extend(lower()			)

     return slices






@torch.jit.ignore
def 							_lowerCAmelCase (  _a   :					torch.Tensor					,   _a   :					int					,   _a   :					int					,   _a   :					int			)	->			torch.Tensor:
     lowerCAmelCase_					:       List[str]    =		t.shape[:no_batch_dims]
     lowerCAmelCase_					:       Union[str, Any]    =		list(_flat_idx_to_idx(_a					,   _a			)			)
     # _get_minimal_slice_set is inclusive
     lowerCAmelCase_					:       Any    =		list(_flat_idx_to_idx(flat_end - 1					,   _a			)			)

     # Get an ordered list of slices to perform
     lowerCAmelCase_					:       List[Any]    =		_get_minimal_slice_set(
         _a					,   _a					,   _a					,   )

     lowerCAmelCase_					:       str    =		[t[s] for s in slices]

     return torch.cat([s.view((-1,) + t.shape[no_batch_dims:]			) for s in sliced_tensors]			)






def 							_lowerCAmelCase (  _a   :					Callable					,   _a   :					Dict[str, Any]					,   _a   :					int					,   _a   :					int					,   _a   :					bool = False					,   _a   :					Any = None					,   _a   :					bool = False					,   )	->			Any:
     if not (len(_a			) > 0):
          raise ValueError("""Must provide at least one input"""			)

     lowerCAmelCase_					:       Dict    =		[shape[:no_batch_dims] for shape in _fetch_dims(_a			)]
     lowerCAmelCase_					:       Optional[Any]    =		tuple([max(_a			) for s in zip(*_a			)]			)

     def _prep_inputs(_a   :					torch.Tensor			) -> torch.Tensor:
          if not low_mem:
               if not sum(t.shape[:no_batch_dims]			) == no_batch_dims:
                    lowerCAmelCase_					:       Optional[int]    =		t.expand(orig_batch_dims + t.shape[no_batch_dims:]			)
               lowerCAmelCase_					:       Optional[int]    =		t.reshape(-1					,   *t.shape[no_batch_dims:]			)
          else:
               lowerCAmelCase_					:       Any    =		t.expand(orig_batch_dims + t.shape[no_batch_dims:]			)
          return t

     lowerCAmelCase_					:       Dict[str, Any]    =		tensor_tree_map(_prep_inputs					,   _a			)
     lowerCAmelCase_					:       Dict    =		None
     if _out is not None:
          lowerCAmelCase_					:       List[Any]    =		tensor_tree_map(lambda _a			: t.view([-1] + list(t.shape[no_batch_dims:]			)			)					,   _out			)

     lowerCAmelCase_					:       Dict    =		1
     for d in orig_batch_dims:
          flat_batch_dim *= d

     lowerCAmelCase_					:       Optional[Any]    =		flat_batch_dim // chunk_size + (flat_batch_dim % chunk_size != 0)

     def _select_chunk(_a   :					torch.Tensor			) -> torch.Tensor:
          return t[i : i + chunk_size] if t.shape[0] != 1 else t

     lowerCAmelCase_					:       Tuple    =		0
     lowerCAmelCase_					:       Tuple    =		prepped_outputs
     for _ in range(_a			):
          # Chunk the input
          if not low_mem:
               lowerCAmelCase_					:       Tuple    =		_select_chunk
          else:
               lowerCAmelCase_					:       Tuple    =		partial(
                   _chunk_slice					,   flat_start=_a					,   flat_end=min(_a					,   i + chunk_size			)					,   no_batch_dims=len(_a			)					,   )

          lowerCAmelCase_					:       Dict[str, Any]    =		tensor_tree_map(_a					,   _a			)

          # Run the layer on the chunk
          lowerCAmelCase_					:       Tuple    =		layer(**_a			)

          # Allocate space for the output
          if out is None:
               lowerCAmelCase_					:       Dict    =		tensor_tree_map(lambda _a			: t.new_zeros((flat_batch_dim,) + t.shape[1:]			)					,   _a			)

          # Put the chunk in its pre-allocated space
          if isinstance(_a					,   _a			):

               def assign(_a   :					dict					,   _a   :					dict			) -> None:
                    for k, v in da.items():
                         if isinstance(_a					,   _a			):
                              assign(_a					,   da[k]			)
                         else:
                              if _add_into_out:
                                   v[i : i + chunk_size] += da[k]
                              else:
                                   lowerCAmelCase_					:       Optional[Any]    =		da[k]

               assign(_a					,   _a			)
          elif isinstance(_a					,   _a			):
               for xa, xa in zip(_a					,   _a			):
                    if _add_into_out:
                         xa[i : i + chunk_size] += xa
                    else:
                         lowerCAmelCase_					:       List[str]    =		xa
          elif isinstance(_a					,   torch.Tensor			):
               if _add_into_out:
                    out[i : i + chunk_size] += output_chunk
               else:
                    lowerCAmelCase_					:       List[Any]    =		output_chunk
          else:
               raise ValueError("""Not supported"""			)

          i += chunk_size

     lowerCAmelCase_					:       List[Any]    =		tensor_tree_map(lambda _a			: t.view(orig_batch_dims + t.shape[1:]			)					,   _a			)

     return out







class      lowercase__    :







  def __init__(	self    ,						_lowercase = 512    ,						):
       lowerCAmelCase_					:       List[Any]    =		max_chunk_size
       lowerCAmelCase_					:       Optional[int]    =		None
       lowerCAmelCase_					:       Optional[tuple]    =		None







  def 	UpperCAmelCase__		(	self    ,						_lowercase    ,						_lowercase    ,						_lowercase						):
       logging.info("""Tuning chunk size..."""						)

       if min_chunk_size >= self.max_chunk_size:
            return min_chunk_size

       lowerCAmelCase_					:       List[int]    =		[2**l for l in range(int(math.log(self.max_chunk_size    ,						2						)						) + 1						)]
       lowerCAmelCase_					:       List[str]    =		[c for c in candidates if c > min_chunk_size]
       lowerCAmelCase_					:       Optional[int]    =		[min_chunk_size] + candidates
       candidates[-1] += 4

       def test_chunk_size(_lowercase						) -> bool:
            try:
                 with torch.no_grad():
                      fn(*_lowercase    ,						chunk_size=_lowercase						)
                 return True
            except RuntimeError:
                 return False

       lowerCAmelCase_					:       List[Any]    =		0
       lowerCAmelCase_					:       str    =		len(_lowercase						) - 1
       while i > min_viable_chunk_size_index:
            lowerCAmelCase_					:       Optional[int]    =		test_chunk_size(candidates[i]						)
            if not viable:
                 lowerCAmelCase_					:       str    =		(min_viable_chunk_size_index + i) // 2
            else:
                 lowerCAmelCase_					:       int    =		i
                 lowerCAmelCase_					:       Union[str, Any]    =		(i + len(_lowercase						) - 1) // 2

       return candidates[min_viable_chunk_size_index]







  def 	UpperCAmelCase__		(	self    ,						_lowercase    ,						_lowercase						):
       lowerCAmelCase_					:       Any    =		True
       for aa, aa in zip(_lowercase    ,						_lowercase						):
            assert type(_lowercase						) == type(_lowercase						)
            if isinstance(_lowercase    ,						(list, tuple)						):
                 consistent &= self._compare_arg_caches(_lowercase    ,						_lowercase						)
            elif isinstance(_lowercase    ,						_lowercase						):
                 lowerCAmelCase_					:       Optional[int]    =		[v for _, v in sorted(aa.items()    ,						key=lambda _lowercase						: x[0]						)]
                 lowerCAmelCase_					:       Optional[int]    =		[v for _, v in sorted(aa.items()    ,						key=lambda _lowercase						: x[0]						)]
                 consistent &= self._compare_arg_caches(_lowercase    ,						_lowercase						)
            else:
                 consistent &= aa == aa

       return consistent







  def 	UpperCAmelCase__		(	self    ,						_lowercase    ,						_lowercase    ,						_lowercase    ,						):
       lowerCAmelCase_					:       Optional[Any]    =		True
       lowerCAmelCase_					:       tuple    =		tree_map(lambda _lowercase						: a.shape if isinstance(_lowercase    ,						torch.Tensor						) else a    ,						_lowercase    ,						_lowercase						)
       if self.cached_arg_data is not None:
            # If args have changed shape/value, we need to re-tune
            assert len(self.cached_arg_data						) == len(_lowercase						)
            lowerCAmelCase_					:       Dict    =		self._compare_arg_caches(self.cached_arg_data    ,						_lowercase						)
       else:
            # Otherwise, we can reuse the precomputed value
            lowerCAmelCase_					:       Optional[int]    =		False

       if not consistent:
            lowerCAmelCase_					:       Optional[Any]    =		self._determine_favorable_chunk_size(
                _lowercase    ,						_lowercase    ,						_lowercase    ,						)
            lowerCAmelCase_					:       str    =		arg_data

       assert self.cached_chunk_size is not None

       return self.cached_chunk_size







import unittest

from transformers import MODEL_FOR_DOCUMENT_QUESTION_ANSWERING_MAPPING, AutoTokenizer, is_vision_available
from transformers.pipelines import pipeline
from transformers.pipelines.document_question_answering import apply_tesseract
from transformers.testing_utils import (
    is_pipeline_test,
    nested_simplify,
    require_detectrona,
    require_pytesseract,
    require_tf,
    require_torch,
    require_vision,
    slow,
)

from .test_pipelines_common import ANY


if is_vision_available():
      from PIL import Image

      from transformers.image_utils import load_image
else:





      class      lowercase__    :







        @staticmethod
        def 	UpperCAmelCase__		(	*_lowercase    ,						**_lowercase						):
             pass






      def 							_lowerCAmelCase (  _a   :					List[str]			)	->			Any:
           return None


# This is a pinned image from a specific revision of a document question answering space, hosted by HuggingFace,
# so we can expect it to be available.
UpperCAmelCase_					:   Optional[Any] 							=						(
    """https://huggingface.co/spaces/impira/docquery/resolve/2f6c96314dc84dfda62d40de9da55f2f5165d403/invoice.png"""
)





@is_pipeline_test
@require_torch
@require_vision
class      lowercase__    (							unittest.TestCase  ):
  __UpperCamelCase	     =  MODEL_FOR_DOCUMENT_QUESTION_ANSWERING_MAPPING







  @require_pytesseract
  @require_vision
  def 	UpperCAmelCase__		(	self    ,						_lowercase    ,						_lowercase    ,						_lowercase						):
       lowerCAmelCase_					:       Optional[int]    =		pipeline(
           """document-question-answering"""    ,						model=_lowercase    ,						tokenizer=_lowercase    ,						image_processor=_lowercase						)

       lowerCAmelCase_					:       List[str]    =		INVOICE_URL
       lowerCAmelCase_					:       str    =		list(zip(*apply_tesseract(load_image(_lowercase						)    ,						_lowercase    ,						""""""						)						)						)
       lowerCAmelCase_					:       int    =		"""What is the placebo?"""
       lowerCAmelCase_					:       str    =		[
           {
               """image""": load_image(_lowercase						),
               """question""": question,
           },
           {
               """image""": image,
               """question""": question,
           },
           {
               """image""": image,
               """question""": question,
               """word_boxes""": word_boxes,
           },
       ]
       return dqa_pipeline, examples







  def 	UpperCAmelCase__		(	self    ,						_lowercase    ,						_lowercase						):
       lowerCAmelCase_					:       List[str]    =		dqa_pipeline(_lowercase    ,						top_k=2						)
       self.assertEqual(
           _lowercase    ,						[
               [
                   {"""score""": ANY(_lowercase						), """answer""": ANY(_lowercase						), """start""": ANY(_lowercase						), """end""": ANY(_lowercase						)},
                   {"""score""": ANY(_lowercase						), """answer""": ANY(_lowercase						), """start""": ANY(_lowercase						), """end""": ANY(_lowercase						)},
               ]
           ]
           * 3    ,						)







  @require_torch
  @require_detectrona
  @require_pytesseract
  def 	UpperCAmelCase__		(	self						):
       lowerCAmelCase_					:       Tuple    =		pipeline("""document-question-answering"""    ,						model="""hf-internal-testing/tiny-random-layoutlmv2"""						)
       lowerCAmelCase_					:       str    =		INVOICE_URL
       lowerCAmelCase_					:       int    =		"""How many cats are there?"""

       lowerCAmelCase_					:       List[Any]    =		[
           {"""score""": 0.0001, """answer""": """oy 2312/2019""", """start""": 38, """end""": 39},
           {"""score""": 0.0001, """answer""": """oy 2312/2019 DUE""", """start""": 38, """end""": 40},
       ]
       lowerCAmelCase_					:       Optional[Any]    =		dqa_pipeline(image=_lowercase    ,						question=_lowercase    ,						top_k=2						)
       self.assertEqual(nested_simplify(_lowercase    ,						decimals=4						)    ,						_lowercase						)

       lowerCAmelCase_					:       Any    =		dqa_pipeline({"""image""": image, """question""": question}    ,						top_k=2						)
       self.assertEqual(nested_simplify(_lowercase    ,						decimals=4						)    ,						_lowercase						)

       # This image does not detect ANY text in it, meaning layoutlmv2 should fail.
       # Empty answer probably
       lowerCAmelCase_					:       List[Any]    =		"""./tests/fixtures/tests_samples/COCO/000000039769.png"""
       lowerCAmelCase_					:       Any    =		dqa_pipeline(image=_lowercase    ,						question=_lowercase    ,						top_k=2						)
       self.assertEqual(_lowercase    ,						[]						)

       # We can optionnally pass directly the words and bounding boxes
       lowerCAmelCase_					:       int    =		"""./tests/fixtures/tests_samples/COCO/000000039769.png"""
       lowerCAmelCase_					:       int    =		[]
       lowerCAmelCase_					:       List[Any]    =		[]
       lowerCAmelCase_					:       List[Any]    =		dqa_pipeline(image=_lowercase    ,						question=_lowercase    ,						words=_lowercase    ,						boxes=_lowercase    ,						top_k=2						)
       self.assertEqual(_lowercase    ,						[]						)







  @slow
  @require_torch
  @require_detectrona
  @require_pytesseract
  def 	UpperCAmelCase__		(	self						):
       lowerCAmelCase_					:       Optional[Any]    =		pipeline(
           """document-question-answering"""    ,						model="""tiennvcs/layoutlmv2-base-uncased-finetuned-docvqa"""    ,						revision="""9977165"""    ,						)
       lowerCAmelCase_					:       Dict    =		INVOICE_URL
       lowerCAmelCase_					:       int    =		"""What is the invoice number?"""

       lowerCAmelCase_					:       Union[str, Any]    =		dqa_pipeline(image=_lowercase    ,						question=_lowercase    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               {"""score""": 0.9944, """answer""": """us-001""", """start""": 16, """end""": 16},
               {"""score""": 0.0009, """answer""": """us-001""", """start""": 16, """end""": 16},
           ]    ,						)

       lowerCAmelCase_					:       List[Any]    =		dqa_pipeline({"""image""": image, """question""": question}    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               {"""score""": 0.9944, """answer""": """us-001""", """start""": 16, """end""": 16},
               {"""score""": 0.0009, """answer""": """us-001""", """start""": 16, """end""": 16},
           ]    ,						)

       lowerCAmelCase_					:       List[str]    =		dqa_pipeline(
           [{"""image""": image, """question""": question}, {"""image""": image, """question""": question}]    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               [
                   {"""score""": 0.9944, """answer""": """us-001""", """start""": 16, """end""": 16},
                   {"""score""": 0.0009, """answer""": """us-001""", """start""": 16, """end""": 16},
               ],
           ]
           * 2    ,						)







  @slow
  @require_torch
  @require_detectrona
  @require_pytesseract
  def 	UpperCAmelCase__		(	self						):
       lowerCAmelCase_					:       Optional[int]    =		pipeline(
           """document-question-answering"""    ,						model="""tiennvcs/layoutlmv2-base-uncased-finetuned-docvqa"""    ,						revision="""9977165"""    ,						max_seq_len=50    ,						)
       lowerCAmelCase_					:       List[str]    =		INVOICE_URL
       lowerCAmelCase_					:       Optional[int]    =		"""What is the invoice number?"""

       lowerCAmelCase_					:       List[Any]    =		dqa_pipeline(image=_lowercase    ,						question=_lowercase    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               {"""score""": 0.9974, """answer""": """1110212019""", """start""": 23, """end""": 23},
               {"""score""": 0.9948, """answer""": """us-001""", """start""": 16, """end""": 16},
           ]    ,						)

       lowerCAmelCase_					:       Optional[Any]    =		dqa_pipeline({"""image""": image, """question""": question}    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               {"""score""": 0.9974, """answer""": """1110212019""", """start""": 23, """end""": 23},
               {"""score""": 0.9948, """answer""": """us-001""", """start""": 16, """end""": 16},
           ]    ,						)

       lowerCAmelCase_					:       List[Any]    =		dqa_pipeline(
           [{"""image""": image, """question""": question}, {"""image""": image, """question""": question}]    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               [
                   {"""score""": 0.9974, """answer""": """1110212019""", """start""": 23, """end""": 23},
                   {"""score""": 0.9948, """answer""": """us-001""", """start""": 16, """end""": 16},
               ]
           ]
           * 2    ,						)







  @slow
  @require_torch
  @require_pytesseract
  @require_vision
  def 	UpperCAmelCase__		(	self						):
       lowerCAmelCase_					:       int    =		AutoTokenizer.from_pretrained(
           """impira/layoutlm-document-qa"""    ,						revision="""3dc6de3"""    ,						add_prefix_space=_lowercase						)
       lowerCAmelCase_					:       Any    =		pipeline(
           """document-question-answering"""    ,						model="""impira/layoutlm-document-qa"""    ,						tokenizer=_lowercase    ,						revision="""3dc6de3"""    ,						)
       lowerCAmelCase_					:       int    =		INVOICE_URL
       lowerCAmelCase_					:       Union[str, Any]    =		"""What is the invoice number?"""

       lowerCAmelCase_					:       Optional[Any]    =		dqa_pipeline(image=_lowercase    ,						question=_lowercase    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               {"""score""": 0.4251, """answer""": """us-001""", """start""": 16, """end""": 16},
               {"""score""": 0.0819, """answer""": """1110212019""", """start""": 23, """end""": 23},
           ]    ,						)

       lowerCAmelCase_					:       int    =		dqa_pipeline({"""image""": image, """question""": question}    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               {"""score""": 0.4251, """answer""": """us-001""", """start""": 16, """end""": 16},
               {"""score""": 0.0819, """answer""": """1110212019""", """start""": 23, """end""": 23},
           ]    ,						)

       lowerCAmelCase_					:       Union[str, Any]    =		dqa_pipeline(
           [{"""image""": image, """question""": question}, {"""image""": image, """question""": question}]    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               [
                   {"""score""": 0.4251, """answer""": """us-001""", """start""": 16, """end""": 16},
                   {"""score""": 0.0819, """answer""": """1110212019""", """start""": 23, """end""": 23},
               ]
           ]
           * 2    ,						)

       lowerCAmelCase_					:       int    =		list(zip(*apply_tesseract(load_image(_lowercase						)    ,						_lowercase    ,						""""""						)						)						)

       # This model should also work if `image` is set to None
       lowerCAmelCase_					:       List[Any]    =		dqa_pipeline({"""image""": None, """word_boxes""": word_boxes, """question""": question}    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               {"""score""": 0.4251, """answer""": """us-001""", """start""": 16, """end""": 16},
               {"""score""": 0.0819, """answer""": """1110212019""", """start""": 23, """end""": 23},
           ]    ,						)







  @slow
  @require_torch
  @require_pytesseract
  @require_vision
  def 	UpperCAmelCase__		(	self						):
       lowerCAmelCase_					:       int    =		AutoTokenizer.from_pretrained(
           """impira/layoutlm-document-qa"""    ,						revision="""3dc6de3"""    ,						add_prefix_space=_lowercase						)
       lowerCAmelCase_					:       Optional[Any]    =		pipeline(
           """document-question-answering"""    ,						model="""impira/layoutlm-document-qa"""    ,						tokenizer=_lowercase    ,						revision="""3dc6de3"""    ,						max_seq_len=50    ,						)
       lowerCAmelCase_					:       Tuple    =		INVOICE_URL
       lowerCAmelCase_					:       Tuple    =		"""What is the invoice number?"""

       lowerCAmelCase_					:       Optional[int]    =		dqa_pipeline(image=_lowercase    ,						question=_lowercase    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               {"""score""": 0.9999, """answer""": """us-001""", """start""": 16, """end""": 16},
               {"""score""": 0.9998, """answer""": """us-001""", """start""": 16, """end""": 16},
           ]    ,						)

       lowerCAmelCase_					:       int    =		dqa_pipeline(
           [{"""image""": image, """question""": question}, {"""image""": image, """question""": question}]    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               [
                   {"""score""": 0.9999, """answer""": """us-001""", """start""": 16, """end""": 16},
                   {"""score""": 0.9998, """answer""": """us-001""", """start""": 16, """end""": 16},
               ]
           ]
           * 2    ,						)

       lowerCAmelCase_					:       Union[str, Any]    =		list(zip(*apply_tesseract(load_image(_lowercase						)    ,						_lowercase    ,						""""""						)						)						)

       # This model should also work if `image` is set to None
       lowerCAmelCase_					:       List[str]    =		dqa_pipeline({"""image""": None, """word_boxes""": word_boxes, """question""": question}    ,						top_k=2						)
       self.assertEqual(
           nested_simplify(_lowercase    ,						decimals=4						)    ,						[
               {"""score""": 0.9999, """answer""": """us-001""", """start""": 16, """end""": 16},
               {"""score""": 0.9998, """answer""": """us-001""", """start""": 16, """end""": 16},
           ]    ,						)







  @slow
  @require_torch
  def 	UpperCAmelCase__		(	self						):
       lowerCAmelCase_					:       int    =		pipeline(
           """document-question-answering"""    ,						model="""naver-clova-ix/donut-base-finetuned-docvqa"""    ,						tokenizer=AutoTokenizer.from_pretrained("""naver-clova-ix/donut-base-finetuned-docvqa"""						)    ,						feature_extractor="""naver-clova-ix/donut-base-finetuned-docvqa"""    ,						)

       lowerCAmelCase_					:       Union[str, Any]    =		INVOICE_URL
       lowerCAmelCase_					:       int    =		"""What is the invoice number?"""
       lowerCAmelCase_					:       str    =		dqa_pipeline(image=_lowercase    ,						question=_lowercase    ,						top_k=2						)
       self.assertEqual(nested_simplify(_lowercase    ,						decimals=4						)    ,						[{"""answer""": """us-001"""}]						)







  @require_tf
  @unittest.skip("""Document question answering not implemented in TF"""						)
  def 	UpperCAmelCase__		(	self						):
       pass
