Spaces:
Running
Running
File size: 6,258 Bytes
1190db4 8468afb 1190db4 5c85d81 8468afb 1190db4 8468afb 1190db4 8468afb 1190db4 8468afb 1190db4 8468afb 1190db4 8468afb 1190db4 8468afb 1190db4 d44dfc0 8468afb 1190db4 8468afb 1190db4 8468afb 1190db4 8468afb d44dfc0 8468afb d44dfc0 8468afb d44dfc0 8468afb 5c85d81 8468afb d48101f 8468afb 59d4d10 8468afb b7680b4 d44dfc0 59d4d10 5c85d81 8468afb 59d4d10 8468afb d44dfc0 59d4d10 a2f0e99 8468afb d44dfc0 b7680b4 8468afb a2f0e99 5c85d81 8468afb d44dfc0 8468afb b7680b4 1190db4 b7680b4 d44dfc0 8468afb d44dfc0 8468afb d48101f 1190db4 8468afb b7680b4 8468afb b7680b4 8468afb b7680b4 8468afb 1190db4 8468afb d48101f b7680b4 |
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 |
import gradio as gr
import os
import asyncio
from openai import AsyncOpenAI
from functools import partial # For handle_script_processing
# Import UI creation functions and constants
from ui_layout import (
create_main_input_components, create_speaker_config_components,
create_action_and_output_components, create_examples_ui,
TTS_MODELS_AVAILABLE, MODEL_DEFAULT_ENV
)
# Import event handler functions
from event_handlers import (
handle_script_processing, handle_calculate_cost,
update_model_controls_visibility, update_speaker_config_method_visibility,
load_refresh_per_speaker_ui
)
# --- Application Secrets and Global Client ---
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
NSFW_API_URL_TEMPLATE = os.getenv("NSFW_API_URL_TEMPLATE")
MODEL_DEFAULT_FROM_ENV = os.getenv("MODEL_DEFAULT", MODEL_DEFAULT_ENV)
# Validate MODEL_DEFAULT_FROM_ENV or use hardcoded default
EFFECTIVE_MODEL_DEFAULT = MODEL_DEFAULT_FROM_ENV if MODEL_DEFAULT_FROM_ENV in TTS_MODELS_AVAILABLE else MODEL_DEFAULT_ENV
async_openai_client = None
if not OPENAI_API_KEY:
try:
# Attempt to load from Hugging Face Hub secrets if not in env
from huggingface_hub import HfApi
api = HfApi()
space_id = os.getenv("SPACE_ID") # Provided by HF Spaces
if space_id:
secrets = api.get_space_secrets(repo_id=space_id)
OPENAI_API_KEY = secrets.get("OPENAI_API_KEY")
NSFW_API_URL_TEMPLATE = secrets.get("NSFW_API_URL_TEMPLATE", NSFW_API_URL_TEMPLATE)
MODEL_DEFAULT_FROM_HUB = secrets.get("MODEL_DEFAULT", EFFECTIVE_MODEL_DEFAULT)
EFFECTIVE_MODEL_DEFAULT = MODEL_DEFAULT_FROM_HUB if MODEL_DEFAULT_FROM_HUB in TTS_MODELS_AVAILABLE else EFFECTIVE_MODEL_DEFAULT
print("Loaded secrets from Hugging Face Hub.")
except Exception as e:
print(f"Could not retrieve secrets from Hugging Face Hub: {e}. OPENAI_API_KEY might be missing.")
if OPENAI_API_KEY:
async_openai_client = AsyncOpenAI(api_key=OPENAI_API_KEY)
else:
print("CRITICAL ERROR: OPENAI_API_KEY secret is not set. The application will not function properly.")
# --- Gradio Application UI and Logic ---
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# Dialogue Script to Speech (OpenAI TTS) - Refactored")
if not OPENAI_API_KEY or not async_openai_client:
gr.Markdown("<h3 style='color:red;'>⚠️ Warning: OPENAI_API_KEY not set or invalid. Audio generation will fail. Please configure it in your Space settings.</h3>")
# Central state for detailed speaker configurations
speaker_configs_state = gr.State({}) # This is crucial for dynamic UI
# --- Define UI Components by calling layout functions ---
(script_input, tts_model_dropdown, pause_input,
global_speed_input, global_instructions_input) = create_main_input_components(EFFECTIVE_MODEL_DEFAULT)
(speaker_config_method_dropdown, single_voice_group, global_voice_dropdown,
detailed_per_speaker_ui_group, load_per_speaker_ui_button,
dynamic_speaker_ui_area) = create_speaker_config_components()
(calculate_cost_button, generate_button, cost_output,
individual_lines_zip_output, merged_dialogue_mp3_output,
status_output) = create_action_and_output_components()
# --- Event Wiring ---
# When TTS model changes, update visibility of global speed/instructions & refresh dynamic UI
tts_model_dropdown.change(
fn=update_model_controls_visibility,
inputs=[tts_model_dropdown, script_input, speaker_configs_state, speaker_configs_state],
outputs=[global_speed_input, global_instructions_input, dynamic_speaker_ui_area, speaker_configs_state]
)
# When speaker config method changes, update visibility of relevant UI groups
speaker_config_method_dropdown.change(
fn=update_speaker_config_method_visibility,
inputs=[speaker_config_method_dropdown],
outputs=[single_voice_group, detailed_per_speaker_ui_group]
)
# Button to load/refresh the detailed per-speaker UI configurations
load_per_speaker_ui_button.click(
fn=load_refresh_per_speaker_ui,
inputs=[script_input, speaker_configs_state, tts_model_dropdown, speaker_configs_state],
outputs=[dynamic_speaker_ui_area, speaker_configs_state]
)
# Calculate cost button
calculate_cost_button.click(
fn=handle_calculate_cost,
inputs=[script_input, tts_model_dropdown],
outputs=[cost_output]
)
# Generate audio button
# Use functools.partial to pass fixed arguments like API key and client to the handler
# Gradio inputs will be appended to these fixed arguments when the handler is called.
generate_button_fn = partial(handle_script_processing, OPENAI_API_KEY, async_openai_client, NSFW_API_URL_TEMPLATE)
generate_button.click(
fn=generate_button_fn,
inputs=[
script_input, tts_model_dropdown, pause_input,
speaker_config_method_dropdown, global_voice_dropdown,
speaker_configs_state, # The gr.State object itself
global_speed_input, global_instructions_input
],
outputs=[individual_lines_zip_output, merged_dialogue_mp3_output, status_output]
)
# --- Examples UI ---
example_inputs_list = [
script_input, tts_model_dropdown, pause_input,
speaker_config_method_dropdown, global_voice_dropdown,
speaker_configs_state,
global_speed_input, global_instructions_input
]
example_outputs_list = [individual_lines_zip_output, merged_dialogue_mp3_output, status_output]
# Make examples runnable
example_process_fn = partial(handle_script_processing, OPENAI_API_KEY, async_openai_client, NSFW_API_URL_TEMPLATE)
_ = create_examples_ui(
inputs_for_examples=example_inputs_list,
process_fn=example_process_fn if OPENAI_API_KEY else None, # Only make runnable if API key exists
outputs_for_examples=example_outputs_list if OPENAI_API_KEY else None
)
# --- Launch ---
if __name__ == "__main__":
if os.name == 'nt':
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
demo.queue().launch(debug=True, share=False) |