File size: 4,001 Bytes
e0c636b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import os

import pypinyin
import yaml
import jieba
from pypinyin.contrib.tone_convert import to_tone, to_initials, to_finals_tone3

from config import config, BASE_DIR


# 定义自定义的表示器来确保列表显示在同一行
class MyDumper(yaml.Dumper):
    def increase_indent(self, flow=False, indentless=False):
        return super(MyDumper, self).increase_indent(flow, False)


# 自定义表示器来强制使用单引号和流格式
def represent_list(self, data):
    value = self.represent_sequence('tag:yaml.org,2002:seq', data, flow_style=True)
    for item in value.value:
        item.style = "'"
    return value


def represent_str(self, data):
    if isinstance(data, str):
        return self.represent_scalar('tag:yaml.org,2002:str', data, style="'")
    return self.represent_scalar('tag:yaml.org,2002:str', data)


MyDumper.add_representer(list, represent_list)
MyDumper.add_representer(str, represent_str)


def load_polyphonic_dict(path: str) -> dict:
    with open(path, 'r', encoding='utf-8') as polyphonic_file:
        # 解析yaml
        polyphonic_dict = yaml.load(polyphonic_file, Loader=yaml.FullLoader)

    return polyphonic_dict


def save_polyphonic_dict(path: str, polyphonic_dict: dict):
    with open(path, 'w', encoding='utf-8') as polyphonic_file:
        yaml.dump(polyphonic_dict, polyphonic_file, Dumper=MyDumper, allow_unicode=True, default_flow_style=False,
                  sort_keys=False)


class Polyphonic:
    def __init__(self):
        self.path: str = os.path.join(BASE_DIR, config.system.data_path, config.polyphonic.dict_path)
        self.polyphonic_dict = load_polyphonic_dict(self.path)
        self.polyphonic_words = self.polyphonic_dict["polyphonic"]

        for word in self.polyphonic_words.keys():
            jieba.add_word(word)

        pypinyin.load_phrases_dict(self.polyphonic_dict)

    def correct_pronunciation(self, word: str, pinyin: list[list[str]] | tuple[list[str], list[str]], style=1):
        if word in self.polyphonic_words.keys():
            _pinyin = self.polyphonic_words[word]
            if style == 1:
                pinyin: list[list[str]] = [[to_tone(x)] for x in _pinyin]
            elif style == 2:
                initials = [to_initials(x) for x in _pinyin]
                finals = [to_finals_tone3(x, neutral_tone_with_five=True) for x in _pinyin]
                pinyin: tuple[list[str], list[str]] = (initials, finals)
            elif style == 3:  # GPT-SoVITS v2
                pinyin: list[str] = [to_tone(x) for x in _pinyin]

        return pinyin

    def update_polyphonic(self):
        self.polyphonic_dict = load_polyphonic_dict(self.path)
        self.polyphonic_words = self.polyphonic_dict["polyphonic"]

        for word in self.polyphonic_words.keys():
            jieba.add_word(word)

        pypinyin.load_phrases_dict(self.polyphonic_dict)

    def save_polyphonic(self):
        save_polyphonic_dict(self.path, self.polyphonic_dict)


corrector: Polyphonic | None = None


def load_polyphonic():
    global corrector
    if corrector is None:
        corrector = Polyphonic()


def get_polyphonic_dict():
    if corrector is None:
        load_polyphonic()
    return corrector.polyphonic_dict


def correct_pronunciation(word, pinyin, style=1):
    if corrector is None:
        load_polyphonic()
    return corrector.correct_pronunciation(word, pinyin, style)


def add_polyphonic(word, pinyin):
    if corrector is None:
        load_polyphonic()

    if len(word) != len(pinyin):
        return False

    corrector.polyphonic_words[word] = pinyin
    corrector.save_polyphonic()
    return True


def delete_polyphonic(word):
    if corrector is None:
        load_polyphonic()

    if word in corrector.polyphonic_words.keys():
        del corrector.polyphonic_words[word]
        corrector.save_polyphonic()
        return True

    return False


def update_polyphonic():
    if corrector is None:
        load_polyphonic()
    corrector.update_polyphonic()