Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions piper/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
# Changelog

## 2.5.2

- Upgrade to `wyoming-piper` 2.5.2
- Add Japanese (OpenJTalk) and Thai (TLTK) support behind the new
`enable_japanese` and `enable_thai` options, and the Thai voice they enable
(`th_TH-tsync2-medium`)
- Japanese and Thai voices are hidden from Home Assistant until their option is
turned on. They used to be offered and then produce silence
- A voice that fails to synthesize now reports why instead of returning empty
audio
- An interrupted voice download is retried on the next start instead of leaving
a truncated file that stayed broken until it was deleted by hand
- Voice models are included in backups again. They were skipped because they
were only re-downloadable copies, but voices can now be uploaded and deleted
from the web interface, so which ones are installed is your choice and an
uploaded voice exists nowhere else. Large re-downloadable caches are still
skipped
- Add 1 new Estonian voice (`et_EE-news-medium`)
- Japanese, Thai and OmniVoice are downloaded when their option is turned on
rather than shipped in the app image, which keeps the image at roughly its
previous size instead of growing to ~2 GB. The download is cached in `/data`
and reused on later starts
- Add a voice management web interface, available through the app's "Open Web
UI" button (ingress). Upload and delete custom Piper voices, and upload
OmniVoice cloning voices, without needing file access to `/share`. Only Home
Assistant's ingress proxy is allowed to reach it
- Add a `backend` option to switch between `piper` (default) and the
experimental `omnivoice` backend. OmniVoice is higher quality and supports
voice cloning, but is much slower and really wants a desktop or server CPU;
it runs elsewhere with a warning, but expect it to be too slow to be useful
- Add an `omnivoice_steps` option to trade OmniVoice quality for speed
- Custom OmniVoice voices are stored in `/data/omnivoice_voices`, kept separate
from the Piper voice models
- Replace the health check with a Wyoming Describe/Info round trip, which also
works with the `omnivoice` backend
- Exclude the OmniVoice model and the HuggingFace cache from backups

## 2.3.4

