The GradioOutputManager is a robust system designed to prevent output ordering bugs in Gradio applications. Instead of manually managing tuples and remembering the correct order of outputs, this system allows you to set outputs by name and automatically generates the correct tuple.
Before this system, Gradio functions returned tuples like this:
return (
gr.update(value="All feedback collected. Thank you!", visible=True), # recommendations
gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), # keep_btn, adjust_btn, reject_btn
idx, feedback_log, # rec_index_state, feedback_log_state
chatbox, # chatbox
updated_memory, # agent_memory
gr.update(interactive=False, value="", placeholder="Chat will be enabled when feedback explanation is needed..."), # chat_input
gr.update(visible=False, interactive=False), # send_btn
gr.update(visible=True), # new_recs_btn
updated_memory_editor # memory_display
)This approach was error-prone because:
- Easy to mix up the order of outputs
- Hard to maintain when adding/removing outputs
- Comments could get out of sync with actual order
- Debugging was difficult when values went to wrong UI elements
First, define the expected output order for each function:
FEEDBACK_OUTPUTS = [
"recommendations", # 0
"keep_btn", # 1
"adjust_btn", # 2
"reject_btn", # 3
"rec_index_state", # 4
"feedback_log_state", # 5
"chatbox", # 6
"agent_memory", # 7
"chat_input", # 8
"send_btn", # 9
"new_recs_btn", # 10
"memory_display" # 11
]def feedback_action(feedback_type, recs, idx, feedback_log, user_id_state, agent_memory, chatbox):
outputs = GradioOutputManager(FEEDBACK_OUTPUTS)
# Set outputs by name instead of position
return outputs.set_multiple(
recommendations=gr.update(value="All feedback collected. Thank you!", visible=True),
keep_btn=gr.update(visible=False),
adjust_btn=gr.update(visible=False),
reject_btn=gr.update(visible=False),
rec_index_state=idx,
feedback_log_state=feedback_log,
chatbox=chatbox,
agent_memory=updated_memory,
chat_input=gr.update(interactive=False, value="", placeholder="Chat will be enabled when feedback explanation is needed..."),
send_btn=gr.update(visible=False, interactive=False),
new_recs_btn=gr.update(visible=True),
memory_display=updated_memory_editor
).get_tuple()- Type Safety: Error if you try to set an output that doesn't exist
- Order Independence: Set outputs in any order, the manager handles correct positioning
- Maintainable: Easy to add/remove outputs by updating the schema
- Debuggable: Clear names make it obvious what each output does
- Self-Documenting: The schema serves as documentation
Initialize with a list of output component names in the expected order.
Set a value for a named output. Returns self for chaining.
Set multiple outputs at once using keyword arguments. Returns self for chaining.
Return the values as a tuple in the correct order for Gradio.
Reset all values to None. Returns self for chaining.
Used by feedback_action and reason_action functions.
Used by on_see_recommendations_click function.
Used by on_profile_submit function.
The manager will raise a ValueError if you try to set an output that doesn't exist in the schema:
try:
outputs.set("invalid_output", "test")
except ValueError as e:
print(f"Error: {e}")
# Error: Unknown output name: invalid_output. Available: ['recommendations', 'keep_btn', ...]Run the test script to verify the system works:
python test_output_manager_standalone.pyTo migrate existing functions:
- Define an output schema list
- Replace the function's return statement with GradioOutputManager
- Use
set_multiple()to set all outputs by name - Call
get_tuple()to get the final result
return (
gr.update(value=next_card, visible=True), # recommendations
gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), # buttons
next_idx, feedback_log, # state
chatbox, # chatbox
format_agent_memory_panel(load_user_profile(user_id_state)) if user_id_state else "", # agent_memory
)outputs = GradioOutputManager(FEEDBACK_OUTPUTS)
return outputs.set_multiple(
recommendations=gr.update(value=next_card, visible=True),
keep_btn=gr.update(visible=True),
adjust_btn=gr.update(visible=True),
reject_btn=gr.update(visible=True),
rec_index_state=next_idx,
feedback_log_state=feedback_log,
chatbox=chatbox,
agent_memory=format_agent_memory_panel(load_user_profile(user_id_state)) if user_id_state else ""
).get_tuple()