diff --git a/software/source/server/services/tts/piper/tts.py b/software/source/server/services/tts/piper/tts.py index b9a00d3..effd1ea 100644 --- a/software/source/server/services/tts/piper/tts.py +++ b/software/source/server/services/tts/piper/tts.py @@ -1,9 +1,12 @@ -import ffmpeg -import tempfile import os +import platform import subprocess -import urllib.request import tarfile +import tempfile +import urllib.request + +import ffmpeg + class Tts: def __init__(self, config): @@ -11,31 +14,46 @@ class Tts: self.install(config["service_directory"]) def tts(self, text): - + with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_file: output_file = temp_file.name piper_dir = self.piper_directory - subprocess.run([ - os.path.join(piper_dir, 'piper'), - '--model', 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) + subprocess.run( + [ + os.path.join(piper_dir, "piper"), + "--model", + 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 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 def install(self, service_directory): PIPER_FOLDER_PATH = service_directory - self.piper_directory = os.path.join(PIPER_FOLDER_PATH, 'piper') - if not os.path.isdir(self.piper_directory): # Check if the Piper directory exists + self.piper_directory = os.path.join(PIPER_FOLDER_PATH, "piper") + if not os.path.isdir( + self.piper_directory + ): # Check if the Piper directory exists os.makedirs(PIPER_FOLDER_PATH, exist_ok=True) # Determine OS and architecture - OS = os.uname().sysname - ARCH = os.uname().machine + OS = platform.system() + ARCH = platform.machine() if OS == "Darwin": OS = "macos" if ARCH == "arm64": @@ -50,33 +68,79 @@ class Tts: PIPER_URL = "https://github.com/rhasspy/piper/releases/latest/download/" # Download and extract Piper - urllib.request.urlretrieve(f"{PIPER_URL}{PIPER_ASSETNAME}", os.path.join(PIPER_FOLDER_PATH, PIPER_ASSETNAME)) - with tarfile.open(os.path.join(PIPER_FOLDER_PATH, PIPER_ASSETNAME), 'r:gz') as tar: + urllib.request.urlretrieve( + f"{PIPER_URL}{PIPER_ASSETNAME}", + os.path.join(PIPER_FOLDER_PATH, PIPER_ASSETNAME), + ) + with tarfile.open( + os.path.join(PIPER_FOLDER_PATH, PIPER_ASSETNAME), "r:gz" + ) as tar: 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') + 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")) + 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 if OS == "macos": 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_URL = "https://github.com/rhasspy/piper-phonemize/releases/latest/download/" - urllib.request.urlretrieve(f"{PIPER_PHONEMIZE_URL}{PIPER_PHONEMIZE_ASSETNAME}", os.path.join(self.piper_directory, PIPER_PHONEMIZE_ASSETNAME)) + urllib.request.urlretrieve( + 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) PIPER_DIR = self.piper_directory - subprocess.run(['install_name_tool', '-change', '@rpath/libespeak-ng.1.dylib', 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"]) + subprocess.run( + [ + "install_name_tool", + "-change", + "@rpath/libespeak-ng.1.dylib", + 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 setup completed.") else: