






import datasets

from .evaluate import evaluate


__lowerCamelCase      :    Optional[int]   		=   """\
@article{hendrycks2021cuad,
      title={CUAD: An Expert-Annotated NLP Dataset for Legal Contract Review},
      author={Dan Hendrycks and Collin Burns and Anya Chen and Spencer Ball},
      journal={arXiv preprint arXiv:2103.06268},
      year={2021}
}
"""

__lowerCamelCase      :    int   		=   """
This metric wrap the official scoring script for version 1 of the Contract
Understanding Atticus Dataset (CUAD).
Contract Understanding Atticus Dataset (CUAD) v1 is a corpus of more than 13,000 labels in 510
commercial legal contracts that have been manually labeled to identify 41 categories of important
clauses that lawyers look for when reviewing contracts in connection with corporate transactions.
"""

__lowerCamelCase      :    str   		=   """
Computes CUAD scores (EM, F1, AUPR, Precision@80%Recall, and Precision@90%Recall).
Args:
    predictions: List of question-answers dictionaries with the following key-values:
        - 'id': id of the question-answer pair as given in the references (see below)
        - 'prediction_text': list of possible texts for the answer, as a list of strings
        depending on a threshold on the confidence probability of each prediction.
    references: List of question-answers dictionaries with the following key-values:
        - 'id': id of the question-answer pair (see above),
        - 'answers': a Dict in the CUAD dataset format
            {
                'text': list of possible texts for the answer, as a list of strings
                'answer_start': list of start positions for the answer, as a list of ints
            }
            Note that answer_start values are not taken into account to compute the metric.
Returns:
    'exact_match': Exact match (the normalized answer exactly match the gold answer)
    'f1': The F-score of predicted tokens versus the gold answer
    'aupr': Area Under the Precision-Recall curve
    'prec_at_80_recall': Precision at 80% recall
    'prec_at_90_recall': Precision at 90% recall
Examples:
    >>> predictions = [{'prediction_text': ['The seller:', 'The buyer/End-User: Shenzhen LOHAS Supply Chain Management Co., Ltd.'], 'id': 'LohaCompanyltd_20191209_F-1_EX-10.16_11917878_EX-10.16_Supply Agreement__Parties'}]
    >>> references = [{'answers': {'answer_start': [143, 49], 'text': ['The seller:', 'The buyer/End-User: Shenzhen LOHAS Supply Chain Management Co., Ltd.']}, 'id': 'LohaCompanyltd_20191209_F-1_EX-10.16_11917878_EX-10.16_Supply Agreement__Parties'}]
    >>> cuad_metric = datasets.load_metric(\"cuad\")
    >>> results = cuad_metric.compute(predictions=predictions, references=references)
    >>> print(results)
    {'exact_match': 100.0, 'f1': 100.0, 'aupr': 0.0, 'prec_at_80_recall': 1.0, 'prec_at_90_recall': 1.0}
"""



@datasets.utils.file_utils.add_start_docstrings(_DESCRIPTION				,     _KWARGS_DESCRIPTION		)
class 							SCREAMING_SNAKE_CASE__		(       datasets.Metric		):





					"""simple docstring"""






					def  _lowercase  (      self  :						List[str] ):
						return datasets.MetricInfo(
						    description=_DESCRIPTION							,	citation=_CITATION							,	inputs_description=_KWARGS_DESCRIPTION							,	features=datasets.Features(
						        {
						            "predictions": {
						                "id": datasets.Value("string" ),
						                "prediction_text": datasets.features.Sequence(datasets.Value("string" ) ),
						            },
						            "references": {
						                "id": datasets.Value("string" ),
						                "answers": datasets.features.Sequence(
						                    {
						                        "text": datasets.Value("string" ),
						                        "answer_start": datasets.Value("int32" ),
						                    } ),
						            },
						        } )							,	codebase_urls=["https://www.atticusprojectai.org/cuad"]							,	reference_urls=["https://www.atticusprojectai.org/cuad"]							,	)






					def  _lowercase  (      self  :						Union[str, Any]							,	__A  :						Any							,	__A  :						List[Any] ):
						snake_case__				:   int     =						{prediction["id"]: prediction["prediction_text"] for prediction in predictions}
						snake_case__				:   Union[str, Any]     =						[
						    {
						        "paragraphs": [
						            {
						                "qas": [
						                    {
						                        "answers": [{"text": answer_text} for answer_text in ref["answers"]["text"]],
						                        "id": ref["id"],
						                    }
						                    for ref in references
						                ]
						            }
						        ]
						    }
						]
						snake_case__				:   Optional[int]     =						evaluate(dataset=__A							,	predictions=__A )
						return score











