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,
|
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.
|
262 |
-
inputs=[self.
|
263 |
concurrency_limit=1,
|
264 |
concurrency_id="render_output_fields",
|
265 |
)
|
266 |
-
def render_output_fields(
|
267 |
pipeline_state = self.sm.make_pipeline_state(pipeline_state_dict)
|
268 |
-
logger.info(f"Rerendering output panel: {
|
269 |
-
self._render_output_panel(
|
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 |
-
|
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
|
74 |
-
method = buzzer.method if
|
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=
|
83 |
-
gr.update(value=method, interactive=
|
84 |
gr.update(
|
85 |
value=tiny_styled_warning(
|
86 |
-
f"{model_name} does not support
|
87 |
),
|
88 |
-
visible=not
|
89 |
),
|
90 |
)
|
91 |
|
92 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
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 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
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 |
-
|
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 |
-
|
142 |
-
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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):
|