
'''simple docstring'''







import html

from ...feature_extraction_utils import BatchFeature, FeatureExtractionMixin
from ...utils import is_bsa_available, logging, requires_backends


if is_bsa_available():
					import bsa
					from bsa import BeautifulSoup


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


class 		__UpperCAmelCase (   __a		):


							def __init__(			self       ,  **lowerCAmelCase_    ):





								"""simple docstring"""






								requires_backends(self       ,  ['bs4']    )
								super().__init__(**lowerCAmelCase__    )


							def 					lowerCamelCase							(			self       ,  lowerCAmelCase_    ):





								"""simple docstring"""






								_snake_case  		=						[]
								_snake_case  		=						[]
								_snake_case  		=						element if element.name else element.parent
								for parent in child.parents:  # type: bs4.element.Tag
									_snake_case  		=						parent.find_all(child.name       ,  recursive=lowerCAmelCase__    )
									xpath_tags.append(child.name    )
									xpath_subscripts.append(
									    0 if 1 == len(lowerCAmelCase__    ) else next(i for i, s in enumerate(lowerCAmelCase__       ,  1    ) if s is child    )    )
									_snake_case  		=						parent
								xpath_tags.reverse()
								xpath_subscripts.reverse()
								return xpath_tags, xpath_subscripts


							def 					lowerCamelCase							(			self       ,  lowerCAmelCase_    ):





								"""simple docstring"""






								_snake_case  		=						BeautifulSoup(lowerCAmelCase__       ,  'html.parser'    )

								_snake_case  		=						[]
								_snake_case  		=						[]
								_snake_case  		=						[]

								for element in html_code.descendants:
									if type(lowerCAmelCase__    ) == bsa.element.NavigableString:
										if type(element.parent    ) != bsa.element.Tag:
											continue

										_snake_case  		=						html.unescape(lowerCAmelCase__    ).strip()
										if not text_in_this_tag:
											continue

										all_doc_strings.append(lowerCAmelCase__    )

										_snake_case		,					_snake_case  		=						self.xpath_soup(lowerCAmelCase__    )
										stringaxtag_seq.append(lowerCAmelCase__    )
										stringaxsubs_seq.append(lowerCAmelCase__    )

								if len(lowerCAmelCase__    ) != len(lowerCAmelCase__    ):
									raise ValueError('Number of doc strings and xtags does not correspond'    )
								if len(lowerCAmelCase__    ) != len(lowerCAmelCase__    ):
									raise ValueError('Number of doc strings and xsubs does not correspond'    )

								return all_doc_strings, stringaxtag_seq, stringaxsubs_seq


							def 					lowerCamelCase							(			self       ,  lowerCAmelCase_       ,  lowerCAmelCase_    ):





								"""simple docstring"""






								_snake_case  		=						''
								for tagname, subs in zip(lowerCAmelCase__       ,  lowerCAmelCase__    ):
									xpath += F'/{tagname}'
									if subs != 0:
										xpath += F'[{subs}]'
								return xpath




							def __call__(			self       ,  lowerCAmelCase_    ):





								"""simple docstring"""






								_snake_case  		=						False

								# Check that strings has a valid type
								if isinstance(lowerCAmelCase__       ,  lowerCAmelCase__    ):
									_snake_case  		=						True
								elif isinstance(lowerCAmelCase__       ,  (list, tuple)    ):
									if len(lowerCAmelCase__    ) == 0 or isinstance(html_strings[0]       ,  lowerCAmelCase__    ):
										_snake_case  		=						True

								if not valid_strings:
									raise ValueError(
									    'HTML strings must of type `str`, `List[str]` (batch of examples), '
									    F'but is of type {type(lowerCAmelCase__    )}.'    )

								_snake_case  		=						bool(isinstance(lowerCAmelCase__       ,  (list, tuple)    ) and (isinstance(html_strings[0]       ,  lowerCAmelCase__    ))    )

								if not is_batched:
									_snake_case  		=						[html_strings]

								# Get nodes + xpaths
								_snake_case  		=						[]
								_snake_case  		=						[]
								for html_string in html_strings:
									_snake_case		,					_snake_case		,					_snake_case  		=						self.get_three_from_single(lowerCAmelCase__    )
									nodes.append(lowerCAmelCase__    )
									_snake_case  		=						[]
									for node, tag_list, sub_list in zip(lowerCAmelCase__       ,  lowerCAmelCase__       ,  lowerCAmelCase__    ):
										_snake_case  		=						self.construct_xpath(lowerCAmelCase__       ,  lowerCAmelCase__    )
										xpath_strings.append(lowerCAmelCase__    )
									xpaths.append(lowerCAmelCase__    )

								# return as Dict
								_snake_case  		=						{'nodes': nodes, 'xpaths': xpaths}
								_snake_case  		=						BatchFeature(data=lowerCAmelCase__       ,  tensor_type=lowerCAmelCase__    )

								return encoded_inputs



