from typing import NamedTuple, Type, Union import gradio as gr MAX_INPUTS = 10 MAX_TASKS = 50 class Input: def render(self, visible: bool) -> gr.Box: with gr.Box(visible=visible) as gr_component: # TODO: Remove this with gr.Row(): self.output_name = gr.Textbox( label="Input name (can be referenced with {})", interactive=True, placeholder="Variable name", ) self.output = gr.Textbox( label="Input value", interactive=True, placeholder="Variable value", ) return gr_component class AITask: @property def vars(self): return [self.prompt] def render(self, visible: bool) -> gr.Box: with gr.Box(visible=visible) as gr_component: gr.Markdown(f"AI task") with gr.Row(): with gr.Column(): self.prompt = gr.Textbox( label="Instructions", lines=13, interactive=True, placeholder="What is the AI assistant meant to do?", ) with gr.Column(): self.output_name = gr.Textbox( label="Output name (can be referenced with {})", interactive=True, placeholder="Variable name", ) self.output = gr.Textbox( show_label=False, lines=10, interactive=False, ) return gr_component class Component: def __init__(self, id_: int, internal: Union[Input, AITask], visible: str = "0"): self._id = id_ self.component_id: gr.Textbox self.internal = internal self.gr_component = gr.Box self._visible = visible self.output_name: gr.Textbox self.output: gr.Textbox self.source: gr.Textbox def render(self) -> None: self.component_id = gr.Textbox(value=str(self._id), visible=False) self.source = gr.Textbox(value=self.internal.__class__.__name__, visible=False) self.visible = gr.Textbox(value=self._visible, visible=False) self.gr_component = self.internal.render(bool(self._visible)) self.output_name = self.internal.output_name self.output = self.internal.output class Variable(NamedTuple): source: Type[Union[Input, AITask]] id_: int name: str value: str all_inputs = [Component(i, Input()) for i in range(MAX_INPUTS)] all_tasks = [Component(i, AITask()) for i in range(MAX_TASKS)] all_components = all_inputs + all_tasks all_inputs[0]._visible = "1" all_tasks[0]._visible = "1" def _update_components(i: int, max: int): return [gr.Box.update(visible=True)] * i + [gr.Box.update(visible=False)] * ( max - i ) def add_input(): global next_input if next_input < MAX_INPUTS: next_input += 1 return _update_components(next_input, MAX_INPUTS) def remove_input(): global next_input if next_input > 0: next_input -= 1 return _update_components(next_input, MAX_INPUTS) def add_task(): global next_task if next_task < MAX_TASKS: next_task += 1 return _update_components(next_task, MAX_TASKS) def remove_task(): global next_task if next_task > 0: next_task -= 1 return _update_components(next_task, MAX_TASKS) def execute(output_names, outputs): for output_name in output_names: print(output_name) with gr.Blocks() as demo: # Initial layout for i in all_inputs: i.render() input_error = gr.HighlightedText( [("Repeated variable names in inputs. Please pick different names.", "Error")], show_label=False, visible=False, ) with gr.Row(): add_input_btn = gr.Button("Add input variable") remove_input_btn = gr.Button("Remove input variable") execute_btn = gr.Button("Execute") for t in all_tasks: t.render() task_error = gr.HighlightedText( [("Repeated variable names in tasks. Please pick different names.", "Error")], show_label=False, visible=False, ) with gr.Row(): add_task_btn = gr.Button("Add task") remove_task_btn = gr.Button("Remove task") # Layout editing add_input_btn.click( add_input, inputs=[], outputs=[i.gr_component for i in all_inputs], ) remove_input_btn.click( remove_input, inputs=[], outputs=[i.gr_component for i in all_inputs], ) add_task_btn.click( add_task, inputs=[], outputs=[t.gr_component for t in all_tasks], ) remove_task_btn.click( remove_task, inputs=[], outputs=[t.gr_component for t in all_tasks], ) demo.launch()