- Add XTTS v2 configuration to .env.example - Refactor Dockerfile to multi-stage build with CUDA 12.1 support - Update Makefile with Kokoro and XTTS test environment targets - Refactor Piper engine (app/engines/piper.py) to use python module execution - Add comprehensive documentation for Kokoro and XTTS plans - Add helper scripts and patches for build process
80 lines
2.8 KiB
Python
Executable File
80 lines
2.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
A simple CLI client to test the AudioEngineHub TTS server.
|
|
|
|
This script requires the 'requests' library.
|
|
Install it with: pip install requests
|
|
"""
|
|
|
|
import argparse
|
|
import requests
|
|
import os
|
|
from urllib.parse import urljoin
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="CLI client for AudioEngineHub TTS server.")
|
|
parser.add_argument("--server-url", required=True, help="Base URL of the TTS server (e.g., http://localhost:8000).")
|
|
parser.add_argument("--text", required=True, help="Text to synthesize.")
|
|
parser.add_argument("--engine", required=True, help="TTS engine to use (e.g., piper).")
|
|
parser.add_argument("--model", help="Model to use (optional).")
|
|
parser.add_argument("--speaker", help="Speaker to use (optional).")
|
|
parser.add_argument("--output", required=True, help="Path to save the output audio file (e.g., output.ogg).")
|
|
|
|
args = parser.parse_args()
|
|
|
|
# --- 1. Make the TTS request ---
|
|
tts_url = urljoin(args.server_url, "/tts")
|
|
payload = {
|
|
"text": args.text,
|
|
"engine": args.engine,
|
|
"format": "ogg" # Or determine from output file extension
|
|
}
|
|
if args.model:
|
|
payload["model"] = args.model
|
|
if args.speaker:
|
|
payload["speaker"] = args.speaker
|
|
|
|
print(f"Requesting synthesis from {tts_url} with payload: {payload}")
|
|
# Add a short delay to mitigate potential connection race conditions
|
|
import time
|
|
time.sleep(1)
|
|
try:
|
|
response = requests.post(tts_url, json=payload)
|
|
response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"ERROR: Could not connect to the server: {e}")
|
|
return
|
|
|
|
try:
|
|
data = response.json()
|
|
except requests.exceptions.JSONDecodeError:
|
|
print(f"ERROR: Failed to decode JSON response from server. Response text: {response.text}")
|
|
return
|
|
|
|
if "audio_url" not in data:
|
|
print(f"ERROR: Server response did not contain 'audio_url'. Response: {data}")
|
|
return
|
|
|
|
# --- 2. Download the audio file ---
|
|
audio_url = urljoin(args.server_url, data["audio_url"])
|
|
print(f"Downloading audio from {audio_url}...")
|
|
|
|
try:
|
|
audio_response = requests.get(audio_url, stream=True)
|
|
audio_response.raise_for_status()
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"ERROR: Could not download the audio file: {e}")
|
|
return
|
|
|
|
# --- 3. Save the audio file ---
|
|
try:
|
|
with open(args.output, "wb") as f:
|
|
for chunk in audio_response.iter_content(chunk_size=8192):
|
|
f.write(chunk)
|
|
print(f"Successfully saved audio to '{args.output}'")
|
|
except IOError as e:
|
|
print(f"ERROR: Could not write to output file '{args.output}': {e}")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|