Spaces:
Sleeping
Sleeping
Download chatterbox_invocation.py from ShubhamSantoki/chatterbox-test: direct link, hf CLI and curl.
- Browser
- Download file 5.45 kB
-
https://huggingface.co/spaces/ShubhamSantoki/chatterbox-test/resolve/main/chatterbox_invocation.py
- Command line
-
hf download hf://spaces/ShubhamSantoki/chatterbox-test/chatterbox_invocation.py
-
curl -L -o chatterbox_invocation.py https://huggingface.co/spaces/ShubhamSantoki/chatterbox-test/resolve/main/chatterbox_invocation.py
5.45 kB
| """Invoke the Chatterbox Multilingual TTS Azure ML online endpoint. | |
| Request/response schema here is taken directly from the deployed scoring | |
| script (chatterbox-tts-endpoint/deployment/score.py), not guessed: | |
| request {text, language_id, audio_prompt_base64?, exaggeration?, | |
| cfg_weight?, temperature?} | |
| response {audio_base64, sample_rate, format: "wav", language_id} | |
| or {"error": "..."} (score.py can return an error body with a | |
| 2xx status for request-validation failures, so callers must | |
| check for an "error" key rather than trusting response.ok alone) | |
| """ | |
| import argparse | |
| import json | |
| import os | |
| from typing import Any, Optional | |
| import requests | |
| from config import DEFAULT_URL, DEFAULT_DEPLOYMENT | |
| class ChatterboxError(RuntimeError): | |
| """Raised when the endpoint returns a validation/error body.""" | |
| def invoke_chatterbox( | |
| text: str, | |
| api_key: str, | |
| url: str = DEFAULT_URL, | |
| language_id: str = "en", | |
| audio_prompt_base64: Optional[str] = None, | |
| exaggeration: Optional[float] = None, | |
| cfg_weight: Optional[float] = None, | |
| temperature: Optional[float] = None, | |
| deployment_name: Optional[str] = DEFAULT_DEPLOYMENT, | |
| timeout: float = 60.0, | |
| ) -> dict: | |
| """Call the Chatterbox TTS endpoint and return the parsed JSON response. | |
| Args: | |
| text: Text to synthesize. | |
| api_key: Primary/secondary key, AMLToken, or Microsoft Entra ID token for the endpoint. | |
| url: Endpoint scoring URL. | |
| language_id: One of score.py's SUPPORTED_LANGUAGES (see resolve_languages.py | |
| to fetch the live list from the endpoint itself). | |
| audio_prompt_base64: Base64-encoded WAV reference clip for zero-shot voice | |
| cloning (<=10MB decoded). Omit for the default voice. | |
| exaggeration: Emotional intensity, 0.0-2.0 (endpoint default 0.5). | |
| cfg_weight: Pacing/deliberateness, 0.0-1.0 (endpoint default 0.5). | |
| temperature: Delivery variability, 0.0-2.0 (endpoint default 0.8). | |
| deployment_name: Specific deployment to target via the | |
| "azureml-model-deployment" header. Pass None to let the | |
| endpoint's traffic rules decide. | |
| timeout: Request timeout in seconds. | |
| Returns: | |
| The parsed JSON response body: {"audio_base64", "sample_rate", "format", "language_id"}. | |
| Raises: | |
| ValueError: If api_key or text is empty. | |
| ChatterboxError: If the endpoint returns an {"error": ...} body. | |
| requests.HTTPError: If the HTTP request itself fails. | |
| """ | |
| if not api_key: | |
| raise ValueError("A key should be provided to invoke the endpoint") | |
| if not text or not text.strip(): | |
| raise ValueError("text must be non-empty") | |
| request_body: dict[str, Any] = {"text": text, "language_id": language_id} | |
| if exaggeration is not None: | |
| request_body["exaggeration"] = exaggeration | |
| if cfg_weight is not None: | |
| request_body["cfg_weight"] = cfg_weight | |
| if temperature is not None: | |
| request_body["temperature"] = temperature | |
| if audio_prompt_base64: | |
| request_body["audio_prompt_base64"] = audio_prompt_base64 | |
| headers = { | |
| "Content-Type": "application/json", | |
| "Authorization": f"Bearer {api_key}", | |
| } | |
| if deployment_name: | |
| headers["azureml-model-deployment"] = deployment_name | |
| response = requests.post(url, json=request_body, headers=headers, timeout=timeout) | |
| if not response.ok: | |
| print("Response headers:", dict(response.headers)) | |
| print("Response body:", response.text) | |
| response.raise_for_status() | |
| result = response.json() | |
| if isinstance(result, dict) and "error" in result: | |
| raise ChatterboxError(result["error"]) | |
| return result | |
| def _parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser(description="Invoke the Chatterbox TTS endpoint") | |
| parser.add_argument("--text", default="Hello, this is a test message for Chatterbox text to speech.") | |
| parser.add_argument("--api-key", default=os.environ.get("CHATTERBOX_API_KEY", "")) | |
| parser.add_argument("--url", default=DEFAULT_URL) | |
| parser.add_argument("--language-id", default="en") | |
| parser.add_argument("--audio-prompt-path", default=None, help="Local WAV file for voice cloning") | |
| parser.add_argument("--exaggeration", type=float, default=None) | |
| parser.add_argument("--cfg-weight", type=float, default=None) | |
| parser.add_argument("--temperature", type=float, default=None) | |
| parser.add_argument("--deployment-name", default=DEFAULT_DEPLOYMENT) | |
| parser.add_argument("--timeout", type=float, default=60.0) | |
| return parser.parse_args() | |
| if __name__ == "__main__": | |
| from audio_utils import encode_reference_clip | |
| args = _parse_args() | |
| audio_prompt_b64 = encode_reference_clip(args.audio_prompt_path) if args.audio_prompt_path else None | |
| result = invoke_chatterbox( | |
| text=args.text, | |
| api_key=args.api_key, | |
| url=args.url, | |
| language_id=args.language_id, | |
| audio_prompt_base64=audio_prompt_b64, | |
| exaggeration=args.exaggeration, | |
| cfg_weight=args.cfg_weight, | |
| temperature=args.temperature, | |
| deployment_name=args.deployment_name, | |
| timeout=args.timeout, | |
| ) | |
| printable = {k: v for k, v in result.items() if k != "audio_base64"} | |
| printable["audio_base64_len"] = len(result.get("audio_base64", "")) | |
| print(json.dumps(printable, indent=2)) | |