Spaces:
Running
Running
File size: 4,739 Bytes
adecb62 c8f7e68 adecb62 bc5091e 5a007ca adecb62 bc5091e adecb62 a375dbf 0e508c8 e9bcee8 0e508c8 5a007ca adecb62 c0b34a2 5a007ca adecb62 0e508c8 adecb62 e9bcee8 d1ed6b1 d4b2b49 bc5091e 0e508c8 adecb62 e9bcee8 d1ed6b1 d4b2b49 d1ed6b1 0e508c8 e9bcee8 d1ed6b1 adecb62 a6d4367 adecb62 d1ed6b1 adecb62 a5cafbd 7f25817 a5cafbd d1ed6b1 a5cafbd 5bf19b3 adecb62 0e508c8 adecb62 5bf19b3 adecb62 5bf19b3 adecb62 7f25817 adecb62 d1ed6b1 5bf19b3 d1ed6b1 adecb62 5bf19b3 adecb62 bc5091e adecb62 d4b2b49 adecb62 7f25817 8047063 0e508c8 d4b2b49 0e508c8 d4b2b49 0e508c8 d4b2b49 0e508c8 5bf19b3 0e508c8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
"""
hume_api.py
This file defines the interaction with the Hume text-to-speech (TTS) API.
It includes functionality for API request handling and processing API responses.
Key Features:
- Encapsulates all logic related to the Hume TTS API.
- Implements retry logic for handling transient API errors.
- Handles received audio and processes it for playback on the web.
- Provides detailed logging for debugging and error tracking.
Classes:
- HumeConfig: Immutable configuration for interacting with Hume's TTS API.
- HumeError: Custom exception for Hume API-related errors.
Functions:
- text_to_speech_with_hume: Synthesizes speech from text using Hume's TTS API.
"""
# Standard Library Imports
from dataclasses import dataclass
import logging
import os
import random
from typing import Literal, Optional
# Third-Party Library Imports
import requests
from tenacity import retry, stop_after_attempt, wait_fixed, before_log, after_log
# Local Application Imports
from src.config import logger
from src.utils import save_base64_audio_to_file, validate_env_var
HumeSupportedFileFormat = Literal["mp3", "pcm", "wav"]
""" Support audio file formats for the Hume TTS API"""
@dataclass(frozen=True)
class HumeConfig:
"""Immutable configuration for interacting with the Hume TTS API."""
api_key: str = validate_env_var("HUME_API_KEY")
url: str = "https://test-api.hume.ai/v0/tts/octave"
headers: dict = None
file_format: HumeSupportedFileFormat = "mp3"
def __post_init__(self):
# Validate required attributes
if not self.api_key:
raise ValueError("Hume API key is not set.")
if not self.url:
raise ValueError("Hume TTS endpoint URL is not set.")
if not self.file_format:
raise ValueError("Hume TTS file format is not set.")
# Set headers dynamically after validation
object.__setattr__(
self,
"headers",
{
"X-Hume-Api-Key": f"{self.api_key}",
"Content-Type": "application/json",
},
)
class HumeError(Exception):
"""Custom exception for errors related to the Hume TTS API."""
def __init__(self, message: str, original_exception: Optional[Exception] = None):
super().__init__(message)
self.original_exception = original_exception
# Initialize the Hume client
hume_config = HumeConfig()
@retry(
stop=stop_after_attempt(3),
wait=wait_fixed(2),
before=before_log(logger, logging.DEBUG),
after=after_log(logger, logging.DEBUG),
reraise=True,
)
def text_to_speech_with_hume(character_description: str, text: str) -> bytes:
"""
Synthesizes text to speech using the Hume TTS API, processes audio data, and writes audio to a file.
Args:
character_description (str): The original user character description to use as the description for generating the voice.
text (str): The generated text to be converted to speech.
Returns:
Tuple[str, str]: A tuple containing:
- generation_id (str): The generation ID returned from the Hume API.
- file_path (str): The relative path to the file where the synthesized audio was saved.
Raises:
HumeError: If there is an error communicating with the Hume TTS API or parsing the response.
"""
logger.debug(
f"Processing TTS with Hume. Prompt length: {len(character_description)} characters. Text length: {len(text)} characters."
)
request_body = {
"utterances": [{"text": text, "description": character_description}]
}
try:
# Synthesize speech using the Hume TTS API
response = requests.post(
url=hume_config.url,
headers=hume_config.headers,
json=request_body,
)
response.raise_for_status()
response_data = response.json()
generations = response_data.get("generations")
if not generations:
msg = "No generations returned by Hume API."
logger.error(msg)
raise HumeError(msg)
# Extract the base64 encoded audio and generation ID from the generation
generation = generations[0]
generation_id = generation.get("generation_id")
base64_audio = generation.get("audio")
filename = f"{generation_id}.mp3"
# Write audio to file and return the relative path
return generation_id, save_base64_audio_to_file(base64_audio, filename)
except Exception as e:
logger.exception(f"Error synthesizing speech with Hume: {e}")
raise HumeError(
message=f"Failed to synthesize speech with Hume: {e}",
original_exception=e,
) from e
|