"""
    #################################################################################################################################################################################################
    # This code library is an adaptation of the original Transformers and was designed, developed and programmed by Sapiens Technology®.                                                            #
    # Any alteration and/or disclosure of this code without prior authorization is strictly prohibited and is subject to legal action that will be forwarded by the Sapiens Technology® legal team. #
    # This set of algorithms aims to download, train, fine-tune and/or infer large language models from various sources and slopes.                                                                 #
    #################################################################################################################################################################################################
"""
import collections
import copy
import os
import unicodedata
from typing import Any, Dict, List, Optional, Tuple
from ...tokenization_utils import PreTrainedTokenizer, _is_control, _is_punctuation, _is_whitespace
from ...utils import is_sentencepiece_available, is_sudachi_projection_available, logging
if is_sentencepiece_available(): import sentencepiece as spm
else: spm = None
logger = logging.get_logger(__name__)
VOCAB_FILES_NAMES = {"vocab_file": "vocab.txt", "spm_file": "spiece.model"}
SPIECE_UNDERLINE = "▁"
def load_vocab(vocab_file):
    vocab = collections.OrderedDict()
    with open(vocab_file, "r", encoding="utf-8") as reader: tokens = reader.readlines()
    for index, token in enumerate(tokens):
        token = token.rstrip("\n")
        vocab[token] = index
    return vocab
def whitespace_tokenize(text):
    text = text.strip()
    if not text: return []
    tokens = text.split()
    return tokens
