



from typing import List

from packaging import version
from sklearn.metrics import fa_score

import datasets
from datasets.config import PY_VERSION


if PY_VERSION < version.parse("""3.8"""):
	import importlib_metadata
else:
	import importlib.metadata as importlib_metadata


# TODO(Patrick/Anton)
A__     				=	"""\
"""

A__     				=	"""\
    XTREME-S is a benchmark to evaluate universal cross-lingual speech representations in many languages.
    XTREME-S covers four task families: speech recognition, classification, speech-to-text translation and retrieval.
"""

A__     				=	"""
Compute XTREME-S evaluation metric associated to each XTREME-S dataset.
Args:
    predictions: list of predictions to score.
        Each translation should be tokenized into a list of tokens.
    references: list of lists of references for each translation.
        Each reference should be tokenized into a list of tokens.
    bleu_kwargs: optional dict of keywords to be passed when computing 'bleu'.
        Keywords include Dict can be one of 'smooth_method', 'smooth_value', 'force', 'lowercase',
        'tokenize', 'use_effective_order'.
    wer_kwargs: optional dict of keywords to be passed when computing 'wer' and 'cer'.
        Keywords include 'concatenate_texts'.
Returns: depending on the XTREME-S task, one or several of:
    \"accuracy\": Accuracy - for 'fleurs-lang_id', 'minds14'
    \"f1\": F1 score - for 'minds14'
    \"wer\": Word error rate - for 'mls', 'fleurs-asr', 'voxpopuli', 'babel'
    \"cer\": Character error rate - for 'mls', 'fleurs-asr', 'voxpopuli', 'babel'
    \"bleu\": BLEU score according to the `sacrebleu` metric - for 'covost2'
Examples:

    >>> xtreme_s_metric = datasets.load_metric('xtreme_s', 'mls')  # 'mls', 'voxpopuli', 'fleurs-asr' or 'babel'
    >>> references = [\"it is sunny here\", \"paper and pen are essentials\"]
    >>> predictions = [\"it's sunny\", \"paper pen are essential\"]
    >>> results = xtreme_s_metric.compute(predictions=predictions, references=references)
    >>> print({k: round(v, 2) for k, v in results.items()})
    {'wer': 0.56, 'cer': 0.27}

    >>> xtreme_s_metric = datasets.load_metric('xtreme_s', 'covost2')
    >>> references = [\"bonjour paris\", \"il est necessaire de faire du sport de temps en temp\"]
    >>> predictions = [\"bonjour paris\", \"il est important de faire du sport souvent\"]
    >>> results = xtreme_s_metric.compute(predictions=predictions, references=references)
    >>> print({k: round(v, 2) for k, v in results.items()})
    {'bleu': 31.65}

    >>> xtreme_s_metric = datasets.load_metric('xtreme_s', 'fleurs-lang_id')
    >>> references = [0, 1, 0, 0, 1]
    >>> predictions = [0, 1, 1, 0, 0]
    >>> results = xtreme_s_metric.compute(predictions=predictions, references=references)
    >>> print({k: round(v, 2) for k, v in results.items()})
    {'accuracy': 0.6}

    >>> xtreme_s_metric = datasets.load_metric('xtreme_s', 'minds14')
    >>> references = [0, 1, 0, 0, 1]
    >>> predictions = [0, 1, 1, 0, 0]
    >>> results = xtreme_s_metric.compute(predictions=predictions, references=references)
    >>> print({k: round(v, 2) for k, v in results.items()})
    {'f1': 0.58, 'accuracy': 0.6}
"""

A__     				=	["""fleurs-asr""", """mls""", """voxpopuli""", """babel""", """covost2""", """fleurs-lang_id""", """minds14"""]
A__     				=	""""""

try:
	from jiwer import transforms as tr

	A__     				=	True
except ImportError:
	A__     				=	False

if _jiwer_available and version.parse(importlib_metadata.version("""jiwer""")) < version.parse("""2.3.0"""):





	class  __lowerCAmelCase			(					tr.AbstractTransform	):




					def __init__(							self						,    _snake_case = " "		):



										"""simple docstring"""





										_lowerCAmelCase      =   sentence_delimiter




					def 							snake_case       (							self						,    _snake_case		):



										"""simple docstring"""





										return list(_snake_case		)




					def 							snake_case       (							self						,    _snake_case		):



										"""simple docstring"""





										_lowerCAmelCase      =   []
										for sent_idx, sentence in enumerate(_snake_case		):
															chars.extend(self.process_string(_snake_case		)		)
															if self.sentence_delimiter is not None and self.sentence_delimiter != "" and sent_idx < len(_snake_case		) - 1:
																				chars.append(self.sentence_delimiter		)
										return chars

	A__     				=	tr.Compose(
	    [tr.RemoveMultipleSpaces(), tr.Strip(), SentencesToListOfCharacters(SENTENCE_DELIMITER)]
	)
