Spaces:
Running
Running
zach
Update application flow to accept a character description and normalize a prompt for claude
5bf19b3
""" | |
utils.py | |
This file contains utility functions that are shared across the project. | |
These functions provide reusable logic to simplify code in other modules. | |
Functions: | |
- truncate_text: Truncates a string to a specified length with ellipses. (used for logging) | |
- validate_env_var: Ensures the presence of a specific environment variable and retrieves its value. | |
- validate_character_description_length: Ensures that a voice description does not exceed the specified minimum or maximum length. | |
""" | |
# Standard Library Imports | |
import base64 | |
import os | |
# Local Application Imports | |
from src.config import AUDIO_DIR, logger | |
from src.constants import ( | |
CHARACTER_DESCRIPTION_MIN_LENGTH, | |
CHARACTER_DESCRIPTION_MAX_LENGTH, | |
) | |
def truncate_text(text: str, max_length: int = 50) -> str: | |
""" | |
Truncate a string to the specified length, appending ellipses if necessary. | |
Args: | |
text (str): The text to truncate. | |
max_length (int): The maximum length of the truncated string. | |
Returns: | |
str: The truncated text. | |
Examples: | |
>>> truncate_text("Hello, World!", 5) | |
'Hello...' | |
>>> truncate_text("Short string", 20) | |
'Short string' | |
>>> truncate_text("Edge case with zero length", 0) | |
'' | |
""" | |
if max_length <= 0: | |
logger.warning(f"Invalid max_length={max_length}. Returning empty string.") | |
return "" | |
is_truncated = len(text) > max_length | |
if is_truncated: | |
logger.debug(f"Truncated text to {max_length} characters.") | |
return text[:max_length] + ("..." if is_truncated else "") | |
def validate_env_var(var_name: str) -> str: | |
""" | |
Validates that an environment variable is set and returns its value. | |
Args: | |
var_name (str): The name of the environment variable to validate. | |
Returns: | |
str: The value of the environment variable. | |
Raises: | |
ValueError: If the environment variable is not set. | |
Examples: | |
>>> import os | |
>>> os.environ["EXAMPLE_VAR"] = "example_value" | |
>>> validate_env_var("EXAMPLE_VAR") | |
'example_value' | |
>>> validate_env_var("MISSING_VAR") | |
Traceback (most recent call last): | |
... | |
ValueError: MISSING_VAR is not set. Please ensure it is defined in your environment variables. | |
""" | |
value = os.environ.get(var_name, "") | |
if not value: | |
raise ValueError( | |
f"{var_name} is not set. Please ensure it is defined in your environment variables." | |
) | |
return value | |
def validate_character_description_length(character_description: str) -> None: | |
""" | |
Validates that a voice description is within specified minimum and maximum length limits. | |
Args: | |
character_description (str): The input character description to validate. | |
Raises: | |
ValueError: If the character description is empty, too short, or exceeds max length. | |
Example: | |
>>> validate_character_description_length("This is a character description.") | |
# Passes validation | |
>>> validate_character_description_length("") | |
# Raises ValueError: "Voice Description must be at least 20 characters long." | |
""" | |
stripped_character_description = character_description.strip() | |
character_description_length = len(stripped_character_description) | |
logger.debug( | |
f"Voice description length being validated: {character_description_length} characters" | |
) | |
if character_description_length < CHARACTER_DESCRIPTION_MIN_LENGTH: | |
raise ValueError( | |
f"Your character description is too short. Please enter at least {CHARACTER_DESCRIPTION_MIN_LENGTH} characters. " | |
f"(Current length: {character_description_length})" | |
) | |
if character_description_length > CHARACTER_DESCRIPTION_MAX_LENGTH: | |
raise ValueError( | |
f"Your character description is too long. Please limit it to {CHARACTER_DESCRIPTION_MAX_LENGTH} characters. " | |
f"(Current length: {character_description_length})" | |
) | |
logger.debug( | |
f"Character description length validation passed for character_description: {truncate_text(stripped_character_description)}" | |
) | |
def save_base64_audio_to_file(base64_audio: str, filename: str) -> str: | |
""" | |
Decode a base64-encoded audio string and write the resulting binary data to a file | |
within the preconfigured AUDIO_DIR directory. This function verifies the file was created, | |
logs the absolute and relative file paths, and returns a path relative to the current | |
working directory (which is what Gradio requires to serve static files). | |
Args: | |
base64_audio (str): The base64-encoded string representing the audio data. | |
filename (str): The name of the file (including extension, e.g., | |
'b4a335da-9786-483a-b0a5-37e6e4ad5fd1.mp3') where the decoded | |
audio will be saved. | |
Returns: | |
str: The relative file path to the saved audio file. | |
Raises: | |
Exception: Propagates any exceptions raised during the decoding or file I/O operations. | |
""" | |
# Decode the base64-encoded audio into binary data. | |
audio_bytes = base64.b64decode(base64_audio) | |
# Construct the full absolute file path within the AUDIO_DIR directory. | |
file_path = os.path.join(AUDIO_DIR, filename) | |
# Write the binary audio data to the file. | |
with open(file_path, "wb") as audio_file: | |
audio_file.write(audio_bytes) | |
# Verify that the file was created. | |
if not os.path.exists(file_path): | |
raise FileNotFoundError(f"Audio file was not created at {file_path}") | |
# Compute a relative path for Gradio to serve (relative to the project root). | |
relative_path = os.path.relpath(file_path, os.getcwd()) | |
logger.debug(f"Audio file absolute path: {file_path}") | |
logger.debug(f"Audio file relative path: {relative_path}") | |
return relative_path | |