Spaces:
Running
Running
examples doc
Browse files- app.py +58 -46
- ui_layout.py +1 -73
app.py
CHANGED
@@ -6,9 +6,10 @@ from openai import AsyncOpenAI
|
|
6 |
from functools import partial
|
7 |
import datetime
|
8 |
|
|
|
9 |
from ui_layout import (
|
10 |
create_main_input_components, create_speaker_config_components,
|
11 |
-
create_action_and_output_components,
|
12 |
TTS_MODELS_AVAILABLE, MODEL_DEFAULT_ENV, APP_AVAILABLE_VOICES,
|
13 |
DEFAULT_GLOBAL_VOICE, VIBE_CHOICES, DEFAULT_VIBE, PREDEFINED_VIBES
|
14 |
)
|
@@ -30,7 +31,7 @@ EFFECTIVE_MODEL_DEFAULT = MODEL_DEFAULT_FROM_ENV if MODEL_DEFAULT_FROM_ENV in TT
|
|
30 |
async_openai_client = None
|
31 |
if not OPENAI_API_KEY:
|
32 |
# ... (secret loading logic) ...
|
33 |
-
pass
|
34 |
if OPENAI_API_KEY:
|
35 |
async_openai_client = AsyncOpenAI(api_key=OPENAI_API_KEY)
|
36 |
else:
|
@@ -45,6 +46,7 @@ with gr.Blocks(theme=gr.themes.Soft(), elem_id="main_blocks_ui") as demo:
|
|
45 |
|
46 |
speaker_configs_state = gr.State({})
|
47 |
|
|
|
48 |
(script_input, tts_model_dropdown, pause_input,
|
49 |
global_speed_input, global_instructions_input) = create_main_input_components(EFFECTIVE_MODEL_DEFAULT)
|
50 |
|
@@ -63,7 +65,7 @@ with gr.Blocks(theme=gr.themes.Soft(), elem_id="main_blocks_ui") as demo:
|
|
63 |
triggers=[load_per_speaker_ui_button.click, tts_model_dropdown.change]
|
64 |
)
|
65 |
def render_dynamic_speaker_ui(current_script_text: str, current_speaker_configs: dict, current_tts_model: str):
|
66 |
-
|
67 |
print(f"DEBUG: @gr.render CALLED. Model: {current_tts_model}. Script: '{current_script_text[:30]}...'. State Keys: {list(current_speaker_configs.keys()) if isinstance(current_speaker_configs,dict) else 'Not a dict'}")
|
68 |
unique_speakers = get_speakers_from_script(current_script_text)
|
69 |
if not unique_speakers:
|
@@ -93,58 +95,68 @@ with gr.Blocks(theme=gr.themes.Soft(), elem_id="main_blocks_ui") as demo:
|
|
93 |
custom_instructions_textbox = gr.Textbox(label="Custom Instructions", value=default_custom_instructions, placeholder="e.g., Speak slightly hesitant.", lines=2, visible=(default_vibe == "Custom..."), elem_id=custom_instr_tb_elem_id)
|
94 |
vibe_dropdown.change(fn=partial(handle_dynamic_accordion_input_change, speaker_name=speaker_name, config_key="vibe"), inputs=[vibe_dropdown, speaker_configs_state], outputs=[speaker_configs_state]).then(fn=lambda vibe_val: gr.update(visible=(vibe_val == "Custom...")), inputs=[vibe_dropdown], outputs=[custom_instructions_textbox])
|
95 |
custom_instructions_textbox.change(fn=partial(handle_dynamic_accordion_input_change, speaker_name=speaker_name, config_key="custom_instructions"), inputs=[custom_instructions_textbox, speaker_configs_state], outputs=[speaker_configs_state])
|
96 |
-
|
97 |
|
98 |
# --- Event Listeners (Same as before) ---
|
99 |
-
tts_model_dropdown.change(
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
)
|
104 |
-
speaker_config_method_dropdown.change(
|
105 |
-
fn=handle_speaker_config_method_visibility_change,
|
106 |
-
inputs=[speaker_config_method_dropdown],
|
107 |
-
outputs=[single_voice_group, detailed_per_speaker_ui_group_container]
|
108 |
-
)
|
109 |
-
load_per_speaker_ui_button.click(
|
110 |
-
fn=handle_load_refresh_per_speaker_ui_trigger,
|
111 |
-
inputs=[script_input, speaker_configs_state, tts_model_dropdown],
|
112 |
-
outputs=[speaker_configs_state]
|
113 |
-
)
|
114 |
-
calculate_cost_button.click(
|
115 |
-
fn=handle_calculate_cost,
|
116 |
-
inputs=[script_input, tts_model_dropdown],
|
117 |
-
outputs=[cost_output]
|
118 |
-
)
|
119 |
generate_button_fn = partial(handle_script_processing, OPENAI_API_KEY, async_openai_client, NSFW_API_URL_TEMPLATE)
|
120 |
-
generate_button.click(
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
],
|
128 |
-
outputs=[individual_lines_zip_output, merged_dialogue_mp3_output, status_output]
|
129 |
-
)
|
130 |
-
|
131 |
-
# --- Examples Section Definition ---
|
132 |
-
example_inputs_list = [
|
133 |
script_input, tts_model_dropdown, pause_input,
|
134 |
speaker_config_method_dropdown, global_voice_dropdown,
|
135 |
speaker_configs_state,
|
136 |
global_speed_input, global_instructions_input
|
137 |
]
|
138 |
-
|
139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
|
141 |
-
#
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
148 |
|
149 |
# --- Launch ---
|
150 |
if __name__ == "__main__":
|
|
|
6 |
from functools import partial
|
7 |
import datetime
|
8 |
|
9 |
+
# Remove create_examples_ui from ui_layout imports if it's not used elsewhere
|
10 |
from ui_layout import (
|
11 |
create_main_input_components, create_speaker_config_components,
|
12 |
+
create_action_and_output_components, # Removed create_examples_ui
|
13 |
TTS_MODELS_AVAILABLE, MODEL_DEFAULT_ENV, APP_AVAILABLE_VOICES,
|
14 |
DEFAULT_GLOBAL_VOICE, VIBE_CHOICES, DEFAULT_VIBE, PREDEFINED_VIBES
|
15 |
)
|
|
|
31 |
async_openai_client = None
|
32 |
if not OPENAI_API_KEY:
|
33 |
# ... (secret loading logic) ...
|
34 |
+
pass
|
35 |
if OPENAI_API_KEY:
|
36 |
async_openai_client = AsyncOpenAI(api_key=OPENAI_API_KEY)
|
37 |
else:
|
|
|
46 |
|
47 |
speaker_configs_state = gr.State({})
|
48 |
|
49 |
+
# --- Create Main UI Components ---
|
50 |
(script_input, tts_model_dropdown, pause_input,
|
51 |
global_speed_input, global_instructions_input) = create_main_input_components(EFFECTIVE_MODEL_DEFAULT)
|
52 |
|
|
|
65 |
triggers=[load_per_speaker_ui_button.click, tts_model_dropdown.change]
|
66 |
)
|
67 |
def render_dynamic_speaker_ui(current_script_text: str, current_speaker_configs: dict, current_tts_model: str):
|
68 |
+
# ... (Full @gr.render implementation from previous correct step) ...
|
69 |
print(f"DEBUG: @gr.render CALLED. Model: {current_tts_model}. Script: '{current_script_text[:30]}...'. State Keys: {list(current_speaker_configs.keys()) if isinstance(current_speaker_configs,dict) else 'Not a dict'}")
|
70 |
unique_speakers = get_speakers_from_script(current_script_text)
|
71 |
if not unique_speakers:
|
|
|
95 |
custom_instructions_textbox = gr.Textbox(label="Custom Instructions", value=default_custom_instructions, placeholder="e.g., Speak slightly hesitant.", lines=2, visible=(default_vibe == "Custom..."), elem_id=custom_instr_tb_elem_id)
|
96 |
vibe_dropdown.change(fn=partial(handle_dynamic_accordion_input_change, speaker_name=speaker_name, config_key="vibe"), inputs=[vibe_dropdown, speaker_configs_state], outputs=[speaker_configs_state]).then(fn=lambda vibe_val: gr.update(visible=(vibe_val == "Custom...")), inputs=[vibe_dropdown], outputs=[custom_instructions_textbox])
|
97 |
custom_instructions_textbox.change(fn=partial(handle_dynamic_accordion_input_change, speaker_name=speaker_name, config_key="custom_instructions"), inputs=[custom_instructions_textbox, speaker_configs_state], outputs=[speaker_configs_state])
|
98 |
+
|
99 |
|
100 |
# --- Event Listeners (Same as before) ---
|
101 |
+
tts_model_dropdown.change(fn=handle_tts_model_change, inputs=[tts_model_dropdown, speaker_configs_state], outputs=[global_speed_input, global_instructions_input, speaker_configs_state])
|
102 |
+
speaker_config_method_dropdown.change(fn=handle_speaker_config_method_visibility_change, inputs=[speaker_config_method_dropdown], outputs=[single_voice_group, detailed_per_speaker_ui_group_container])
|
103 |
+
load_per_speaker_ui_button.click(fn=handle_load_refresh_per_speaker_ui_trigger, inputs=[script_input, speaker_configs_state, tts_model_dropdown], outputs=[speaker_configs_state])
|
104 |
+
calculate_cost_button.click(fn=handle_calculate_cost, inputs=[script_input, tts_model_dropdown], outputs=[cost_output])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
generate_button_fn = partial(handle_script_processing, OPENAI_API_KEY, async_openai_client, NSFW_API_URL_TEMPLATE)
|
106 |
+
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, global_speed_input, global_instructions_input], outputs=[individual_lines_zip_output, merged_dialogue_mp3_output, status_output])
|
107 |
+
|
108 |
+
# --- Examples Section Definition (Moved here) ---
|
109 |
+
gr.Markdown("## Example Scripts") # Keep the header if desired
|
110 |
+
|
111 |
+
# Define the lists needed for Examples right here
|
112 |
+
example_inputs_list_comps = [
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
script_input, tts_model_dropdown, pause_input,
|
114 |
speaker_config_method_dropdown, global_voice_dropdown,
|
115 |
speaker_configs_state,
|
116 |
global_speed_input, global_instructions_input
|
117 |
]
|
118 |
+
example_outputs_list_comps = [individual_lines_zip_output, merged_dialogue_mp3_output, status_output]
|
119 |
+
example_process_fn_actual = partial(handle_script_processing, OPENAI_API_KEY, async_openai_client, NSFW_API_URL_TEMPLATE) if OPENAI_API_KEY else None
|
120 |
+
|
121 |
+
# Define the example data directly
|
122 |
+
examples_data = [
|
123 |
+
["[Alice] Hello Bob, this is a test using the detailed configuration method.\\n[Bob] Hi Alice! I'm Bob, and I'll have my own voice settings.\\n[Alice] Let's see how this sounds.", "tts-1-hd", 300, "Detailed Configuration (Per Speaker UI)", DEFAULT_GLOBAL_VOICE, {}, 1.0, ""],
|
124 |
+
["[Narrator] This is a short story.\\n[CharacterA] Once upon a time...\\n[Narrator] ...there was a Gradio app.\\n[CharacterB] And it could talk!", "gpt-4o-mini-tts", 200, "Random per Speaker", DEFAULT_GLOBAL_VOICE, {}, 1.0, "Speak with a gentle, storytelling voice for the narrator."],
|
125 |
+
["[Solo] Just one line, using global voice and speed.", "tts-1", 0, "Single Voice (Global)", "fable", {}, 1.2, ""],
|
126 |
+
]
|
127 |
|
128 |
+
# Validate example data length against input components length
|
129 |
+
num_inputs_expected = len(example_inputs_list_comps)
|
130 |
+
valid_examples_data_inline = []
|
131 |
+
for ex_data in examples_data:
|
132 |
+
if len(ex_data) == num_inputs_expected:
|
133 |
+
valid_examples_data_inline.append(ex_data)
|
134 |
+
else:
|
135 |
+
print(f"Warning (Inline Examples): Example data mismatch. Expected {num_inputs_expected}, got {len(ex_data)}. Skipping.")
|
136 |
+
|
137 |
+
# Directly instantiate gr.Examples if valid data exists
|
138 |
+
if valid_examples_data_inline:
|
139 |
+
if example_process_fn_actual:
|
140 |
+
gr.Examples(
|
141 |
+
examples=valid_examples_data_inline,
|
142 |
+
inputs=example_inputs_list_comps,
|
143 |
+
outputs=example_outputs_list_comps,
|
144 |
+
fn=example_process_fn_actual,
|
145 |
+
cache_examples=False,
|
146 |
+
examples_per_page=5,
|
147 |
+
label="Example Scripts (Click to Load & Run)", # Label is optional if header exists
|
148 |
+
run_on_click=True
|
149 |
+
)
|
150 |
+
else:
|
151 |
+
gr.Examples(
|
152 |
+
examples=valid_examples_data_inline,
|
153 |
+
inputs=example_inputs_list_comps,
|
154 |
+
examples_per_page=5,
|
155 |
+
label="Example Scripts (Click to Load Inputs)", # Label is optional if header exists
|
156 |
+
)
|
157 |
+
else:
|
158 |
+
gr.Markdown("<p style='color: orange;'>No valid examples could be loaded due to configuration mismatch.</p>")
|
159 |
+
|
160 |
|
161 |
# --- Launch ---
|
162 |
if __name__ == "__main__":
|
ui_layout.py
CHANGED
@@ -126,76 +126,4 @@ def create_action_and_output_components():
|
|
126 |
individual_lines_zip_output = gr.File(label="Download Individual Lines (ZIP)", elem_id="individual_lines_zip_output")
|
127 |
merged_dialogue_mp3_output = gr.Audio(label="Play/Download Merged Dialogue (MP3)", type="filepath", elem_id="merged_dialogue_mp3_output")
|
128 |
status_output = gr.Textbox(label="Status", interactive=False, lines=2, max_lines=5, elem_id="status_output")
|
129 |
-
return calculate_cost_button, generate_button, cost_output, individual_lines_zip_output, merged_dialogue_mp3_output, status_output
|
130 |
-
|
131 |
-
def create_examples_ui(inputs_for_examples, process_fn, outputs_for_examples=None):
|
132 |
-
"""Creates the examples section."""
|
133 |
-
print("--- DEBUG: Entering create_examples_ui ---") # DEBUG ENTRY PRINT
|
134 |
-
gr.Markdown("## Example Scripts")
|
135 |
-
example_script_1 = "[Alice] Hello Bob, this is a test using the detailed configuration method.\\n[Bob] Hi Alice! I'm Bob, and I'll have my own voice settings.\\n[Alice] Let's see how this sounds."
|
136 |
-
example_script_2 = "[Narrator] This is a short story.\\n[CharacterA] Once upon a time...\\n[Narrator] ...there was a Gradio app.\\n[CharacterB] And it could talk!"
|
137 |
-
|
138 |
-
examples_data = [
|
139 |
-
[example_script_1, "tts-1-hd", 300, "Detailed Configuration (Per Speaker UI)", DEFAULT_GLOBAL_VOICE, {}, 1.0, ""],
|
140 |
-
[example_script_2, "gpt-4o-mini-tts", 200, "Random per Speaker", DEFAULT_GLOBAL_VOICE, {}, 1.0, "Speak with a gentle, storytelling voice for the narrator."],
|
141 |
-
["[Solo] Just one line, using global voice and speed.", "tts-1", 0, "Single Voice (Global)", "fable", {}, 1.2, ""],
|
142 |
-
]
|
143 |
-
|
144 |
-
# It's crucial that inputs_for_examples is correctly passed from app.py
|
145 |
-
if not inputs_for_examples:
|
146 |
-
print("ERROR (Examples): inputs_for_examples list is None or empty!")
|
147 |
-
return None # Cannot create examples without knowing the input components
|
148 |
-
|
149 |
-
num_inputs = len(inputs_for_examples)
|
150 |
-
valid_examples_data = []
|
151 |
-
print(f"DEBUG (Examples): Expected number of inputs based on inputs_for_examples: {num_inputs}")
|
152 |
-
|
153 |
-
for i, ex_data in enumerate(examples_data):
|
154 |
-
print(f"DEBUG (Examples): Checking example {i+1}, data length: {len(ex_data)}")
|
155 |
-
if len(ex_data) == num_inputs:
|
156 |
-
valid_examples_data.append(ex_data)
|
157 |
-
print(f"DEBUG (Examples): Example {i+1} length matches. Added to valid_examples_data.")
|
158 |
-
else:
|
159 |
-
print(f"Warning (Examples): Example data {i+1} mismatch. Expected {num_inputs} items, got {len(ex_data)}. Skipping example: {ex_data[0][:30]}...")
|
160 |
-
|
161 |
-
if not valid_examples_data:
|
162 |
-
print("DEBUG (Examples): valid_examples_data list is empty after checking all examples. Returning None.")
|
163 |
-
gr.Markdown("<p style='color: orange;'>No valid examples could be loaded due to configuration mismatch.</p>")
|
164 |
-
return None
|
165 |
-
|
166 |
-
print(f"DEBUG (Examples): Found {len(valid_examples_data)} valid examples. API Key Present: {bool(process_fn)}. Creating Examples component.")
|
167 |
-
|
168 |
-
if process_fn and outputs_for_examples:
|
169 |
-
print("DEBUG (Examples): Creating Examples component with run capability.")
|
170 |
-
try:
|
171 |
-
examples_component = gr.Examples(
|
172 |
-
examples=valid_examples_data,
|
173 |
-
inputs=inputs_for_examples,
|
174 |
-
outputs=outputs_for_examples,
|
175 |
-
fn=process_fn,
|
176 |
-
cache_examples=False,
|
177 |
-
examples_per_page=5,
|
178 |
-
label="Example Scripts (Click to Load & Run)",
|
179 |
-
run_on_click=True
|
180 |
-
)
|
181 |
-
print("DEBUG (Examples): Runnable Examples component created successfully.")
|
182 |
-
return examples_component
|
183 |
-
except Exception as e:
|
184 |
-
print(f"ERROR (Examples): Failed to create runnable Examples component: {e}")
|
185 |
-
gr.Markdown(f"<p style='color: red;'>Error creating runnable examples: {e}</p>")
|
186 |
-
return None # Return None if creation fails
|
187 |
-
else:
|
188 |
-
print("DEBUG (Examples): Creating Examples component as input loaders only (no API key or outputs).")
|
189 |
-
try:
|
190 |
-
examples_component = gr.Examples(
|
191 |
-
examples=valid_examples_data,
|
192 |
-
inputs=inputs_for_examples,
|
193 |
-
examples_per_page=5,
|
194 |
-
label="Example Scripts (Click to Load Inputs)",
|
195 |
-
)
|
196 |
-
print("DEBUG (Examples): Input-only Examples component created successfully.")
|
197 |
-
return examples_component
|
198 |
-
except Exception as e:
|
199 |
-
print(f"ERROR (Examples): Failed to create input-only Examples component: {e}")
|
200 |
-
gr.Markdown(f"<p style='color: red;'>Error creating input-only examples: {e}</p>")
|
201 |
-
return None # Return None if creation fails
|
|
|
126 |
individual_lines_zip_output = gr.File(label="Download Individual Lines (ZIP)", elem_id="individual_lines_zip_output")
|
127 |
merged_dialogue_mp3_output = gr.Audio(label="Play/Download Merged Dialogue (MP3)", type="filepath", elem_id="merged_dialogue_mp3_output")
|
128 |
status_output = gr.Textbox(label="Status", interactive=False, lines=2, max_lines=5, elem_id="status_output")
|
129 |
+
return calculate_cost_button, generate_button, cost_output, individual_lines_zip_output, merged_dialogue_mp3_output, status_output
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|