ipin-vr/ipin_vr/tts.py

68 lines
2.1 KiB
Python
Raw Permalink Normal View History

import os
import shutil
import subprocess
import sys
import tempfile
_LINUX_PLAYERS = ["pw-play", "paplay", "aplay"]
def speak(text: str, voice_path: str) -> None:
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tf:
wav_path = tf.name
try:
proc = subprocess.run(
["piper", "--model", voice_path, "--output_file", wav_path],
input=text.encode(),
capture_output=True,
timeout=15,
)
if proc.returncode != 0:
stderr = proc.stderr.decode(errors="replace").strip()
print(f"[TTS off: piper błąd {proc.returncode}: {stderr}]")
return
_play(wav_path)
except FileNotFoundError:
print("[TTS off: piper nie znaleziony — zainstaluj piper-tts]")
except subprocess.TimeoutExpired:
print("[TTS off: piper timeout]")
except Exception as exc:
print(f"[TTS off: {exc}]")
finally:
try:
os.unlink(wav_path)
except OSError:
pass
def _play(wav_path: str) -> None:
if sys.platform.startswith("linux"):
player = next((p for p in _LINUX_PLAYERS if shutil.which(p)), None)
if player is None:
print("[TTS: brak odtwarzacza audio]")
return
_run_player(player, wav_path)
elif sys.platform == "darwin":
_run_player("afplay", wav_path)
elif sys.platform == "win32":
try:
import winsound
winsound.PlaySound(wav_path, winsound.SND_FILENAME)
except Exception as exc:
print(f"[TTS off: winsound: {exc}]")
else:
print(f"[TTS off: nieobsługiwana platforma {sys.platform}]")
def _run_player(player: str, wav_path: str) -> None:
try:
proc = subprocess.run([player, wav_path], capture_output=True, timeout=30)
if proc.returncode != 0:
stderr = proc.stderr.decode(errors="replace").strip()
print(f"[TTS: {player} błąd {proc.returncode}: {stderr}]")
except FileNotFoundError:
print(f"[TTS off: {player} nie znaleziony]")
except Exception as exc:
print(f"[TTS off: {exc}]")