- Disable ONNX Runtime telemetry: onnxruntime 1.29.0 (pulled in by the 2.3.3
Expand Down
86 changes: 85 additions & 1 deletion piper/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,46 @@ for more information.

## Configuration

### Option: `backend`

The text-to-speech engine to use.

- `piper` (the default) is fast, runs well on a Raspberry Pi, and uses the
voices listed under the `voice` option below.
- `omnivoice` is **experimental**. It is considerably higher quality, supports
many more languages, and can clone a voice from a short recording, but it is
much slower and really needs a desktop or server CPU. It will run on
`aarch64`, with a warning, but expect it to be impractically slow there.

OmniVoice is not part of the app image. Selecting it downloads it, along with a
model of several GB, the first time the app starts, so it can take a long time
before the app becomes available in Home Assistant. Later starts reuse the
download.

The two backends have separate voices. Switching backends changes the list of
voices the app advertises, so reload the Wyoming integration for Piper
afterwards.

### Option: `enable_japanese` / `enable_thai`

Japanese and Thai voices need an extra phonemizer that is not part of the app
image, because it is large and most installs do not need it. Turning the option
on downloads it the first time the app starts (around 350 MB for Japanese,
390 MB for Thai), so that start takes noticeably longer than usual. Later starts
reuse the download.

While an option is off, its voices are not offered to Home Assistant at all, so
they will not appear in the Wyoming integration's voice list. Reload that
integration after turning one on. If the app's own `voice` option is set to a
Japanese or Thai voice without its option turned on, the app stops at startup
and says which one to enable.

### Option: `omnivoice_steps`

Number of decode steps used by the `omnivoice` backend. Fewer steps are faster,
more steps sound better; the default of 32 is a safe choice, and values as low
as 10 still sound clean. Ignored by the `piper` backend.

### Option: `voice`

[Listen to voice samples](https://rhasspy.github.io/piper-samples/)
Expand Down Expand Up @@ -71,11 +111,55 @@ Download the list of new voices automatically every time the app starts. You mus

Print DEBUG level messages to the app's log.

## Web Interface

The app has a small web interface for managing voices, reachable with the "Open
Web UI" button on the app page. It is served through Home Assistant ingress, so
using it means going through Home Assistant and being an administrator. Its port
is not published, and it only answers Home Assistant's ingress proxy — other
apps on the same machine are refused.

It has two sections:

- **Piper** — upload and delete custom Piper voices (a `<voice>.onnx` model plus
its `<voice>.onnx.json` config).
- **OmniVoice** — upload a reference recording (a WAV file) and its transcript
to create a cloning voice.

The app picks up added and removed voices on its own, but Home Assistant caches
the voice list, so **reload the Wyoming integration for Piper** for a new voice
to show up there.

Voices in `/share/piper` are listed but cannot be deleted from the web
interface, because that directory is mounted read-only. Delete those files
directly instead.

Because voices can be added and removed here, the set you end up with is your
own and is included in the app's backups — including uploads, which exist
nowhere else. Only the large re-downloadable caches are left out: the OmniVoice
model weights and the downloads for the Japanese and Thai options.

## Custom Voices

Add custom voice files to the `/share/piper` directory. Each custom voice must include a model file (`<voice>.onnx`) and config file (`<voice>.onnx.json`).
Add custom voice files to the `/share/piper` directory, or upload them through
the web interface. Each custom voice must include a model file (`<voice>.onnx`)
and config file (`<voice>.onnx.json`).
See the [training guide](https://github.com/rhasspy/piper/blob/master/TRAINING.md) for details on how to train and export a custom voice.

## Custom OmniVoice Voices

The `omnivoice` backend uses its own voices, which are not Piper voice models.
They live in `/data/omnivoice_voices` inside the app, organized as
`<language>/<voice_name>/`, and are managed through the **OmniVoice** section of
the web interface. Each voice is a reference recording (`ref.wav`) plus its
transcript (`ref.txt`), which OmniVoice clones.

A `default` voice is always available for every supported language and uses
OmniVoice's built-in speaker, so cloning voices are optional.

These voices are included in app backups. The downloaded OmniVoice model is not,
since it is several GB and is re-downloaded when needed.

## Support

Got questions?
Expand Down
48 changes: 31 additions & 17 deletions piper/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,49 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]

# Install Piper
WORKDIR /usr/src
ARG BUILD_ARCH
ARG WYOMING_PIPER_VERSION
ARG UV_VERSION

ENV WYOMING_PIPER_VERSION=${WYOMING_PIPER_VERSION}

# There is no virtual environment in this image
ENV UV_SYSTEM_PYTHON=true

# A unique approach is taken in this image to dependency management. Different
# voices (th, ja) and backends (omnivoice) require large Python dependencies.
# Rather than making everyone pay the disk space for them, a new "pack" s6
# dependency installs them on startup when enabled.
#
# Importantly, the uv cache is stored in /data and because uv caches wheels
# uncompressed already, the relevant files can be symlinked into the container's
# filesystem with virtually no overhead. This only works if we target the system
# Python because the build time and runtime dependencies need to be layered.
# Hence, there is no virtual environment anymore.

RUN \
apt-get update \
&& apt-get install -y --no-install-recommends \
netcat-traditional \
python3 \
python3-pip \
python3-venv \
\
&& python3 -m venv .venv \
&& .venv/bin/pip3 install --no-cache-dir -U \
setuptools \
wheel \
&& .venv/bin/pip3 install --no-cache-dir \
--extra-index-url https://www.piwheels.org/simple \
--extra-index-url https://download.pytorch.org/whl/cpu \
"wyoming-piper[zeroconf,zh] @ https://github.com/rhasspy/wyoming-piper/archive/refs/tags/v${WYOMING_PIPER_VERSION}.tar.gz" \
# Install into the system interpreter rather than a venv
&& rm -f /usr/lib/python3*/EXTERNALLY-MANAGED \
# pip is only here to bootstrap uv
&& pip3 install --no-cache-dir "uv==${UV_VERSION}" \
\
# --no-cache: the runtime cache lives in /data and must not be seeded with
# build-time downloads baked into the image.
&& uv pip install --no-cache \
"wyoming-piper[zeroconf,zh,web] @ https://github.com/rhasspy/wyoming-piper/archive/refs/tags/v${WYOMING_PIPER_VERSION}.tar.gz" \
\
&& rm -rf /var/lib/apt/lists/*

ENV PATH="/usr/src/.venv/bin:$PATH"

ENV ORT_DISABLE_TELEMETRY=1
WORKDIR /
COPY rootfs /

HEALTHCHECK --start-period=10m \
CMD echo '{ "type": "describe" }' \
| nc -w 1 localhost 10200 \
| grep -q "piper" \
# A Describe/Info round trip rather than a bare port check
HEALTHCHECK --start-period=30m --interval=30s --timeout=20s --retries=3 \
CMD /usr/bin/python3 -m wyoming_piper.health_check \
--uri tcp://127.0.0.1:10200 \
|| exit 1
3 changes: 2 additions & 1 deletion piper/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ build_from:
amd64: ghcr.io/home-assistant/amd64-base-debian:trixie
aarch64: ghcr.io/home-assistant/aarch64-base-debian:trixie
args:
WYOMING_PIPER_VERSION: 2.3.1
WYOMING_PIPER_VERSION: 2.5.2
UV_VERSION: 0.12.12
30 changes: 27 additions & 3 deletions piper/config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
version: 2.3.4
version: 2.5.2
slug: piper
name: Piper
description: Text-to-speech with Piper
Expand All @@ -10,27 +10,51 @@ arch:
init: false
discovery:
- wyoming
# Voice models ("*.onnx") used to be excluded, back when /data held nothing but
# re-downloadable copies of catalog voices. The web interface now uploads and
# deletes voices there, so which models are present is the user's own choice and
# has to survive a backup -- an uploaded voice exists nowhere else. Only the
# genuinely disposable caches below are skipped.
backup_exclude:
- "*.onnx"
# OmniVoice weights, 632 MB. The 1.5 MB graph beside them is kept, but the
# backend needs both files, so a restore without the weights just downloads
# them again.
- "*.onnx.data"
# HuggingFace cache (HF_HOME is /data, so models land in /data/hub).
- "*/hub"
# Wheel cache for the optional packs, rebuilt on demand.
- "*/uv-cache"
map:
- share
ingress: true
ingress_port: 8099
panel_icon: mdi:account-voice
panel_title: Piper voices
options:
backend: piper
voice: en_US-lessac-medium
speaker: 0
length_scale: 1.0
noise_scale: 0.667
noise_w: 0.333
sentence_silence: 0.0
omnivoice_steps: 32
enable_japanese: false
enable_thai: false
debug_logging: false
update_voices: true
schema:
backend: list(piper|omnivoice)
voice: |
list(ar_JO-kareem-low|ar_JO-kareem-medium|bg_BG-dimitar-medium|bn_BD-google-medium|ca_ES-upc_ona-medium|ca_ES-upc_ona-x_low|ca_ES-upc_pau-x_low|ca-upc_ona-x-low|ca-upc_pau-x-low|cs_CZ-jirka-low|cs_CZ-jirka-medium|cs_CZ-kasandra-medium|cy_GB-bu_tts-medium|cy_GB-gwryw_gogleddol-medium|da_DK-talesyntese-medium|da-nst_talesyntese-medium|de_DE-eva_k-x_low|de_DE-karlsson-low|de_DE-kerstin-low|de_DE-mls-medium|de_DE-pavoque-low|de_DE-ramona-low|de_DE-thorsten_emotional-medium|de_DE-thorsten-high|de_DE-thorsten-low|de_DE-thorsten-medium|de-eva_k-x-low|de-karlsson-low|de-kerstin-low|de-pavoque-low|de-ramona-low|de-thorsten-low|el_GR-joy-medium|el-gr-rapunzelina-low|el_GR-rapunzelina-low|el_GR-rapunzelina-medium|en-gb-alan-low|en_GB-alan-low|en_GB-alan-medium|en_GB-alba-medium|en_GB-aru-medium|en_GB-cori-high|en_GB-cori-medium|en_GB-jenny_dioco-medium|en_GB-northern_english_male-medium|en_GB-semaine-medium|en-gb-southern_english_female-low|en_GB-southern_english_female-low|en_GB-vctk-medium|en-us-amy-low|en_US-amy-low|en_US-amy-medium|en_US-arctic-medium|en_US-bryce-medium|en-us-danny-low|en_US-danny-low|en_US-hfc_female-medium|en_US-hfc_male-medium|en_US-joe-medium|en_US-john-medium|en-us-kathleen-low|en_US-kathleen-low|en_US-kristin-medium|en_US-kusal-medium|en_US-l2arctic-medium|en_US-lessac-high|en-us-lessac-low|en_US-lessac-low|en-us-lessac-medium|en_US-lessac-medium|en-us-libritts-high|en_US-libritts-high|en_US-libritts_r-medium|en_US-ljspeech-high|en_US-ljspeech-medium|en_US-mike-medium|en_US-norman-medium|en_US-reza_ibrahim-medium|en-us-ryan-high|en_US-ryan-high|en-us-ryan-low|en_US-ryan-low|en-us-ryan-medium|en_US-ryan-medium|en_US-sam-medium|es_AR-daniela-high|es-carlfm-x-low|es_ES-carlfm-x_low|es_ES-davefx-medium|es_ES-mls_10246-low|es_ES-mls_9972-low|es_ES-sharvard-medium|es-mls_10246-low|es-mls_9972-low|es_MX-ald-medium|es_MX-ald-x_low|es_MX-claude-high|eu_ES-antton-medium|eu_ES-maider-medium|fa_IR-amir-medium|fa_IR-ganji_adabi-medium|fa_IR-ganji-medium|fa_IR-gyro-medium|fa_IR-reza_ibrahim-medium|fi_FI-harri-low|fi_FI-harri-medium|fi-harri-low|fr_FR-gilles-low|fr_FR-mls_1840-low|fr_FR-mls-medium|fr_FR-siwis-low|fr_FR-siwis-medium|fr_FR-tom-medium|fr_FR-upmc-medium|fr-gilles-low|fr-mls_1840-low|fr-siwis-low|fr-siwis-medium|he_IL-saspeech-medium|hi_IN-pratham-medium|hi_IN-priyamvada-medium|hi_IN-rohan-medium|hu_HU-anna-medium|hu_HU-berta-medium|hu_HU-imre-medium|hy_AM-gor-medium|id_ID-news_tts-medium|is-bui-medium|is_IS-bui-medium|is_IS-salka-medium|is_IS-steinn-medium|is_IS-ugla-medium|is-salka-medium|is-steinn-medium|is-ugla-medium|it_IT-paola-medium|it_IT-riccardo-x_low|it-riccardo_fasol-x-low|it_IT-serena-high|it_IT-serena-medium|ja_JA-hi_fi_captain-medium|ka_GE-natia-medium|kk-iseke-x-low|kk-issai-high|kk_KZ-iseke-x_low|kk_KZ-issai-high|kk_KZ-raya-x_low|kk-raya-x-low|ko_KR-kss-medium|ku_TR-berfin_renas-medium|lb_LU-marylux-medium|lv_LV-aivars-medium|ml_IN-arjun-medium|ml_IN-meera-medium|mr_IN-google-medium|ne-google-medium|ne-google-x-low|ne_NP-chitwan-medium|ne_NP-google-medium|ne_NP-google-x_low|nl_BE-nathalie-medium|nl_BE-nathalie-x_low|nl_BE-rdh-medium|nl_BE-rdh-x_low|nl-mls_5809-low|nl-mls_7432-low|nl-nathalie-x-low|nl_NL-alex-medium|nl_NL-mls_5809-low|nl_NL-mls_7432-low|nl_NL-mls-medium|nl_NL-pim-medium|nl_NL-ronnie-medium|nl-rdh-medium|nl-rdh-x-low|no_NO-nvcc-medium|no_NO-talesyntese-medium|no-talesyntese-medium|pl-mls_6892-low|pl_PL-bass-high|pl_PL-darkman-medium|pl_PL-gosia-medium|pl_PL-mc_speech-medium|pl_PL-mls_6892-low|pt_BR-cadu-medium|pt-br-edresson-low|pt_BR-edresson-low|pt_BR-faber-medium|pt_BR-jeff-medium|pt_PT-tugão-medium|ro_RO-mihai-medium|ru-irinia-medium|ru_RU-denis-medium|ru_RU-dmitri-medium|ru_RU-irina-medium|ru_RU-ruslan-medium|sk_SK-lili-medium|sl_SI-artur-medium|sq_AL-edon-medium|sr_RS-serbski_institut-medium|sv_SE-alma-medium|sv_SE-lisa-medium|sv_SE-nst-medium|sw_CD-lanfrica-medium|te_IN-maya-medium|te_IN-padmavathi-medium|te_IN-venkatesh-medium|tr_TR-dfki-medium|uk-lada-x-low|uk_UA-lada-x_low|uk_UA-mykyta-high|uk_UA-oleksa-high|uk_UA-tetiana-high|uk_UA-ukrainian_tts-medium|ur_PK-aegis_female-medium|ur_PK-fasih-medium|vi-25hours-single-low|vi-vivos-x-low|vi_VN-25hours_single-low|vi_VN-vais1000-medium|vi_VN-vivos-x_low|zh_CN-chaowen-medium|zh_CN-huayan-medium|zh-cn-huayan-x-low|zh_CN-huayan-x_low|zh_CN-xiao_ya-medium)
list(ar_JO-kareem-low|ar_JO-kareem-medium|bg_BG-dimitar-medium|bn_BD-google-medium|ca_ES-upc_ona-medium|ca_ES-upc_ona-x_low|ca_ES-upc_pau-x_low|ca-upc_ona-x-low|ca-upc_pau-x-low|cs_CZ-jirka-low|cs_CZ-jirka-medium|cs_CZ-kasandra-medium|cy_GB-bu_tts-medium|cy_GB-gwryw_gogleddol-medium|da_DK-talesyntese-medium|da-nst_talesyntese-medium|de_DE-eva_k-x_low|de_DE-karlsson-low|de_DE-kerstin-low|de_DE-mls-medium|de_DE-pavoque-low|de_DE-ramona-low|de_DE-thorsten_emotional-medium|de_DE-thorsten-high|de_DE-thorsten-low|de_DE-thorsten-medium|de-eva_k-x-low|de-karlsson-low|de-kerstin-low|de-pavoque-low|de-ramona-low|de-thorsten-low|el_GR-joy-medium|el-gr-rapunzelina-low|el_GR-rapunzelina-low|el_GR-rapunzelina-medium|en-gb-alan-low|en_GB-alan-low|en_GB-alan-medium|en_GB-alba-medium|en_GB-aru-medium|en_GB-cori-high|en_GB-cori-medium|en_GB-jenny_dioco-medium|en_GB-northern_english_male-medium|en_GB-semaine-medium|en-gb-southern_english_female-low|en_GB-southern_english_female-low|en_GB-vctk-medium|en-us-amy-low|en_US-amy-low|en_US-amy-medium|en_US-arctic-medium|en_US-bryce-medium|en-us-danny-low|en_US-danny-low|en_US-hfc_female-medium|en_US-hfc_male-medium|en_US-joe-medium|en_US-john-medium|en-us-kathleen-low|en_US-kathleen-low|en_US-kristin-medium|en_US-kusal-medium|en_US-l2arctic-medium|en_US-lessac-high|en-us-lessac-low|en_US-lessac-low|en-us-lessac-medium|en_US-lessac-medium|en-us-libritts-high|en_US-libritts-high|en_US-libritts_r-medium|en_US-ljspeech-high|en_US-ljspeech-medium|en_US-mike-medium|en_US-norman-medium|en_US-reza_ibrahim-medium|en-us-ryan-high|en_US-ryan-high|en-us-ryan-low|en_US-ryan-low|en-us-ryan-medium|en_US-ryan-medium|en_US-sam-medium|es_AR-daniela-high|es-carlfm-x-low|es_ES-carlfm-x_low|es_ES-davefx-medium|es_ES-mls_10246-low|es_ES-mls_9972-low|es_ES-sharvard-medium|es-mls_10246-low|es-mls_9972-low|es_MX-ald-medium|es_MX-ald-x_low|es_MX-claude-high|et_EE-news-medium|eu_ES-antton-medium|eu_ES-maider-medium|fa_IR-amir-medium|fa_IR-ganji_adabi-medium|fa_IR-ganji-medium|fa_IR-gyro-medium|fa_IR-reza_ibrahim-medium|fi_FI-harri-low|fi_FI-harri-medium|fi-harri-low|fr_FR-gilles-low|fr_FR-mls_1840-low|fr_FR-mls-medium|fr_FR-siwis-low|fr_FR-siwis-medium|fr_FR-tom-medium|fr_FR-upmc-medium|fr-gilles-low|fr-mls_1840-low|fr-siwis-low|fr-siwis-medium|he_IL-saspeech-medium|hi_IN-pratham-medium|hi_IN-priyamvada-medium|hi_IN-rohan-medium|hu_HU-anna-medium|hu_HU-berta-medium|hu_HU-imre-medium|hy_AM-gor-medium|id_ID-news_tts-medium|is-bui-medium|is_IS-bui-medium|is_IS-salka-medium|is_IS-steinn-medium|is_IS-ugla-medium|is-salka-medium|is-steinn-medium|is-ugla-medium|it_IT-paola-medium|it_IT-riccardo-x_low|it-riccardo_fasol-x-low|it_IT-serena-high|it_IT-serena-medium|ja_JA-hi_fi_captain-medium|ka_GE-natia-medium|kk-iseke-x-low|kk-issai-high|kk_KZ-iseke-x_low|kk_KZ-issai-high|kk_KZ-raya-x_low|kk-raya-x-low|ko_KR-kss-medium|ku_TR-berfin_renas-medium|lb_LU-marylux-medium|lv_LV-aivars-medium|ml_IN-arjun-medium|ml_IN-meera-medium|mr_IN-google-medium|ne-google-medium|ne-google-x-low|ne_NP-chitwan-medium|ne_NP-google-medium|ne_NP-google-x_low|nl_BE-nathalie-medium|nl_BE-nathalie-x_low|nl_BE-rdh-medium|nl_BE-rdh-x_low|nl-mls_5809-low|nl-mls_7432-low|nl-nathalie-x-low|nl_NL-alex-medium|nl_NL-mls_5809-low|nl_NL-mls_7432-low|nl_NL-mls-medium|nl_NL-pim-medium|nl_NL-ronnie-medium|nl-rdh-medium|nl-rdh-x-low|no_NO-nvcc-medium|no_NO-talesyntese-medium|no-talesyntese-medium|pl-mls_6892-low|pl_PL-bass-high|pl_PL-darkman-medium|pl_PL-gosia-medium|pl_PL-mc_speech-medium|pl_PL-mls_6892-low|pt_BR-cadu-medium|pt-br-edresson-low|pt_BR-edresson-low|pt_BR-faber-medium|pt_BR-jeff-medium|pt_PT-tugão-medium|ro_RO-mihai-medium|ru-irinia-medium|ru_RU-denis-medium|ru_RU-dmitri-medium|ru_RU-irina-medium|ru_RU-ruslan-medium|sk_SK-lili-medium|sl_SI-artur-medium|sq_AL-edon-medium|sr_RS-serbski_institut-medium|sv_SE-alma-medium|sv_SE-lisa-medium|sv_SE-nst-medium|sw_CD-lanfrica-medium|te_IN-maya-medium|te_IN-padmavathi-medium|te_IN-venkatesh-medium|th_TH-tsync2-medium|tr_TR-dfki-medium|uk-lada-x-low|uk_UA-lada-x_low|uk_UA-mykyta-high|uk_UA-oleksa-high|uk_UA-tetiana-high|uk_UA-ukrainian_tts-medium|ur_PK-aegis_female-medium|ur_PK-fasih-medium|vi-25hours-single-low|vi-vivos-x-low|vi_VN-25hours_single-low|vi_VN-vais1000-medium|vi_VN-vivos-x_low|zh_CN-chaowen-medium|zh_CN-huayan-medium|zh-cn-huayan-x-low|zh_CN-huayan-x_low|zh_CN-xiao_ya-medium)
speaker: int
length_scale: float
noise_scale: float
noise_w: float
sentence_silence: float
omnivoice_steps: int(1,)
enable_japanese: bool
enable_thai: bool
debug_logging: bool
update_voices: bool
ports:
Expand Down
Empty file.
Loading
Loading