class BertJapaneseTokenizer(PreTrainedTokenizer):
    vocab_files_names = VOCAB_FILES_NAMES
    def __init__(self, vocab_file, spm_file=None, do_lower_case=False, do_word_tokenize=True, do_subword_tokenize=True, word_tokenizer_type="basic", subword_tokenizer_type="wordpiece",
    never_split=None, unk_token="[UNK]", sep_token="[SEP]", pad_token="[PAD]", cls_token="[CLS]", mask_token="[MASK]", mecab_kwargs=None, sudachi_kwargs=None, jumanpp_kwargs=None, **kwargs):
        if subword_tokenizer_type == "sentencepiece":
            if not os.path.isfile(spm_file): raise ValueError(f"Can't find a vocabulary file at path '{spm_file}'. To load the vocabulary from a Google pretrained model use `tokenizer = AutoTokenizer.from_pretrained(PRETRAINED_MODEL_NAME)`")
            self.spm_file = spm_file
        else:
            if not os.path.isfile(vocab_file): raise ValueError(f"Can't find a vocabulary file at path '{vocab_file}'. To load the vocabulary from a Google pretrained model use `tokenizer = AutoTokenizer.from_pretrained(PRETRAINED_MODEL_NAME)`")
            self.vocab = load_vocab(vocab_file)
            self.ids_to_tokens = collections.OrderedDict([(ids, tok) for tok, ids in self.vocab.items()])
        self.do_word_tokenize = do_word_tokenize
        self.word_tokenizer_type = word_tokenizer_type
        self.lower_case = do_lower_case
        self.never_split = never_split
        self.mecab_kwargs = copy.deepcopy(mecab_kwargs)
        self.sudachi_kwargs = copy.deepcopy(sudachi_kwargs)
        self.jumanpp_kwargs = copy.deepcopy(jumanpp_kwargs)
        if do_word_tokenize:
            if word_tokenizer_type == "basic": self.word_tokenizer = BasicTokenizer(do_lower_case=do_lower_case, never_split=never_split, tokenize_chinese_chars=False)
            elif word_tokenizer_type == "mecab": self.word_tokenizer = MecabTokenizer(do_lower_case=do_lower_case, never_split=never_split, **(mecab_kwargs or {}))
            elif word_tokenizer_type == "sudachi": self.word_tokenizer = SudachiTokenizer(do_lower_case=do_lower_case, never_split=never_split, **(sudachi_kwargs or {}))
            elif word_tokenizer_type == "jumanpp": self.word_tokenizer = JumanppTokenizer(do_lower_case=do_lower_case, never_split=never_split, **(jumanpp_kwargs or {}))
            else: raise ValueError(f"Invalid word_tokenizer_type '{word_tokenizer_type}' is specified.")
        self.do_subword_tokenize = do_subword_tokenize
        self.subword_tokenizer_type = subword_tokenizer_type
        if do_subword_tokenize:
            if subword_tokenizer_type == "wordpiece": self.subword_tokenizer = WordpieceTokenizer(vocab=self.vocab, unk_token=str(unk_token))
            elif subword_tokenizer_type == "character": self.subword_tokenizer = CharacterTokenizer(vocab=self.vocab, unk_token=str(unk_token))
            elif subword_tokenizer_type == "sentencepiece": self.subword_tokenizer = SentencepieceTokenizer(vocab=self.spm_file, unk_token=str(unk_token))
            else: raise ValueError(f"Invalid subword_tokenizer_type '{subword_tokenizer_type}' is specified.")
        super().__init__(spm_file=spm_file, unk_token=unk_token, sep_token=sep_token, pad_token=pad_token, cls_token=cls_token, mask_token=mask_token, do_lower_case=do_lower_case,
        do_word_tokenize=do_word_tokenize, do_subword_tokenize=do_subword_tokenize, word_tokenizer_type=word_tokenizer_type, subword_tokenizer_type=subword_tokenizer_type,
        never_split=never_split, mecab_kwargs=mecab_kwargs, sudachi_kwargs=sudachi_kwargs, jumanpp_kwargs=jumanpp_kwargs, **kwargs)
    @property
    def do_lower_case(self): return self.lower_case
    def __getstate__(self):
        state = dict(self.__dict__)
        if self.word_tokenizer_type in ["mecab", "sudachi", "jumanpp"]: del state["word_tokenizer"]
        return state
    def __setstate__(self, state):
        self.__dict__ = state
        if self.word_tokenizer_type == "mecab": self.word_tokenizer = MecabTokenizer(do_lower_case=self.do_lower_case, never_split=self.never_split, **(self.mecab_kwargs or {}))
        elif self.word_tokenizer_type == "sudachi": self.word_tokenizer = SudachiTokenizer(do_lower_case=self.do_lower_case, never_split=self.never_split, **(self.sudachi_kwargs or {}))
        elif self.word_tokenizer_type == "jumanpp": self.word_tokenizer = JumanppTokenizer(do_lower_case=self.do_lower_case, never_split=self.never_split, **(self.jumanpp_kwargs or {}))
    def _tokenize(self, text):
        if self.do_word_tokenize: tokens = self.word_tokenizer.tokenize(text, never_split=self.all_special_tokens)
        else: tokens = [text]
        if self.do_subword_tokenize: split_tokens = [sub_token for token in tokens for sub_token in self.subword_tokenizer.tokenize(token)]
        else: split_tokens = tokens
        return split_tokens
    @property
    def vocab_size(self):
        if self.subword_tokenizer_type == "sentencepiece": return len(self.subword_tokenizer.sp_model)
        return len(self.vocab)
    def get_vocab(self):
        if self.subword_tokenizer_type == "sentencepiece":
            vocab = {self.convert_ids_to_tokens(i): i for i in range(self.vocab_size)}
            vocab.update(self.added_tokens_encoder)
            return vocab
        return dict(self.vocab, **self.added_tokens_encoder)
    def _convert_token_to_id(self, token):
        if self.subword_tokenizer_type == "sentencepiece": return self.subword_tokenizer.sp_model.PieceToId(token)
        return self.vocab.get(token, self.vocab.get(self.unk_token))
    def _convert_id_to_token(self, index):
        if self.subword_tokenizer_type == "sentencepiece": return self.subword_tokenizer.sp_model.IdToPiece(index)
        return self.ids_to_tokens.get(index, self.unk_token)
    def convert_tokens_to_string(self, tokens):
        if self.subword_tokenizer_type == "sentencepiece": return self.subword_tokenizer.sp_model.decode(tokens)
        out_string = " ".join(tokens).replace(" ##", "").strip()
        return out_string
    def build_inputs_with_special_tokens(self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None) -> List[int]:
        if token_ids_1 is None: return [self.cls_token_id] + token_ids_0 + [self.sep_token_id]
        cls = [self.cls_token_id]
        sep = [self.sep_token_id]
        return cls + token_ids_0 + sep + token_ids_1 + sep
    def get_special_tokens_mask(self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None, already_has_special_tokens: bool = False) -> List[int]:
        if already_has_special_tokens: return super().get_special_tokens_mask(token_ids_0=token_ids_0, token_ids_1=token_ids_1, already_has_special_tokens=True)
        if token_ids_1 is not None: return [1] + ([0] * len(token_ids_0)) + [1] + ([0] * len(token_ids_1)) + [1]
        return [1] + ([0] * len(token_ids_0)) + [1]
    def create_token_type_ids_from_sequences(self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None) -> List[int]:
        sep = [self.sep_token_id]
        cls = [self.cls_token_id]
        if token_ids_1 is None: return len(cls + token_ids_0 + sep) * [0]
        return len(cls + token_ids_0 + sep) * [0] + len(token_ids_1 + sep) * [1]
    def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> Tuple[str]:
        if os.path.isdir(save_directory):
            if self.subword_tokenizer_type == "sentencepiece": vocab_file = os.path.join(save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["spm_file"])
            else: vocab_file = os.path.join(save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"])
        else: vocab_file = (filename_prefix + "-" if filename_prefix else "") + save_directory
        if self.subword_tokenizer_type == "sentencepiece":
            with open(vocab_file, "wb") as writer:
                content_spiece_model = self.subword_tokenizer.sp_model.serialized_model_proto()
                writer.write(content_spiece_model)
        else:
            with open(vocab_file, "w", encoding="utf-8") as writer:
                index = 0
                for token, token_index in sorted(self.vocab.items(), key=lambda kv: kv[1]):
                    if index != token_index:
                        logger.warning(f"Saving vocabulary to {vocab_file}: vocabulary indices are not consecutive. Please check that the vocabulary is not corrupted!")
                        index = token_index
                    writer.write(token + "\n")
                    index += 1
        return (vocab_file,)
class MecabTokenizer:
    def __init__(self, do_lower_case=False, never_split=None, normalize_text=True, mecab_dic: Optional[str] = "ipadic", mecab_option: Optional[str] = None):
        self.do_lower_case = do_lower_case
        self.never_split = never_split if never_split is not None else []
        self.normalize_text = normalize_text
        try: import fugashi
        except ModuleNotFoundError as error: raise error.__class__("You need to install fugashi to use MecabTokenizer. See https://pypi.org/project/fugashi/ for installation.")
        mecab_option = mecab_option or ""
        if mecab_dic is not None:
            if mecab_dic == "ipadic":
                try: import ipadic
                except ModuleNotFoundError as error: raise error.__class__("The ipadic dictionary is not installed. See https://github.com/polm/ipadic-py for installation.")
                dic_dir = ipadic.DICDIR
            elif mecab_dic == "unidic_lite":
                try: import unidic_lite
                except ModuleNotFoundError as error: raise error.__class__("The unidic_lite dictionary is not installed. See https://github.com/polm/unidic-lite for installation.")
                dic_dir = unidic_lite.DICDIR
            elif mecab_dic == "unidic":
                try: import unidic
                except ModuleNotFoundError as error: raise error.__class__("The unidic dictionary is not installed. See https://github.com/polm/unidic-py for installation.")
                dic_dir = unidic.DICDIR
                if not os.path.isdir(dic_dir): raise RuntimeError("The unidic dictionary itself is not found. See https://github.com/polm/unidic-py for installation.")
            else: raise ValueError("Invalid mecab_dic is specified.")
            mecabrc = os.path.join(dic_dir, "mecabrc")
            mecab_option = f'-d "{dic_dir}" -r "{mecabrc}" ' + mecab_option
        self.mecab = fugashi.GenericTagger(mecab_option)
    def tokenize(self, text, never_split=None, **kwargs):
        if self.normalize_text: text = unicodedata.normalize("NFKC", text)
        never_split = self.never_split + (never_split if never_split is not None else [])
        tokens = []
        for word in self.mecab(text):
            token = word.surface
            if self.do_lower_case and token not in never_split: token = token.lower()
            tokens.append(token)
        return tokens
class SudachiTokenizer:
    def __init__(self, do_lower_case=False, never_split=None, normalize_text=True, trim_whitespace=False, sudachi_split_mode="A", sudachi_config_path=None, sudachi_resource_dir=None, sudachi_dict_type="core", sudachi_projection=None):
        self.do_lower_case = do_lower_case
        self.never_split = never_split if never_split is not None else []
        self.normalize_text = normalize_text
        self.trim_whitespace = trim_whitespace
        try: from sudachipy import dictionary, tokenizer
        except ImportError: raise ImportError("You need to install sudachipy to use SudachiTokenizer. See https://github.com/WorksApplications/SudachiPy for installation.")
        if sudachi_split_mode == "A": self.split_mode = tokenizer.Tokenizer.SplitMode.A
        elif sudachi_split_mode == "B": self.split_mode = tokenizer.Tokenizer.SplitMode.B
        elif sudachi_split_mode == "C": self.split_mode = tokenizer.Tokenizer.SplitMode.C
        else: raise ValueError("Invalid sudachi_split_mode is specified.")
        self.projection = sudachi_projection
        sudachi_dictionary = dictionary.Dictionary(config_path=sudachi_config_path, resource_dir=sudachi_resource_dir, dict=sudachi_dict_type)
        if is_sudachi_projection_available(): self.sudachi = sudachi_dictionary.create(self.split_mode, projection=self.projection)
        elif self.projection is not None: raise ImportError("You need to install sudachipy>=0.6.8 to specify `projection` field in sudachi_kwargs.")
        else: self.sudachi = sudachi_dictionary.create(self.split_mode)
    def tokenize(self, text, never_split=None, **kwargs):
        if self.normalize_text: text = unicodedata.normalize("NFKC", text)
        never_split = self.never_split + (never_split if never_split is not None else [])
        tokens = []
        for word in self.sudachi.tokenize(text):
            token = word.surface()
            if self.do_lower_case and token not in never_split: token = token.lower()
            if self.trim_whitespace:
                if token.strip() == "": continue
                else: token = token.strip()
            tokens.append(token)
        return tokens
class JumanppTokenizer:
    def __init__(self, do_lower_case=False, never_split=None, normalize_text=True, trim_whitespace=False):
        self.do_lower_case = do_lower_case
        self.never_split = never_split if never_split is not None else []
        self.normalize_text = normalize_text
        self.trim_whitespace = trim_whitespace
        try: import rhoknp
        except ImportError: raise ImportError("You need to install rhoknp to use JumanppTokenizer. See https://github.com/ku-nlp/rhoknp for installation.")
        self.juman = rhoknp.Jumanpp()
    def tokenize(self, text, never_split=None, **kwargs):
        if self.normalize_text: text = unicodedata.normalize("NFKC", text)
        text = text.strip()
        never_split = self.never_split + (never_split if never_split is not None else [])
        tokens = []
        for mrph in self.juman.apply_to_sentence(text).morphemes:
            token = mrph.text
            if self.do_lower_case and token not in never_split: token = token.lower()
            if self.trim_whitespace:
                if token.strip() == "": continue
                else: token = token.strip()
            tokens.append(token)
        return tokens
class CharacterTokenizer:
    def __init__(self, vocab, unk_token, normalize_text=True):
        self.vocab = vocab
        self.unk_token = unk_token
        self.normalize_text = normalize_text
    def tokenize(self, text):
        if self.normalize_text: text = unicodedata.normalize("NFKC", text)
        output_tokens = []
        for char in text:
            if char not in self.vocab:
                output_tokens.append(self.unk_token)
                continue
            output_tokens.append(char)
        return output_tokens
class BasicTokenizer:
    def __init__(self, do_lower_case=True, never_split=None, tokenize_chinese_chars=True, strip_accents=None, do_split_on_punc=True):
        if never_split is None: never_split = []
        self.do_lower_case = do_lower_case
        self.never_split = set(never_split)
        self.tokenize_chinese_chars = tokenize_chinese_chars
        self.strip_accents = strip_accents
        self.do_split_on_punc = do_split_on_punc
    def tokenize(self, text, never_split=None):
        never_split = self.never_split.union(set(never_split)) if never_split else self.never_split
        text = self._clean_text(text)
        if self.tokenize_chinese_chars: text = self._tokenize_chinese_chars(text)
        unicode_normalized_text = unicodedata.normalize("NFC", text)
        orig_tokens = whitespace_tokenize(unicode_normalized_text)
        split_tokens = []
        for token in orig_tokens:
            if token not in never_split:
                if self.do_lower_case:
                    token = token.lower()
                    if self.strip_accents is not False: token = self._run_strip_accents(token)
                elif self.strip_accents: token = self._run_strip_accents(token)
            split_tokens.extend(self._run_split_on_punc(token, never_split))
        output_tokens = whitespace_tokenize(" ".join(split_tokens))
        return output_tokens
    def _run_strip_accents(self, text):
        text = unicodedata.normalize("NFD", text)
        output = []
        for char in text:
            cat = unicodedata.category(char)
            if cat == "Mn": continue
            output.append(char)
        return "".join(output)
    def _run_split_on_punc(self, text, never_split=None):
        if not self.do_split_on_punc or (never_split is not None and text in never_split): return [text]
        chars = list(text)
        i = 0
        start_new_word = True
        output = []
        while i < len(chars):
            char = chars[i]
            if _is_punctuation(char):
                output.append([char])
                start_new_word = True
            else:
                if start_new_word: output.append([])
                start_new_word = False
                output[-1].append(char)
            i += 1
        return ["".join(x) for x in output]
    def _tokenize_chinese_chars(self, text):
        output = []
        for char in text:
            cp = ord(char)
            if self._is_chinese_char(cp):
                output.append(" ")
                output.append(char)
                output.append(" ")
            else: output.append(char)
        return "".join(output)
    def _is_chinese_char(self, cp):
        if ((cp >= 0x4E00 and cp <= 0x9FFF) or (cp >= 0x3400 and cp <= 0x4DBF) or (cp >= 0x20000 and cp <= 0x2A6DF) or (cp >= 0x2A700 and cp <= 0x2B73F)
        or (cp >= 0x2B740 and cp <= 0x2B81F) or (cp >= 0x2B820 and cp <= 0x2CEAF) or (cp >= 0xF900 and cp <= 0xFAFF) or (cp >= 0x2F800 and cp <= 0x2FA1F)): return True
        return False
    def _clean_text(self, text):
        output = []
        for char in text:
            cp = ord(char)
            if cp == 0 or cp == 0xFFFD or _is_control(char): continue
            if _is_whitespace(char): output.append(" ")
            else: output.append(char)
        return "".join(output)
class WordpieceTokenizer:
    def __init__(self, vocab, unk_token, max_input_chars_per_word=100):
        self.vocab = vocab
        self.unk_token = unk_token
        self.max_input_chars_per_word = max_input_chars_per_word
    def tokenize(self, text):
        output_tokens = []
        for token in whitespace_tokenize(text):
            chars = list(token)
            if len(chars) > self.max_input_chars_per_word:
                output_tokens.append(self.unk_token)
                continue
            is_bad = False
            start = 0
            sub_tokens = []
            while start < len(chars):
                end = len(chars)
                cur_substr = None
                while start < end:
                    substr = "".join(chars[start:end])
                    if start > 0: substr = "##" + substr
                    if substr in self.vocab:
                        cur_substr = substr
                        break
                    end -= 1
                if cur_substr is None:
                    is_bad = True
                    break
                sub_tokens.append(cur_substr)
                start = end
            if is_bad: output_tokens.append(self.unk_token)
            else: output_tokens.extend(sub_tokens)
        return output_tokens
class SentencepieceTokenizer:
    def __init__(self, vocab, unk_token, do_lower_case=False, remove_space=True, keep_accents=True, sp_model_kwargs: Optional[Dict[str, Any]] = None):
        self.vocab = vocab
        self.unk_token = unk_token
        self.do_lower_case = do_lower_case
        self.remove_space = remove_space
        self.keep_accents = keep_accents
        self.sp_model_kwargs = {} if sp_model_kwargs is None else sp_model_kwargs
        self.sp_model = spm.SentencePieceProcessor(**self.sp_model_kwargs)
        self.sp_model.Load(self.vocab)
    def preprocess_text(self, inputs):
        if self.remove_space: outputs = " ".join(inputs.strip().split())
        else: outputs = inputs
        outputs = outputs.replace("``", '"').replace("''", '"')
        if not self.keep_accents:
            outputs = unicodedata.normalize("NFKD", outputs)
            outputs = "".join([c for c in outputs if not unicodedata.combining(c)])
        if self.do_lower_case: outputs = outputs.lower()
        return outputs
    def tokenize(self, text):
        text = self.preprocess_text(text)
        pieces = self.sp_model.encode(text, out_type=str)
        new_pieces = []
        for piece in pieces:
            if len(piece) > 1 and piece[-1] == str(",") and piece[-2].isdigit():
                cur_pieces = self.sp_model.EncodeAsPieces(piece[:-1].replace(SPIECE_UNDERLINE, ""))
                if piece[0] != SPIECE_UNDERLINE and cur_pieces[0][0] == SPIECE_UNDERLINE:
                    if len(cur_pieces[0]) == 1: cur_pieces = cur_pieces[1:]
                    else: cur_pieces[0] = cur_pieces[0][1:]
                cur_pieces.append(piece[-1])
                new_pieces.extend(cur_pieces)
            else: new_pieces.append(piece)
        return new_pieces
"""
    #################################################################################################################################################################################################
    # This code library is an adaptation of the original Transformers and was designed, developed and programmed by Sapiens Technology®.                                                            #
    # Any alteration and/or disclosure of this code without prior authorization is strictly prohibited and is subject to legal action that will be forwarded by the Sapiens Technology® legal team. #
    # This set of algorithms aims to download, train, fine-tune and/or infer large language models from various sources and slopes.                                                                 #
    #################################################################################################################################################################################################
"""
