Maharshi Gor commited on
Commit
da814b0
·
1 Parent(s): 9756440

Bugfix: Buzzer update on pipeline change.

Browse files
src/components/model_pipeline/model_pipeline.py CHANGED
@@ -161,8 +161,9 @@ class PipelineInterface:
161
  )
162
  return add_step_btn
163
 
164
- def _render_output_panel(self, available_variables: list[str], pipeline_state: PipelineState):
165
  dropdowns = {}
 
166
  variable_options = [UNSELECTED_VAR_NAME] + [v for v in available_variables if v not in self.input_variables]
167
  with gr.Column(elem_classes="step-accordion control-panel"):
168
  commons.get_panel_header(
@@ -258,15 +259,15 @@ class PipelineInterface:
258
  self._render_add_step_button(-1)
259
 
260
  @gr.render(
261
- triggers=[self.variables_state.change, self.app.load],
262
- inputs=[self.variables_state, self.pipeline_state],
263
  concurrency_limit=1,
264
  concurrency_id="render_output_fields",
265
  )
266
- def render_output_fields(available_variables: list[str], pipeline_state_dict: td.PipelineStateDict):
267
  pipeline_state = self.sm.make_pipeline_state(pipeline_state_dict)
268
- logger.info(f"Rerendering output panel: {available_variables} {pipeline_state.workflow}")
269
- self._render_output_panel(available_variables, pipeline_state)
270
 
271
  export_btn = gr.Button("Export Pipeline", elem_classes="export-button")
272
  # components.append(export_btn)
 
161
  )
162
  return add_step_btn
163
 
164
+ def _render_output_panel(self, pipeline_state: PipelineState):
165
  dropdowns = {}
166
+ available_variables = pipeline_state.workflow.get_available_variables()
167
  variable_options = [UNSELECTED_VAR_NAME] + [v for v in available_variables if v not in self.input_variables]
168
  with gr.Column(elem_classes="step-accordion control-panel"):
169
  commons.get_panel_header(
 
259
  self._render_add_step_button(-1)
260
 
261
  @gr.render(
262
+ triggers=[self.workflow_state.change, self.app.load],
263
+ inputs=[self.pipeline_state],
264
  concurrency_limit=1,
265
  concurrency_id="render_output_fields",
266
  )
267
+ def render_output_fields(pipeline_state_dict: td.PipelineStateDict):
268
  pipeline_state = self.sm.make_pipeline_state(pipeline_state_dict)
269
+ logger.info(f"Rerendering output panel: {pipeline_state.workflow}")
270
+ self._render_output_panel(pipeline_state)
271
 
272
  export_btn = gr.Button("Export Pipeline", elem_classes="export-button")
273
  # components.append(export_btn)
src/components/model_pipeline/tossup_pipeline.py CHANGED
@@ -13,6 +13,22 @@ from .model_pipeline import PipelineInterface, PipelineState, PipelineUIState
13
  from .state_manager import PipelineStateManager, TossupPipelineStateManager
14
 
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  def toggleable_slider(
17
  value, minimum, maximum, step, toggle_value=False, label=None, info=None, min_width=200, scale=1
18
  ):
@@ -65,32 +81,70 @@ class TossupPipelineInterface(PipelineInterface):
65
  gr.update(value="AND", interactive=True),
66
  gr.update(visible=False),
67
  )
68
- step_id = answer_var.split(".")[0]
69
- model_name = state.workflow.steps[step_id].get_full_model_name()
70
- model_config = AVAILABLE_MODELS[model_name]
71
- is_model_with_logprobs = model_config.get("logprobs", False)
72
  buzzer = state.workflow.buzzer
73
- tokens_prob_threshold = tokens_prob if is_model_with_logprobs else None
74
- method = buzzer.method if is_model_with_logprobs else "AND"
75
  state.workflow.buzzer = Buzzer(
76
  method=method,
77
  confidence_threshold=buzzer.confidence_threshold,
78
  prob_threshold=tokens_prob_threshold,
79
  )
 
