CoolFace
Apppublic

lenML/ChatTTS-Forge

sourceHugging Faceagpl-3.0updated 2y agoView on Hugging Face
301likes
normalization.py345 linesDownload Raw Back to modules
1import html2import re3 4import emojiswitch5import ftfy6 7from modules import models8from modules.utils.detect_lang import guess_lang9from modules.utils.HomophonesReplacer import HomophonesReplacer10from modules.utils.html import remove_html_tags as _remove_html_tags11from modules.utils.markdown import markdown_to_text12from modules.utils.zh_normalization.text_normlization import TextNormalizer13 14# 是否关闭 unk token 检查15# NOTE: 单测的时候用于跳过模型加载16DISABLE_UNK_TOKEN_CHECK = False17 18 19post_normalize_pipeline = []20pre_normalize_pipeline = []21 22 23def post_normalize():24    def decorator(func):25        post_normalize_pipeline.append(func)26        return func27 28    return decorator29 30 31def pre_normalize():32    def decorator(func):33        pre_normalize_pipeline.append(func)34        return func35 36    return decorator37 38 39def apply_pre_normalize(text):40    for func in pre_normalize_pipeline:41        text = func(text)42    return text43 44 45def apply_post_normalize(text):46    for func in post_normalize_pipeline:47        text = func(text)48    return text49 50 51def is_markdown(text):52    markdown_patterns = [53        r"(^|\s)#[^#]",  # 标题54        r"\*\*.*?\*\*",  # 加粗55        r"\*.*?\*",  # 斜体56        r"!\[.*?\]\(.*?\)",  # 图片57        r"\[.*?\]\(.*?\)",  # 链接58        r"`[^`]+`",  # 行内代码59        r"```[\s\S]*?```",  # 代码块60        r"(^|\s)\* ",  # 无序列表61        r"(^|\s)\d+\. ",  # 有序列表62        r"(^|\s)> ",  # 引用63        r"(^|\s)---",  # 分隔线64    ]65 66    for pattern in markdown_patterns:67        if re.search(pattern, text, re.MULTILINE):68            return True69 70    return False71 72 73character_map = {74    ":": ",",75    ";": ",",76    "!": "。",77    "(": ",",78    ")": ",",79    "【": ",",80    "】": ",",81    "『": ",",82    "』": ",",83    "「": ",",84    "」": ",",85    "《": ",",86    "》": ",",87    "-": ",",88    "‘": " ",89    "“": " ",90    "’": " ",91    "”": " ",92    '"': " ",93    "'": " ",94    ":": ",",95    ";": ",",96    "!": ".",97    "(": ",",98    ")": ",",99    "[": ",",100    "]": ",",101    ">": ",",102    "<": ",",103    "-": ",",104    "~": " ",105    "~": " ",106    "/": " ",107    "·": " ",108}109 110character_to_word = {111    " & ": " and ",112}113 114## ---------- post normalize ----------115 116 117@post_normalize()118def apply_character_to_word(text):119    for k, v in character_to_word.items():120        text = text.replace(k, v)121    return text122 123 124@post_normalize()125def apply_character_map(text):126    translation_table = str.maketrans(character_map)127    return text.translate(translation_table)128 129 130@post_normalize()131def apply_emoji_map(text):132    lang = guess_lang(text)133    return emojiswitch.demojize(text, delimiters=("", ""), lang=lang)134 135 136@post_normalize()137def insert_spaces_between_uppercase(s):138    # 使用正则表达式在每个相邻的大写字母之间插入空格139    return re.sub(140        r"(?<=[A-Z])(?=[A-Z])|(?<=[a-z])(?=[A-Z])|(?<=[\u4e00-\u9fa5])(?=[A-Z])|(?<=[A-Z])(?=[\u4e00-\u9fa5])",141        " ",142        s,143    )144 145 146@post_normalize()147def replace_unk_tokens(text):148    """149    把不在字典里的字符替换为 " , "150    """151    if DISABLE_UNK_TOKEN_CHECK:152        return text153    chat_tts = models.load_chat_tts()154    if "tokenizer" not in chat_tts.pretrain_models:155        # 这个地方只有在 huggingface spaces 中才会触发156        # 因为 hugggingface 自动处理模型卸载加载,所以如果拿不到就算了...157        return text158    tokenizer = chat_tts.pretrain_models["tokenizer"]159    vocab = tokenizer.get_vocab()160    vocab_set = set(vocab.keys())161    # 添加所有英语字符162    vocab_set.update(set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"))163    vocab_set.update(set(" \n\r\t"))164    replaced_chars = [char if char in vocab_set else " , " for char in text]165    output_text = "".join(replaced_chars)166    return output_text167 168 169homo_replacer = HomophonesReplacer(map_file_path="./data/homophones_map.json")170 171 172@post_normalize()173def replace_homophones(text):174    lang = guess_lang(text)175    if lang == "zh":176        text = homo_replacer.replace(text)177    return text178 179 180## ---------- pre normalize ----------181 182 183@pre_normalize()184def html_unescape(text):185    text = html.unescape(text)186    text = html.unescape(text)187    return text188 189 190@pre_normalize()191def fix_text(text):192    return ftfy.fix_text(text=text)193 194 195@pre_normalize()196def apply_markdown_to_text(text):197    if is_markdown(text):198        text = markdown_to_text(text)199    return text200 201 202@pre_normalize()203def remove_html_tags(text):204    return _remove_html_tags(text)205 206 207# 将 "xxx" => \nxxx\n208# 将 'xxx' => \nxxx\n209@pre_normalize()210def replace_quotes(text):211    repl = r"\n\1\n"212    patterns = [213        ['"', '"'],214        ["'", "'"],215        ["“", "”"],216        ["‘", "’"],217    ]218    for p in patterns:219        text = re.sub(rf"({p[0]}[^{p[0]}{p[1]}]+?{p[1]})", repl, text)220    return text221 222 223def ensure_suffix(a: str, b: str, c: str):224    a = a.strip()225    if not a.endswith(b):226        a += c227    return a228 229 230email_domain_map = {231    "outlook.com": "Out look",232    "hotmail.com": "Hot mail",233    "yahoo.com": "雅虎",234}235 236 237# 找到所有 email 并将 name 分割为单个字母,@替换为 at ,. 替换为 dot,常见域名替换为单词238#239# 例如:240# zhzluke96@outlook.com => z h z l u k e 9 6 at out look dot com241def email_detect(text):242    email_pattern = re.compile(r"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})")243 244    def replace(match):245        email = match.group(1)246        name, domain = email.split("@")247        name = " ".join(name)248        if domain in email_domain_map:249            domain = email_domain_map[domain]250        domain = domain.replace(".", " dot ")251        return f"{name} at {domain}"252 253    return email_pattern.sub(replace, text)254 255 256def sentence_normalize(sentence_text: str):257    # https://github.com/PaddlePaddle/PaddleSpeech/tree/develop/paddlespeech/t2s/frontend/zh_normalization258    tx = TextNormalizer()259 260    # 匹配 \[.+?\] 的部分261    pattern = re.compile(r"(\[.+?\])|([^[]+)")262 263    def normalize_part(part):264        sentences = tx.normalize(part) if guess_lang(part) == "zh" else [part]265        dest_text = ""266        for sentence in sentences:267            sentence = apply_post_normalize(sentence)268            dest_text += sentence269        return dest_text270 271    def replace(match):272        if match.group(1):273            return f" {match.group(1)} "274        else:275            return normalize_part(match.group(2))276 277    result = pattern.sub(replace, sentence_text)278 279    # NOTE: 加了会有杂音...280    # if is_end:281    # 加这个是为了防止吞字282    # result = ensure_suffix(result, "[uv_break]", "。。。[uv_break]。。。")283 284    return result285 286 287def text_normalize(text, is_end=False):288    text = apply_pre_normalize(text)289    lines = text.split("\n")290    lines = [line.strip() for line in lines]291    lines = [line for line in lines if line]292    lines = [sentence_normalize(line) for line in lines]293    content = "\n".join(lines)294    return content295 296 297if __name__ == "__main__":298    from modules.devices import devices299 300    devices.reset_device()301    test_cases = [302        "ChatTTS是专门为对话场景设计的文本转语音模型,例如LLM助手对话任务。它支持英文和中文两种语言。最大的模型使用了10万小时以上的中英文数据进行训练。在HuggingFace中开源的版本为4万小时训练且未SFT的版本.",303        " [oral_9] [laugh_0] [break_0] 电 [speed_0] 影 [speed_0] 中 梁朝伟 [speed_9] 扮演的陈永仁的编号27149",304        " 明天有62%的概率降雨",305        "大🍌,一条大🍌,嘿,你的感觉真的很奇妙  [lbreak]",306        "I like eating 🍏",307        """308# 你好,世界309```js310console.log('1')311```312**加粗**313 314*一条文本*315        """,316        """317在沙漠、岩石、雪地上行走了很长的时间以后,小王子终于发现了一条大路。所有的大路都是通往人住的地方的。318“你们好。”小王子说。319这是一个玫瑰盛开的花园。320“你好。”玫瑰花说道。321小王子瞅着这些花,它们全都和他的那朵花一样。322“你们是什么花?”小王子惊奇地问。323“我们是玫瑰花。”花儿们说道。324“啊!”小王子说……。325        """,326        """327State-of-the-art Machine Learning for PyTorch, TensorFlow, and JAX.328 329🤗 Transformers provides APIs and tools to easily download and train state-of-the-art pretrained models. Using pretrained models can reduce your compute costs, carbon footprint, and save you the time and resources required to train a model from scratch. These models support common tasks in different modalities, such as:330 331📝 Natural Language Processing: text classification, named entity recognition, question answering, language modeling, summarization, translation, multiple choice, and text generation.332🖼️ Computer Vision: image classification, object detection, and segmentation.333🗣️ Audio: automatic speech recognition and audio classification.334🐙 Multimodal: table question answering, optical character recognition, information extraction from scanned documents, video classification, and visual question answering.335        """,336        """337120米338有12%的概率会下雨339埃隆·马斯克340""",341    ]342 343    for i, test_case in enumerate(test_cases):344        print(f"case {i}:\n", {"x": text_normalize(test_case, is_end=True)})345