Add mimic3-client script
This commit is contained in:
parent
824783b05a
commit
b1bb2b3691
8 changed files with 149 additions and 28 deletions
82
docker/mimic3-client
Executable file
82
docker/mimic3-client
Executable file
|
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright 2022 Mycroft AI Inc.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Run mimic3-client --update to update Docker image
|
||||||
|
|
||||||
|
args=()
|
||||||
|
repo='mycroftai/mimic3'
|
||||||
|
tag='latest'
|
||||||
|
docker='docker'
|
||||||
|
port='59125'
|
||||||
|
|
||||||
|
while [[ -n "$1" ]]; do
|
||||||
|
if [[ "$1" == '--update' ]]; then
|
||||||
|
# Update Docker image
|
||||||
|
update='1'
|
||||||
|
elif [[ "$1" == '--port' ]]; then
|
||||||
|
port="$2"
|
||||||
|
args+=('--port' "${port}")
|
||||||
|
shift 1
|
||||||
|
else
|
||||||
|
args+=("$1")
|
||||||
|
fi
|
||||||
|
|
||||||
|
shift 1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -n "${update}" ]]; then
|
||||||
|
docker pull "${repo}:${tag}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker_run_args=()
|
||||||
|
|
||||||
|
if [[ -d /etc/ssl/certs ]]; then
|
||||||
|
# This directory seems to usually have symlinks to other directories
|
||||||
|
docker_run_args+=('-v' '/etc/ssl/certs:/etc/ssl/certs:ro')
|
||||||
|
|
||||||
|
# Create temp file with all certificate directories found
|
||||||
|
cert_dirs_file="$(mktemp)"
|
||||||
|
function finish {
|
||||||
|
rm -rf "${cert_dirs_file}"
|
||||||
|
}
|
||||||
|
trap finish EXIT
|
||||||
|
|
||||||
|
while read -r cert_path; do
|
||||||
|
# Follow symlinks and record directory paths
|
||||||
|
cert_path="$(readlink -f "${cert_path}")"
|
||||||
|
cert_dir="$(dirname "${cert_path}")"
|
||||||
|
echo $cert_dir >> "${cert_dirs_file}"
|
||||||
|
done < <(find /etc/ssl/certs -name '*.pem' -type l)
|
||||||
|
|
||||||
|
# Map unique certificate directories
|
||||||
|
while read -r cert_dir; do
|
||||||
|
docker_run_args+=('-v' "${cert_dir}:${cert_dir}:ro")
|
||||||
|
done < <(sort < "${cert_dirs_file}" | uniq)
|
||||||
|
fi
|
||||||
|
|
||||||
|
"${docker}" run \
|
||||||
|
-i \
|
||||||
|
--network host \
|
||||||
|
-e "HOME=${HOME}" \
|
||||||
|
-v "$HOME:${HOME}" \
|
||||||
|
-w "${PWD}" \
|
||||||
|
--user "$(id -u):$(id -g)" "${docker_run_args[@]}" \
|
||||||
|
--entrypoint '/home/mimic3/app/.venv/bin/python3' \
|
||||||
|
"${repo}:${tag}" \
|
||||||
|
-m mimic3_http.client \
|
||||||
|
--stdout \
|
||||||
|
"${args[@]}"
|
||||||
|
|
@ -73,5 +73,5 @@ fi
|
||||||
--user "$(id -u):$(id -g)" "${docker_run_args[@]}" \
|
--user "$(id -u):$(id -g)" "${docker_run_args[@]}" \
|
||||||
--entrypoint '/home/mimic3/app/.venv/bin/python3' \
|
--entrypoint '/home/mimic3/app/.venv/bin/python3' \
|
||||||
"${repo}:${tag}" \
|
"${repo}:${tag}" \
|
||||||
-m mimic3_download \
|
-m mimic3_tts.download \
|
||||||
"${args[@]}"
|
"${args[@]}"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
import argparse
|
import argparse
|
||||||
|
import subprocess
|
||||||
|
import shlex
|
||||||
|
import shutil
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -28,6 +31,8 @@ _PACKAGE = "mimic3_http.client"
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(_PACKAGE)
|
_LOGGER = logging.getLogger(_PACKAGE)
|
||||||
|
|
||||||
|
_DEFAULT_PLAY_PROGRAMS = ["paplay", "play -q", "aplay -q"]
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -76,14 +81,26 @@ def main():
|
||||||
_LOGGER.debug("Writing WAV data to stdout")
|
_LOGGER.debug("Writing WAV data to stdout")
|
||||||
sys.stdout.buffer.write(wav_bytes)
|
sys.stdout.buffer.write(wav_bytes)
|
||||||
else:
|
else:
|
||||||
from playsound import playsound
|
play_wav_bytes(args, wav_bytes)
|
||||||
|
|
||||||
with tempfile.NamedTemporaryFile(mode="wb+", suffix=".wav") as wav_file:
|
|
||||||
wav_file.write(wav_bytes)
|
|
||||||
wav_file.seek(0)
|
|
||||||
|
|
||||||
_LOGGER.debug("Playing WAV file: %s", wav_file.name)
|
# -----------------------------------------------------------------------------
|
||||||
playsound(wav_file.name)
|
|
||||||
|
|
||||||
|
def play_wav_bytes(args: argparse.Namespace, wav_bytes: bytes):
|
||||||
|
with tempfile.NamedTemporaryFile(mode="wb+", suffix=".wav") as wav_file:
|
||||||
|
wav_file.write(wav_bytes)
|
||||||
|
wav_file.seek(0)
|
||||||
|
|
||||||
|
for play_program in reversed(args.play_program):
|
||||||
|
play_cmd = shlex.split(play_program)
|
||||||
|
if not shutil.which(play_cmd[0]):
|
||||||
|
continue
|
||||||
|
|
||||||
|
play_cmd.append(wav_file.name)
|
||||||
|
_LOGGER.debug("Playing WAV file: %s", play_cmd)
|
||||||
|
subprocess.check_output(play_cmd)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
@ -101,24 +118,16 @@ def get_args() -> argparse.Namespace:
|
||||||
help="URL of mimic3 HTTP server (default: http://localhost:59125/api/tts)",
|
help="URL of mimic3 HTTP server (default: http://localhost:59125/api/tts)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--voice",
|
"--voice", "-v", help="Name of voice (expected in <voices-dir>/<language>)",
|
||||||
"-v",
|
|
||||||
help="Name of voice (expected in <voices-dir>/<language>)",
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--output",
|
"--output", "-o", help="Path to write WAV file (default: play audio)",
|
||||||
"-o",
|
|
||||||
help="Path to write WAV file (default: play audio)",
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--stdout",
|
"--stdout", action="store_true", help="Write WAV data to stdout",
|
||||||
action="store_true",
|
|
||||||
help="Write WAV data to stdout",
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--noise-scale",
|
"--noise-scale", type=float, help="Noise scale [0-1], default is 0.667",
|
||||||
type=float,
|
|
||||||
help="Noise scale [0-1], default is 0.667",
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--length-scale",
|
"--length-scale",
|
||||||
|
|
@ -126,9 +135,13 @@ def get_args() -> argparse.Namespace:
|
||||||
help="Length scale (1.0 is default speed, 0.5 is 2x faster)",
|
help="Length scale (1.0 is default speed, 0.5 is 2x faster)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--noise-w",
|
"--noise-w", type=float, help="Variation in cadence [0-1], default is 0.8",
|
||||||
type=float,
|
)
|
||||||
help="Variation in cadence [0-1], default is 0.8",
|
parser.add_argument(
|
||||||
|
"--play-program",
|
||||||
|
action="append",
|
||||||
|
default=_DEFAULT_PLAY_PROGRAMS,
|
||||||
|
help="Program(s) used to play WAV files",
|
||||||
)
|
)
|
||||||
parser.add_argument("--ssml", action="store_true", help="Input text is SSML")
|
parser.add_argument("--ssml", action="store_true", help="Input text is SSML")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
mimic3-tts<1.0
|
mimic3-tts<1.0
|
||||||
playsound~=1.3.0
|
|
||||||
quart>=0.16,<1.0
|
quart>=0.16,<1.0
|
||||||
quart-cors
|
quart-cors
|
||||||
requests>=2,<3
|
requests>=2,<3
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
from collections import defaultdict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import setuptools
|
import setuptools
|
||||||
|
|
@ -42,6 +43,34 @@ with open(version_path, "r", encoding="utf-8") as version_file:
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# dependency => [tags]
|
||||||
|
extras = {}
|
||||||
|
|
||||||
|
# Create language-specific extras
|
||||||
|
for lang in [
|
||||||
|
"de",
|
||||||
|
"es",
|
||||||
|
"fr",
|
||||||
|
"it",
|
||||||
|
"nl",
|
||||||
|
"ru",
|
||||||
|
"sw",
|
||||||
|
]:
|
||||||
|
extras[f"gruut[{lang}]"] = [lang]
|
||||||
|
|
||||||
|
# Add "all" tag
|
||||||
|
for tags in extras.values():
|
||||||
|
tags.append("all")
|
||||||
|
|
||||||
|
# Invert for setup
|
||||||
|
extras_require = defaultdict(list)
|
||||||
|
for dep, tags in extras.items():
|
||||||
|
for tag in tags:
|
||||||
|
extras_require[tag].append(dep)
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="mimic3_http",
|
name="mimic3_http",
|
||||||
version=version,
|
version=version,
|
||||||
|
|
@ -53,7 +82,7 @@ setup(
|
||||||
packages=setuptools.find_packages(),
|
packages=setuptools.find_packages(),
|
||||||
package_data={"mimic3_http": ["VERSION", "py.typed", "templates", "css", "img"]},
|
package_data={"mimic3_http": ["VERSION", "py.typed", "templates", "css", "img"]},
|
||||||
install_requires=requirements,
|
install_requires=requirements,
|
||||||
extras_require={':python_version<"3.9"': ["importlib_resources"]},
|
extras_require={':python_version<"3.9"': ["importlib_resources"], **extras_require},
|
||||||
entry_points={
|
entry_points={
|
||||||
"console_scripts": [
|
"console_scripts": [
|
||||||
"mimic3-server = mimic3_http.__main__:main",
|
"mimic3-server = mimic3_http.__main__:main",
|
||||||
|
|
|
||||||
|
|
@ -485,7 +485,7 @@ def get_args():
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--interactive",
|
"--interactive",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Play audio after each input line (see --play-command)",
|
help="Play audio after each input line (see --play-program)",
|
||||||
)
|
)
|
||||||
parser.add_argument("--csv", action="store_true", help="Input format is id|text")
|
parser.add_argument("--csv", action="store_true", help="Input format is id|text")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,7 @@ class Mimic3TextToSpeechSystem(TextToSpeechSystem):
|
||||||
# Clear speaker on voice change
|
# Clear speaker on voice change
|
||||||
self.speaker = None
|
self.speaker = None
|
||||||
|
|
||||||
self.settings.voice = new_voice
|
self.settings.voice = new_voice or DEFAULT_VOICE
|
||||||
|
|
||||||
if "#" in self.settings.voice:
|
if "#" in self.settings.voice:
|
||||||
# Split
|
# Split
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,7 @@ for lang in [
|
||||||
"fr",
|
"fr",
|
||||||
"it",
|
"it",
|
||||||
"nl",
|
"nl",
|
||||||
"pt",
|
|
||||||
"ru",
|
"ru",
|
||||||
"sv",
|
|
||||||
"sw",
|
"sw",
|
||||||
]:
|
]:
|
||||||
extras[f"gruut[{lang}]"] = [lang]
|
extras[f"gruut[{lang}]"] = [lang]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue