Fangjun Kuang
Committed by GitHub

Add scripts for exporting Piper TTS models to sherpa-onnx (#2299)

  1 +name: export-piper
  2 +
  3 +on:
  4 + push:
  5 + branches:
  6 + - export-piper
  7 + workflow_dispatch:
  8 +
  9 +concurrency:
  10 + group: export-piper-${{ github.ref }}
  11 + cancel-in-progress: true
  12 +
  13 +jobs:
  14 + export-piper:
  15 + if: github.repository_owner == 'k2-fsa' || github.repository_owner == 'csukuangfj'
  16 + name: ${{ matrix.index }}/${{ matrix.total }}
  17 + runs-on: ${{ matrix.os }}
  18 + strategy:
  19 + fail-fast: false
  20 + matrix:
  21 + os: [ubuntu-latest]
  22 + python-version: ["3.10"]
  23 + total: ["20"]
  24 + index: [
  25 + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
  26 + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
  27 + ]
  28 + # total: ["1"]
  29 + # index: ["0"]
  30 +
  31 + steps:
  32 + - uses: actions/checkout@v4
  33 +
  34 + - name: Setup Python ${{ matrix.python-version }}
  35 + uses: actions/setup-python@v5
  36 + with:
  37 + python-version: ${{ matrix.python-version }}
  38 +
  39 + - name: Install Python dependencies
  40 + shell: bash
  41 + run: |
  42 + python3 -m pip install --upgrade pip jinja2 iso639-lang onnx==1.17.0 onnxruntime==1.17.1 sherpa-onnx onnxmltools==1.13.0
  43 + python3 -m pip install "numpy<2" soundfile
  44 +
  45 + - name: Generate script
  46 + env:
  47 + HF_TOKEN: ${{ secrets.HF_TOKEN }}
  48 + shell: bash
  49 + run: |
  50 + cd scripts/piper
  51 +
  52 + total=${{ matrix.total }}
  53 + index=${{ matrix.index }}
  54 +
  55 + git config --global user.email "csukuangfj@gmail.com"
  56 + git config --global user.name "Fangjun Kuang"
  57 +
  58 + git clone https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/sherpa-onnx-tts-samples hf
  59 +
  60 + python3 ./generate.py --total $total --index $index
  61 + chmod +x ./generate.sh
  62 + ls -lh
  63 +
  64 + - name: Show script
  65 + shell: bash
  66 + run: |
  67 + cd scripts/piper
  68 + cat ./generate.sh
  69 +
  70 + - name: Run script
  71 + shell: bash
  72 + run: |
  73 + cd scripts/piper
  74 + ./generate.sh
  75 +
  76 + - name: Show generated mp3 files
  77 + shell: bash
  78 + run: |
  79 + cd scripts/piper
  80 + ls -lh hf/piper/mp3/*
  81 + echo "----"
  82 + ls -lh hf/piper/mp3/*/*
  83 +
  84 + - name: Push generated mp3 files
  85 + env:
  86 + HF_TOKEN: ${{ secrets.HF_TOKEN }}
  87 + uses: nick-fields/retry@v3
  88 + with:
  89 + max_attempts: 20
  90 + timeout_seconds: 200
  91 + shell: bash
  92 + command: |
  93 + cd scripts/piper/hf
  94 + git pull --rebase
  95 + git lfs track "*.mp3"
  96 + git status .
  97 + git add .
  98 + git commit -m 'Add mp3 files'
  99 + git push https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/sherpa-onnx-tts-samples main
  100 +
  101 + - name: Show generated model files
  102 + shell: bash
  103 + run: |
  104 + cd scripts/piper
  105 + ls -lh *.tar.bz2
  106 +
  107 + - name: Show generated model files(2)
  108 + shell: bash
  109 + run: |
  110 + cd scripts/piper
  111 + ls -lh release/
  112 +
  113 + - name: Publish to huggingface
  114 + env:
  115 + HF_TOKEN: ${{ secrets.HF_TOKEN }}
  116 + uses: nick-fields/retry@v3
  117 + with:
  118 + max_attempts: 20
  119 + timeout_seconds: 200
  120 + shell: bash
  121 + command: |
  122 + git config --global user.email "csukuangfj@gmail.com"
  123 + git config --global user.name "Fangjun Kuang"
  124 +
  125 + export GIT_LFS_SKIP_SMUDGE=1
  126 + export GIT_CLONE_PROTECTION_ACTIVE=false
  127 +
  128 + dirs=(
  129 + vits-piper-de_DE-glados-high
  130 + vits-piper-de_DE-glados-low
  131 + vits-piper-de_DE-glados-medium
  132 + vits-piper-de_DE-glados_turret-high
  133 + vits-piper-de_DE-glados_turret-low
  134 + vits-piper-de_DE-glados_turret-medium
  135 + vits-piper-en_US-glados-high
  136 + )
  137 + for d in ${dirs[@]}; do
  138 + src=scripts/piper/release/$d
  139 + if [ ! -d $src ]; then
  140 + continue;
  141 + fi
  142 +
  143 + rm -rf huggingface
  144 + git clone https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/$d huggingface
  145 + cp -a $src/* ./huggingface
  146 + pushd huggingface
  147 + git lfs track "*.onnx"
  148 + git lfs track af_dict
  149 + git lfs track ar_dict
  150 + git lfs track cmn_dict
  151 + git lfs track da_dict en_dict fa_dict hu_dict ia_dict it_dict lb_dict phondata ru_dict ta_dict
  152 + git lfs track ur_dict yue_dict
  153 +
  154 + git status
  155 + git add .
  156 + git status
  157 + git commit -m "add models"
  158 + git push https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/$d main
  159 + popd
  160 +
  161 + done
  162 +
  163 + - name: Release
  164 + if: github.repository_owner == 'csukuangfj'
  165 + uses: svenstaro/upload-release-action@v2
  166 + with:
  167 + file_glob: true
  168 + file: ./scripts/piper/vits-piper-*.tar.bz2
  169 + overwrite: true
  170 + repo_name: k2-fsa/sherpa-onnx
  171 + repo_token: ${{ secrets.UPLOAD_GH_SHERPA_ONNX_TOKEN }}
  172 + tag: tts-models
  173 +
  174 + - name: Release
  175 + if: github.repository_owner == 'k2-fsa'
  176 + uses: svenstaro/upload-release-action@v2
  177 + with:
  178 + file_glob: true
  179 + file: ./scripts/piper/vits-piper-*.tar.bz2
  180 + overwrite: true
  181 + tag: tts-models
  1 +*.sh
  2 +*.onnx
  3 +*.json
  4 +MODEL_CARD
  5 +generate_samples-vits-piper*.py
  1 +#!/usr/bin/env python3
  2 +# Copyright 2025 Xiaomi Corp. (authors: Fangjun Kuang)
  3 +
  4 +import argparse
  5 +import json
  6 +from typing import Any, Dict
  7 +
  8 +import onnx
  9 +from iso639 import Lang
  10 +
  11 +
  12 +def get_args():
  13 + # For en_GB-semaine-medium
  14 + # --name semaine
  15 + # --kind medium
  16 + # --lang en_GB
  17 + parser = argparse.ArgumentParser(
  18 + formatter_class=argparse.ArgumentDefaultsHelpFormatter
  19 + )
  20 + parser.add_argument(
  21 + "--name",
  22 + type=str,
  23 + required=True,
  24 + )
  25 +
  26 + parser.add_argument(
  27 + "--kind",
  28 + type=str,
  29 + required=True,
  30 + )
  31 +
  32 + parser.add_argument(
  33 + "--lang",
  34 + type=str,
  35 + required=True,
  36 + )
  37 + return parser.parse_args()
  38 +
  39 +
  40 +def add_meta_data(filename: str, meta_data: Dict[str, Any]):
  41 + """Add meta data to an ONNX model. It is changed in-place.
  42 +
  43 + Args:
  44 + filename:
  45 + Filename of the ONNX model to be changed.
  46 + meta_data:
  47 + Key-value pairs.
  48 + """
  49 + model = onnx.load(filename)
  50 +
  51 + while len(model.metadata_props):
  52 + model.metadata_props.pop()
  53 +
  54 + for key, value in meta_data.items():
  55 + meta = model.metadata_props.add()
  56 + meta.key = key
  57 + meta.value = str(value)
  58 +
  59 + onnx.save(model, filename)
  60 +
  61 +
  62 +def load_config(filename):
  63 + with open(filename, "r") as file:
  64 + config = json.load(file)
  65 + return config
  66 +
  67 +
  68 +def generate_tokens(config):
  69 + id_map = config["phoneme_id_map"]
  70 + with open("tokens.txt", "w", encoding="utf-8") as f:
  71 + for s, i in id_map.items():
  72 + f.write(f"{s} {i[0]}\n")
  73 + print("Generated tokens.txt")
  74 +
  75 +
  76 +# for en_US-lessac-medium.onnx
  77 +# export LANG=en_US
  78 +# export TYPE=lessac
  79 +# export NAME=medium
  80 +def main():
  81 + args = get_args()
  82 + print(args)
  83 + lang = args.lang
  84 +
  85 + lang_iso = Lang(lang.split("_")[0])
  86 + print(lang, lang_iso)
  87 +
  88 + kind = args.kind
  89 +
  90 + name = args.name
  91 +
  92 + # en_GB-alan-low.onnx.json
  93 + config = load_config(f"{lang}-{name}-{kind}.onnx.json")
  94 +
  95 + print("generate tokens")
  96 + generate_tokens(config)
  97 +
  98 + sample_rate = config["audio"]["sample_rate"]
  99 + if sample_rate == 22500:
  100 + print("Change sample rate from 22500 to 22050")
  101 + sample_rate = 22050
  102 +
  103 + print("add model metadata")
  104 + meta_data = {
  105 + "model_type": "vits",
  106 + "comment": "piper", # must be piper for models from piper
  107 + "language": lang_iso.name,
  108 + "voice": config["espeak"]["voice"], # e.g., en-us
  109 + "has_espeak": 1,
  110 + "n_speakers": config["num_speakers"],
  111 + "sample_rate": sample_rate,
  112 + }
  113 + print(meta_data)
  114 + add_meta_data(f"{lang}-{name}-{kind}.onnx", meta_data)
  115 +
  116 +
  117 +main()
  1 +#!/usr/bin/env python3
  2 +# Copyright 2025 Xiaomi Corp. (authors: Fangjun Kuang)
  3 +
  4 +import argparse
  5 +
  6 +import onnxmltools
  7 +from onnxmltools.utils.float16_converter import convert_float_to_float16
  8 +from onnxruntime.quantization import QuantType, quantize_dynamic
  9 +
  10 +
  11 +def get_args():
  12 + parser = argparse.ArgumentParser()
  13 + parser.add_argument(
  14 + "--input",
  15 + type=str,
  16 + required=True,
  17 + )
  18 + parser.add_argument(
  19 + "--output-fp16",
  20 + type=str,
  21 + required=True,
  22 + )
  23 +
  24 + parser.add_argument(
  25 + "--output-int8",
  26 + type=str,
  27 + required=True,
  28 + )
  29 + return parser.parse_args()
  30 +
  31 +
  32 +# for op_block_list, see also
  33 +# https://github.com/microsoft/onnxruntime/blob/089c52e4522491312e6839af146a276f2351972e/onnxruntime/python/tools/transformers/float16.py#L115
  34 +#
  35 +# libc++abi: terminating with uncaught exception of type Ort::Exception:
  36 +# Type Error: Type (tensor(float16)) of output arg (/dp/RandomNormalLike_output_0)
  37 +# of node (/dp/RandomNormalLike) does not match expected type (tensor(float)).
  38 +#
  39 +# libc++abi: terminating with uncaught exception of type Ort::Exception:
  40 +# This is an invalid model. Type Error: Type 'tensor(float16)' of input
  41 +# parameter (/enc_p/encoder/attn_layers.0/Constant_84_output_0) of
  42 +# operator (Range) in node (/Range_1) is invalid.
  43 +def export_onnx_fp16(onnx_fp32_path, onnx_fp16_path):
  44 + onnx_fp32_model = onnxmltools.utils.load_model(onnx_fp32_path)
  45 + onnx_fp16_model = convert_float_to_float16(
  46 + onnx_fp32_model,
  47 + keep_io_types=True,
  48 + op_block_list=[
  49 + "RandomNormalLike",
  50 + "Range",
  51 + ],
  52 + )
  53 + onnxmltools.utils.save_model(onnx_fp16_model, onnx_fp16_path)
  54 +
  55 +
  56 +def main():
  57 + args = get_args()
  58 + print(args)
  59 +
  60 + in_filename = args.input
  61 + output_fp16 = args.output_fp16
  62 + output_int8 = args.output_int8
  63 +
  64 + quantize_dynamic(
  65 + model_input=in_filename,
  66 + model_output=output_int8,
  67 + weight_type=QuantType.QUInt8,
  68 + )
  69 +
  70 + export_onnx_fp16(in_filename, output_fp16)
  71 +
  72 +
  73 +if __name__ == "__main__":
  74 + main()
  1 +#!/usr/bin/env python3
  2 +# Copyright 2025 Xiaomi Corp. (authors: Fangjun Kuang)
  3 +
  4 +import argparse
  5 +from dataclasses import dataclass
  6 +from pathlib import Path
  7 +
  8 +import jinja2
  9 +
  10 +"""
  11 +TODO:
  12 + - add https://huggingface.co/csukuangfj/vits-piper-en_US-glados
  13 +"""
  14 +
  15 +
  16 +def get_args():
  17 + parser = argparse.ArgumentParser()
  18 + parser.add_argument(
  19 + "--total",
  20 + type=int,
  21 + default=1,
  22 + help="Number of runners",
  23 + )
  24 + parser.add_argument(
  25 + "--index",
  26 + type=int,
  27 + default=0,
  28 + help="Index of the current runner",
  29 + )
  30 + return parser.parse_args()
  31 +
  32 +
  33 +@dataclass
  34 +class PiperModel:
  35 + # For en_GB-semaine-medium
  36 + name: str # semaine
  37 + kind: str # e.g. medium
  38 + sr: int # sample rate
  39 + ns: int # number of speakers
  40 + lang: str = "" # e.g., en_GB
  41 + cmd: str = ""
  42 + model_name: str = ""
  43 + text: str = ""
  44 + index: int = 0
  45 + url: str = ""
  46 +
  47 +
  48 +# arabic
  49 +def get_ar_models():
  50 + ar_jo = [
  51 + PiperModel(name="kareem", kind="low", sr=16000, ns=1),
  52 + PiperModel(name="kareem", kind="medium", sr=22050, ns=1),
  53 + ]
  54 +
  55 + for m in ar_jo:
  56 + m.lang = "ar_JO"
  57 + if m.model_name == "":
  58 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  59 +
  60 + ans = ar_jo
  61 +
  62 + for m in ans:
  63 + m.text = "كيف حالك اليوم؟"
  64 + code = m.lang[:2]
  65 + if m.cmd == "":
  66 + m.cmd = f"""
  67 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  68 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  69 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  70 + """
  71 + if m.url == "":
  72 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  73 +
  74 + return ans
  75 +
  76 +
  77 +# catlan
  78 +def get_ca_models():
  79 + ca_es = [
  80 + PiperModel(name="upc_ona", kind="medium", sr=22050, ns=1),
  81 + PiperModel(name="upc_ona", kind="x_low", sr=16000, ns=1),
  82 + PiperModel(name="upc_pau", kind="x_low", sr=16000, ns=1),
  83 + ]
  84 +
  85 + for m in ca_es:
  86 + m.lang = "ca_ES"
  87 + if m.model_name == "":
  88 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  89 +
  90 + ans = ca_es
  91 +
  92 + for m in ans:
  93 + m.text = "Si vols estar ben servit, fes-te tu mateix el llit"
  94 + code = m.lang[:2]
  95 + if m.cmd == "":
  96 + m.cmd = f"""
  97 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  98 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  99 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  100 + """
  101 + if m.url == "":
  102 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  103 +
  104 + return ans
  105 +
  106 +
  107 +# czech
  108 +def get_cs_models():
  109 + cs_cz = [
  110 + PiperModel(name="jirka", kind="low", sr=16000, ns=1),
  111 + PiperModel(name="jirka", kind="medium", sr=22050, ns=1),
  112 + ]
  113 +
  114 + for m in cs_cz:
  115 + m.lang = "cs_CZ"
  116 + if m.model_name == "":
  117 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  118 +
  119 + ans = cs_cz
  120 +
  121 + for m in ans:
  122 + m.text = "Co můžeš udělat dnes, neodkládej na zítřek. "
  123 + code = m.lang[:2]
  124 + if m.cmd == "":
  125 + m.cmd = f"""
  126 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  127 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  128 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  129 + """
  130 + if m.url == "":
  131 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  132 +
  133 + return ans
  134 +
  135 +
  136 +# welsh
  137 +def get_cy_models():
  138 + cy_gb = [
  139 + PiperModel(name="bu_tts", kind="medium", sr=22050, ns=7),
  140 + PiperModel(name="gwryw_gogleddol", kind="medium", sr=22050, ns=1),
  141 + ]
  142 +
  143 + for m in cy_gb:
  144 + m.lang = "cy_GB"
  145 + if m.model_name == "":
  146 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  147 +
  148 + ans = cy_gb
  149 +
  150 + for m in ans:
  151 + m.text = "Ni all y gwynt ei hunan ei ddilyn, ac felly mae’n rhaid i’r gŵyr ddod i’r gorwel i weld y llwybr yn gyfarwydd"
  152 + code = m.lang[:2]
  153 + if m.cmd == "":
  154 + m.cmd = f"""
  155 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  156 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  157 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  158 + """
  159 + if m.url == "":
  160 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  161 +
  162 + return ans
  163 +
  164 +
  165 +# danish
  166 +def get_da_models():
  167 + da_dk = [
  168 + PiperModel(name="talesyntese", kind="medium", sr=22050, ns=1),
  169 + ]
  170 +
  171 + for m in da_dk:
  172 + m.lang = "da_DK"
  173 + if m.model_name == "":
  174 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  175 +
  176 + ans = da_dk
  177 +
  178 + for m in ans:
  179 + m.text = (
  180 + "Hvis du går langsomt, men aldrig stopper, når du ender frem til dit mål."
  181 + )
  182 + code = m.lang[:2]
  183 + if m.cmd == "":
  184 + m.cmd = f"""
  185 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  186 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  187 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  188 + """
  189 + if m.url == "":
  190 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  191 +
  192 + return ans
  193 +
  194 +
  195 +# greek
  196 +def get_el_models():
  197 + el_gr = [
  198 + PiperModel(name="rapunzelina", kind="low", sr=16000, ns=1),
  199 + ]
  200 +
  201 + for m in el_gr:
  202 + m.lang = "el_GR"
  203 + if m.model_name == "":
  204 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  205 +
  206 + ans = el_gr
  207 +
  208 + for m in ans:
  209 + m.text = (
  210 + "Όταν το δέντρο είναι μικρό, το στρέβλεις· όταν είναι μεγάλο, το λυγίζεις."
  211 + )
  212 + code = m.lang[:2]
  213 + if m.cmd == "":
  214 + m.cmd = f"""
  215 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  216 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  217 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  218 + """
  219 + if m.url == "":
  220 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  221 +
  222 + return ans
  223 +
  224 +
  225 +# spanish
  226 +def get_es_models():
  227 + es_ES = [
  228 + PiperModel(name="carlfm", kind="x_low", sr=16000, ns=1),
  229 + PiperModel(name="davefx", kind="medium", sr=22050, ns=1),
  230 + PiperModel(name="sharvard", kind="medium", sr=22050, ns=2),
  231 + ]
  232 +
  233 + es_MX = [
  234 + PiperModel(name="ald", kind="medium", sr=22050, ns=1),
  235 + PiperModel(name="claude", kind="high", sr=22050, ns=1),
  236 + ]
  237 +
  238 + for m in es_ES:
  239 + m.lang = "es_ES"
  240 +
  241 + for m in es_MX:
  242 + m.lang = "es_MX"
  243 +
  244 + ans = es_ES + es_MX
  245 +
  246 + for m in ans:
  247 + if m.model_name == "":
  248 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  249 +
  250 + m.text = "Cuando te encuentres ante una puerta cerrada, no olvides que a veces el destino cierra una puerta para que te desvíes hacia un camino que lleva a una ventana que nunca habrías encontrado por tu cuenta."
  251 + code = m.lang[:2]
  252 + if m.cmd == "":
  253 + m.cmd = f"""
  254 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  255 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  256 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  257 + """
  258 + if m.url == "":
  259 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  260 +
  261 + return ans
  262 +
  263 +
  264 +# persian
  265 +def get_fa_models():
  266 + fa_IR = [
  267 + PiperModel(name="amir", kind="medium", sr=22050, ns=1),
  268 + PiperModel(name="ganji", kind="medium", sr=22050, ns=1),
  269 + PiperModel(name="ganji_adabi", kind="medium", sr=22050, ns=1),
  270 + PiperModel(name="gyro", kind="medium", sr=22050, ns=1),
  271 + PiperModel(name="reza_ibrahim", kind="medium", sr=22050, ns=1),
  272 + ]
  273 +
  274 + for m in fa_IR:
  275 + m.lang = "fa_IR"
  276 + if m.model_name == "":
  277 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  278 +
  279 + ans = fa_IR
  280 +
  281 + for m in ans:
  282 + m.text = "همانطور که کوه ها در برابر باد و باران پایدارند، اما به مرور زمان خرد و پخش می شوند، انسان نیز باید در برابر مشکلات قوی باشد، اما با خرد و خویشتن داری در زندگی به پیش برود."
  283 + code = m.lang[:2]
  284 + if m.cmd == "":
  285 + m.cmd = f"""
  286 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  287 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  288 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  289 + """
  290 + if m.url == "":
  291 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  292 +
  293 + return ans
  294 +
  295 +
  296 +# finnish
  297 +def get_fi_models():
  298 + fi_FI = [
  299 + PiperModel(name="harri", kind="low", sr=16000, ns=1),
  300 + PiperModel(name="harri", kind="medium", sr=22050, ns=1),
  301 + ]
  302 +
  303 + for m in fi_FI:
  304 + m.lang = "fi_FI"
  305 + if m.model_name == "":
  306 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  307 +
  308 + ans = fi_FI
  309 +
  310 + for m in ans:
  311 + m.text = "Sateenkaaren päässä on kultaa, mutta vain ne, jotka siihen uskovat, voivat sen löytää."
  312 + code = m.lang[:2]
  313 + if m.cmd == "":
  314 + m.cmd = f"""
  315 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  316 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  317 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  318 + """
  319 + if m.url == "":
  320 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  321 +
  322 + return ans
  323 +
  324 +
  325 +# french
  326 +def get_fr_models():
  327 + fr_FR = [
  328 + PiperModel(name="gilles", kind="low", sr=16000, ns=1),
  329 + PiperModel(name="siwis", kind="low", sr=16000, ns=1),
  330 + PiperModel(name="siwis", kind="medium", sr=22050, ns=1),
  331 + PiperModel(name="tom", kind="medium", sr=44100, ns=1),
  332 + PiperModel(name="upmc", kind="medium", sr=22050, ns=2),
  333 + ]
  334 +
  335 + for m in fr_FR:
  336 + m.lang = "fr_FR"
  337 + if m.model_name == "":
  338 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  339 +
  340 + ans = fr_FR
  341 +
  342 + for m in ans:
  343 + m.text = "Pas de nouvelles, bonnes nouvelles."
  344 + code = m.lang[:2]
  345 + if m.cmd == "":
  346 + m.cmd = f"""
  347 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  348 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  349 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  350 + """
  351 + if m.url == "":
  352 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  353 +
  354 + return ans
  355 +
  356 +
  357 +# hungarian
  358 +def get_hu_models():
  359 + hu_HU = [
  360 + PiperModel(name="anna", kind="medium", sr=22050, ns=1),
  361 + PiperModel(name="berta", kind="medium", sr=22050, ns=1),
  362 + PiperModel(name="imre", kind="medium", sr=22050, ns=1),
  363 + ]
  364 +
  365 + for m in hu_HU:
  366 + m.lang = "hu_HU"
  367 + if m.model_name == "":
  368 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  369 +
  370 + ans = hu_HU
  371 +
  372 + for m in ans:
  373 + m.text = "Ha északról fúj a szél, a lányok nem lógnak együtt."
  374 + code = m.lang[:2]
  375 + if m.cmd == "":
  376 + m.cmd = f"""
  377 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  378 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  379 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  380 + """
  381 + if m.url == "":
  382 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  383 +
  384 + return ans
  385 +
  386 +
  387 +# icelandic
  388 +def get_is_models():
  389 + is_IS = [
  390 + PiperModel(name="bui", kind="medium", sr=22050, ns=1),
  391 + PiperModel(name="salka", kind="medium", sr=22050, ns=1),
  392 + PiperModel(name="steinn", kind="medium", sr=22050, ns=1),
  393 + PiperModel(name="ugla", kind="medium", sr=22050, ns=1),
  394 + ]
  395 +
  396 + for m in is_IS:
  397 + m.lang = "is_IS"
  398 + if m.model_name == "":
  399 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  400 +
  401 + ans = is_IS
  402 +
  403 + for m in ans:
  404 + m.text = "Farðu með allt, eða farðu ekki."
  405 + code = m.lang[:2]
  406 + if m.cmd == "":
  407 + m.cmd = f"""
  408 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  409 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  410 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  411 + """
  412 + if m.url == "":
  413 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  414 +
  415 + return ans
  416 +
  417 +
  418 +# italian
  419 +def get_it_models():
  420 + it_IT = [
  421 + PiperModel(name="paola", kind="medium", sr=22050, ns=1),
  422 + PiperModel(name="riccardo", kind="x_low", sr=16000, ns=1),
  423 + ]
  424 +
  425 + for m in it_IT:
  426 + m.lang = "it_IT"
  427 + if m.model_name == "":
  428 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  429 +
  430 + ans = it_IT
  431 +
  432 + for m in ans:
  433 + m.text = (
  434 + "Se vuoi andare veloce, vai da solo; se vuoi andare lontano, vai insieme."
  435 + )
  436 + code = m.lang[:2]
  437 + if m.cmd == "":
  438 + m.cmd = f"""
  439 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  440 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  441 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  442 + """
  443 + if m.url == "":
  444 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  445 +
  446 + return ans
  447 +
  448 +
  449 +# georgian
  450 +def get_ka_models():
  451 + ka_GE = [
  452 + PiperModel(name="natia", kind="medium", sr=22050, ns=1),
  453 + ]
  454 +
  455 + for m in ka_GE:
  456 + m.lang = "ka_GE"
  457 + if m.model_name == "":
  458 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  459 +
  460 + ans = ka_GE
  461 +
  462 + for m in ans:
  463 + m.text = "ღვინო თბილისში, საქართველო სამტრედში"
  464 + code = m.lang[:2]
  465 + if m.cmd == "":
  466 + m.cmd = f"""
  467 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  468 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  469 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  470 + """
  471 + if m.url == "":
  472 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  473 +
  474 + return ans
  475 +
  476 +
  477 +# kazakh
  478 +def get_kk_models():
  479 + kk_KZ = [
  480 + PiperModel(name="iseke", kind="x_low", sr=16000, ns=1),
  481 + PiperModel(name="issai", kind="high", sr=22050, ns=6),
  482 + PiperModel(name="raya", kind="x_low", sr=16000, ns=1),
  483 + ]
  484 +
  485 + for m in kk_KZ:
  486 + m.lang = "kk_KZ"
  487 + if m.model_name == "":
  488 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  489 +
  490 + ans = kk_KZ
  491 +
  492 + for m in ans:
  493 + m.text = "Әлемнің жұлдыздары сенің көзің, жаным."
  494 + code = m.lang[:2]
  495 + if m.cmd == "":
  496 + m.cmd = f"""
  497 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  498 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  499 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  500 + """
  501 + if m.url == "":
  502 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  503 +
  504 + return ans
  505 +
  506 +
  507 +# luxembourgish
  508 +def get_lb_models():
  509 + lb_LU = [
  510 + PiperModel(name="marylux", kind="medium", sr=22050, ns=1),
  511 + ]
  512 +
  513 + for m in lb_LU:
  514 + m.lang = "lb_LU"
  515 + if m.model_name == "":
  516 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  517 +
  518 + ans = lb_LU
  519 +
  520 + for m in ans:
  521 + m.text = "Op der Haaptstrooss sinn all Stroossen Brécken, awer d'Dier kann iwwerall erreecht ginn."
  522 + code = m.lang[:2]
  523 + if m.cmd == "":
  524 + m.cmd = f"""
  525 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  526 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  527 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  528 + """
  529 + if m.url == "":
  530 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  531 +
  532 + return ans
  533 +
  534 +
  535 +# latvian
  536 +def get_lv_models():
  537 + lv_LV = [
  538 + PiperModel(name="aivars", kind="medium", sr=22050, ns=1),
  539 + ]
  540 +
  541 + for m in lv_LV:
  542 + m.lang = "lv_LV"
  543 + if m.model_name == "":
  544 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  545 +
  546 + ans = lv_LV
  547 +
  548 + for m in ans:
  549 + m.text = "Zeme nenes augļus, ja tēvs sēj, bet māte auž."
  550 + code = m.lang[:2]
  551 + if m.cmd == "":
  552 + m.cmd = f"""
  553 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  554 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  555 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  556 + """
  557 + if m.url == "":
  558 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  559 +
  560 + return ans
  561 +
  562 +
  563 +# malayalam
  564 +def get_ml_models():
  565 + ml_IN = [
  566 + PiperModel(name="arjun", kind="medium", sr=22050, ns=1),
  567 + PiperModel(name="meera", kind="medium", sr=22050, ns=1),
  568 + ]
  569 +
  570 + for m in ml_IN:
  571 + m.lang = "ml_IN"
  572 + if m.model_name == "":
  573 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  574 +
  575 + ans = ml_IN
  576 +
  577 + for m in ans:
  578 + m.text = "മണ്ണ് മരിക്കുമ്പോൾ കാട്ടിലെ വെള്ളവും മരിക്കുന്നു."
  579 + code = m.lang[:2]
  580 + if m.cmd == "":
  581 + m.cmd = f"""
  582 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  583 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  584 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  585 + """
  586 + if m.url == "":
  587 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  588 +
  589 + return ans
  590 +
  591 +
  592 +# Nepali
  593 +def get_ne_models():
  594 + ne_NP = [
  595 + PiperModel(name="chitwan", kind="medium", sr=22050, ns=1),
  596 + PiperModel(name="google", kind="medium", sr=22050, ns=18),
  597 + PiperModel(name="google", kind="x_low", sr=16000, ns=18),
  598 + ]
  599 +
  600 + for m in ne_NP:
  601 + m.lang = "ne_NP"
  602 + if m.model_name == "":
  603 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  604 +
  605 + ans = ne_NP
  606 +
  607 + for m in ans:
  608 + m.text = "घाँसको पातले पहाडलाई अभिवादन गर्दै झुक्छ।"
  609 + code = m.lang[:2]
  610 + if m.cmd == "":
  611 + m.cmd = f"""
  612 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  613 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  614 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  615 + """
  616 + if m.url == "":
  617 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  618 +
  619 + return ans
  620 +
  621 +
  622 +# dutch
  623 +def get_nl_models():
  624 + nl_BE = [
  625 + PiperModel(name="nathalie", kind="medium", sr=22050, ns=1),
  626 + PiperModel(name="nathalie", kind="x_low", sr=16000, ns=1),
  627 + ]
  628 +
  629 + nl_NL = [
  630 + PiperModel(name="pim", kind="medium", sr=22050, ns=1),
  631 + PiperModel(name="ronnie", kind="medium", sr=22050, ns=1),
  632 + ]
  633 +
  634 + for m in nl_BE:
  635 + m.lang = "nl_BE"
  636 +
  637 + for m in nl_NL:
  638 + m.lang = "nl_NL"
  639 +
  640 + ans = nl_BE + nl_NL
  641 +
  642 + for m in ans:
  643 + m.text = "God schiep het water, maar de Nederlander schiep de dijk"
  644 +
  645 + if m.model_name == "":
  646 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  647 +
  648 + code = m.lang[:2]
  649 + if m.cmd == "":
  650 + m.cmd = f"""
  651 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  652 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  653 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  654 + """
  655 + if m.url == "":
  656 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  657 +
  658 + return ans
  659 +
  660 +
  661 +# norwegian
  662 +def get_no_models():
  663 + no_NO = [
  664 + PiperModel(name="talesyntese", kind="medium", sr=22050, ns=1),
  665 + ]
  666 +
  667 + for m in no_NO:
  668 + m.lang = "no_NO"
  669 +
  670 + ans = no_NO
  671 +
  672 + for m in ans:
  673 + m.text = "Uskyldig kan stormen veroorzaken"
  674 +
  675 + if m.model_name == "":
  676 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  677 +
  678 + code = m.lang[:2]
  679 + if m.cmd == "":
  680 + m.cmd = f"""
  681 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  682 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  683 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  684 + """
  685 + if m.url == "":
  686 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  687 +
  688 + return ans
  689 +
  690 +
  691 +# polish
  692 +def get_pl_models():
  693 + pl_PL = [
  694 + PiperModel(name="darkman", kind="medium", sr=22050, ns=1),
  695 + PiperModel(name="gosia", kind="medium", sr=22050, ns=1),
  696 + PiperModel(name="mc_speech", kind="medium", sr=22050, ns=1),
  697 + ]
  698 +
  699 + for m in pl_PL:
  700 + m.lang = "pl_PL"
  701 +
  702 + ans = pl_PL
  703 +
  704 + for m in ans:
  705 + m.text = "Nieważne, za kogo walczysz, i tak popełnisz błąd"
  706 +
  707 + if m.model_name == "":
  708 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  709 +
  710 + code = m.lang[:2]
  711 + if m.cmd == "":
  712 + m.cmd = f"""
  713 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  714 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  715 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  716 + """
  717 + if m.url == "":
  718 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  719 +
  720 + return ans
  721 +
  722 +
  723 +# Portuguese
  724 +def get_pt_models():
  725 + pt_BR = [
  726 + PiperModel(name="cadu", kind="medium", sr=22050, ns=1),
  727 + PiperModel(name="edresson", kind="low", sr=16000, ns=1),
  728 + PiperModel(name="faber", kind="medium", sr=22050, ns=1),
  729 + PiperModel(name="jeff", kind="medium", sr=22050, ns=1),
  730 + ]
  731 +
  732 + pt_PT = [
  733 + PiperModel(name="tugão", kind="medium", sr=22050, ns=1),
  734 + ]
  735 +
  736 + for m in pt_BR:
  737 + m.lang = "pt_BR"
  738 +
  739 + for m in pt_PT:
  740 + m.lang = "pt_PT"
  741 +
  742 + ans = pt_BR + pt_PT
  743 +
  744 + for m in ans:
  745 + m.text = "Marinha sem vento, não chega a porto"
  746 +
  747 + if m.model_name == "":
  748 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  749 +
  750 + code = m.lang[:2]
  751 + if m.cmd == "":
  752 + m.cmd = f"""
  753 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  754 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  755 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  756 + """
  757 + if m.url == "":
  758 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  759 +
  760 + return ans
  761 +
  762 +
  763 +# Romanian
  764 +def get_ro_models():
  765 + ro_RO = [
  766 + PiperModel(name="mihai", kind="medium", sr=22050, ns=1),
  767 + ]
  768 +
  769 + for m in ro_RO:
  770 + m.lang = "ro_RO"
  771 +
  772 + ans = ro_RO
  773 +
  774 + for m in ans:
  775 + m.text = "Un foc fără lemne se stinge, o lume fără poveste moare."
  776 +
  777 + if m.model_name == "":
  778 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  779 +
  780 + code = m.lang[:2]
  781 + if m.cmd == "":
  782 + m.cmd = f"""
  783 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  784 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  785 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  786 + """
  787 + if m.url == "":
  788 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  789 +
  790 + return ans
  791 +
  792 +
  793 +# Russian
  794 +def get_ru_models():
  795 + ru_RU = [
  796 + PiperModel(name="denis", kind="medium", sr=22050, ns=1),
  797 + PiperModel(name="dmitri", kind="medium", sr=22050, ns=1),
  798 + PiperModel(name="irina", kind="medium", sr=22050, ns=1),
  799 + PiperModel(name="ruslan", kind="medium", sr=22050, ns=1),
  800 + ]
  801 +
  802 + for m in ru_RU:
  803 + m.lang = "ru_RU"
  804 +
  805 + ans = ru_RU
  806 +
  807 + for m in ans:
  808 + m.text = "Если курица укусит, ей отрубят голову."
  809 +
  810 + if m.model_name == "":
  811 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  812 +
  813 + code = m.lang[:2]
  814 + if m.cmd == "":
  815 + m.cmd = f"""
  816 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  817 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  818 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  819 + """
  820 + if m.url == "":
  821 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  822 +
  823 + return ans
  824 +
  825 +
  826 +# Slovak
  827 +def get_sk_models():
  828 + sk_SK = [
  829 + PiperModel(name="lili", kind="medium", sr=22050, ns=1),
  830 + ]
  831 +
  832 + for m in sk_SK:
  833 + m.lang = "sk_SK"
  834 +
  835 + ans = sk_SK
  836 +
  837 + for m in ans:
  838 + m.text = "Kto nepozná strach, nepozná vôľu."
  839 +
  840 + if m.model_name == "":
  841 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  842 +
  843 + code = m.lang[:2]
  844 + if m.cmd == "":
  845 + m.cmd = f"""
  846 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  847 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  848 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  849 + """
  850 + if m.url == "":
  851 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  852 +
  853 + return ans
  854 +
  855 +
  856 +# Slovenian
  857 +def get_sl_models():
  858 + sl_SI = [
  859 + PiperModel(name="artur", kind="medium", sr=22050, ns=1),
  860 + ]
  861 +
  862 + for m in sl_SI:
  863 + m.lang = "sl_SI"
  864 +
  865 + ans = sl_SI
  866 +
  867 + for m in ans:
  868 + m.text = "Kto sa nebojí, nie je hlúpy."
  869 +
  870 + if m.model_name == "":
  871 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  872 +
  873 + code = m.lang[:2]
  874 + if m.cmd == "":
  875 + m.cmd = f"""
  876 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  877 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  878 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  879 + """
  880 + if m.url == "":
  881 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  882 +
  883 + return ans
  884 +
  885 +
  886 +# Serbian
  887 +def get_sr_models():
  888 + sr_RS = [
  889 + PiperModel(name="serbski_institut", kind="medium", sr=22050, ns=2),
  890 + ]
  891 +
  892 + for m in sr_RS:
  893 + m.lang = "sr_RS"
  894 +
  895 + ans = sr_RS
  896 +
  897 + for m in ans:
  898 + m.text = "Круг не може постојати без свог центра, а нација не може постојати без својих хероја."
  899 +
  900 + if m.model_name == "":
  901 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  902 +
  903 + code = m.lang[:2]
  904 + if m.cmd == "":
  905 + m.cmd = f"""
  906 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  907 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  908 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  909 + """
  910 + if m.url == "":
  911 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  912 +
  913 + return ans
  914 +
  915 +
  916 +# Swedish
  917 +def get_sv_models():
  918 + sv_SE = [
  919 + PiperModel(name="lisa", kind="medium", sr=22050, ns=1),
  920 + PiperModel(name="nst", kind="medium", sr=22050, ns=1),
  921 + ]
  922 +
  923 + for m in sv_SE:
  924 + m.lang = "sv_SE"
  925 +
  926 + ans = sv_SE
  927 +
  928 + for m in ans:
  929 + m.text = "Liten skog, med många träd"
  930 +
  931 + if m.model_name == "":
  932 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  933 +
  934 + code = m.lang[:2]
  935 + if m.cmd == "":
  936 + m.cmd = f"""
  937 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  938 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  939 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  940 + """
  941 + if m.url == "":
  942 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  943 +
  944 + return ans
  945 +
  946 +
  947 +# Swahili
  948 +def get_sw_models():
  949 + sw_CD = [
  950 + PiperModel(name="lanfrica", kind="medium", sr=22050, ns=1),
  951 + ]
  952 +
  953 + for m in sw_CD:
  954 + m.lang = "sw_CD"
  955 +
  956 + ans = sw_CD
  957 +
  958 + for m in ans:
  959 + m.text = "Mtu mmoja hawezi kuiba mazingira."
  960 +
  961 + if m.model_name == "":
  962 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  963 +
  964 + code = m.lang[:2]
  965 + if m.cmd == "":
  966 + m.cmd = f"""
  967 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  968 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  969 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  970 + """
  971 + if m.url == "":
  972 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  973 +
  974 + return ans
  975 +
  976 +
  977 +# Turkish
  978 +def get_tr_models():
  979 + tr_TR = [
  980 + PiperModel(name="dfki", kind="medium", sr=22050, ns=1),
  981 + PiperModel(name="fahrettin", kind="medium", sr=22050, ns=1),
  982 + PiperModel(name="fettah", kind="medium", sr=22050, ns=1),
  983 + ]
  984 +
  985 + for m in tr_TR:
  986 + m.lang = "tr_TR"
  987 +
  988 + ans = tr_TR
  989 +
  990 + for m in ans:
  991 + m.text = "Bir evin duvarları, bir adamın sözü, bir kadının gülü kırılmaz"
  992 +
  993 + if m.model_name == "":
  994 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  995 +
  996 + code = m.lang[:2]
  997 + if m.cmd == "":
  998 + m.cmd = f"""
  999 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  1000 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  1001 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  1002 + """
  1003 + if m.url == "":
  1004 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  1005 +
  1006 + return ans
  1007 +
  1008 +
  1009 +# Ukrainian
  1010 +def get_uk_models():
  1011 + uk_UA = [
  1012 + PiperModel(name="lada", kind="x_low", sr=16000, ns=1),
  1013 + PiperModel(name="ukrainian_tts", kind="medium", sr=22050, ns=3),
  1014 + ]
  1015 +
  1016 + for m in uk_UA:
  1017 + m.lang = "uk_UA"
  1018 +
  1019 + ans = uk_UA
  1020 +
  1021 + for m in ans:
  1022 + m.text = "Ви не можете навчити коня, якщо не відвикнете від годівлі."
  1023 +
  1024 + if m.model_name == "":
  1025 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  1026 +
  1027 + code = m.lang[:2]
  1028 + if m.cmd == "":
  1029 + m.cmd = f"""
  1030 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  1031 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  1032 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  1033 + """
  1034 + if m.url == "":
  1035 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  1036 +
  1037 + return ans
  1038 +
  1039 +
  1040 +# Vietnamese
  1041 +def get_vi_models():
  1042 + vi_VN = [
  1043 + PiperModel(name="25hours_single", kind="low", sr=16000, ns=1),
  1044 + PiperModel(name="vais1000", kind="medium", sr=22050, ns=1),
  1045 + PiperModel(name="vivos", kind="x_low", sr=16000, ns=65),
  1046 + ]
  1047 +
  1048 + for m in vi_VN:
  1049 + m.lang = "vi_VN"
  1050 +
  1051 + ans = vi_VN
  1052 +
  1053 + for m in ans:
  1054 + m.text = "Nước cũ đào gỗ mới, sông cũ chảy nước mới"
  1055 +
  1056 + if m.model_name == "":
  1057 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  1058 +
  1059 + code = m.lang[:2]
  1060 + if m.cmd == "":
  1061 + m.cmd = f"""
  1062 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  1063 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  1064 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  1065 + """
  1066 + if m.url == "":
  1067 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  1068 +
  1069 + return ans
  1070 +
  1071 +
  1072 +def get_en_models():
  1073 + en_gb = [
  1074 + PiperModel(name="alan", kind="low", sr=16000, ns=1),
  1075 + PiperModel(name="alan", kind="medium", sr=22050, ns=1),
  1076 + PiperModel(name="alba", kind="medium", sr=22050, ns=1),
  1077 + PiperModel(name="aru", kind="medium", sr=22050, ns=12),
  1078 + PiperModel(name="cori", kind="high", sr=22050, ns=1),
  1079 + PiperModel(name="cori", kind="medium", sr=22050, ns=1),
  1080 + PiperModel(name="jenny_dioco", kind="medium", sr=22050, ns=1),
  1081 + PiperModel(name="northern_english_male", kind="medium", sr=22050, ns=1),
  1082 + PiperModel(name="semaine", kind="medium", sr=22050, ns=4),
  1083 + PiperModel(name="southern_english_female", kind="low", sr=16000, ns=1),
  1084 + PiperModel(name="vctk", kind="medium", sr=22050, ns=109),
  1085 + ]
  1086 + en_us = [
  1087 + PiperModel(name="amy", kind="low", sr=16000, ns=1),
  1088 + PiperModel(name="amy", kind="medium", sr=22050, ns=1),
  1089 + PiperModel(name="arctic", kind="medium", sr=22050, ns=18),
  1090 + PiperModel(name="bryce", kind="medium", sr=22050, ns=1),
  1091 + PiperModel(name="danny", kind="low", sr=16000, ns=1),
  1092 + PiperModel(name="hfc_female", kind="medium", sr=22050, ns=1),
  1093 + PiperModel(name="hfc_male", kind="medium", sr=22050, ns=1),
  1094 + PiperModel(name="joe", kind="medium", sr=22050, ns=1),
  1095 + PiperModel(name="john", kind="medium", sr=22050, ns=1),
  1096 + PiperModel(name="kathleen", kind="low", sr=16000, ns=1),
  1097 + PiperModel(name="kristin", kind="medium", sr=22050, ns=1),
  1098 + PiperModel(name="kusal", kind="medium", sr=22050, ns=1),
  1099 + PiperModel(name="l2arctic", kind="medium", sr=22050, ns=24),
  1100 + PiperModel(name="lessac", kind="high", sr=22050, ns=1),
  1101 + PiperModel(name="lessac", kind="low", sr=16000, ns=1),
  1102 + PiperModel(name="lessac", kind="medium", sr=22050, ns=1),
  1103 + PiperModel(name="libritts", kind="high", sr=22050, ns=904),
  1104 + PiperModel(name="libritts_r", kind="medium", sr=22050, ns=904),
  1105 + PiperModel(name="ljspeech", kind="high", sr=22050, ns=1),
  1106 + PiperModel(name="ljspeech", kind="medium", sr=22050, ns=1),
  1107 + PiperModel(name="norman", kind="medium", sr=22050, ns=1),
  1108 + PiperModel(name="reza_ibrahim", kind="medium", sr=22050, ns=1),
  1109 + PiperModel(name="ryan", kind="high", sr=22050, ns=1),
  1110 + PiperModel(name="ryan", kind="low", sr=16000, ns=1),
  1111 + PiperModel(name="ryan", kind="medium", sr=22050, ns=1),
  1112 + PiperModel(name="sam", kind="medium", sr=22050, ns=1),
  1113 + ]
  1114 +
  1115 + en_gb.extend(
  1116 + [
  1117 + PiperModel(
  1118 + name="southern_english_female",
  1119 + kind="medium",
  1120 + sr=22050,
  1121 + ns=6,
  1122 + cmd="""
  1123 + wget -qq https://huggingface.co/csukuangfj/vits-piper-en_GB-southern_english_female-medium/resolve/main/en_GB-southern_english_female-medium.onnx
  1124 + wget -qq https://huggingface.co/csukuangfj/vits-piper-en_GB-southern_english_female-medium/resolve/main/en_GB-southern_english_female-medium.onnx.json
  1125 + """,
  1126 + url="https://huggingface.co/csukuangfj/vits-piper-en_GB-southern_english_female-medium",
  1127 + ),
  1128 + PiperModel(
  1129 + name="southern_english_male",
  1130 + kind="medium",
  1131 + sr=22050,
  1132 + ns=8,
  1133 + cmd="""
  1134 + wget -qq https://huggingface.co/csukuangfj/vits-piper-en_GB-southern_english_male-medium/resolve/main/en_GB-southern_english_male-medium.onnx
  1135 + wget -qq https://huggingface.co/csukuangfj/vits-piper-en_GB-southern_english_male-medium/resolve/main/en_GB-southern_english_male-medium.onnx.json
  1136 + """,
  1137 + url="https://huggingface.co/csukuangfj/vits-piper-en_GB-southern_english_male-medium",
  1138 + ),
  1139 + ]
  1140 + )
  1141 +
  1142 + en_us.extend(
  1143 + [
  1144 + # https://github.com/rhasspy/piper/issues/187#issuecomment-1805709037
  1145 + # https://drive.google.com/file/d/1t2D7zP-e2flduS5duHm__UMB9RjuGqWK/view
  1146 + PiperModel(
  1147 + name="glados",
  1148 + kind="high",
  1149 + sr=22050,
  1150 + ns=1,
  1151 + cmd="""
  1152 + wget -qq https://huggingface.co/csukuangfj/en_US-glados-high/resolve/main/en_US-glados-high.onnx
  1153 + wget -qq https://huggingface.co/csukuangfj/en_US-glados-high/resolve/main/en_US-glados-high.onnx.json
  1154 + wget -qq https://huggingface.co/csukuangfj/en_US-glados-high/resolve/main/README.md
  1155 + wget -qq https://huggingface.co/csukuangfj/en_US-glados-high/resolve/main/MODEL_CARD
  1156 + """,
  1157 + url="https://github.com/rhasspy/piper/issues/187#issuecomment-1805709037",
  1158 + ),
  1159 + ]
  1160 + )
  1161 +
  1162 + for m in en_gb:
  1163 + m.lang = "en_GB"
  1164 + if m.model_name == "":
  1165 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  1166 +
  1167 + for m in en_us:
  1168 + m.lang = "en_US"
  1169 + if m.model_name == "":
  1170 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  1171 +
  1172 + ans = en_gb + en_us
  1173 +
  1174 + for m in ans:
  1175 + m.text = "Friends fell out often because life was changing so fast. The easiest thing in the world was to lose touch with someone."
  1176 + code = m.lang[:2]
  1177 + if m.cmd == "":
  1178 + m.cmd = f"""
  1179 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  1180 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  1181 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  1182 + """
  1183 + if m.url == "":
  1184 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  1185 +
  1186 + return ans
  1187 +
  1188 +
  1189 +def get_de_models():
  1190 + de_de = [
  1191 + PiperModel(name="eva_k", kind="x_low", sr=16000, ns=1),
  1192 + PiperModel(name="karlsson", kind="low", sr=16000, ns=1),
  1193 + PiperModel(name="kerstin", kind="low", sr=16000, ns=1),
  1194 + PiperModel(name="pavoque", kind="low", sr=16000, ns=1),
  1195 + PiperModel(name="ramona", kind="low", sr=16000, ns=1),
  1196 + PiperModel(name="thorsten", kind="high", sr=22050, ns=1),
  1197 + PiperModel(name="thorsten", kind="low", sr=16000, ns=1),
  1198 + PiperModel(name="thorsten", kind="medium", sr=22050, ns=1),
  1199 + PiperModel(name="thorsten_emotional", kind="medium", sr=22050, ns=8),
  1200 + # https://github.com/rhasspy/piper/issues/187#issuecomment-2691653607
  1201 + PiperModel(
  1202 + name="glados",
  1203 + kind="high",
  1204 + sr=22050,
  1205 + ns=1,
  1206 + cmd="""
  1207 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados/high/de_DE-glados-high.onnx
  1208 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados/high/de_DE-glados-high.onnx.json
  1209 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados/high/MODEL_CARD
  1210 + wget -qq https://huggingface.co/csukuangfj/vits-piper-de_DE-glados-high/resolve/main/README.md
  1211 + """,
  1212 + url="https://huggingface.co/systemofapwne/piper-de-glados",
  1213 + ),
  1214 + PiperModel(
  1215 + name="glados",
  1216 + kind="low",
  1217 + sr=16000,
  1218 + ns=1,
  1219 + cmd="""
  1220 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados/low/de_DE-glados-low.onnx
  1221 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados/low/de_DE-glados-low.onnx.json
  1222 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados/low/MODEL_CARD
  1223 + wget -qq https://huggingface.co/csukuangfj/vits-piper-de_DE-glados-low/resolve/main/README.md
  1224 + """,
  1225 + url="https://huggingface.co/systemofapwne/piper-de-glados",
  1226 + ),
  1227 + PiperModel(
  1228 + name="glados",
  1229 + kind="medium",
  1230 + sr=22050,
  1231 + ns=1,
  1232 + cmd="""
  1233 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados/medium/de_DE-glados-medium.onnx
  1234 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados/medium/de_DE-glados-medium.onnx.json
  1235 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados/medium/MODEL_CARD
  1236 + wget -qq https://huggingface.co/csukuangfj/vits-piper-de_DE-glados-medium/resolve/main/README.md
  1237 + """,
  1238 + url="https://huggingface.co/systemofapwne/piper-de-glados",
  1239 + ),
  1240 + PiperModel(
  1241 + name="glados_turret",
  1242 + kind="high",
  1243 + sr=22050,
  1244 + ns=1,
  1245 + cmd="""
  1246 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados-turret/high/de_DE-glados-turret-high.onnx
  1247 + mv de_DE-glados-turret-high.onnx de_DE-glados_turret-high.onnx
  1248 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados-turret/high/de_DE-glados-turret-high.onnx.json
  1249 + mv de_DE-glados-turret-high.onnx.json de_DE-glados_turret-high.onnx.json
  1250 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados-turret/high/MODEL_CARD
  1251 + wget https://huggingface.co/csukuangfj/vits-piper-de_DE-glados_turret-high/resolve/main/README.md
  1252 + """,
  1253 + url="https://huggingface.co/systemofapwne/piper-de-glados",
  1254 + ),
  1255 + PiperModel(
  1256 + name="glados_turret",
  1257 + kind="low",
  1258 + sr=16000,
  1259 + ns=1,
  1260 + cmd="""
  1261 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados-turret/low/de_DE-glados-turret-low.onnx
  1262 + mv de_DE-glados-turret-low.onnx de_DE-glados_turret-low.onnx
  1263 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados-turret/low/de_DE-glados-turret-low.onnx.json
  1264 + mv de_DE-glados-turret-low.onnx.json de_DE-glados_turret-low.onnx.json
  1265 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados-turret/low/MODEL_CARD
  1266 + wget https://huggingface.co/csukuangfj/vits-piper-de_DE-glados_turret-low/resolve/main/README.md
  1267 + """,
  1268 + url="https://huggingface.co/systemofapwne/piper-de-glados",
  1269 + ),
  1270 + PiperModel(
  1271 + name="glados_turret",
  1272 + kind="medium",
  1273 + sr=22050,
  1274 + ns=1,
  1275 + cmd="""
  1276 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados-turret/medium/de_DE-glados-turret-medium.onnx
  1277 + mv de_DE-glados-turret-medium.onnx de_DE-glados_turret-medium.onnx
  1278 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados-turret/medium/de_DE-glados-turret-medium.onnx.json
  1279 + mv de_DE-glados-turret-medium.onnx.json de_DE-glados_turret-medium.onnx.json
  1280 + wget -qq https://huggingface.co/systemofapwne/piper-de-glados/resolve/main/de/de_DE/glados-turret/medium/MODEL_CARD
  1281 + wget https://huggingface.co/csukuangfj/vits-piper-de_DE-glados_turret-medium/resolve/main/README.md
  1282 + """,
  1283 + url="https://huggingface.co/systemofapwne/piper-de-glados",
  1284 + ),
  1285 + ]
  1286 + for m in de_de:
  1287 + m.lang = "de_DE"
  1288 + if m.model_name == "":
  1289 + m.model_name = f"{m.lang}-{m.name}-{m.kind}.onnx"
  1290 +
  1291 + ans = de_de
  1292 +
  1293 + for m in ans:
  1294 + m.text = "Alles hat ein Ende, nur die Wurst hat zwei."
  1295 + code = m.lang[:2]
  1296 + if m.cmd == "":
  1297 + m.cmd = f"""
  1298 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}
  1299 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/{m.model_name}.json
  1300 + wget -qq https://huggingface.co/rhasspy/piper-voices/resolve/main/{code}/{m.lang}/{m.name}/{m.kind}/MODEL_CARD
  1301 + """
  1302 +
  1303 + if m.url == "":
  1304 + m.url = f"https://huggingface.co/rhasspy/piper-voices/tree/main/{code}/{m.lang}/{m.name}/{m.kind}"
  1305 +
  1306 + return ans
  1307 +
  1308 +
  1309 +def get_all_models():
  1310 + ans = []
  1311 + ans += get_ar_models()
  1312 + ans += get_ca_models()
  1313 + ans += get_cs_models()
  1314 + ans += get_cy_models()
  1315 + ans += get_da_models()
  1316 + ans += get_de_models()
  1317 + ans += get_el_models()
  1318 + ans += get_en_models()
  1319 + ans += get_es_models()
  1320 + ans += get_fa_models()
  1321 + ans += get_fi_models()
  1322 + ans += get_fr_models()
  1323 + ans += get_hu_models()
  1324 + ans += get_is_models()
  1325 + ans += get_it_models()
  1326 + ans += get_ka_models()
  1327 + ans += get_kk_models()
  1328 + ans += get_lb_models()
  1329 + ans += get_lv_models()
  1330 + ans += get_ml_models()
  1331 + ans += get_ne_models()
  1332 + ans += get_nl_models()
  1333 + ans += get_no_models()
  1334 + ans += get_pl_models()
  1335 + ans += get_pt_models()
  1336 + ans += get_ro_models()
  1337 + ans += get_ru_models()
  1338 + ans += get_sk_models()
  1339 + ans += get_sl_models()
  1340 + ans += get_sr_models()
  1341 + ans += get_sv_models()
  1342 + ans += get_sw_models()
  1343 + ans += get_tr_models()
  1344 + ans += get_uk_models()
  1345 + ans += get_vi_models()
  1346 +
  1347 + for i, m in enumerate(ans):
  1348 + m.index = i
  1349 +
  1350 + return ans
  1351 +
  1352 +
  1353 +def main():
  1354 + args = get_args()
  1355 + index = args.index
  1356 + total = args.total
  1357 + assert 0 <= index < total, (index, total)
  1358 +
  1359 + all_model_list = get_all_models()
  1360 +
  1361 + print(all_model_list)
  1362 +
  1363 + num_models = len(all_model_list)
  1364 + num_per_runner = num_models // total
  1365 + if num_per_runner <= 0:
  1366 + raise ValueError(f"num_models: {num_models}, num_runners: {total}")
  1367 +
  1368 + start = index * num_per_runner
  1369 + end = start + num_per_runner
  1370 +
  1371 + remaining = num_models - args.total * num_per_runner
  1372 +
  1373 + print(f"{index}/{total}: {start}-{end}/{num_models}")
  1374 +
  1375 + d = dict()
  1376 + d["model_list"] = all_model_list[start:end]
  1377 +
  1378 + if index < remaining:
  1379 + s = args.total * num_per_runner + index
  1380 + d["model_list"].append(all_model_list[s])
  1381 + print(f"{s}/{num_models}")
  1382 +
  1383 + filename_list = [
  1384 + "./generate.sh",
  1385 + ]
  1386 + for filename in filename_list:
  1387 + environment = jinja2.Environment()
  1388 + if not Path(f"{filename}.in").is_file():
  1389 + print(f"skip {filename}")
  1390 + continue
  1391 +
  1392 + with open(f"{filename}.in") as f:
  1393 + s = f.read()
  1394 + template = environment.from_string(s)
  1395 +
  1396 + s = template.render(**d)
  1397 + with open(filename, "w") as f:
  1398 + print(s, file=f)
  1399 +
  1400 + print(f"There are {len(all_model_list)} models")
  1401 + for m in all_model_list:
  1402 + print(m.index, m.model_name)
  1403 +
  1404 + if Path("hf").is_dir():
  1405 + with open("./generate_samples.py.in") as f:
  1406 + s = f.read()
  1407 + template = environment.from_string(s)
  1408 + for m in all_model_list:
  1409 + model_dir = f"vits-piper-{m.lang}-{m.name}-{m.kind}"
  1410 + d = {
  1411 + "model": f"{model_dir}/{m.model_name}",
  1412 + "data_dir": f"{model_dir}/espeak-ng-data",
  1413 + "tokens": f"{model_dir}/tokens.txt",
  1414 + "text": m.text,
  1415 + }
  1416 + for i in range(m.ns):
  1417 + s = template.render(
  1418 + **d,
  1419 + sid=i,
  1420 + output_filename=f"hf/piper/mp3/{m.lang}/{model_dir}/{i}.mp3",
  1421 + )
  1422 +
  1423 + with open(f"generate_samples-{model_dir}-{i}.py", "w") as f:
  1424 + print(s, file=f)
  1425 +
  1426 +
  1427 +if __name__ == "__main__":
  1428 + main()
  1 +#!/usr/bin/env bash
  2 +# Copyright 2025 Xiaomi Corp. (authors: Fangjun Kuang)
  3 +#
  4 +# Auto generated! Do NOT edit!
  5 +
  6 +set -ex
  7 +
  8 +log() {
  9 + # This function is from espnet
  10 + local fname=${BASH_SOURCE[1]##*/}
  11 + echo -e "$(date '+%Y-%m-%d %H:%M:%S') (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $*"
  12 +}
  13 +
  14 +wget -qq https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/espeak-ng-data.tar.bz2
  15 +tar xf espeak-ng-data.tar.bz2
  16 +rm espeak-ng-data.tar.bz2
  17 +
  18 +mkdir -p release
  19 +
  20 +{% for model in model_list %}
  21 +
  22 +name={{ model.name }}
  23 +kind={{ model.kind }}
  24 +lang={{ model.lang }}
  25 +model_name={{ model.model_name }}
  26 +text="{{ model.text }}"
  27 +num_speakers={{ model.ns }}
  28 +sample_rate={{ model.sr }}
  29 +
  30 +{{ model.cmd }}
  31 +
  32 +python3 ./add_meta_data.py \
  33 + --name $name \
  34 + --kind $kind \
  35 + --lang $lang
  36 +
  37 +dst=vits-piper-$lang-$name-$kind
  38 +dst_int8=vits-piper-$lang-$name-$kind-int8
  39 +dst_fp16=vits-piper-$lang-$name-$kind-fp16
  40 +mkdir -p $dst
  41 +
  42 +mv -v tokens.txt $dst/
  43 +mv -v MODEL_CARD $dst/ || true
  44 +mv -v README $dst/ || true
  45 +mv -v *.json $dst/
  46 +cp -a ./espeak-ng-data $dst/
  47 +
  48 +cp -a $dst $dst_int8
  49 +cp -a $dst $dst_fp16
  50 +
  51 +mv -v *.onnx $dst/
  52 +
  53 +python3 ./dynamic_quantization.py \
  54 + --input $dst/$model_name \
  55 + --output-int8 $dst_int8/$model_name \
  56 + --output-fp16 $dst_fp16/$model_name >/dev/null 2>&1
  57 +
  58 +echo "---fp32---"
  59 +ls -lh $dst
  60 +
  61 +echo "---int8---"
  62 +ls -lh $dst_int8
  63 +
  64 +echo "---fp16---"
  65 +ls -lh $dst_fp16
  66 +
  67 +tar cjf ${dst}.tar.bz2 $dst
  68 +tar cjf ${dst_int8}.tar.bz2 $dst_int8
  69 +tar cjf ${dst_fp16}.tar.bz2 $dst_fp16
  70 +
  71 +if [ -d hf ]; then
  72 + mkdir -p hf/piper/mp3/$lang/vits-piper-$lang-$name-$kind
  73 + for i in $(seq $num_speakers); do
  74 + i=$((i-1))
  75 + python3 ./generate_samples-$dst-$i.py
  76 + done
  77 + ls -lh hf/piper/mp3/$lang/vits-piper-$lang-$name-$kind
  78 +fi
  79 +
  80 +mv $dst release
  81 +mv $dst_int8 release
  82 +mv $dst_fp16 release
  83 +
  84 +ls -lh release/*
  85 +
  86 +{% endfor %}
  1 +import sherpa_onnx
  2 +import soundfile as sf
  3 +
  4 +config = sherpa_onnx.OfflineTtsConfig(
  5 + model=sherpa_onnx.OfflineTtsModelConfig(
  6 + vits=sherpa_onnx.OfflineTtsVitsModelConfig(
  7 + model="{{ model }}",
  8 + lexicon="",
  9 + data_dir="{{ data_dir }}",
  10 + tokens="{{ tokens }}",
  11 + ),
  12 + num_threads=1,
  13 + ),
  14 +)
  15 +
  16 +if not config.validate():
  17 + raise ValueError("Please check your config")
  18 +
  19 +tts = sherpa_onnx.OfflineTts(config)
  20 +audio = tts.generate(text="{{text}}", sid={{sid}}, speed=1.0)
  21 +
  22 +sf.write("{{ output_filename }}", audio.samples, samplerate=audio.sample_rate)
@@ -18,7 +18,7 @@ void PybindOfflineTtsVitsModelConfig(py::module *m) { @@ -18,7 +18,7 @@ void PybindOfflineTtsVitsModelConfig(py::module *m) {
18 .def(py::init<const std::string &, const std::string &, 18 .def(py::init<const std::string &, const std::string &,
19 const std::string &, const std::string &, 19 const std::string &, const std::string &,
20 const std::string &, float, float, float>(), 20 const std::string &, float, float, float>(),
21 - py::arg("model"), py::arg("lexicon"), py::arg("tokens"), 21 + py::arg("model"), py::arg("lexicon") = "", py::arg("tokens"),
22 py::arg("data_dir") = "", py::arg("dict_dir") = "", 22 py::arg("data_dir") = "", py::arg("dict_dir") = "",
23 py::arg("noise_scale") = 0.667, py::arg("noise_scale_w") = 0.8, 23 py::arg("noise_scale") = 0.667, py::arg("noise_scale_w") = 0.8,
24 py::arg("length_scale") = 1.0) 24 py::arg("length_scale") = 1.0)