80
  return (
81
  state.model_dump(),
82
- gr.update(interactive=is_model_with_logprobs),
83
- gr.update(value=method, interactive=is_model_with_logprobs),
84
  gr.update(
85
  value=tiny_styled_warning(
86
- f"{model_name} does not support `logprobs`. The probability slider will be disabled."
87
  ),
88
- visible=not is_model_with_logprobs,
89
  ),
90
  )
91
 
92
- def _render_output_panel(self, available_variables: list[str], pipeline_state: TossupPipelineState):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  dropdowns = {}
 
94
  variable_options = [UNSELECTED_VAR_NAME] + [v for v in available_variables if v not in self.input_variables]
95
  with gr.Column(elem_classes="step-accordion control-panel"):
96
  commons.get_panel_header(
@@ -98,7 +152,8 @@ class TossupPipelineInterface(PipelineInterface):
98
  )
99
  with gr.Row(elem_classes="output-fields-row"):
100
  for output_field in self.required_output_variables:
101
- value = pipeline_state.workflow.outputs.get(output_field, UNSELECTED_VAR_NAME)
 
102
  dropdown = gr.Dropdown(
103
  label=output_field,
104
  value=value,
@@ -117,42 +172,19 @@ class TossupPipelineInterface(PipelineInterface):
117
  header="Buzzer settings:",
118
  subheader="Set your thresholds for confidence and output tokens probability.",
119
  )
120
- with gr.Row(elem_classes="control-panel"):
121
- self.confidence_slider = gr.Slider(
122
- minimum=0.0,
123
- maximum=1.0,
124
- value=self.defaults.get("confidence_threshold", 0.85),
125
- step=0.01,
126
- label="Confidence",
127
- elem_classes="slider-container",
128
- )
129
- self.buzzer_method_dropdown = gr.Dropdown(
130
- choices=["AND", "OR"],
131
- value=self.defaults.get("buzzer_method", "AND"),
132
- label="Method",
133
- interactive=True,
134
- min_width=80,
135
- scale=0,
136
- )
137
- self.prob_slider = gr.Slider(
138
- value=self.defaults.get("logits_prob", 0.0),
139
- label="Probability",
140
- minimum=0.0,
141
- maximum=1.0,
142
- step=0.001,
143
- elem_classes="slider-container",
144
- )
145
- self.buzzer_warning_display = gr.HTML(visible=False)
146
-
147
- def update_choices(available_variables: list[str]):
148
- """Update the choices for the dropdowns"""
149
- return [gr.update(choices=available_variables, value=None, selected=None) for _ in dropdowns.values()]
150
-
151
- self.variables_state.change(
152
- update_choices,
153
- inputs=[self.variables_state],
154
- outputs=list(dropdowns.values()),
155
- )
156
 