elif _jiwer_available:
	A__     				=	tr.Compose(
	    [
	        tr.RemoveMultipleSpaces(),
	        tr.Strip(),
	        tr.ReduceToSingleSentence(SENTENCE_DELIMITER),
	        tr.ReduceToListOfListOfChars(),
	    ]
	)
else:
	A__     				=	None


def 		_UpperCAmelCase    (				snake_case     ,						snake_case      ):





					"""simple docstring"""

					return float((preds == labels).mean()      )


def 		_UpperCAmelCase    (				snake_case     ,						snake_case      ):





					"""simple docstring"""

					return {
					    "f1": float(fa_score(y_true=snake_case     ,						y_pred=snake_case     ,						average="""macro"""      )      ),
					    "accuracy": simple_accuracy(snake_case     ,						snake_case      ),
					}


def 		_UpperCAmelCase    (				snake_case     ,						snake_case     ,						snake_case="exp"     ,						snake_case=None     ,						snake_case=False     ,						snake_case=False     ,						snake_case=None     ,						snake_case=False     ,						):





					"""simple docstring"""

					_lowerCAmelCase      =   [[label] for label in labels]
					_lowerCAmelCase      =   list(snake_case      )
					try:
										import sacrebleu as scb
					except ImportError:
										raise ValueError(
										    """sacrebleu has to be installed in order to apply the bleu metric for covost2."""
										    """You can install it via `pip install sacrebleu`."""      )

					if version.parse(scb.__version__      ) < version.parse("""1.4.12"""      ):
										raise ImportWarning(
										    """To use `sacrebleu`, the module `sacrebleu>=1.4.12` is required, and the current version of `sacrebleu` doesn't match this condition.\n"""
										    """You can install it with `pip install \"sacrebleu>=1.4.12\"`."""      )

					_lowerCAmelCase      =   len(labels[0]      )
					if any(len(snake_case      ) != references_per_prediction for refs in labels      ):
										raise ValueError("""Sacrebleu requires the same number of references for each prediction"""      )
					_lowerCAmelCase      =   [[refs[i] for refs in labels] for i in range(snake_case      )]
					_lowerCAmelCase      =   scb.corpus_bleu(
					    snake_case     ,						snake_case     ,						smooth_method=snake_case     ,						smooth_value=snake_case     ,						force=snake_case     ,						lowercase=snake_case     ,						use_effective_order=snake_case     ,						**({"""tokenize""": tokenize} if tokenize else {})     ,						)
					return {"bleu": output.score}


def 		_UpperCAmelCase    (				snake_case     ,						snake_case     ,						snake_case     ,						snake_case      ):





					"""simple docstring"""

					try:
										from jiwer import compute_measures
					except ImportError:
										raise ValueError(
										    F'jiwer has to be installed in order to apply the wer metric for {config_name}.'
										    """You can install it via `pip install jiwer`."""      )

					if concatenate_texts:
										_lowerCAmelCase      =   compute_measures(snake_case     ,						snake_case      )["""wer"""]

										_lowerCAmelCase      =   compute_measures(snake_case     ,						snake_case     ,						truth_transform=snake_case     ,						hypothesis_transform=snake_case      )["""wer"""]
										return {"wer": wer, "cer": cer}
					else:

										def compute_score(snake_case     ,						snake_case     ,						snake_case="wer"      ):
															_lowerCAmelCase      =   0
															_lowerCAmelCase      =   0
															for prediction, reference in zip(snake_case     ,						snake_case      ):
																				if score_type == "wer":
																									_lowerCAmelCase      =   compute_measures(snake_case     ,						snake_case      )
																				elif score_type == "cer":
																									_lowerCAmelCase      =   compute_measures(
																									    snake_case     ,						snake_case     ,						truth_transform=snake_case     ,						hypothesis_transform=snake_case      )
																				incorrect += measures["substitutions"] + measures["deletions"] + measures["insertions"]
																				total += measures["substitutions"] + measures["deletions"] + measures["hits"]
															return incorrect / total

										return {"wer": compute_score(snake_case     ,						snake_case     ,						"""wer"""      ), "cer": compute_score(snake_case     ,						snake_case     ,						"""cer"""      )}





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




				def 							snake_case       (							self		):



									"""simple docstring"""





									if self.config_name not in _CONFIG_NAMES:
														raise KeyError(F'You should supply a configuration name selected in {_CONFIG_NAMES}'		)

									_lowerCAmelCase      =   """int64""" if self.config_name in ["""fleurs-lang_id""", """minds14"""] else """string"""

									return datasets.MetricInfo(
									    description=_DESCRIPTION						,    citation=_CITATION						,    inputs_description=_KWARGS_DESCRIPTION						,    features=datasets.Features(
									        {"""predictions""": datasets.Value(_snake_case		), """references""": datasets.Value(_snake_case		)}		)						,    codebase_urls=[]						,    reference_urls=[]						,    format="""numpy"""						,    )




				def 							snake_case       (							self						,    _snake_case						,    _snake_case						,    _snake_case=None						,    _snake_case=None		):



									"""simple docstring"""





									_lowerCAmelCase      =   bleu_kwargs if bleu_kwargs is not None else {}
									_lowerCAmelCase      =   wer_kwargs if wer_kwargs is not None else {}

									if self.config_name == "fleurs-lang_id":
														return {"accuracy": simple_accuracy(_snake_case						,    _snake_case		)}
									elif self.config_name == "minds14":
														return fa_and_simple_accuracy(_snake_case						,    _snake_case		)
									elif self.config_name == "covost2":
														_lowerCAmelCase      =   bleu_kwargs.pop("""smooth_method"""						,    """exp"""		)
														_lowerCAmelCase      =   bleu_kwargs.pop("""smooth_value"""						,    _snake_case		)
														_lowerCAmelCase      =   bleu_kwargs.pop("""force"""						,    _snake_case		)
														_lowerCAmelCase      =   bleu_kwargs.pop("""lowercase"""						,    _snake_case		)
														_lowerCAmelCase      =   bleu_kwargs.pop("""tokenize"""						,    _snake_case		)
														_lowerCAmelCase      =   bleu_kwargs.pop("""use_effective_order"""						,    _snake_case		)
														return bleu(
														    preds=_snake_case						,    labels=_snake_case						,    smooth_method=_snake_case						,    smooth_value=_snake_case						,    force=_snake_case						,    lowercase=_snake_case						,    tokenize=_snake_case						,    use_effective_order=_snake_case						,    )
									elif self.config_name in ["fleurs-asr", "mls", "voxpopuli", "babel"]:
														_lowerCAmelCase      =   wer_kwargs.pop("""concatenate_texts"""						,    _snake_case		)
														return wer_and_cer(_snake_case						,    _snake_case						,    _snake_case						,    self.config_name		)
									else:
														raise KeyError(F'You should supply a configuration name selected in {_CONFIG_NAMES}'		)








