File size: 13,307 Bytes
7e9eac8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ebb01fc
7e9eac8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ebb01fc
7e9eac8
 
0969649
7e9eac8
 
 
 
 
 
 
40de727
4cd7d34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40de727
588b97f
f7215c7
bd7955f
 
4cd7d34
 
 
bd7955f
4cd7d34
 
 
 
 
 
 
 
 
 
 
 
 
dd6a80b
 
4cd7d34
 
 
 
 
 
 
 
 
 
 
 
7e9eac8
 
ebb01fc
7e9eac8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23e7dca
 
 
 
 
 
7e9eac8
 
 
 
 
 
ebb01fc
7e9eac8
 
0969649
7e9eac8
23e7dca
 
7e9eac8
 
 
 
 
 
d5f48a5
51a3cc9
407c586
51a3cc9
7552061
 
51a3cc9
 
d5f48a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15402cf
 
 
 
 
 
 
 
d5f48a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e9eac8
ebb01fc
7e9eac8
ebb01fc
0c75795
 
7e9eac8
ebb01fc
3344c9b
 
9c1cd2f
 
4826b58
 
20b641c
 
 
 
267004a
 
f18e30d
 
7e9eac8
 
 
 
073ea05
407c586
 
 
7e9eac8
4fb6891
 
 
 
7e9eac8
51a3cc9
ead5f56
bddfec7
73ba5d9
cbfcc94
51a3cc9
4fb6891
51a3cc9
 
83bc222
 
7e9eac8
 
 
dcb3ca8
4930465
7552061
48dc914
7552061
 
4930465
f7215c7
 
dcb3ca8
f7215c7
 
 
 
 
dcb3ca8
f7215c7
 
 
dcb3ca8
 
f7215c7
 
 
4930465
 
 
 
 
 
 
 
 
7e9eac8
 
3344c9b
f7215c7
 
 
 
 
 
 
 
dcb3ca8
3344c9b
 
9c1cd2f
 
71288ec
 
 
d5f48a5
71288ec
9c1cd2f
7e9eac8
4826b58
34a7ff6
 
d5f48a5
 
4826b58
ae43e39
 
 
4826b58
 
20b641c
 
1caf33f
20b641c
 
 
 
 
 
 
 
 
267004a
 
 
 
 
f18e30d
 
 
 
 
 
7e9eac8
 
407c586
 
267004a
f18e30d
267004a
40de727
267004a
9c1cd2f
20b641c
7e9eac8
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# Copyright      2022-2023  Xiaomi Corp.        (authors: Fangjun Kuang)
#
# See LICENSE for clarification regarding multiple authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from functools import lru_cache

import sherpa_onnx
from huggingface_hub import hf_hub_download


def get_file(
    repo_id: str,
    filename: str,
    subfolder: str = ".",
) -> str:
    model_filename = hf_hub_download(
        repo_id=repo_id,
        filename=filename,
        subfolder=subfolder,
    )
    return model_filename


@lru_cache(maxsize=10)
def _get_vits_vctk(repo_id: str, speed: float) -> sherpa_onnx.OfflineTts:
    assert repo_id == "csukuangfj/vits-vctk"

    model = get_file(
        repo_id=repo_id,
        filename="vits-vctk.onnx",
        subfolder=".",
    )

    lexicon = get_file(
        repo_id=repo_id,
        filename="lexicon.txt",
        subfolder=".",
    )

    tokens = get_file(
        repo_id=repo_id,
        filename="tokens.txt",
        subfolder=".",
    )

    tts_config = sherpa_onnx.OfflineTtsConfig(
        model=sherpa_onnx.OfflineTtsModelConfig(
            vits=sherpa_onnx.OfflineTtsVitsModelConfig(
                model=model,
                lexicon=lexicon,
                tokens=tokens,
                length_scale=1.0 / speed,
            ),
            provider="cpu",
            debug=True,
            num_threads=2,
        )
    )
    tts = sherpa_onnx.OfflineTts(tts_config)

    return tts