157
  gr.on(
158
  triggers=[
 
13
  from .state_manager import PipelineStateManager, TossupPipelineStateManager
14
 
15
 
16
+ def get_probs_model_name(workflow: TossupWorkflow, answer_var: str | None = None) -> str | None:
17
+ if answer_var is None:
18
+ answer_var = workflow.outputs["answer"]
19
+ if answer_var is None or answer_var == UNSELECTED_VAR_NAME:
20
+ return None
21
+ step_id = answer_var.split(".")[0]
22
+ return workflow.steps[step_id].get_full_model_name()
23
+
24
+
25
+ def is_logprobs_supported(workflow: TossupWorkflow, answer_var: str | None = None) -> bool:
26
+ model_name = get_probs_model_name(workflow, answer_var)
27
+ if model_name is None:
28
+ return True
29
+ return AVAILABLE_MODELS[model_name].get("logprobs", False)
30
+
31
+
32
  def toggleable_slider(
33
  value, minimum, maximum, step, toggle_value=False, label=None, info=None, min_width=200, scale=1
34
  ):
 
81
  gr.update(value="AND", interactive=True),
82
  gr.update(visible=False),
83
  )
84
+ logprobs_supported = is_logprobs_supported(state.workflow, answer_var)
 
 
 
85
  buzzer = state.workflow.buzzer
86
+ tokens_prob_threshold = tokens_prob if logprobs_supported else None
87
+ method = buzzer.method if logprobs_supported else "AND"
88
  state.workflow.buzzer = Buzzer(
89
  method=method,
90
  confidence_threshold=buzzer.confidence_threshold,
91
  prob_threshold=tokens_prob_threshold,
92
  )
93
+ model_name = get_probs_model_name(state.workflow, answer_var)
94
  return (
95
  state.model_dump(),
96
+ gr.update(interactive=logprobs_supported),
97
+ gr.update(value=method, interactive=logprobs_supported),
98
  gr.update(
99
  value=tiny_styled_warning(
100
+ f"<code>{model_name}</code> does not support <code>logprobs</code>. The probability slider will be disabled."
101
  ),
102
+ visible=not logprobs_supported,
103
  ),
104
  )
105
 
106
+ def _render_buzzer_panel(
107
+ self, buzzer: Buzzer, prob_slider_supported: bool, selected_model_name: str | None = None
108
+ ):
109
+ with gr.Row(elem_classes="control-panel"):
110
+ self.confidence_slider = gr.Slider(
111
+ minimum=0.0,
112
+ maximum=1.0,
113
+ value=buzzer.confidence_threshold,
114
+ step=0.01,
115
+ label="Confidence",
116
+ elem_classes="slider-container",
117
+ show_reset_button=False,
118
+ )
119
+ value = buzzer.method if prob_slider_supported else "AND"
120
+ self.buzzer_method_dropdown = gr.Dropdown(
121
+ choices=["AND", "OR"],
122
+ value=value,
123
+ label="Method",
124
+ interactive=prob_slider_supported,
125
+ min_width=80,
126
+ scale=0,
127
+ )
128
+ self.prob_slider = gr.Slider(
129
+ value=buzzer.prob_threshold or 0.0,
130
+ interactive=prob_slider_supported,
131
+ label="Probability",
132
+ minimum=0.0,
133
+ maximum=1.0,
134
+ step=0.001,
135
+ elem_classes="slider-container",
136
+ show_reset_button=False,
137
+ )
138
+ display_html = ""
139
+ if selected_model_name is not None:
140
+ display_html = tiny_styled_warning(
141
+ f"<code>{selected_model_name}</code> does not support <code>logprobs</code>. The probability slider will be disabled."
142
+ )
143
+ self.buzzer_warning_display = gr.HTML(display_html, visible=not prob_slider_supported)
144
+
145
+ def _render_output_panel(self, pipeline_state: TossupPipelineState):
146
  dropdowns = {}
147
+ available_variables = pipeline_state.workflow.get_available_variables()
148
  variable_options = [UNSELECTED_VAR_NAME] + [v for v in available_variables if v not in self.input_variables]
149
  with gr.Column(elem_classes="step-accordion control-panel"):
150
  commons.get_panel_header(
 
152
  )
153
  with gr.Row(elem_classes="output-fields-row"):
154
  for output_field in self.required_output_variables:
155
+ value = pipeline_state.workflow.outputs.get(output_field)
156
+ value = value or UNSELECTED_VAR_NAME
157
  dropdown = gr.Dropdown(
158
  label=output_field,
159
  value=value,
 
172
  header="Buzzer settings:",
173
  subheader="Set your thresholds for confidence and output tokens probability.",
174
  )
175
+ logprobs_supported = is_logprobs_supported(pipeline_state.workflow)
176
+ selected_model_name = get_probs_model_name(pipeline_state.workflow)
177
+ self._render_buzzer_panel(pipeline_state.workflow.buzzer, logprobs_supported, selected_model_name)
178
+
179
+ # def update_choices(available_variables: list[str]):
180
+ # """Update the choices for the dropdowns"""
181
+ # return [gr.update(choices=available_variables, value=None, selected=None) for _ in dropdowns.values()]
182
+
183
+ # self.variables_state.change(
184
+ # update_choices,
185
+ # inputs=[self.variables_state],
186
+ # outputs=list(dropdowns.values()),
187
+ # )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
  gr.on(
190
  triggers=[
src/components/structs.py CHANGED
@@ -128,40 +128,19 @@ class PipelineState(BaseModel):
128
  step_id = self.ui_state.step_ids.pop(position)
129
 
130
  workflow = self.workflow.remove_step(step_id)
131
- self.ui_state = self.ui_state.remove_step(step_id)
132
-
133
- # Return a new PipelineState with the updated workflow
134
- updated_outputs = self.get_output_variables_updates(workflow)
135
- return self.model_copy(update={"workflow": workflow, "outputs": updated_outputs})
136
 
137
  def update_step(self, step: ModelStep, ui_state: ModelStepUIState | None = None) -> "PipelineState":
138
  """Update a step in the pipeline."""
139
  if step.id not in self.workflow.steps:
140
  raise ValueError(f"Step {step.id} not found in pipeline")
141
- steps = self.workflow.steps | {step.id: step}
142
- workflow = self.workflow.model_copy(update={"steps": steps})
143
- update = {"workflow": workflow, "outputs": self.get_output_variables_updates(workflow)}
144
  if ui_state is not None:
145
  update["ui_state"] = self.ui_state.update_step(step.id, ui_state)
146
  return self.model_copy(update=update)
147
 
148
- def get_output_variables_updates(self, new_workflow: Workflow) -> dict[str, str | None]:
149
- available_variables = set(self.available_variables)
150
- updated_outputs = new_workflow.outputs.copy()
151
- for output_field in updated_outputs:
152
- if updated_outputs[output_field] not in available_variables:
153
- updated_outputs[output_field] = None
154
- return updated_outputs
155
-
156
- def update_output_variables_mapping(self) -> "PipelineState":
157
- updated_outputs = self.get_output_variables_updates(self.workflow)
158
-
159
- # Create a new workflow with updated outputs
160
- workflow = self.workflow.model_copy(update={"outputs": updated_outputs})
161
-
162
- # Return a new PipelineState with the updated workflow
163
- return self.model_copy(update={"workflow": workflow})
164
-
165
  def get_available_variables(self, model_step_id: str | None = None) -> list[str]:
166
  """Get all variables from all steps."""
167
  available_variables = self.available_variables
 
128
  step_id = self.ui_state.step_ids.pop(position)
129
 
130
  workflow = self.workflow.remove_step(step_id)
131
+ ui_state = self.ui_state.remove_step(step_id)
132
+ return self.model_copy(update={"workflow": workflow, "ui_state": ui_state})
 
 
 
133
 
134
  def update_step(self, step: ModelStep, ui_state: ModelStepUIState | None = None) -> "PipelineState":
135
  """Update a step in the pipeline."""
136
  if step.id not in self.workflow.steps:
137
  raise ValueError(f"Step {step.id} not found in pipeline")
138
+ workflow = self.workflow.update_step(step)
139
+ update = {"workflow": workflow}
 
140
  if ui_state is not None:
141
  update["ui_state"] = self.ui_state.update_step(step.id, ui_state)
142
  return self.model_copy(update=update)
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  def get_available_variables(self, model_step_id: str | None = None) -> list[str]:
145
  """Get all variables from all steps."""
146
  available_variables = self.available_variables
src/workflows/structs.py CHANGED
@@ -269,7 +269,24 @@ class Workflow(BaseModel):
269
  def remove_step(self, step_id: str) -> "Workflow":
270
  """Remove a step from the workflow."""
271
  self.steps.pop(step_id)
272
- return self.model_copy(update={"steps": self.steps})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
 
274
 
275
  class BuzzerMethod(str, Enum):
 
269
  def remove_step(self, step_id: str) -> "Workflow":
270
  """Remove a step from the workflow."""
271
  self.steps.pop(step_id)
272
+ workflow = self.model_copy(update={"steps": self.steps})
273
+ workflow.refresh_output_variables()
274
+ return workflow
275
+
276
+ def update_step(self, step: ModelStep) -> "Workflow":
277
+ """Update a step in the workflow."""
278
+ self.steps[step.id] = step
279
+ steps = self.steps | {step.id: step}
280
+ workflow = self.model_copy(update={"steps": steps})
281
+ workflow.refresh_output_variables()
282
+ return workflow
283
+
284
+ # Output variables
285
+ def refresh_output_variables(self) -> "Workflow":
286
+ """Refresh the output variables for the workflow."""
287
+ produced_variables = self.get_available_variables()
288
+ self.outputs = {k: (v if v in produced_variables else None) for k, v in self.outputs.items()}
289
+ return self
290
 
291
 
292
  class BuzzerMethod(str, Enum):