from typing import List, Optional, Union

import numpy as np

from ....audio_utils import mel_filter_bank, optimal_fft_length, spectrogram, window_function
from ....feature_extraction_sequence_utils import SequenceFeatureExtractor
from ....feature_extraction_utils import BatchFeature
from ....file_utils import PaddingStrategy, TensorType
from ....utils import logging


_snake_case      :							Any     	=    logging.get_logger(__name__)





class   UpperCamelCase_      (      __a		):







						'''simple docstring'''



						UpperCamelCase      :  Any				   =					['''input_features''', '''attention_mask''']





						def __init__(			self							:List[Any]		,    lowerCAmelCase__							:List[Any]=80		,    lowerCAmelCase__							:int=16000		,    lowerCAmelCase__							:str=0.0		,    lowerCAmelCase__							:int=10		,    lowerCAmelCase__							:List[Any]=25		,    lowerCAmelCase__							:List[str]="hamming_window"		,    lowerCAmelCase__							:int=3_27_68.0		,    lowerCAmelCase__							:str=0.97		,    lowerCAmelCase__							:List[str]=1.0		,    lowerCAmelCase__							:Optional[int]=True		,    lowerCAmelCase__							:Tuple=True		,    lowerCAmelCase__							:str=False		,    **lowerCAmelCase__							:Optional[Any]		,    )  ->Union[str, Any]:
										super().__init__(feature_size=lowerCAmelCase__		,    sampling_rate=lowerCAmelCase__		,    padding_value=lowerCAmelCase__		,    **lowerCAmelCase__     )

										lowercase         =      feature_size
										lowercase         =      sampling_rate
										lowercase         =      padding_value
										lowercase         =      hop_length
										lowercase         =      win_length
										lowercase         =      frame_signal_scale
										lowercase         =      preemphasis_coeff
										lowercase         =      mel_floor
										lowercase         =      normalize_means
										lowercase         =      normalize_vars
										lowercase         =      win_function
										lowercase         =      return_attention_mask

										lowercase         =      win_length * sampling_rate // 1000
										lowercase         =      hop_length * sampling_rate // 1000

										lowercase         =      optimal_fft_length(self.sample_size     )
										lowercase         =      (self.n_fft // 2) + 1





						def        SCREAMING_SNAKE_CASE(			self							:Union[str, Any]		,    lowerCAmelCase__							:np.array     )  ->np.ndarray:
										if self.win_function == "hamming_window":
														lowercase         =      window_function(window_length=self.sample_size		,    name=self.win_function		,    periodic=lowerCAmelCase__     )
										else:
														lowercase         =      window_function(window_length=self.sample_size		,    name=self.win_function     )

										lowercase         =      mel_filter_bank(
										    num_frequency_bins=self.n_freqs		,    num_mel_filters=self.feature_size		,    min_frequency=0.0		,    max_frequency=self.sampling_rate / 2.0		,    sampling_rate=self.sampling_rate		,    )

										lowercase         =      spectrogram(
										    one_waveform * self.frame_signal_scale		,    window=lowerCAmelCase__		,    frame_length=self.sample_size		,    hop_length=self.sample_stride		,    fft_length=self.n_fft		,    center=lowerCAmelCase__		,    preemphasis=self.preemphasis_coeff		,    mel_filters=lowerCAmelCase__		,    mel_floor=self.mel_floor		,    log_mel="log"		,    )
										return msfc_features.T





						def        SCREAMING_SNAKE_CASE(			self							:Tuple		,    lowerCAmelCase__							:Optional[Any]		,    lowerCAmelCase__							:Optional[Any]		,    lowerCAmelCase__							:Dict     )  ->int:
										# make sure we normalize float32 arrays
										if self.normalize_means:
														lowercase         =      x[:input_length].mean(axis=0     )
														lowercase         =      np.subtract(lowerCAmelCase__		,    lowerCAmelCase__     )
										if self.normalize_vars:
														lowercase         =      x[:input_length].std(axis=0     )
														lowercase         =      np.divide(lowerCAmelCase__		,    lowerCAmelCase__     )

										if input_length < x.shape[0]:
														lowercase         =      padding_value

										# make sure array is in float32
										lowercase         =      x.astype(np.floataa     )

										return x





						def        SCREAMING_SNAKE_CASE(			self							:Optional[Any]		,    lowerCAmelCase__							:List[np.ndarray]		,    lowerCAmelCase__							:Optional[np.ndarray] = None     )  ->List[np.ndarray]:
										lowercase         =      attention_mask.sum(-1     ) if attention_mask is not None else [x.shape[0] for x in input_features]
										return [self._normalize_one(lowerCAmelCase__		,    lowerCAmelCase__		,    self.padding_value     ) for x, n in zip(lowerCAmelCase__		,    lowerCAmelCase__     )]





						def __call__(			self							:Any		,    lowerCAmelCase__							:Union[np.ndarray, List[float], List[np.ndarray], List[List[float]]]		,    lowerCAmelCase__							:Union[bool, str, PaddingStrategy] = False		,    lowerCAmelCase__							:Optional[int] = None		,    lowerCAmelCase__							:bool = False		,    lowerCAmelCase__							:Optional[int] = None		,    lowerCAmelCase__							:Optional[bool] = None		,    lowerCAmelCase__							:Optional[Union[str, TensorType]] = None		,    lowerCAmelCase__							:Optional[int] = None		,    **lowerCAmelCase__							:Union[str, Any]		,    )  ->BatchFeature:

										if sampling_rate is not None:
														if sampling_rate != self.sampling_rate:
																		raise ValueError(
																		    F'''The model corresponding to this feature extractor: {self} was trained using a sampling rate of'''
																		    F''' {self.sampling_rate}. Please make sure that the provided `raw_speech` input was sampled with'''
																		    F''' {self.sampling_rate} and not {sampling_rate}.'''     )
										else:
														logger.warning(
														    "It is strongly recommended to pass the ``sampling_rate`` argument to this function. "
														    "Failing to do so can result in silent errors that might be hard to debug."     )

										lowercase         =      isinstance(lowerCAmelCase__		,    np.ndarray     ) and len(raw_speech.shape     ) > 1
										if is_batched_numpy and len(raw_speech.shape     ) > 2:
														raise ValueError(F'''Only mono-channel audio is supported for input to {self}'''     )
										lowercase         =      is_batched_numpy or (
										    isinstance(lowerCAmelCase__		,    (list, tuple)     ) and (isinstance(raw_speech[0]		,    (np.ndarray, tuple, list)     ))
										)

										if is_batched:
														lowercase         =      [np.asarray(lowerCAmelCase__		,    dtype=np.floataa     ) for speech in raw_speech]
										elif not is_batched and not isinstance(lowerCAmelCase__		,    np.ndarray     ):
														lowercase         =      np.asarray(lowerCAmelCase__		,    dtype=np.floataa     )
										elif isinstance(lowerCAmelCase__		,    np.ndarray     ) and raw_speech.dtype is np.dtype(np.floataa     ):
														lowercase         =      raw_speech.astype(np.floataa     )

										# always return batch
										if not is_batched:
														lowercase         =      [raw_speech]

										# extract fbank features
										lowercase         =      [self._extract_mfsc_features(lowerCAmelCase__     ) for one_waveform in raw_speech]

										# convert into correct format for padding
										lowercase         =      BatchFeature({"input_features": features}     )

										lowercase         =      self.pad(
										    lowerCAmelCase__		,    padding=lowerCAmelCase__		,    max_length=lowerCAmelCase__		,    truncation=lowerCAmelCase__		,    pad_to_multiple_of=lowerCAmelCase__		,    return_attention_mask=lowerCAmelCase__		,    **lowerCAmelCase__		,    )
										# make sure list is in array format
										lowercase         =      padded_inputs.get("input_features"     )
										if isinstance(input_features[0]		,    lowerCAmelCase__     ):
														lowercase         =      [np.asarray(lowerCAmelCase__		,    dtype=np.floataa     ) for feature in input_features]

										lowercase         =      padded_inputs.get("attention_mask"     )
										if attention_mask is not None:
														lowercase         =      [np.asarray(lowerCAmelCase__		,    dtype=np.intaa     ) for array in attention_mask]

										if self.normalize_means or self.normalize_vars:
														lowercase         =      (
														    np.array(lowerCAmelCase__		,    dtype=np.intaa     )
														    if self._get_padding_strategies(lowerCAmelCase__		,    max_length=lowerCAmelCase__     ) is not PaddingStrategy.DO_NOT_PAD
														    and padding
														    else None
														)
														lowercase         =      self.normalize(
														    padded_inputs["input_features"]		,    attention_mask=lowerCAmelCase__     )

										if return_tensors is not None:
														lowercase         =      padded_inputs.convert_to_tensors(lowerCAmelCase__     )

										return padded_inputs