@lru_cache(maxsize=10)
def _get_vits_ljs(repo_id: str, speed: float) -> sherpa_onnx.OfflineTts:
    assert repo_id == "csukuangfj/vits-ljs"

    model = get_file(
        repo_id=repo_id,
        filename="vits-ljs.onnx",
        subfolder=".",
    )

    lexicon = get_file(
        repo_id=repo_id,
        filename="lexicon.txt",
        subfolder=".",
    )

    tokens = get_file(
        repo_id=repo_id,
        filename="tokens.txt",
        subfolder=".",
    )

    tts_config = sherpa_onnx.OfflineTtsConfig(
        model=sherpa_onnx.OfflineTtsModelConfig(
            vits=sherpa_onnx.OfflineTtsVitsModelConfig(
                model=model,
                lexicon=lexicon,
                tokens=tokens,
                length_scale=1.0 / speed,
            ),
            provider="cpu",
            debug=True,
            num_threads=2,
        )
    )
    tts = sherpa_onnx.OfflineTts(tts_config)

    return tts


@lru_cache(maxsize=10)
def _get_vits_piper(repo_id: str, speed: float) -> sherpa_onnx.OfflineTts:
    n = len("vits-piper-")
    name = repo_id.split("/")[1][n:]

    model = get_file(
        repo_id=repo_id,
        filename=f"{name}.onnx",
        subfolder=".",
    )

    tokens = get_file(
        repo_id=repo_id,
        filename="tokens.txt",
        subfolder=".",
    )

    tts_config = sherpa_onnx.OfflineTtsConfig(
        model=sherpa_onnx.OfflineTtsModelConfig(
            vits=sherpa_onnx.OfflineTtsVitsModelConfig(
                model=model,
                lexicon="",
                data_dir="/tmp/espeak-ng-data",
                tokens=tokens,
                length_scale=1.0 / speed,
            ),
            provider="cpu",
            debug=True,
            num_threads=2,
        )
    )
    tts = sherpa_onnx.OfflineTts(tts_config)

    return tts


@lru_cache(maxsize=10)
def _get_vits_zh_aishell3(repo_id: str, speed: float) -> sherpa_onnx.OfflineTts:
    assert repo_id == "csukuangfj/vits-zh-aishell3"

    model = get_file(
        repo_id=repo_id,
        filename="vits-aishell3.onnx",
        subfolder=".",
    )

    lexicon = get_file(
        repo_id=repo_id,
        filename="lexicon.txt",
        subfolder=".",
    )

    tokens = get_file(
        repo_id=repo_id,
        filename="tokens.txt",
        subfolder=".",
    )

    rule_fst = get_file(
        repo_id=repo_id,
        filename="rule.fst",
        subfolder=".",
    )

    tts_config = sherpa_onnx.OfflineTtsConfig(
        model=sherpa_onnx.OfflineTtsModelConfig(
            vits=sherpa_onnx.OfflineTtsVitsModelConfig(
                model=model,
                lexicon=lexicon,
                tokens=tokens,
                length_scale=1.0 / speed,
            ),
            provider="cpu",
            debug=True,
            num_threads=2,
        ),
        rule_fsts=rule_fst,
    )
    tts = sherpa_onnx.OfflineTts(tts_config)

    return tts


@lru_cache(maxsize=10)
def _get_vits_hf(repo_id: str, speed: float) -> sherpa_onnx.OfflineTts:
    if "fanchen" in repo_id or "vits-cantonese-hf-xiaomaiiwn" in repo_id:
        model = repo_id.split("/")[-1]
    elif "coqui" in repo_id:
        model = "model"
    else:
        model = repo_id.split("-")[-1]

    model = get_file(
        repo_id=repo_id,
        filename=f"{model}.onnx",
        subfolder=".",
    )

    lexicon = get_file(
        repo_id=repo_id,
        filename="lexicon.txt",
        subfolder=".",
    )

    tokens = get_file(
        repo_id=repo_id,
        filename="tokens.txt",
        subfolder=".",
    )

    if "coqui" not in repo_id:
        rule_fst = get_file(
            repo_id=repo_id,
            filename="rule.fst",
            subfolder=".",
        )
    else:
        rule_fst = ""

    tts_config = sherpa_onnx.OfflineTtsConfig(
        model=sherpa_onnx.OfflineTtsModelConfig(
            vits=sherpa_onnx.OfflineTtsVitsModelConfig(
                model=model,
                lexicon=lexicon,
                tokens=tokens,
                length_scale=1.0 / speed,
            ),
            provider="cpu",
            debug=True,
            num_threads=2,
        ),
        rule_fsts=rule_fst,
    )
    tts = sherpa_onnx.OfflineTts(tts_config)

    return tts


