[add] Load voice parameters from .env file
Configure Piper TTS synthesis via environment variables (speaker_id, length_scale, noise_scale, noise_w_scale, volume) loaded from .env with python-dotenv. Includes .env.example as reference template. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
# Piper TTS voice configuration
|
||||||
|
VOICE_MODEL=en_GB-alan-medium.onnx # Path to Piper .onnx voice model (relative to project root)
|
||||||
|
VOICE_SPEAKER_ID= # Speaker ID for multi-speaker models (integer, leave empty for default)
|
||||||
|
VOICE_LENGTH_SCALE= # Speech speed: >1.0 = slower, <1.0 = faster (leave empty for model default)
|
||||||
|
VOICE_NOISE_SCALE= # Phoneme variability: 0.0 = robotic, 1.0 = expressive (leave empty for model default)
|
||||||
|
VOICE_NOISE_W_SCALE= # Phoneme width variability (leave empty for model default)
|
||||||
|
VOICE_VOLUME=1.0 # Playback volume multiplier (default: 1.0)
|
||||||
|
|
||||||
|
# Vosk STT configuration
|
||||||
|
STT_MODEL=vosk-model-small-en-us-0.15 # Vosk model directory name (relative to project root)
|
||||||
@@ -4,3 +4,4 @@ __pycache__/
|
|||||||
save.qzl
|
save.qzl
|
||||||
vosk-model-*/
|
vosk-model-*/
|
||||||
.wolf
|
.wolf
|
||||||
|
.env
|
||||||
|
|||||||
+18
-2
@@ -9,13 +9,29 @@ import wave
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from piper import PiperVoice
|
from piper import PiperVoice
|
||||||
|
from piper.config import SynthesisConfig
|
||||||
|
|
||||||
|
|
||||||
class TTS:
|
class TTS:
|
||||||
"""Speaks text using Piper TTS and aplay for playback."""
|
"""Speaks text using Piper TTS and aplay for playback."""
|
||||||
|
|
||||||
def __init__(self, model_path: str | Path) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
model_path: str | Path,
|
||||||
|
speaker_id: int | None = None,
|
||||||
|
length_scale: float | None = None,
|
||||||
|
noise_scale: float | None = None,
|
||||||
|
noise_w_scale: float | None = None,
|
||||||
|
volume: float = 1.0,
|
||||||
|
) -> None:
|
||||||
self._voice = PiperVoice.load(str(model_path))
|
self._voice = PiperVoice.load(str(model_path))
|
||||||
|
self._syn_config = SynthesisConfig(
|
||||||
|
speaker_id=speaker_id,
|
||||||
|
length_scale=length_scale,
|
||||||
|
noise_scale=noise_scale,
|
||||||
|
noise_w_scale=noise_w_scale,
|
||||||
|
volume=volume,
|
||||||
|
)
|
||||||
self._thread: threading.Thread | None = None
|
self._thread: threading.Thread | None = None
|
||||||
self._last_wav: bytes | None = None
|
self._last_wav: bytes | None = None
|
||||||
|
|
||||||
@@ -39,7 +55,7 @@ class TTS:
|
|||||||
def _synthesize(self, text: str) -> bytes:
|
def _synthesize(self, text: str) -> bytes:
|
||||||
buf = io.BytesIO()
|
buf = io.BytesIO()
|
||||||
with wave.open(buf, "wb") as wav_file:
|
with wave.open(buf, "wb") as wav_file:
|
||||||
self._voice.synthesize_wav(text, wav_file)
|
self._voice.synthesize_wav(text, wav_file, syn_config=self._syn_config)
|
||||||
return buf.getvalue()
|
return buf.getvalue()
|
||||||
|
|
||||||
def _play(self, wav_data: bytes) -> None:
|
def _play(self, wav_data: bytes) -> None:
|
||||||
|
|||||||
+30
-4
@@ -2,8 +2,11 @@
|
|||||||
"""The Hitchhiker's Guide to the Galaxy — Python text adventure engine."""
|
"""The Hitchhiker's Guide to the Galaxy — Python text adventure engine."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
from h2g2.engine.clock import Clock
|
from h2g2.engine.clock import Clock
|
||||||
from h2g2.engine.loop import GameLoop
|
from h2g2.engine.loop import GameLoop
|
||||||
from h2g2.engine.output import Output
|
from h2g2.engine.output import Output
|
||||||
@@ -17,9 +20,25 @@ import h2g2.engine.verbs # noqa: F401
|
|||||||
# Import content modules
|
# Import content modules
|
||||||
from h2g2.content import globals_content, earth, vogon, heart, unearth, dark
|
from h2g2.content import globals_content, earth, vogon, heart, unearth, dark
|
||||||
|
|
||||||
# Default model locations (project root)
|
# Load .env from project root
|
||||||
_DEFAULT_VOICE = Path(__file__).resolve().parent.parent / "en_GB-alan-medium.onnx"
|
_PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
||||||
_DEFAULT_STT_MODEL = Path(__file__).resolve().parent.parent / "vosk-model-small-en-us-0.15"
|
load_dotenv(_PROJECT_ROOT / ".env")
|
||||||
|
|
||||||
|
# Default model locations (from env or project root)
|
||||||
|
_DEFAULT_VOICE = _PROJECT_ROOT / os.getenv("VOICE_MODEL", "en_GB-alan-medium.onnx")
|
||||||
|
_DEFAULT_STT_MODEL = _PROJECT_ROOT / os.getenv("STT_MODEL", "vosk-model-small-en-us-0.15")
|
||||||
|
|
||||||
|
|
||||||
|
def _env_float(key: str) -> float | None:
|
||||||
|
"""Read an env var as float, returning None if empty/unset."""
|
||||||
|
val = os.getenv(key, "").strip()
|
||||||
|
return float(val) if val else None
|
||||||
|
|
||||||
|
|
||||||
|
def _env_int(key: str) -> int | None:
|
||||||
|
"""Read an env var as int, returning None if empty/unset."""
|
||||||
|
val = os.getenv(key, "").strip()
|
||||||
|
return int(val) if val else None
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
@@ -116,7 +135,14 @@ def main() -> None:
|
|||||||
tts = None
|
tts = None
|
||||||
if args.audio:
|
if args.audio:
|
||||||
from h2g2.engine.tts import TTS
|
from h2g2.engine.tts import TTS
|
||||||
tts = TTS(args.voice)
|
tts = TTS(
|
||||||
|
args.voice,
|
||||||
|
speaker_id=_env_int("VOICE_SPEAKER_ID"),
|
||||||
|
length_scale=_env_float("VOICE_LENGTH_SCALE"),
|
||||||
|
noise_scale=_env_float("VOICE_NOISE_SCALE"),
|
||||||
|
noise_w_scale=_env_float("VOICE_NOISE_W_SCALE"),
|
||||||
|
volume=_env_float("VOICE_VOLUME") or 1.0,
|
||||||
|
)
|
||||||
|
|
||||||
# Initialize STT if requested
|
# Initialize STT if requested
|
||||||
stt = None
|
stt = None
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ dependencies = [
|
|||||||
"piper-tts>=1.2.0",
|
"piper-tts>=1.2.0",
|
||||||
"vosk>=0.3.45",
|
"vosk>=0.3.45",
|
||||||
"pyaudio>=0.2.14",
|
"pyaudio>=0.2.14",
|
||||||
|
"python-dotenv>=1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
|
|||||||
Reference in New Issue
Block a user