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 |
]
|