@lru_cache(maxsize=10)
def get_pretrained_model(repo_id: str, speed: float) -> sherpa_onnx.OfflineTts:
    if repo_id in chinese_models:
        return chinese_models[repo_id](repo_id, speed)
    if repo_id in cantonese_models:
        return cantonese_models[repo_id](repo_id, speed)
    elif repo_id in english_models:
        return english_models[repo_id](repo_id, speed)
    elif repo_id in german_models:
        return german_models[repo_id](repo_id, speed)
    elif repo_id in spanish_models:
        return spanish_models[repo_id](repo_id, speed)
    elif repo_id in french_models:
        return french_models[repo_id](repo_id, speed)
    elif repo_id in ukrainian_models:
        return ukrainian_models[repo_id](repo_id, speed)
    elif repo_id in russian_models:
        return russian_models[repo_id](repo_id, speed)
    elif repo_id in arabic_models:
        return arabic_models[repo_id](repo_id, speed)
    elif repo_id in catalan_models:
        return catalan_models[repo_id](repo_id, speed)
    else:
        raise ValueError(f"Unsupported repo_id: {repo_id}")


cantonese_models = {
    "csukuangfj/vits-cantonese-hf-xiaomaiiwn": _get_vits_hf,
}

chinese_models = {
    "csukuangfj/vits-zh-hf-theresa": _get_vits_hf,
    "csukuangfj/vits-zh-hf-eula": _get_vits_hf,
    "csukuangfj/vits-zh-hf-echo": _get_vits_hf,
    "csukuangfj/vits-zh-hf-bronya": _get_vits_hf,
    "csukuangfj/vits-zh-aishell3": _get_vits_zh_aishell3,
    "csukuangfj/vits-zh-hf-fanchen-wnj": _get_vits_hf,
    "csukuangfj/vits-zh-hf-fanchen-C": _get_vits_hf,
    "csukuangfj/vits-zh-hf-fanchen-ZhiHuiLaoZhe": _get_vits_hf,
    "csukuangfj/vits-zh-hf-fanchen-ZhiHuiLaoZhe_new": _get_vits_hf,
    "csukuangfj/vits-zh-hf-fanchen-unity": _get_vits_hf,
    "csukuangfj/vits-zh-hf-doom": _get_vits_hf,
    "csukuangfj/vits-zh-hf-zenyatta": _get_vits_hf,  # 804
    "csukuangfj/vits-zh-hf-abyssinvoker": _get_vits_hf,
    "csukuangfj/vits-zh-hf-keqing": _get_vits_hf,
    #  "csukuangfj/vits-piper-zh_CN-huayan-x_low": _get_vits_piper,
    #  "csukuangfj/vits-piper-zh_CN-huayan-medium": _get_vits_piper,
}

english_models = {
    "csukuangfj/vits-vctk": _get_vits_vctk,  # 109 speakers
    "csukuangfj/vits-ljs": _get_vits_ljs,
    # coqui-ai
    "csukuangfj/vits-coqui-en-vctk": _get_vits_hf,
    "csukuangfj/vits-coqui-en-ljspeech": _get_vits_hf,
    "csukuangfj/vits-coqui-en-ljspeech-neon": _get_vits_hf,
    # piper, US
    "csukuangfj/vits-piper-en_US-amy-low": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-amy-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-arctic-medium": _get_vits_piper,  # 18 speakers
    "csukuangfj/vits-piper-en_US-danny-low": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-hfc_male-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-joe-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-kathleen-low": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-kusal-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-l2arctic-medium": _get_vits_piper,  # 24 speakers
    "csukuangfj/vits-piper-en_US-lessac-low": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-lessac-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-lessac-high": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-libritts-high": _get_vits_piper,  # 904 speakers
    "csukuangfj/vits-piper-en_US-libritts_r-medium": _get_vits_piper,  # 904 speakers
    "csukuangfj/vits-piper-en_US-ryan-low": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-ryan-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_US-ryan-high": _get_vits_piper,
    # piper, GB
    "csukuangfj/vits-piper-en_GB-alan-low": _get_vits_piper,
    "csukuangfj/vits-piper-en_GB-alan-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_GB-alba-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_GB-jenny_dioco-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_GB-northern_english_male-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_GB-semaine-medium": _get_vits_piper,
    "csukuangfj/vits-piper-en_GB-southern_english_female-low": _get_vits_piper,
    "csukuangfj/vits-piper-en_GB-vctk-medium": _get_vits_piper,
}