import json
import os
from functools import lru_cache
from typing import Dict, List, Optional, Tuple, Union

import regex as re

from ...tokenization_utils import AddedToken, PreTrainedTokenizer
from ...tokenization_utils_base import BatchEncoding, EncodedInput
from ...utils import PaddingStrategy, logging


__lowerCamelCase      :    List[str]   		=   logging.get_logger(__name__)


__lowerCamelCase      :    Optional[Any]   		=   {"""vocab_file""": """vocab.json""", """merges_file""": """merges.txt"""}

# See all LED models at https://huggingface.co/models?filter=LED
__lowerCamelCase      :    Tuple   		=   {
    """vocab_file""": {
        """allenai/led-base-16384""": """https://huggingface.co/allenai/led-base-16384/resolve/main/vocab.json""",
    },
    """merges_file""": {
        """allenai/led-base-16384""": """https://huggingface.co/allenai/led-base-16384/resolve/main/merges.txt""",
    },
    """tokenizer_file""": {
        """allenai/led-base-16384""": """https://huggingface.co/allenai/led-base-16384/resolve/main/tokenizer.json""",
    },
}

__lowerCamelCase      :    Dict   		=   {
    """allenai/led-base-16384""": 1_6384,
}







@lru_cache()
# Copied from transformers.models.bart.tokenization_bart.bytes_to_unicode
def   SCREAMING_SNAKE_CASE       (				):
	snake_case__				:   Optional[int]     =						(
	    list(range(ord("!"     )  ,						ord("~"     ) + 1     )     ) + list(range(ord("¡"     )  ,						ord("¬"     ) + 1     )     ) + list(range(ord("®"     )  ,						ord("ÿ"     ) + 1     )     )
	)
	snake_case__				:   Optional[int]     =						bs[:]
	snake_case__				:   Any     =						0
	for b in range(2**8     ):
		if b not in bs:
			bs.append(snake_case_     )
			cs.append(2**8 + n     )
			n += 1
	snake_case__				:   Dict     =						[chr(snake_case_     ) for n in cs]
	return dict(zip(snake_case_  ,						snake_case_     )     )







def   SCREAMING_SNAKE_CASE       (				snake_case_      :							List[Any]     ):
	snake_case__				:   Dict     =						set()
	snake_case__				:   Tuple     =						word[0]
	for char in word[1:]:
		pairs.add((prev_char, char)     )
		snake_case__				:   List[Any]     =						char
	return pairs





