Working single-file binary build
This commit is contained in:
parent
5a972ea0c6
commit
b1d75d7ff6
16 changed files with 202 additions and 78 deletions
|
|
@ -1,5 +1,7 @@
|
|||
*
|
||||
!LICENSE
|
||||
!install.sh
|
||||
!pyinstaller/*.py
|
||||
|
||||
# opentts-abc
|
||||
!opentts-abc/setup.py
|
||||
|
|
@ -14,6 +16,7 @@
|
|||
!mimic3-tts/MANIFEST.in
|
||||
!mimic3-tts/requirements.txt
|
||||
!mimic3-tts/mimic3_tts/*.py
|
||||
!mimic3-tts/mimic3_tts/voices.json
|
||||
!mimic3-tts/mimic3_tts/VERSION
|
||||
|
||||
# HTTP server
|
||||
|
|
|
|||
15
Dockerfile
15
Dockerfile
|
|
@ -38,22 +38,13 @@ RUN --mount=type=cache,id=apt-build,target=/var/cache/apt \
|
|||
python3 python3-pip python3-venv \
|
||||
build-essential python3-dev
|
||||
|
||||
RUN mkdir -p /home/mimic3/app
|
||||
WORKDIR /home/mimic3/app
|
||||
|
||||
# Create virtual environment
|
||||
RUN --mount=type=cache,id=pip-venv,target=/root/.cache/pip \
|
||||
python3 -m venv .venv && \
|
||||
.venv/bin/pip3 install --upgrade pip && \
|
||||
.venv/bin/pip3 install --upgrade wheel setuptools
|
||||
COPY ./ ./
|
||||
|
||||
COPY ./ /home/mimic3/app/
|
||||
|
||||
# Install packages in order
|
||||
# Install mimic3
|
||||
RUN --mount=type=cache,id=pip-requirements,target=/root/.cache/pip \
|
||||
.venv/bin/pip3 install -e opentts-abc && \
|
||||
.venv/bin/pip3 install -e mimic3-tts && \
|
||||
.venv/bin/pip3 install -e mimic3-http
|
||||
./install.sh
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
116
Dockerfile.binary
Normal file
116
Dockerfile.binary
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# 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/>.
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
# Dockerfile for Mimic 3 (https://github.com/MycroftAI/mimic3)
|
||||
#
|
||||
# Creates self-contained binaries using PyInstaller
|
||||
# (https://pyinstaller.readthedocs.io/en/stable/).
|
||||
#
|
||||
# Requires Docker buildx: https://docs.docker.com/buildx/working-with-buildx/
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
FROM debian:bullseye as build
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN echo "Dir::Cache var/cache/apt/${TARGETARCH}${TARGETVARIANT};" > /etc/apt/apt.conf.d/01cache
|
||||
|
||||
RUN --mount=type=cache,id=apt-build,target=/var/cache/apt \
|
||||
mkdir -p /var/cache/apt/${TARGETARCH}${TARGETVARIANT}/archives/partial && \
|
||||
apt-get update && \
|
||||
apt-get install --yes --no-install-recommends \
|
||||
python3 python3-pip python3-venv \
|
||||
build-essential python3-dev \
|
||||
libespeak-ng1
|
||||
|
||||
WORKDIR /build/mimic3
|
||||
COPY ./ ./
|
||||
|
||||
# Install mimic3
|
||||
RUN --mount=type=cache,id=pip-venv,target=/root/.cache/pip \
|
||||
./install.sh
|
||||
|
||||
# Install PyInstaller
|
||||
RUN --mount=type=cache,id=pip-venv,target=/root/.cache/pip \
|
||||
.venv/bin/pip3 install 'pyinstaller>=4,<5'
|
||||
|
||||
# Create binary for command-line interface
|
||||
RUN .venv/bin/pyinstaller \
|
||||
--onefile \
|
||||
--noconfirm \
|
||||
--name mimic3 \
|
||||
--hidden-import 'pycrfsuite._dumpparser' \
|
||||
--hidden-import 'pycrfsuite._logparser' \
|
||||
--collect-binaries 'onnxruntime' \
|
||||
--add-binary "$(/sbin/ldconfig -p | grep libespeak-ng.so.1 | awk '{print $4}'):." \
|
||||
--collect-data 'gruut' \
|
||||
--hidden-import "gruut_lang_de" \
|
||||
--collect-data "gruut_lang_de" \
|
||||
--hidden-import "gruut_lang_en" \
|
||||
--collect-data "gruut_lang_en" \
|
||||
--hidden-import "gruut_lang_fr" \
|
||||
--collect-data "gruut_lang_fr" \
|
||||
--hidden-import "gruut_lang_it" \
|
||||
--collect-data "gruut_lang_it" \
|
||||
--hidden-import "gruut_lang_nl" \
|
||||
--collect-data "gruut_lang_nl" \
|
||||
--hidden-import "gruut_lang_ru" \
|
||||
--collect-data "gruut_lang_ru" \
|
||||
--hidden-import "gruut_lang_sw" \
|
||||
--collect-data "gruut_lang_sw" \
|
||||
--collect-data 'espeak_phonemizer' \
|
||||
--collect-data 'phonemes2ids' \
|
||||
--collect-data 'mimic3_tts' \
|
||||
pyinstaller/mimic3.py
|
||||
|
||||
# Create binary for web server
|
||||
RUN .venv/bin/pyinstaller \
|
||||
--onefile \
|
||||
--noconfirm \
|
||||
--name mimic3-server \
|
||||
--hidden-import 'pycrfsuite._dumpparser' \
|
||||
--hidden-import 'pycrfsuite._logparser' \
|
||||
--collect-binaries 'onnxruntime' \
|
||||
--add-binary "$(/sbin/ldconfig -p | grep libespeak-ng.so.1 | awk '{print $4}'):." \
|
||||
--collect-data 'gruut' \
|
||||
--hidden-import "gruut_lang_de" \
|
||||
--collect-data "gruut_lang_de" \
|
||||
--hidden-import "gruut_lang_en" \
|
||||
--collect-data "gruut_lang_en" \
|
||||
--hidden-import "gruut_lang_fr" \
|
||||
--collect-data "gruut_lang_fr" \
|
||||
--hidden-import "gruut_lang_it" \
|
||||
--collect-data "gruut_lang_it" \
|
||||
--hidden-import "gruut_lang_nl" \
|
||||
--collect-data "gruut_lang_nl" \
|
||||
--hidden-import "gruut_lang_ru" \
|
||||
--collect-data "gruut_lang_ru" \
|
||||
--hidden-import "gruut_lang_sw" \
|
||||
--collect-data "gruut_lang_sw" \
|
||||
--collect-data 'espeak_phonemizer' \
|
||||
--collect-data 'phonemes2ids' \
|
||||
--collect-data 'mimic3_tts' \
|
||||
--collect-data 'mimic3_http' \
|
||||
pyinstaller/mimic3_server.py
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
FROM scratch
|
||||
|
||||
COPY --from=build /build/mimic3/dist/ /
|
||||
10
Makefile
10
Makefile
|
|
@ -13,7 +13,10 @@
|
|||
# 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/>.
|
||||
#
|
||||
.PHONY: dist install docker
|
||||
.PHONY: dist install docker binaries
|
||||
|
||||
SHELL := bash
|
||||
DOCKER_PLATFORM := linux/amd64
|
||||
|
||||
dist:
|
||||
cd opentts-abc && python3 setup.py sdist
|
||||
|
|
@ -28,4 +31,7 @@ install:
|
|||
./install.sh
|
||||
|
||||
docker:
|
||||
docker buildx build . -f Dockerfile --tag mycroftai/mimic3 --load
|
||||
docker buildx build . -f Dockerfile --platform $(DOCKER_PLATFORM) --tag mycroftai/mimic3 --load
|
||||
|
||||
binaries:
|
||||
docker buildx build . -f Dockerfile.binary $(DOCKER_PLATFORM) --output type=local,dest=dist/$(DOCKER_PLATFORM)
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@ this_dir="$( cd "$( dirname "$0" )" && pwd )"
|
|||
|
||||
# Kebab to snake case
|
||||
module_name="$(basename "${this_dir}" | sed -e 's/-/_/g')"
|
||||
base_dir="$(realpath "${this_dir}/..")"
|
||||
src_dir="${this_dir}/${module_name}"
|
||||
|
||||
# Path to virtual environment
|
||||
: "${venv:=${this_dir}/.venv}"
|
||||
: "${venv:=${base_dir}/.venv}"
|
||||
|
||||
if [ -d "${venv}" ]; then
|
||||
# Activate virtual environment if available
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@ import csv
|
|||
import io
|
||||
import logging
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
|
|
@ -39,6 +42,7 @@ if typing.TYPE_CHECKING:
|
|||
|
||||
_LOGGER = logging.getLogger(_PACKAGE)
|
||||
|
||||
_DEFAULT_PLAY_PROGRAMS = ["paplay", "play -q", "aplay -q"]
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -264,7 +268,7 @@ def process_result(state: CommandLineInterfaceState):
|
|||
wav_bytes = result.to_wav_bytes()
|
||||
|
||||
if wav_bytes:
|
||||
play_wav_bytes(wav_bytes)
|
||||
play_wav_bytes(state.args, wav_bytes)
|
||||
|
||||
if args.output_dir:
|
||||
if not wav_bytes:
|
||||
|
|
@ -387,7 +391,7 @@ def process_lines(state: CommandLineInterfaceState):
|
|||
wav_file_play.setnchannels(state.num_channels)
|
||||
wav_file_play.writeframes(state.all_audio)
|
||||
|
||||
play_wav_bytes(wav_io.getvalue())
|
||||
play_wav_bytes(state.args, wav_io.getvalue())
|
||||
else:
|
||||
# Write output directly to stdout
|
||||
wav_file_write: wave.Wave_write = wave.open(sys.stdout.buffer, "wb")
|
||||
|
|
@ -406,15 +410,20 @@ def shutdown_tts(state: CommandLineInterfaceState):
|
|||
state.tts = None
|
||||
|
||||
|
||||
def play_wav_bytes(wav_bytes: bytes):
|
||||
from playsound import playsound
|
||||
|
||||
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)
|
||||
|
||||
_LOGGER.debug("Playing WAV file: %s", wav_file.name)
|
||||
playsound(wav_file.name)
|
||||
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
|
||||
|
||||
|
||||
def print_voices(state: CommandLineInterfaceState):
|
||||
|
|
@ -521,6 +530,12 @@ def get_args():
|
|||
parser.add_argument(
|
||||
"--preload-voice", action="append", help="Preload voice when starting up"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--play-program",
|
||||
action="append",
|
||||
default=_DEFAULT_PLAY_PROGRAMS,
|
||||
help="Program(s) used to play WAV files",
|
||||
)
|
||||
parser.add_argument("--seed", type=int, help="Set random seed (default: not set)")
|
||||
parser.add_argument("--version", action="store_true", help="Print version and exit")
|
||||
parser.add_argument(
|
||||
|
|
|
|||
|
|
@ -19,5 +19,7 @@ from xdgenvpy import XDG
|
|||
|
||||
DEFAULT_VOICE = "en_US/vctk_low"
|
||||
DEFAULT_LANGUAGE = "en_US"
|
||||
DEFAULT_VOICES_URL_FORMAT = "https://github.com/MycroftAI/mimic3-voices/raw/master/voices/{lang}/{name}"
|
||||
DEFAULT_VOICES_URL_FORMAT = (
|
||||
"https://github.com/MycroftAI/mimic3-voices/raw/master/voices/{lang}/{name}"
|
||||
)
|
||||
DEFAULT_VOICES_DOWNLOAD_DIR = Path(XDG().XDG_DATA_HOME) / "mimic3" / "voices"
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@ ignore_missing_imports = True
|
|||
[mypy-onnxruntime.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-playsound.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-tqdm.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
dataclasses-json<1.0
|
||||
espeak-phonemizer>=1.0,<2.0
|
||||
gruut>=2.2.2,<3.0
|
||||
gruut>=2.3.0,<3.0
|
||||
numpy<2.0
|
||||
onnxruntime>=1.6,<2.0
|
||||
opentts_abc<1.0
|
||||
phonemes2ids<2.0
|
||||
playsound~=1.3.0
|
||||
tqdm>=4,<5
|
||||
xdgenvpy>2.0,<3
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
black==22.1.0
|
||||
coverage==5.0.4
|
||||
flake8==3.7.9
|
||||
mypy==0.910
|
||||
pylint==2.10.2
|
||||
pytest==5.4.1
|
||||
pytest-cov==2.8.1
|
||||
|
|
@ -81,7 +81,7 @@ setup(
|
|||
author_email="michael.hansen@mycroft.ai",
|
||||
license="AGPLv3+",
|
||||
packages=setuptools.find_packages(),
|
||||
package_data={"mimic3_tts": ["VERSION", "py.typed"]},
|
||||
package_data={"mimic3_tts": ["VERSION", "py.typed", "voices.json"]},
|
||||
install_requires=requirements,
|
||||
extras_require={':python_version<"3.9"': ["importlib_resources"], **extras_require},
|
||||
entry_points={"console_scripts": ["mimic3 = mimic3_cli.__main__:main"]},
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
# Directory of *this* script
|
||||
this_dir="$( cd "$( dirname "$0" )" && pwd )"
|
||||
|
||||
# Path to virtual environment
|
||||
: "${venv:=${this_dir}/.venv}"
|
||||
|
||||
# Python binary to use
|
||||
: "${PYTHON=python3}"
|
||||
|
||||
# pip install command
|
||||
: "${PIP_INSTALL=install}"
|
||||
|
||||
python_version="$(${PYTHON} --version)"
|
||||
|
||||
# Create virtual environment
|
||||
echo "Creating virtual environment at ${venv} (${python_version})"
|
||||
rm -rf "${venv}"
|
||||
"${PYTHON}" -m venv "${venv}"
|
||||
source "${venv}/bin/activate"
|
||||
|
||||
# Install Python dependencies
|
||||
echo 'Installing Python dependencies'
|
||||
pip3 ${PIP_INSTALL} --upgrade pip
|
||||
pip3 ${PIP_INSTALL} --upgrade wheel setuptools
|
||||
|
||||
find "${this_dir}" -name 'requirements*.txt' -type f -print0 | \
|
||||
xargs -0 -n1 pip3 ${PIP_INSTALL} -r
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
echo "OK"
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
black==22.1.0
|
||||
coverage==5.0.4
|
||||
flake8==3.7.9
|
||||
mypy==0.910
|
||||
pylint==2.10.2
|
||||
pytest==5.4.1
|
||||
pytest-cov==2.8.1
|
||||
21
pyinstaller/mimic3.py
Normal file
21
pyinstaller/mimic3.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
# 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/>.
|
||||
#
|
||||
"""Stub for PyInstaller"""
|
||||
|
||||
from mimic3_tts.__main__ import main
|
||||
|
||||
main()
|
||||
21
pyinstaller/mimic3_server.py
Normal file
21
pyinstaller/mimic3_server.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
# 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/>.
|
||||
#
|
||||
"""Stub for PyInstaller"""
|
||||
|
||||
from mimic3_http.__main__ import main
|
||||
|
||||
main()
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
black==22.1.0
|
||||
black==22.3.0
|
||||
coverage==5.0.4
|
||||
flake8==3.7.9
|
||||
mypy==0.910
|
||||
Loading…
Add table
Add a link
Reference in a new issue