Spaces:
Running
Running
zach
commited on
Commit
·
bf6610d
1
Parent(s):
4a475d2
Update hume integration to use Hume python sdk
Browse files- pyproject.toml +3 -2
- src/assets/styles.css +1 -1
- src/integrations/hume_api.py +60 -70
- uv.lock +68 -49
pyproject.toml
CHANGED
|
@@ -8,15 +8,16 @@ dependencies = [
|
|
| 8 |
"anthropic>=0.45.2",
|
| 9 |
"asyncpg>=0.28.0",
|
| 10 |
"elevenlabs>=1.50.7",
|
| 11 |
-
"gradio>=5.
|
| 12 |
"greenlet>=2.0.0",
|
| 13 |
-
"
|
| 14 |
"python-dotenv>=1.0.1",
|
| 15 |
"sqlalchemy>=2.0.0",
|
| 16 |
"tenacity>=9.0.0",
|
| 17 |
]
|
| 18 |
|
| 19 |
[tool.uv]
|
|
|
|
| 20 |
dev-dependencies = [
|
| 21 |
"mypy>=1.15.0",
|
| 22 |
"pre-commit>=4.1.0",
|
|
|
|
| 8 |
"anthropic>=0.45.2",
|
| 9 |
"asyncpg>=0.28.0",
|
| 10 |
"elevenlabs>=1.50.7",
|
| 11 |
+
"gradio>=5.18.0",
|
| 12 |
"greenlet>=2.0.0",
|
| 13 |
+
"hume>=0.7.8",
|
| 14 |
"python-dotenv>=1.0.1",
|
| 15 |
"sqlalchemy>=2.0.0",
|
| 16 |
"tenacity>=9.0.0",
|
| 17 |
]
|
| 18 |
|
| 19 |
[tool.uv]
|
| 20 |
+
override-dependencies = ["aiofiles==24.1.0"]
|
| 21 |
dev-dependencies = [
|
| 22 |
"mypy>=1.15.0",
|
| 23 |
"pre-commit>=4.1.0",
|
src/assets/styles.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
/* Remove Gradio footer from UI */
|
| 2 |
-
footer.svelte-
|
| 3 |
display: none !important;
|
| 4 |
}
|
| 5 |
|
|
|
|
| 1 |
/* Remove Gradio footer from UI */
|
| 2 |
+
footer.svelte-1byz9vf {
|
| 3 |
display: none !important;
|
| 4 |
}
|
| 5 |
|
src/integrations/hume_api.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
"""
|
| 2 |
hume_api.py
|
| 3 |
|
| 4 |
-
This file defines the interaction with the Hume text-to-speech (TTS) API
|
| 5 |
-
It includes functionality for API request handling and processing API responses.
|
| 6 |
|
| 7 |
Key Features:
|
| 8 |
- Encapsulates all logic related to the Hume TTS API.
|
|
@@ -15,10 +15,14 @@ Key Features:
|
|
| 15 |
import logging
|
| 16 |
import time
|
| 17 |
from dataclasses import dataclass, field
|
| 18 |
-
from typing import
|
| 19 |
|
| 20 |
# Third-Party Library Imports
|
| 21 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
from tenacity import after_log, before_log, retry, retry_if_exception, stop_after_attempt, wait_exponential
|
| 23 |
|
| 24 |
# Local Application Imports
|
|
@@ -26,34 +30,22 @@ from src.config import Config, logger
|
|
| 26 |
from src.constants import CLIENT_ERROR_CODE, SERVER_ERROR_CODE
|
| 27 |
from src.utils import save_base64_audio_to_file, validate_env_var
|
| 28 |
|
| 29 |
-
HumeSupportedFileFormat = Literal["mp3", "pcm", "wav"]
|
| 30 |
-
"""Supported audio file formats for the Hume TTS API"""
|
| 31 |
-
|
| 32 |
|
| 33 |
@dataclass(frozen=True)
|
| 34 |
class HumeConfig:
|
| 35 |
"""Immutable configuration for interacting with the Hume TTS API."""
|
| 36 |
|
| 37 |
api_key: str = field(init=False)
|
| 38 |
-
|
| 39 |
-
url: str = "https://api.hume.ai/v0/tts/octave"
|
| 40 |
-
file_format: HumeSupportedFileFormat = "mp3"
|
| 41 |
request_timeout: float = 40.0
|
| 42 |
|
| 43 |
def __post_init__(self) -> None:
|
| 44 |
-
|
| 45 |
-
if not self.url:
|
| 46 |
-
raise ValueError("Hume TTS endpoint URL is not set.")
|
| 47 |
if not self.file_format:
|
| 48 |
raise ValueError("Hume TTS file format is not set.")
|
| 49 |
|
| 50 |
computed_api_key = validate_env_var("HUME_API_KEY")
|
| 51 |
object.__setattr__(self, "api_key", computed_api_key)
|
| 52 |
-
computed_headers = {
|
| 53 |
-
"X-Hume-Api-Key": f"{computed_api_key}",
|
| 54 |
-
"Content-Type": "application/json",
|
| 55 |
-
}
|
| 56 |
-
object.__setattr__(self, "headers", computed_headers)
|
| 57 |
|
| 58 |
|
| 59 |
class HumeError(Exception):
|
|
@@ -91,10 +83,10 @@ async def text_to_speech_with_hume(
|
|
| 91 |
"""
|
| 92 |
Asynchronously synthesizes speech using the Hume TTS API, processes audio data, and writes audio to a file.
|
| 93 |
|
| 94 |
-
This function
|
| 95 |
-
speech. Depending on the specified number of generations (1 or 2), the API
|
| 96 |
-
For each generation, the function extracts the base64-encoded audio
|
| 97 |
-
file, and returns the relevant details.
|
| 98 |
|
| 99 |
Args:
|
| 100 |
character_description (str): Description used for voice synthesis.
|
|
@@ -122,27 +114,32 @@ async def text_to_speech_with_hume(
|
|
| 122 |
raise ValueError("Invalid number of generations specified. Must be 1 or 2.")
|
| 123 |
|
| 124 |
hume_config = config.hume_config
|
| 125 |
-
request_body = {
|
| 126 |
-
"utterances": [{"text": text, "description": character_description or None}],
|
| 127 |
-
"format": {"type": hume_config.file_format},
|
| 128 |
-
"num_generations": num_generations,
|
| 129 |
-
}
|
| 130 |
|
| 131 |
start_time = time.time()
|
| 132 |
try:
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
if not generations:
|
| 147 |
msg = "No generations returned by Hume API."
|
| 148 |
logger.error(msg)
|
|
@@ -158,22 +155,19 @@ async def text_to_speech_with_hume(
|
|
| 158 |
generation_b_id, audio_b_path = _parse_hume_tts_generation(generation_b, config)
|
| 159 |
return (generation_a_id, audio_a_path, generation_b_id, audio_b_path)
|
| 160 |
|
| 161 |
-
except
|
|
|
|
| 162 |
logger.error(f"Hume API request failed after {elapsed_time:.2f} seconds: {e!s}")
|
| 163 |
-
raise HumeError(
|
| 164 |
-
message=f"Connection to Hume API failed: {e!s}. Please try again later.",
|
| 165 |
-
original_exception=e,
|
| 166 |
-
) from e
|
| 167 |
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
logger.error(error_message)
|
| 178 |
raise HumeError(
|
| 179 |
message=error_message,
|
|
@@ -184,34 +178,30 @@ async def text_to_speech_with_hume(
|
|
| 184 |
error_type = type(e).__name__
|
| 185 |
error_message = str(e) if str(e) else f"An error of type {error_type} occurred"
|
| 186 |
logger.error("Error during Hume API call: %s - %s", error_type, error_message)
|
| 187 |
-
raise HumeError(
|
| 188 |
-
|
| 189 |
-
original_exception=e,
|
| 190 |
-
) from e
|
| 191 |
|
| 192 |
-
def _parse_hume_tts_generation(generation:
|
| 193 |
"""
|
| 194 |
Parses a Hume TTS generation response and saves the decoded audio as an MP3 file.
|
| 195 |
|
| 196 |
Args:
|
| 197 |
-
generation (
|
| 198 |
config (Config): Application configuration for saving the audio file.
|
| 199 |
|
| 200 |
Returns:
|
| 201 |
Tuple[str, str]: (generation_id, audio_path)
|
| 202 |
|
| 203 |
Raises:
|
| 204 |
-
KeyError: If expected
|
| 205 |
Exception: Propagates exceptions from saving the audio file.
|
| 206 |
"""
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
raise KeyError("The generation dictionary is missing the 'generation_id' key.")
|
| 210 |
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
raise KeyError("The generation dictionary is missing the 'audio' key.")
|
| 214 |
|
| 215 |
-
filename = f"{generation_id}.mp3"
|
| 216 |
-
audio_file_path = save_base64_audio_to_file(
|
| 217 |
-
return generation_id, audio_file_path
|
|
|
|
| 1 |
"""
|
| 2 |
hume_api.py
|
| 3 |
|
| 4 |
+
This file defines the interaction with the Hume text-to-speech (TTS) API using the
|
| 5 |
+
Hume Python SDK. It includes functionality for API request handling and processing API responses.
|
| 6 |
|
| 7 |
Key Features:
|
| 8 |
- Encapsulates all logic related to the Hume TTS API.
|
|
|
|
| 15 |
import logging
|
| 16 |
import time
|
| 17 |
from dataclasses import dataclass, field
|
| 18 |
+
from typing import Tuple, Union
|
| 19 |
|
| 20 |
# Third-Party Library Imports
|
| 21 |
+
from hume import AsyncHumeClient
|
| 22 |
+
from hume.core.api_error import ApiError
|
| 23 |
+
from hume.tts import PostedUtterance
|
| 24 |
+
from hume.tts.types import ReturnGeneration, ReturnTts
|
| 25 |
+
from hume.tts.types.format import Format, FormatMp3
|
| 26 |
from tenacity import after_log, before_log, retry, retry_if_exception, stop_after_attempt, wait_exponential
|
| 27 |
|
| 28 |
# Local Application Imports
|
|
|
|
| 30 |
from src.constants import CLIENT_ERROR_CODE, SERVER_ERROR_CODE
|
| 31 |
from src.utils import save_base64_audio_to_file, validate_env_var
|
| 32 |
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
@dataclass(frozen=True)
|
| 35 |
class HumeConfig:
|
| 36 |
"""Immutable configuration for interacting with the Hume TTS API."""
|
| 37 |
|
| 38 |
api_key: str = field(init=False)
|
| 39 |
+
file_format: Format = field(default_factory=FormatMp3)
|
|
|
|
|
|
|
| 40 |
request_timeout: float = 40.0
|
| 41 |
|
| 42 |
def __post_init__(self) -> None:
|
| 43 |
+
"""Validate required attributes and set computed fields."""
|
|
|
|
|
|
|
| 44 |
if not self.file_format:
|
| 45 |
raise ValueError("Hume TTS file format is not set.")
|
| 46 |
|
| 47 |
computed_api_key = validate_env_var("HUME_API_KEY")
|
| 48 |
object.__setattr__(self, "api_key", computed_api_key)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
|
| 51 |
class HumeError(Exception):
|
|
|
|
| 83 |
"""
|
| 84 |
Asynchronously synthesizes speech using the Hume TTS API, processes audio data, and writes audio to a file.
|
| 85 |
|
| 86 |
+
This function uses the Hume Python SDK to send a request to the Hume TTS API with a character description
|
| 87 |
+
and text to be converted to speech. Depending on the specified number of generations (1 or 2), the API
|
| 88 |
+
returns one or two generations. For each generation, the function extracts the base64-encoded audio
|
| 89 |
+
and generation ID, saves the audio as an MP3 file, and returns the relevant details.
|
| 90 |
|
| 91 |
Args:
|
| 92 |
character_description (str): Description used for voice synthesis.
|
|
|
|
| 114 |
raise ValueError("Invalid number of generations specified. Must be 1 or 2.")
|
| 115 |
|
| 116 |
hume_config = config.hume_config
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
start_time = time.time()
|
| 119 |
try:
|
| 120 |
+
# Initialize the client for this request
|
| 121 |
+
hume_client = AsyncHumeClient(
|
| 122 |
+
api_key=hume_config.api_key,
|
| 123 |
+
timeout=hume_config.request_timeout
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
# Create the utterance with the character description and text
|
| 127 |
+
utterance = PostedUtterance(
|
| 128 |
+
text=text,
|
| 129 |
+
description=character_description or None
|
| 130 |
+
)
|
| 131 |
+
|
| 132 |
+
# Call the TTS API through the SDK
|
| 133 |
+
response: ReturnTts = await hume_client.tts.synthesize_json(
|
| 134 |
+
utterances=[utterance],
|
| 135 |
+
format=hume_config.file_format,
|
| 136 |
+
num_generations=num_generations
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
elapsed_time = time.time() - start_time
|
| 140 |
+
logger.info(f"Hume API request completed in {elapsed_time:.2f} seconds")
|
| 141 |
+
|
| 142 |
+
generations = response.generations
|
| 143 |
if not generations:
|
| 144 |
msg = "No generations returned by Hume API."
|
| 145 |
logger.error(msg)
|
|
|
|
| 155 |
generation_b_id, audio_b_path = _parse_hume_tts_generation(generation_b, config)
|
| 156 |
return (generation_a_id, audio_a_path, generation_b_id, audio_b_path)
|
| 157 |
|
| 158 |
+
except ApiError as e:
|
| 159 |
+
elapsed_time = time.time() - start_time
|
| 160 |
logger.error(f"Hume API request failed after {elapsed_time:.2f} seconds: {e!s}")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
|
| 162 |
+
if hasattr(e, 'status_code') and e.status_code is not None:
|
| 163 |
+
if CLIENT_ERROR_CODE <= e.status_code < SERVER_ERROR_CODE:
|
| 164 |
+
error_message = f"HTTP Error {e.status_code}: {e!s}"
|
| 165 |
+
logger.error(error_message)
|
| 166 |
+
raise UnretryableHumeError(message=error_message, original_exception=e) from e
|
| 167 |
+
error_message = f"HTTP Error {e.status_code}: {e!s}"
|
| 168 |
+
else:
|
| 169 |
+
error_message = str(e)
|
| 170 |
+
|
| 171 |
logger.error(error_message)
|
| 172 |
raise HumeError(
|
| 173 |
message=error_message,
|
|
|
|
| 178 |
error_type = type(e).__name__
|
| 179 |
error_message = str(e) if str(e) else f"An error of type {error_type} occurred"
|
| 180 |
logger.error("Error during Hume API call: %s - %s", error_type, error_message)
|
| 181 |
+
raise HumeError(message=error_message, original_exception=e) from e
|
| 182 |
+
|
|
|
|
|
|
|
| 183 |
|
| 184 |
+
def _parse_hume_tts_generation(generation: ReturnGeneration, config: Config) -> Tuple[str, str]:
|
| 185 |
"""
|
| 186 |
Parses a Hume TTS generation response and saves the decoded audio as an MP3 file.
|
| 187 |
|
| 188 |
Args:
|
| 189 |
+
generation (ReturnGeneration): TTS generation response containing generation_id and audio.
|
| 190 |
config (Config): Application configuration for saving the audio file.
|
| 191 |
|
| 192 |
Returns:
|
| 193 |
Tuple[str, str]: (generation_id, audio_path)
|
| 194 |
|
| 195 |
Raises:
|
| 196 |
+
KeyError: If expected attributes are missing.
|
| 197 |
Exception: Propagates exceptions from saving the audio file.
|
| 198 |
"""
|
| 199 |
+
if not generation.generation_id:
|
| 200 |
+
raise KeyError("The generation is missing the generation_id.")
|
|
|
|
| 201 |
|
| 202 |
+
if not generation.audio:
|
| 203 |
+
raise KeyError("The generation is missing the audio data.")
|
|
|
|
| 204 |
|
| 205 |
+
filename = f"{generation.generation_id}.mp3"
|
| 206 |
+
audio_file_path = save_base64_audio_to_file(generation.audio, filename, config)
|
| 207 |
+
return generation.generation_id, audio_file_path
|
uv.lock
CHANGED
|
@@ -6,13 +6,16 @@ resolution-markers = [
|
|
| 6 |
"python_full_version >= '3.13'",
|
| 7 |
]
|
| 8 |
|
|
|
|
|
|
|
|
|
|
| 9 |
[[package]]
|
| 10 |
name = "aiofiles"
|
| 11 |
-
version = "
|
| 12 |
source = { registry = "https://pypi.org/simple" }
|
| 13 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 14 |
wheels = [
|
| 15 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 16 |
]
|
| 17 |
|
| 18 |
[[package]]
|
|
@@ -250,6 +253,15 @@ wheels = [
|
|
| 250 |
{ url = "https://files.pythonhosted.org/packages/39/92/6096e18b5d673195fb5f702f9d2cc881595d876659db4e025760faed9b42/elevenlabs-1.50.7-py3-none-any.whl", hash = "sha256:3b75a28e6e81d677d2525f51713167f521bc0dab062984d7a3d1e29411ae424a", size = 264723 },
|
| 251 |
]
|
| 252 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
[[package]]
|
| 254 |
name = "expressive-tts-arena"
|
| 255 |
version = "0.1.0"
|
|
@@ -260,7 +272,7 @@ dependencies = [
|
|
| 260 |
{ name = "elevenlabs" },
|
| 261 |
{ name = "gradio" },
|
| 262 |
{ name = "greenlet" },
|
| 263 |
-
{ name = "
|
| 264 |
{ name = "python-dotenv" },
|
| 265 |
{ name = "sqlalchemy" },
|
| 266 |
{ name = "tenacity" },
|
|
@@ -282,9 +294,9 @@ requires-dist = [
|
|
| 282 |
{ name = "anthropic", specifier = ">=0.45.2" },
|
| 283 |
{ name = "asyncpg", specifier = ">=0.28.0" },
|
| 284 |
{ name = "elevenlabs", specifier = ">=1.50.7" },
|
| 285 |
-
{ name = "gradio", specifier = ">=5.
|
| 286 |
{ name = "greenlet", specifier = ">=2.0.0" },
|
| 287 |
-
{ name = "
|
| 288 |
{ name = "python-dotenv", specifier = ">=1.0.1" },
|
| 289 |
{ name = "sqlalchemy", specifier = ">=2.0.0" },
|
| 290 |
{ name = "tenacity", specifier = ">=9.0.0" },
|
|
@@ -344,7 +356,7 @@ wheels = [
|
|
| 344 |
|
| 345 |
[[package]]
|
| 346 |
name = "gradio"
|
| 347 |
-
version = "5.
|
| 348 |
source = { registry = "https://pypi.org/simple" }
|
| 349 |
dependencies = [
|
| 350 |
{ name = "aiofiles" },
|
|
@@ -377,12 +389,12 @@ dependencies = [
|
|
| 377 |
{ name = "uvicorn", marker = "sys_platform != 'emscripten'" },
|
| 378 |
]
|
| 379 |
wheels = [
|
| 380 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 381 |
]
|
| 382 |
|
| 383 |
[[package]]
|
| 384 |
name = "gradio-client"
|
| 385 |
-
version = "1.7.
|
| 386 |
source = { registry = "https://pypi.org/simple" }
|
| 387 |
dependencies = [
|
| 388 |
{ name = "fsspec" },
|
|
@@ -392,9 +404,9 @@ dependencies = [
|
|
| 392 |
{ name = "typing-extensions" },
|
| 393 |
{ name = "websockets" },
|
| 394 |
]
|
| 395 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 396 |
wheels = [
|
| 397 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 398 |
]
|
| 399 |
|
| 400 |
[[package]]
|
|
@@ -494,6 +506,24 @@ wheels = [
|
|
| 494 |
{ url = "https://files.pythonhosted.org/packages/ea/da/6c2bea5327b640920267d3bf2c9fc114cfbd0a5de234d81cda80cc9e33c8/huggingface_hub-0.28.1-py3-none-any.whl", hash = "sha256:aa6b9a3ffdae939b72c464dbb0d7f99f56e649b55c3d52406f49e0a5a620c0a7", size = 464068 },
|
| 495 |
]
|
| 496 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 497 |
[[package]]
|
| 498 |
name = "identify"
|
| 499 |
version = "2.6.6"
|
|
@@ -1405,42 +1435,31 @@ wheels = [
|
|
| 1405 |
|
| 1406 |
[[package]]
|
| 1407 |
name = "websockets"
|
| 1408 |
-
version = "
|
| 1409 |
-
source = { registry = "https://pypi.org/simple" }
|
| 1410 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 1411 |
-
wheels = [
|
| 1412 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1413 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1414 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1415 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1416 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1417 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1418 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1419 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1420 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1421 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1422 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1423 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1424 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1425 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1426 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1427 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1428 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1429 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1430 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1431 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1432 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1433 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1434 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 1435 |
-
{ url = "https://files.pythonhosted.org/packages/8e/b7/7484905215627909d9a79ae07070057afe477433fdacb59bf608ce86365a/websockets-14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4da98b72009836179bb596a92297b1a61bb5a830c0e483a7d0766d45070a08ad", size = 160766 },
|
| 1436 |
-
{ url = "https://files.pythonhosted.org/packages/a3/a4/edb62efc84adb61883c7d2c6ad65181cb087c64252138e12d655989eec05/websockets-14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03", size = 160998 },
|
| 1437 |
-
{ url = "https://files.pythonhosted.org/packages/f5/79/036d320dc894b96af14eac2529967a6fc8b74f03b83c487e7a0e9043d842/websockets-14.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86cf1aaeca909bf6815ea714d5c5736c8d6dd3a13770e885aafe062ecbd04f1f", size = 170780 },
|
| 1438 |
-
{ url = "https://files.pythonhosted.org/packages/63/75/5737d21ee4dd7e4b9d487ee044af24a935e36a9ff1e1419d684feedcba71/websockets-14.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b0f6c3ba3b1240f602ebb3971d45b02cc12bd1845466dd783496b3b05783a5", size = 169717 },
|
| 1439 |
-
{ url = "https://files.pythonhosted.org/packages/2c/3c/bf9b2c396ed86a0b4a92ff4cdaee09753d3ee389be738e92b9bbd0330b64/websockets-14.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c3e101c246aa85bc8534e495952e2ca208bd87994650b90a23d745902db9a", size = 170155 },
|
| 1440 |
-
{ url = "https://files.pythonhosted.org/packages/75/2d/83a5aca7247a655b1da5eb0ee73413abd5c3a57fc8b92915805e6033359d/websockets-14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eabdb28b972f3729348e632ab08f2a7b616c7e53d5414c12108c29972e655b20", size = 170495 },
|
| 1441 |
-
{ url = "https://files.pythonhosted.org/packages/79/dd/699238a92761e2f943885e091486378813ac8f43e3c84990bc394c2be93e/websockets-14.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2066dc4cbcc19f32c12a5a0e8cc1b7ac734e5b64ac0a325ff8353451c4b15ef2", size = 169880 },
|
| 1442 |
-
{ url = "https://files.pythonhosted.org/packages/c8/c9/67a8f08923cf55ce61aadda72089e3ed4353a95a3a4bc8bf42082810e580/websockets-14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab95d357cd471df61873dadf66dd05dd4709cae001dd6342edafc8dc6382f307", size = 169856 },
|
| 1443 |
-
{ url = "https://files.pythonhosted.org/packages/17/b1/1ffdb2680c64e9c3921d99db460546194c40d4acbef999a18c37aa4d58a3/websockets-14.2-cp313-cp313-win32.whl", hash = "sha256:a9e72fb63e5f3feacdcf5b4ff53199ec8c18d66e325c34ee4c551ca748623bbc", size = 163974 },
|
| 1444 |
-
{ url = "https://files.pythonhosted.org/packages/14/13/8b7fc4cb551b9cfd9890f0fd66e53c18a06240319915533b033a56a3d520/websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f", size = 164420 },
|
| 1445 |
-
{ url = "https://files.pythonhosted.org/packages/7b/c8/d529f8a32ce40d98309f4470780631e971a5a842b60aec864833b3615786/websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b", size = 157416 },
|
| 1446 |
]
|
|
|
|
| 6 |
"python_full_version >= '3.13'",
|
| 7 |
]
|
| 8 |
|
| 9 |
+
[manifest]
|
| 10 |
+
overrides = [{ name = "aiofiles", specifier = "==24.1.0" }]
|
| 11 |
+
|
| 12 |
[[package]]
|
| 13 |
name = "aiofiles"
|
| 14 |
+
version = "24.1.0"
|
| 15 |
source = { registry = "https://pypi.org/simple" }
|
| 16 |
+
sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247 }
|
| 17 |
wheels = [
|
| 18 |
+
{ url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896 },
|
| 19 |
]
|
| 20 |
|
| 21 |
[[package]]
|
|
|
|
| 253 |
{ url = "https://files.pythonhosted.org/packages/39/92/6096e18b5d673195fb5f702f9d2cc881595d876659db4e025760faed9b42/elevenlabs-1.50.7-py3-none-any.whl", hash = "sha256:3b75a28e6e81d677d2525f51713167f521bc0dab062984d7a3d1e29411ae424a", size = 264723 },
|
| 254 |
]
|
| 255 |
|
| 256 |
+
[[package]]
|
| 257 |
+
name = "eval-type-backport"
|
| 258 |
+
version = "0.2.2"
|
| 259 |
+
source = { registry = "https://pypi.org/simple" }
|
| 260 |
+
sdist = { url = "https://files.pythonhosted.org/packages/30/ea/8b0ac4469d4c347c6a385ff09dc3c048c2d021696664e26c7ee6791631b5/eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1", size = 9079 }
|
| 261 |
+
wheels = [
|
| 262 |
+
{ url = "https://files.pythonhosted.org/packages/ce/31/55cd413eaccd39125368be33c46de24a1f639f2e12349b0361b4678f3915/eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a", size = 5830 },
|
| 263 |
+
]
|
| 264 |
+
|
| 265 |
[[package]]
|
| 266 |
name = "expressive-tts-arena"
|
| 267 |
version = "0.1.0"
|
|
|
|
| 272 |
{ name = "elevenlabs" },
|
| 273 |
{ name = "gradio" },
|
| 274 |
{ name = "greenlet" },
|
| 275 |
+
{ name = "hume" },
|
| 276 |
{ name = "python-dotenv" },
|
| 277 |
{ name = "sqlalchemy" },
|
| 278 |
{ name = "tenacity" },
|
|
|
|
| 294 |
{ name = "anthropic", specifier = ">=0.45.2" },
|
| 295 |
{ name = "asyncpg", specifier = ">=0.28.0" },
|
| 296 |
{ name = "elevenlabs", specifier = ">=1.50.7" },
|
| 297 |
+
{ name = "gradio", specifier = ">=5.18.0" },
|
| 298 |
{ name = "greenlet", specifier = ">=2.0.0" },
|
| 299 |
+
{ name = "hume", specifier = ">=0.7.8" },
|
| 300 |
{ name = "python-dotenv", specifier = ">=1.0.1" },
|
| 301 |
{ name = "sqlalchemy", specifier = ">=2.0.0" },
|
| 302 |
{ name = "tenacity", specifier = ">=9.0.0" },
|
|
|
|
| 356 |
|
| 357 |
[[package]]
|
| 358 |
name = "gradio"
|
| 359 |
+
version = "5.18.0"
|
| 360 |
source = { registry = "https://pypi.org/simple" }
|
| 361 |
dependencies = [
|
| 362 |
{ name = "aiofiles" },
|
|
|
|
| 389 |
{ name = "uvicorn", marker = "sys_platform != 'emscripten'" },
|
| 390 |
]
|
| 391 |
wheels = [
|
| 392 |
+
{ url = "https://files.pythonhosted.org/packages/e2/e4/1a9ec913da5480907d14d2c527278c6c09011d8ff370a1caa09cdb3f5d23/gradio-5.18.0-py3-none-any.whl", hash = "sha256:0ec8461de962a851a9c3dc75c6707dddd942f7b292dec425acc6d5dcfa685902", size = 62263574 },
|
| 393 |
]
|
| 394 |
|
| 395 |
[[package]]
|
| 396 |
name = "gradio-client"
|
| 397 |
+
version = "1.7.2"
|
| 398 |
source = { registry = "https://pypi.org/simple" }
|
| 399 |
dependencies = [
|
| 400 |
{ name = "fsspec" },
|
|
|
|
| 404 |
{ name = "typing-extensions" },
|
| 405 |
{ name = "websockets" },
|
| 406 |
]
|
| 407 |
+
sdist = { url = "https://files.pythonhosted.org/packages/65/b8/682e1868c47ce723fece65ae71405a560a8455d1e06bd70d4f60c1e6ac03/gradio_client-1.7.2.tar.gz", hash = "sha256:e3f1e1a63292a06a22a748719849bc6dbacdc89645f089c219f3d7a24e68d183", size = 320199 }
|
| 408 |
wheels = [
|
| 409 |
+
{ url = "https://files.pythonhosted.org/packages/95/cb/002424d4f5af1425f9cfe7dcee3ed795ed1367bf0f185a6c4bf81385e1d6/gradio_client-1.7.2-py3-none-any.whl", hash = "sha256:50d61b4db3e87639430a121a7cde4303055486ed72a5035edae94b4fbe6a0e6b", size = 322052 },
|
| 410 |
]
|
| 411 |
|
| 412 |
[[package]]
|
|
|
|
| 506 |
{ url = "https://files.pythonhosted.org/packages/ea/da/6c2bea5327b640920267d3bf2c9fc114cfbd0a5de234d81cda80cc9e33c8/huggingface_hub-0.28.1-py3-none-any.whl", hash = "sha256:aa6b9a3ffdae939b72c464dbb0d7f99f56e649b55c3d52406f49e0a5a620c0a7", size = 464068 },
|
| 507 |
]
|
| 508 |
|
| 509 |
+
[[package]]
|
| 510 |
+
name = "hume"
|
| 511 |
+
version = "0.7.8"
|
| 512 |
+
source = { registry = "https://pypi.org/simple" }
|
| 513 |
+
dependencies = [
|
| 514 |
+
{ name = "aiofiles" },
|
| 515 |
+
{ name = "eval-type-backport" },
|
| 516 |
+
{ name = "httpx" },
|
| 517 |
+
{ name = "pydantic" },
|
| 518 |
+
{ name = "pydantic-core" },
|
| 519 |
+
{ name = "typing-extensions" },
|
| 520 |
+
{ name = "websockets" },
|
| 521 |
+
]
|
| 522 |
+
sdist = { url = "https://files.pythonhosted.org/packages/73/22/71dbdb36974a87433478347dd0ce124d3ea1f933f1246d252fcbd11e6696/hume-0.7.8.tar.gz", hash = "sha256:b2acfc93bde001c1de4e8c122db5fecd3db48f9c88d3771b393981bb5124eedc", size = 131970 }
|
| 523 |
+
wheels = [
|
| 524 |
+
{ url = "https://files.pythonhosted.org/packages/68/29/b365a2b6bbfa229fc815c6b04ed444ee560b7720b25cc1278d4a0789c700/hume-0.7.8-py3-none-any.whl", hash = "sha256:50ef51053e4e1a69ed7efd489e23cc053ebbd8e10bbc06cf1de96631f2f7a732", size = 320580 },
|
| 525 |
+
]
|
| 526 |
+
|
| 527 |
[[package]]
|
| 528 |
name = "identify"
|
| 529 |
version = "2.6.6"
|
|
|
|
| 1435 |
|
| 1436 |
[[package]]
|
| 1437 |
name = "websockets"
|
| 1438 |
+
version = "12.0"
|
| 1439 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1440 |
+
sdist = { url = "https://files.pythonhosted.org/packages/2e/62/7a7874b7285413c954a4cca3c11fd851f11b2fe5b4ae2d9bee4f6d9bdb10/websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b", size = 104994 }
|
| 1441 |
+
wheels = [
|
| 1442 |
+
{ url = "https://files.pythonhosted.org/packages/02/73/9c1e168a2e7fdf26841dc98f5f5502e91dea47428da7690a08101f616169/websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4", size = 124047 },
|
| 1443 |
+
{ url = "https://files.pythonhosted.org/packages/e4/2d/9a683359ad2ed11b2303a7a94800db19c61d33fa3bde271df09e99936022/websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f", size = 121282 },
|
| 1444 |
+
{ url = "https://files.pythonhosted.org/packages/95/aa/75fa3b893142d6d98a48cb461169bd268141f2da8bfca97392d6462a02eb/websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3", size = 121325 },
|
| 1445 |
+
{ url = "https://files.pythonhosted.org/packages/6e/a4/51a25e591d645df71ee0dc3a2c880b28e5514c00ce752f98a40a87abcd1e/websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c", size = 131502 },
|
| 1446 |
+
{ url = "https://files.pythonhosted.org/packages/cd/ea/0ceeea4f5b87398fe2d9f5bcecfa00a1bcd542e2bfcac2f2e5dd612c4e9e/websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45", size = 130491 },
|
| 1447 |
+
{ url = "https://files.pythonhosted.org/packages/e3/05/f52a60b66d9faf07a4f7d71dc056bffafe36a7e98c4eb5b78f04fe6e4e85/websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04", size = 130872 },
|
| 1448 |
+
{ url = "https://files.pythonhosted.org/packages/ac/4e/c7361b2d7b964c40fea924d64881145164961fcd6c90b88b7e3ab2c4f431/websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447", size = 136318 },
|
| 1449 |
+
{ url = "https://files.pythonhosted.org/packages/0a/31/337bf35ae5faeaf364c9cddec66681cdf51dc4414ee7a20f92a18e57880f/websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca", size = 135594 },
|
| 1450 |
+
{ url = "https://files.pythonhosted.org/packages/95/aa/1ac767825c96f9d7e43c4c95683757d4ef28cf11fa47a69aca42428d3e3a/websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53", size = 136191 },
|
| 1451 |
+
{ url = "https://files.pythonhosted.org/packages/28/4b/344ec5cfeb6bc417da097f8253607c3aed11d9a305fb58346f506bf556d8/websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402", size = 124453 },
|
| 1452 |
+
{ url = "https://files.pythonhosted.org/packages/d1/40/6b169cd1957476374f51f4486a3e85003149e62a14e6b78a958c2222337a/websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b", size = 124971 },
|
| 1453 |
+
{ url = "https://files.pythonhosted.org/packages/a9/6d/23cc898647c8a614a0d9ca703695dd04322fb5135096a20c2684b7c852b6/websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df", size = 124061 },
|
| 1454 |
+
{ url = "https://files.pythonhosted.org/packages/39/34/364f30fdf1a375e4002a26ee3061138d1571dfda6421126127d379d13930/websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc", size = 121296 },
|
| 1455 |
+
{ url = "https://files.pythonhosted.org/packages/2e/00/96ae1c9dcb3bc316ef683f2febd8c97dde9f254dc36c3afc65c7645f734c/websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b", size = 121326 },
|
| 1456 |
+
{ url = "https://files.pythonhosted.org/packages/af/f1/bba1e64430685dd456c1a1fd6b0c791ae33104967b928aefeff261761e8d/websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb", size = 131807 },
|
| 1457 |
+
{ url = "https://files.pythonhosted.org/packages/62/3b/98ee269712f37d892b93852ce07b3e6d7653160ca4c0d4f8c8663f8021f8/websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92", size = 130751 },
|
| 1458 |
+
{ url = "https://files.pythonhosted.org/packages/f1/00/d6f01ca2b191f8b0808e4132ccd2e7691f0453cbd7d0f72330eb97453c3a/websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed", size = 131176 },
|
| 1459 |
+
{ url = "https://files.pythonhosted.org/packages/af/9c/703ff3cd8109dcdee6152bae055d852ebaa7750117760ded697ab836cbcf/websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5", size = 136246 },
|
| 1460 |
+
{ url = "https://files.pythonhosted.org/packages/0b/a5/1a38fb85a456b9dc874ec984f3ff34f6550eafd17a3da28753cd3c1628e8/websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2", size = 135466 },
|
| 1461 |
+
{ url = "https://files.pythonhosted.org/packages/3c/98/1261f289dff7e65a38d59d2f591de6ed0a2580b729aebddec033c4d10881/websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113", size = 136083 },
|
| 1462 |
+
{ url = "https://files.pythonhosted.org/packages/a9/1c/f68769fba63ccb9c13fe0a25b616bd5aebeef1c7ddebc2ccc32462fb784d/websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d", size = 124460 },
|
| 1463 |
+
{ url = "https://files.pythonhosted.org/packages/20/52/8915f51f9aaef4e4361c89dd6cf69f72a0159f14e0d25026c81b6ad22525/websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f", size = 124985 },
|
| 1464 |
+
{ url = "https://files.pythonhosted.org/packages/79/4d/9cc401e7b07e80532ebc8c8e993f42541534da9e9249c59ee0139dcb0352/websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e", size = 118370 },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1465 |
]
|