download new piper voice if it doesn't exist

This commit is contained in:
victor 2024-03-28 19:10:43 +00:00
parent c819eba22c
commit ca0ab75451
1 changed files with 95 additions and 34 deletions

View File

@ -1,10 +1,11 @@
import ffmpeg
import tempfile
import os import os
import subprocess
import urllib.request
import tarfile
import platform import platform
import subprocess
import tarfile
import tempfile
import urllib.request
import ffmpeg
class Tts: class Tts:
@ -17,22 +18,41 @@ class Tts:
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_file: with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_file:
output_file = temp_file.name output_file = temp_file.name
piper_dir = self.piper_directory piper_dir = self.piper_directory
subprocess.run([ subprocess.run(
os.path.join(piper_dir, 'piper'), [
'--model', os.path.join(piper_dir, os.getenv('PIPER_VOICE_NAME', 'en_US-lessac-medium.onnx')), os.path.join(piper_dir, "piper"),
'--output_file', output_file "--model",
], input=text, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) os.path.join(
piper_dir,
os.getenv("PIPER_VOICE_NAME", "en_US-lessac-medium.onnx"),
),
"--output_file",
output_file,
],
input=text,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
# TODO: hack to format audio correctly for device # TODO: hack to format audio correctly for device
outfile = tempfile.gettempdir() + "/" + "raw.dat" outfile = tempfile.gettempdir() + "/" + "raw.dat"
ffmpeg.input(temp_file.name).output(outfile, f="s16le", ar="16000", ac="1", loglevel='panic').run() ffmpeg.input(temp_file.name).output(
outfile, f="s16le", ar="16000", ac="1", loglevel="panic"
).run()
return outfile return outfile
def install(self, service_directory): def install(self, service_directory):
# Determine OS and architecture
OS = os.uname().sysname
ARCH = os.uname().machine
PIPER_FOLDER_PATH = service_directory PIPER_FOLDER_PATH = service_directory
self.piper_directory = os.path.join(PIPER_FOLDER_PATH, 'piper') self.piper_directory = os.path.join(PIPER_FOLDER_PATH, "piper")
if not os.path.isdir(self.piper_directory): # Check if the Piper directory exists if not os.path.isdir(
self.piper_directory
): # Check if the Piper directory exists
os.makedirs(PIPER_FOLDER_PATH, exist_ok=True) os.makedirs(PIPER_FOLDER_PATH, exist_ok=True)
# Determine OS and architecture # Determine OS and architecture
@ -75,37 +95,78 @@ class Tts:
with tarfile.open(os.path.join(PIPER_FOLDER_PATH, PIPER_ASSETNAME), 'r:gz') as tar: with tarfile.open(os.path.join(PIPER_FOLDER_PATH, PIPER_ASSETNAME), 'r:gz') as tar:
tar.extractall(path=PIPER_FOLDER_PATH) tar.extractall(path=PIPER_FOLDER_PATH)
PIPER_VOICE_URL = os.getenv('PIPER_VOICE_URL',
'https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/lessac/medium/')
PIPER_VOICE_NAME = os.getenv('PIPER_VOICE_NAME', 'en_US-lessac-medium.onnx')
# Download voice model and its json file
urllib.request.urlretrieve(f"{PIPER_VOICE_URL}{PIPER_VOICE_NAME}",
os.path.join(self.piper_directory, PIPER_VOICE_NAME))
urllib.request.urlretrieve(f"{PIPER_VOICE_URL}{PIPER_VOICE_NAME}.json",
os.path.join(self.piper_directory, f"{PIPER_VOICE_NAME}.json"))
# Additional setup for macOS # Additional setup for macOS
if OS == "macos": if OS == "macos":
if ARCH == "x64": if ARCH == "x64":
subprocess.run(['softwareupdate', '--install-rosetta', '--agree-to-license']) subprocess.run(
["softwareupdate", "--install-rosetta", "--agree-to-license"]
)
PIPER_PHONEMIZE_ASSETNAME = f"piper-phonemize_{OS}_{ARCH}.tar.gz" PIPER_PHONEMIZE_ASSETNAME = f"piper-phonemize_{OS}_{ARCH}.tar.gz"
PIPER_PHONEMIZE_URL = "https://github.com/rhasspy/piper-phonemize/releases/latest/download/" PIPER_PHONEMIZE_URL = "https://github.com/rhasspy/piper-phonemize/releases/latest/download/"
urllib.request.urlretrieve(f"{PIPER_PHONEMIZE_URL}{PIPER_PHONEMIZE_ASSETNAME}", urllib.request.urlretrieve(
os.path.join(self.piper_directory, PIPER_PHONEMIZE_ASSETNAME)) f"{PIPER_PHONEMIZE_URL}{PIPER_PHONEMIZE_ASSETNAME}",
os.path.join(self.piper_directory, PIPER_PHONEMIZE_ASSETNAME),
)
with tarfile.open(os.path.join(self.piper_directory, PIPER_PHONEMIZE_ASSETNAME), 'r:gz') as tar: with tarfile.open(
os.path.join(self.piper_directory, PIPER_PHONEMIZE_ASSETNAME),
"r:gz",
) as tar:
tar.extractall(path=self.piper_directory) tar.extractall(path=self.piper_directory)
PIPER_DIR = self.piper_directory PIPER_DIR = self.piper_directory
subprocess.run(['install_name_tool', '-change', '@rpath/libespeak-ng.1.dylib', subprocess.run(
f"{PIPER_DIR}/piper-phonemize/lib/libespeak-ng.1.dylib", f"{PIPER_DIR}/piper"]) [
subprocess.run(['install_name_tool', '-change', '@rpath/libonnxruntime.1.14.1.dylib', "install_name_tool",
f"{PIPER_DIR}/piper-phonemize/lib/libonnxruntime.1.14.1.dylib", f"{PIPER_DIR}/piper"]) "-change",
subprocess.run(['install_name_tool', '-change', '@rpath/libpiper_phonemize.1.dylib', "@rpath/libespeak-ng.1.dylib",
f"{PIPER_DIR}/piper-phonemize/lib/libpiper_phonemize.1.dylib", f"{PIPER_DIR}/piper"]) f"{PIPER_DIR}/piper-phonemize/lib/libespeak-ng.1.dylib",
f"{PIPER_DIR}/piper",
]
)
subprocess.run(
[
"install_name_tool",
"-change",
"@rpath/libonnxruntime.1.14.1.dylib",
f"{PIPER_DIR}/piper-phonemize/lib/libonnxruntime.1.14.1.dylib",
f"{PIPER_DIR}/piper",
]
)
subprocess.run(
[
"install_name_tool",
"-change",
"@rpath/libpiper_phonemize.1.dylib",
f"{PIPER_DIR}/piper-phonemize/lib/libpiper_phonemize.1.dylib",
f"{PIPER_DIR}/piper",
]
)
print("Piper download completed.")
print("Piper setup completed.") PIPER_VOICE_URL = os.getenv(
"PIPER_VOICE_URL",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/lessac/medium/",
)
PIPER_VOICE_NAME = os.getenv("PIPER_VOICE_NAME", "en_US-lessac-medium.onnx")
self.piper_model_file = os.path.join(
PIPER_FOLDER_PATH, "piper", PIPER_VOICE_NAME
)
# Check if model file exists
if not os.path.isfile(self.piper_model_file):
# Download voice model and its json file
urllib.request.urlretrieve(
f"{PIPER_VOICE_URL}{PIPER_VOICE_NAME}",
os.path.join(self.piper_directory, PIPER_VOICE_NAME),
)
urllib.request.urlretrieve(
f"{PIPER_VOICE_URL}{PIPER_VOICE_NAME}.json",
os.path.join(self.piper_directory, f"{PIPER_VOICE_NAME}.json"),
)
print("Piper voice model setup completed.")
else: else:
print("Piper already set up. Skipping download.") print("Piper already set up. Skipping download.")