VoxCPM2-FP8-W8A8 / client.py
ajh-code's picture
Correct release designation to FP8 W8A8
b7102cf verified
Raw History Blame Contribute Delete
2.85 kB
#!/usr/bin/env python3
"""Small standard-library client for the bundled llama-compatible TTS API."""
from __future__ import annotations
import argparse
import base64
import json
import urllib.error
import urllib.request
from pathlib import Path
def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Generate speech with VoxCPM2 FP8 W8A8 V1")
parser.add_argument("--url", default="http://127.0.0.1:8080/v1/audio/speech")
parser.add_argument("--text", required=True)
parser.add_argument("--output", type=Path, default=Path("output.wav"))
parser.add_argument("--reference-audio", type=Path)
parser.add_argument("--reference-text", default="")
parser.add_argument("--seed", type=int, default=42)
parser.add_argument("--cfg-value", type=float, default=2.0)
parser.add_argument("--inference-timesteps", type=int, default=10)
parser.add_argument("--max-steps", type=int, default=200)
parser.add_argument("--temperature", type=float, default=1.0)
parser.add_argument("--timeout", type=float, default=600.0)
parser.add_argument("--force", action="store_true")
return parser
def main() -> None:
args = _parser().parse_args()
output = args.output.expanduser().resolve()
if output.exists() and not args.force:
raise SystemExit(f"Refusing to overwrite {output}; pass --force to replace it")
payload = {
"model": "voxcpm",
"input": args.text,
"voice": "default",
"response_format": "wav",
"seed": args.seed,
"cfg_value": args.cfg_value,
"inference_timesteps": args.inference_timesteps,
"max_steps": args.max_steps,
"temperature": args.temperature,
}
if args.reference_audio is not None:
reference = args.reference_audio.expanduser().resolve()
payload["reference_audio"] = base64.b64encode(reference.read_bytes()).decode()
if args.reference_text:
payload["reference_text"] = args.reference_text
request = urllib.request.Request(
args.url,
data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json"},
)
try:
with urllib.request.urlopen(request, timeout=args.timeout) as response:
content_type = response.headers.get_content_type()
if content_type != "audio/wav":
raise RuntimeError(f"Expected audio/wav, received {content_type}")
audio = response.read()
except urllib.error.HTTPError as exc:
detail = exc.read().decode(errors="replace")
raise SystemExit(f"TTS request failed with HTTP {exc.code}: {detail}") from exc
output.parent.mkdir(parents=True, exist_ok=True)
output.write_bytes(audio)
print(f"Wrote {len(audio)} bytes to {output}")
if __name__ == "__main__":
main()