german_models = {
    "csukuangfj/vits-piper-de_DE-eva_k-x_low": _get_vits_piper,
    "csukuangfj/vits-piper-de_DE-karlsson-low": _get_vits_piper,
    "csukuangfj/vits-piper-de_DE-kerstin-low": _get_vits_piper,
    "csukuangfj/vits-piper-de_DE-pavoque-low": _get_vits_piper,
    "csukuangfj/vits-piper-de_DE-ramona-low": _get_vits_piper,
    "csukuangfj/vits-piper-de_DE-thorsten-low": _get_vits_piper,
    "csukuangfj/vits-piper-de_DE-thorsten-medium": _get_vits_piper,
    "csukuangfj/vits-piper-de_DE-thorsten-high": _get_vits_piper,
    "csukuangfj/vits-piper-de_DE-thorsten_emotional-medium": _get_vits_piper,  # 8 speakers
}

spanish_models = {
    "csukuangfj/vits-piper-es_ES-carlfm-x_low": _get_vits_piper,
    "csukuangfj/vits-piper-es_ES-davefx-medium": _get_vits_piper,
    "csukuangfj/vits-piper-es_ES-mls_10246-low": _get_vits_piper,
    "csukuangfj/vits-piper-es_ES-mls_9972-low": _get_vits_piper,
    "csukuangfj/vits-piper-es_ES-sharvard-medium": _get_vits_piper,  # 2 speakers
    "csukuangfj/vits-piper-es_MX-ald-medium": _get_vits_piper,
}

french_models = {
    #  "csukuangfj/vits-piper-fr_FR-gilles-low": _get_vits_piper,
    #  "csukuangfj/vits-piper-fr_FR-mls_1840-low": _get_vits_piper,
    "csukuangfj/vits-piper-fr_FR-upmc-medium": _get_vits_piper,  # 2 speakers, 0-femal, 1-male
    "csukuangfj/vits-piper-fr_FR-siwis-low": _get_vits_piper,  # female
    "csukuangfj/vits-piper-fr_FR-siwis-medium": _get_vits_piper,
    "csukuangfj/vits-piper-fr_FR-tjiho-model1": _get_vits_piper,
    "csukuangfj/vits-piper-fr_FR-tjiho-model2": _get_vits_piper,
    "csukuangfj/vits-piper-fr_FR-tjiho-model3": _get_vits_piper,
}

ukrainian_models = {
    "csukuangfj/vits-piper-uk_UA-lada-x_low": _get_vits_piper,
    #  "csukuangfj/vits-piper-uk_UA-ukrainian_tts-medium": _get_vits_piper, # does not work somehow
}

russian_models = {
    "csukuangfj/vits-piper-ru_RU-denis-medium": _get_vits_piper,
    "csukuangfj/vits-piper-ru_RU-dmitri-medium": _get_vits_piper,
    "csukuangfj/vits-piper-ru_RU-irina-medium": _get_vits_piper,
    "csukuangfj/vits-piper-ru_RU-ruslan-medium": _get_vits_piper,
}

arabic_models = {
    "csukuangfj/vits-piper-ar_JO-kareem-low": _get_vits_piper,
    "csukuangfj/vits-piper-ar_JO-kareem-medium": _get_vits_piper,
}

catalan_models = {
    "csukuangfj/vits-piper-ca_ES-upc_ona-x_low": _get_vits_piper,
    "csukuangfj/vits-piper-ca_ES-upc_ona-medium": _get_vits_piper,
    "csukuangfj/vits-piper-ca_ES-upc_pau-x_low": _get_vits_piper,
}

language_to_models = {
    "English": list(english_models.keys()),
    "Chinese (Mandarin, 普通话)": list(chinese_models.keys()),
    "Cantonese (粤语)": list(cantonese_models.keys()),
    "Arabic": list(arabic_models.keys()),
    "Catalan": list(catalan_models.keys()),
    "French": list(french_models.keys()),
    "German": list(german_models.keys()),
    "Russian": list(russian_models.keys()),
    "Spanish": list(spanish_models.keys()),
    "Ukrainian": list(ukrainian_models.keys()),
}