class 							SCREAMING_SNAKE_CASE__		(       UpperCamelCase_		):





					"""simple docstring"""






					a_			=	VOCAB_FILES_NAMES
					a_			=	PRETRAINED_VOCAB_FILES_MAP
					a_			=	PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
					a_			=	["input_ids", "attention_mask"]



					def __init__(      self  :						List[str]							,	__A  :						Any							,	__A  :						List[str]							,	__A  :						Optional[Any]="replace"							,	__A  :						Optional[int]="<s>"							,	__A  :						Union[str, Any]="</s>"							,	__A  :						Tuple="</s>"							,	__A  :						List[Any]="<s>"							,	__A  :						Dict="<unk>"							,	__A  :						Any="<pad>"							,	__A  :						Optional[int]="<mask>"							,	__A  :						List[str]=False							,	**__A  :						Union[str, Any]							,	):
						snake_case__				:   List[Any]     =						AddedToken(__A							,	lstrip=__A							,	rstrip=__A ) if isinstance(__A							,	__A ) else bos_token
						snake_case__				:   List[str]     =						AddedToken(__A							,	lstrip=__A							,	rstrip=__A ) if isinstance(__A							,	__A ) else eos_token
						snake_case__				:   Any     =						AddedToken(__A							,	lstrip=__A							,	rstrip=__A ) if isinstance(__A							,	__A ) else sep_token
						snake_case__				:   List[Any]     =						AddedToken(__A							,	lstrip=__A							,	rstrip=__A ) if isinstance(__A							,	__A ) else cls_token
						snake_case__				:   Tuple     =						AddedToken(__A							,	lstrip=__A							,	rstrip=__A ) if isinstance(__A							,	__A ) else unk_token
						snake_case__				:   List[Any]     =						AddedToken(__A							,	lstrip=__A							,	rstrip=__A ) if isinstance(__A							,	__A ) else pad_token

						# Mask token behave like a normal word, i.e. include the space before it
						snake_case__				:   List[str]     =						AddedToken(__A							,	lstrip=__A							,	rstrip=__A ) if isinstance(__A							,	__A ) else mask_token

						super().__init__(
						    errors=__A							,	bos_token=__A							,	eos_token=__A							,	unk_token=__A							,	sep_token=__A							,	cls_token=__A							,	pad_token=__A							,	mask_token=__A							,	add_prefix_space=__A							,	**__A							,	)

						with open(__A							,	encoding="utf-8" ) as vocab_handle:
							snake_case__				:   Any     =						json.load(__A )
						snake_case__				:   Optional[Any]     =						{v: k for k, v in self.encoder.items()}
						snake_case__				:   Union[str, Any]     =						errors  # how to handle errors in decoding
						snake_case__				:   Any     =						bytes_to_unicode()
						snake_case__				:   Optional[Any]     =						{v: k for k, v in self.byte_encoder.items()}
						with open(__A							,	encoding="utf-8" ) as merges_handle:
							snake_case__				:   str     =						merges_handle.read().split("\n" )[1:-1]
						snake_case__				:   int     =						[tuple(merge.split() ) for merge in bpe_merges]
						snake_case__				:   str     =						dict(zip(__A							,	range(len(__A ) ) ) )
						snake_case__				:   Optional[int]     =						{}
						snake_case__				:   Any     =						add_prefix_space

						# Should have added re.IGNORECASE so BPE merges can happen for capitalized versions of contractions
						snake_case__				:   Union[str, Any]     =						re.compile(R"'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+" )



					@property
					# Copied from transformers.models.bart.tokenization_bart.BartTokenizer.vocab_size
					def  _lowercase  (      self  :						List[Any] ):
						return len(self.encoder )



					def  _lowercase  (      self  :						Any ):
						return dict(self.encoder							,	**self.added_tokens_encoder )



					def  _lowercase  (      self  :						Optional[Any]							,	__A  :						Optional[int] ):
						if token in self.cache:
							return self.cache[token]
						snake_case__				:   Union[str, Any]     =						tuple(__A )
						snake_case__				:   List[Any]     =						get_pairs(__A )

						if not pairs:
							return token

						while True:
							snake_case__				:   Tuple     =						min(__A							,	key=lambda __A : self.bpe_ranks.get(__A							,	float("inf" ) ) )
							if bigram not in self.bpe_ranks:
								break
							snake_case__,		snake_case__				:   Dict     =						bigram
							snake_case__				:   str     =						[]
							snake_case__				:   Union[str, Any]     =						0
							while i < len(__A ):
								try:
									snake_case__				:   Dict     =						word.index(__A							,	__A )
								except ValueError:
									new_word.extend(word[i:] )
									break
								else:
									new_word.extend(word[i:j] )
									snake_case__				:   str     =						j

								if word[i] == first and i < len(__A ) - 1 and word[i + 1] == second:
									new_word.append(first + second )
									i += 2
								else:
									new_word.append(word[i] )
									i += 1
							snake_case__				:   str     =						tuple(__A )
							snake_case__				:   int     =						new_word
							if len(__A ) == 1:
								break
							else:
								snake_case__				:   List[str]     =						get_pairs(__A )
						snake_case__				:   List[Any]     =						" ".join(__A )
						snake_case__				:   Optional[int]     =						word
						return word



					def  _lowercase  (      self  :						Optional[Any]							,	__A  :						Optional[Any] ):
						snake_case__				:   List[str]     =						[]
						for token in re.findall(self.pat							,	__A ):
							snake_case__				:   Dict     =						"".join(
							    self.byte_encoder[b] for b in token.encode("utf-8" ) )  # Maps all our bytes to unicode strings, avoiding control tokens of the BPE (spaces in our case)
							bpe_tokens.extend(bpe_token for bpe_token in self.bpe(__A ).split(" " ) )
						return bpe_tokens



					def  _lowercase  (      self  :						Union[str, Any]							,	__A  :						Optional[int] ):
						return self.encoder.get(__A							,	self.encoder.get(self.unk_token ) )



					def  _lowercase  (      self  :						Optional[int]							,	__A  :						Optional[Any] ):
						return self.decoder.get(__A )



					def  _lowercase  (      self  :						Union[str, Any]							,	__A  :						Dict ):
						snake_case__				:   Optional[Any]     =						"".join(__A )
						snake_case__				:   int     =						bytearray([self.byte_decoder[c] for c in text] ).decode("utf-8"							,	errors=self.errors )
						return text



					def  _lowercase  (      self  :						Optional[int]							,	__A  :						str							,	__A  :						Optional[str] = None ):
						if not os.path.isdir(__A ):
							logger.error(f'''Vocabulary path ({save_directory}) should be a directory''' )
							return
						snake_case__				:   List[Any]     =						os.path.join(
						    __A							,	(filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"] )
						snake_case__				:   str     =						os.path.join(
						    __A							,	(filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["merges_file"] )

						with open(__A							,	"w"							,	encoding="utf-8" ) as f:
							f.write(json.dumps(self.encoder							,	indent=2							,	sort_keys=__A							,	ensure_ascii=__A ) + "\n" )

						snake_case__				:   str     =						0
						with open(__A							,	"w"							,	encoding="utf-8" ) as writer:
							writer.write("#version: 0.2\n" )
							for bpe_tokens, token_index in sorted(self.bpe_ranks.items()							,	key=lambda __A : kv[1] ):
								if index != token_index:
									logger.warning(
									    f'''Saving vocabulary to {merge_file}: BPE merge indices are not consecutive.'''
									    " Please check that the tokenizer is not corrupted!" )
									snake_case__				:   int     =						token_index
								writer.write(" ".join(__A ) + "\n" )
								index += 1

						return vocab_file, merge_file



					def  _lowercase  (      self  :						int							,	__A  :						List[int]							,	__A  :						Optional[List[int]] = None ):
						if token_ids_a is None:
							return [self.cls_token_id] + token_ids_a + [self.sep_token_id]
						snake_case__				:   Tuple     =						[self.cls_token_id]
						snake_case__				:   List[Any]     =						[self.sep_token_id]
						return cls + token_ids_a + sep + sep + token_ids_a + sep



					def  _lowercase  (      self  :						Optional[Any]							,	__A  :						List[int]							,	__A  :						Optional[List[int]] = None							,	__A  :						bool = False ):
						if already_has_special_tokens:
							return super().get_special_tokens_mask(
							    token_ids_a=__A							,	token_ids_a=__A							,	already_has_special_tokens=__A )

						if token_ids_a is None:
							return [1] + ([0] * len(__A )) + [1]
						return [1] + ([0] * len(__A )) + [1, 1] + ([0] * len(__A )) + [1]



					def  _lowercase  (      self  :						List[Any]							,	__A  :						List[int]							,	__A  :						Optional[List[int]] = None ):
						snake_case__				:   Any     =						[self.sep_token_id]
						snake_case__				:   List[Any]     =						[self.cls_token_id]

						if token_ids_a is None:
							return len(cls + token_ids_a + sep ) * [0]
						return len(cls + token_ids_a + sep + sep + token_ids_a + sep ) * [0]



					def  _lowercase  (      self  :						Optional[Any]							,	__A  :						int							,	__A  :						int=False							,	**__A  :						Dict ):
						snake_case__				:   Optional[int]     =						kwargs.pop("add_prefix_space"							,	self.add_prefix_space )
						if (is_split_into_words or add_prefix_space) and (len(__A ) > 0 and not text[0].isspace()):
							snake_case__				:   Optional[int]     =						" " + text
						return (text, kwargs)






					def  _lowercase  (      self  :						Any							,	__A  :						Union[Dict[str, EncodedInput], BatchEncoding]							,	__A  :						Optional[int] = None							,	__A  :						PaddingStrategy = PaddingStrategy.DO_NOT_PAD							,	__A  :						Optional[int] = None							,	__A  :						Optional[bool] = None							,	):
						snake_case__				:   Optional[Any]     =						super()._pad(
						    encoded_inputs=__A							,	max_length=__A							,	padding_strategy=__A							,	pad_to_multiple_of=__A							,	return_attention_mask=__A							,	)

						# Load from model defaults
						if return_attention_mask is None:
							snake_case__				:   Union[str, Any]     =						"attention_mask" in self.model_input_names

						if return_attention_mask and "global_attention_mask" in encoded_inputs:
							snake_case__				:   Union[str, Any]     =						encoded_inputs[self.model_input_names[0]]
							# `global_attention_mask` need to have the same length as other (sequential) inputs.
							snake_case__				:   Tuple     =						len(encoded_inputs["global_attention_mask"] ) != len(__A )

							if needs_to_be_padded:
								snake_case__				:   int     =						len(__A ) - len(encoded_inputs["global_attention_mask"] )

								if self.padding_side == "right":
									# Use `-1` since `0` in `global_attention_mask` means `local attention` instead of `not to attend`
									snake_case__				:   int     =						(
									    encoded_inputs["global_attention_mask"] + [-1] * difference
									)
								elif self.padding_side == "left":
									snake_case__				:   Tuple     =						[-1] * difference + encoded_inputs[
									    "global_attention_mask"
									]
								else:
									raise ValueError("Invalid padding strategy:" + str(self.padding_side ) )

						return encoded_inputs



