import gradio as gr import numpy as np from loguru import logger from app_configs import AVAILABLE_MODELS, UNSELECTED_VAR_NAME from components import commons from components.structs import TossupPipelineState from components.typed_dicts import TossupPipelineStateDict from display.formatting import tiny_styled_warning from workflows.structs import Buzzer, TossupWorkflow from .model_pipeline import PipelineInterface, PipelineState, PipelineUIState def toggleable_slider( value, minimum, maximum, step, toggle_value=False, label=None, info=None, min_width=200, scale=1 ): with gr.Column(elem_classes="toggleable", min_width=min_width, scale=scale): show_label = label is not None checkbox = gr.Checkbox(label=label, value=toggle_value, container=False, info=info, show_label=show_label) slider = gr.Slider( minimum=minimum, maximum=maximum, value=value, step=step, label="", interactive=True, show_label=False, container=False, ) checkbox.change(fn=lambda x: gr.update(interactive=x), inputs=[checkbox], outputs=[slider]) return checkbox, slider class TossupPipelineInterface(PipelineInterface): def __init__( self, app: gr.Blocks, workflow: TossupWorkflow, ui_state: PipelineUIState | None = None, model_options: list[str] = None, config: dict = {}, ): super().__init__(app, workflow, ui_state, model_options, config) self.buzzer_state = gr.State(workflow.buzzer.model_dump()) self.pipeline_state.change( lambda x: TossupPipelineState(**x).workflow.buzzer.model_dump(), inputs=[self.pipeline_state], outputs=[self.buzzer_state], ) def update_prob_slider( self, state_dict: TossupPipelineStateDict, answer_var: str, tokens_prob: float | None ) -> tuple[TossupPipelineStateDict, dict, dict, dict]: """Update the probability slider based on the answer variable.""" state = TossupPipelineState(**state_dict) if answer_var == UNSELECTED_VAR_NAME: return ( state.model_dump(), gr.update(interactive=True), gr.update(value="AND", interactive=True), gr.update(visible=False), ) logprobs_supported = state.workflow.is_token_probs_supported(answer_var) buzzer = state.workflow.buzzer tokens_prob_threshold = tokens_prob if logprobs_supported else None method = buzzer.method if logprobs_supported else "AND" state.workflow.buzzer = Buzzer( method=method, confidence_threshold=buzzer.confidence_threshold, prob_threshold=tokens_prob_threshold, ) model_name = state.workflow.get_answer_model(answer_var) return ( state.model_dump(), gr.update(interactive=logprobs_supported, value=tokens_prob if logprobs_supported else 0.0), gr.update(value=method, interactive=logprobs_supported), gr.update( value=tiny_styled_warning( f"'{model_name}' does not support 'logprobs'. The probability slider will be disabled." ), visible=not logprobs_supported, ), ) def _render_buzzer_panel( self, buzzer: Buzzer, prob_slider_supported: bool, selected_model_name: str | None = None ): with gr.Row(elem_classes="control-panel"): self.confidence_slider = gr.Slider( minimum=0.0, maximum=1.0, value=buzzer.confidence_threshold, step=0.01, label="Confidence", elem_classes="slider-container", show_reset_button=False, ) value = buzzer.method if prob_slider_supported else "AND" self.buzzer_method_dropdown = gr.Dropdown( choices=["AND", "OR"], value=value, label="Method", interactive=prob_slider_supported, min_width=80, scale=0, ) self.prob_slider = gr.Slider( value=buzzer.prob_threshold or 0.0, interactive=prob_slider_supported, label="Probability", minimum=0.0, maximum=1.0, step=0.001, elem_classes="slider-container", show_reset_button=False, ) display_html = "" if selected_model_name is not None: display_html = tiny_styled_warning( f"{selected_model_name} does not support logprobs. The probability slider will be disabled." ) self.buzzer_warning_display = gr.HTML(display_html, visible=not prob_slider_supported) def _render_output_panel(self, pipeline_state: TossupPipelineState): dropdowns = {} available_variables = pipeline_state.workflow.get_available_variables() variable_options = [UNSELECTED_VAR_NAME] + [v for v in available_variables if v not in self.input_variables] with gr.Column(elem_classes="step-accordion control-panel"): commons.get_panel_header( header="Final output variables mapping:", ) with gr.Row(elem_classes="output-fields-row"): for output_field in self.required_output_variables: value = pipeline_state.workflow.outputs.get(output_field) value = value or UNSELECTED_VAR_NAME dropdown = gr.Dropdown( label=output_field, value=value, choices=variable_options, interactive=True, elem_classes="output-field-variable", # show_label=False, ) dropdown.change( self.sm.update_output_variables, inputs=[self.pipeline_state, gr.State(output_field), dropdown], outputs=[self.pipeline_state], ) dropdowns[output_field] = dropdown commons.get_panel_header( header="Buzzer settings:", subheader="Set your thresholds for confidence and output tokens probability (computed using logprobs).", ) logprobs_supported = pipeline_state.workflow.is_token_probs_supported() selected_model_name = pipeline_state.workflow.get_answer_model() self._render_buzzer_panel(pipeline_state.workflow.buzzer, logprobs_supported, selected_model_name) def update_choices(available_variables: list[str]): """Update the choices for the dropdowns""" return [gr.update(choices=available_variables, value=None, selected=None) for _ in dropdowns.values()] self.variables_state.change( update_choices, inputs=[self.variables_state], outputs=list(dropdowns.values()), ) # Updating the pipeline buzzer on user input changes in Buzzer panel. gr.on( triggers=[ self.confidence_slider.release, self.buzzer_method_dropdown.input, self.prob_slider.release, ], fn=self.sm.update_buzzer, inputs=[self.pipeline_state, self.confidence_slider, self.buzzer_method_dropdown, self.prob_slider], outputs=[self.pipeline_state], ) # THIS WASN't NEEDED SINCE WE RERENDER THE OUTPUT PANEL ENTIRELY ON CHANGES # answer_dropdown = dropdowns["answer"] # if answer_dropdown is not None: # gr.on( # triggers=[self.buzzer_state.change], # fn=self.update_prob_slider, # inputs=[self.buzzer_state, answer_dropdown, self.prob_slider], # outputs=[ # self.pipeline_state, # self.prob_slider, # self.buzzer_method_dropdown, # self.buzzer_warning_display, # ], # )