# Lint as: python3

import hashlib
from typing import Union


def 		_UpperCAmelCase    (				snake_case      ):





					"""simple docstring"""

					if isinstance(snake_case     ,						snake_case      ):
										# Data already in bytes, returns as it as
										return hash_data
					elif isinstance(snake_case     ,						snake_case      ):
										# We keep the data as it as for it ot be later encoded to UTF-8
										# However replace `\\` with `/` for Windows compatibility
										_lowerCAmelCase      =   hash_data.replace("""\\"""     ,						"""/"""      )
					elif isinstance(snake_case     ,						snake_case      ):
										_lowerCAmelCase      =   str(snake_case      )
					else:
										# If data is not of the required type, raise error
										raise InvalidKeyError(snake_case      )

					return hash_data.encode("""utf-8"""      )





class  __lowerCAmelCase			(					lowerCamelCase__	):




				def __init__(							self						,    _snake_case		):



									"""simple docstring"""





									_lowerCAmelCase      =   """\nFAILURE TO GENERATE DATASET: Invalid key type detected"""
									_lowerCAmelCase      =   F'\nFound Key {hash_data} of type {type(_snake_case		)}'
									_lowerCAmelCase      =   """\nKeys should be either str, int or bytes type"""
									super().__init__(F'{self.prefix}{self.err_msg}{self.suffix}'		)





class  __lowerCAmelCase			(					lowerCamelCase__	):




				def __init__(							self						,    _snake_case						,    _snake_case						,    _snake_case=""		):



									"""simple docstring"""





									_lowerCAmelCase      =   key
									_lowerCAmelCase      =   duplicate_key_indices
									_lowerCAmelCase      =   fix_msg
									_lowerCAmelCase      =   """Found multiple examples generated with the same key"""
									if len(_snake_case		) <= 20:
														_lowerCAmelCase      =   F'\nThe examples at index {", ".join(_snake_case		)} have the key {key}'
									else:
														_lowerCAmelCase      =   F'\nThe examples at index {", ".join(duplicate_key_indices[:20]		)}... ({len(_snake_case		) - 20} more) have the key {key}'
									_lowerCAmelCase      =   """\n""" + fix_msg if fix_msg else """"""
									super().__init__(F'{self.prefix}{self.err_msg}{self.suffix}'		)





class  __lowerCAmelCase			:




				def __init__(							self						,    _snake_case		):



									"""simple docstring"""





									_lowerCAmelCase      =   hashlib.mda(_as_bytes(_snake_case		)		)




				def 							snake_case       (							self						,    _snake_case		):



									"""simple docstring"""





									_lowerCAmelCase      =   self._split_mda.copy()
									_lowerCAmelCase      =   _as_bytes(_snake_case		)
									mda.update(_snake_case		)
									# Convert to integer with hexadecimal conversion
									return int(mda.hexdigest()						,    16		)



