Spaces:
Running
Running
Maharshi Gor
commited on
Commit
·
e00ec4e
1
Parent(s):
3b39b49
BugFix: Step Creation and removal.
Browse files* disallowed removing when there is only step
* reliable new step id creation
src/components/model_pipeline/model_pipeline.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1 |
-
import json
|
2 |
-
|
3 |
import gradio as gr
|
4 |
import yaml
|
|
|
5 |
|
6 |
from components.model_pipeline.state_manager import (
|
7 |
ModelStepUIState,
|
@@ -89,6 +88,7 @@ class PipelineInterface:
|
|
89 |
step_ui_state: ModelStepUIState,
|
90 |
available_variables: list[str],
|
91 |
position: int = 0,
|
|
|
92 |
):
|
93 |
with gr.Column(elem_classes="step-container"):
|
94 |
# Create the step component
|
@@ -115,11 +115,14 @@ class PipelineInterface:
|
|
115 |
if self.simple:
|
116 |
return step_interface
|
117 |
|
|
|
|
|
|
|
118 |
# Add step controls below
|
119 |
-
with gr.Row(elem_classes="step-controls"):
|
120 |
-
up_button = gr.Button("⬆️ Move Up", elem_classes="step-control-btn")
|
121 |
-
down_button = gr.Button("⬇️ Move Down", elem_classes="step-control-btn")
|
122 |
-
remove_button = gr.Button("🗑️ Remove", elem_classes="step-control-btn")
|
123 |
|
124 |
buttons = (up_button, down_button, remove_button)
|
125 |
self._assign_step_controls(buttons, position)
|
@@ -232,10 +235,10 @@ class PipelineInterface:
|
|
232 |
|
233 |
# Function to render all steps
|
234 |
@gr.render(inputs=[self.pipeline_state, self.ui_state])
|
235 |
-
def render_steps(state, ui_state):
|
236 |
"""Render all steps in the pipeline"""
|
|
|
237 |
workflow = state.workflow
|
238 |
-
print(f"\nRerender triggered! Current UI State:{ui_state}")
|
239 |
components = []
|
240 |
|
241 |
step_objects = [] # Reset step objects list
|
@@ -243,7 +246,7 @@ class PipelineInterface:
|
|
243 |
step_data = workflow.steps[step_id]
|
244 |
step_ui_state = ui_state.steps[step_id]
|
245 |
available_variables = self.sm.get_all_variables(state, step_id)
|
246 |
-
sub_components = self._render_step(step_data, step_ui_state, available_variables, i)
|
247 |
step_objects.append(sub_components)
|
248 |
|
249 |
components.append(step_objects)
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
import yaml
|
3 |
+
from loguru import logger
|
4 |
|
5 |
from components.model_pipeline.state_manager import (
|
6 |
ModelStepUIState,
|
|
|
88 |
step_ui_state: ModelStepUIState,
|
89 |
available_variables: list[str],
|
90 |
position: int = 0,
|
91 |
+
n_steps: int = 1,
|
92 |
):
|
93 |
with gr.Column(elem_classes="step-container"):
|
94 |
# Create the step component
|
|
|
115 |
if self.simple:
|
116 |
return step_interface
|
117 |
|
118 |
+
is_multi_step = n_steps > 1
|
119 |
+
logger.debug(f"Rendering step {position} of {n_steps}")
|
120 |
+
|
121 |
# Add step controls below
|
122 |
+
with gr.Row(elem_classes="step-controls", visible=is_multi_step):
|
123 |
+
up_button = gr.Button("⬆️ Move Up", elem_classes="step-control-btn", interactive=is_multi_step)
|
124 |
+
down_button = gr.Button("⬇️ Move Down", elem_classes="step-control-btn", interactive=is_multi_step)
|
125 |
+
remove_button = gr.Button("🗑️ Remove", elem_classes="step-control-btn", interactive=is_multi_step)
|
126 |
|
127 |
buttons = (up_button, down_button, remove_button)
|
128 |
self._assign_step_controls(buttons, position)
|
|
|
235 |
|
236 |
# Function to render all steps
|
237 |
@gr.render(inputs=[self.pipeline_state, self.ui_state])
|
238 |
+
def render_steps(state: PipelineState, ui_state: PipelineUIState):
|
239 |
"""Render all steps in the pipeline"""
|
240 |
+
logger.info(f"\nRerender triggered! Current UI State:{ui_state.model_dump()}")
|
241 |
workflow = state.workflow
|
|
|
242 |
components = []
|
243 |
|
244 |
step_objects = [] # Reset step objects list
|
|
|
246 |
step_data = workflow.steps[step_id]
|
247 |
step_ui_state = ui_state.steps[step_id]
|
248 |
available_variables = self.sm.get_all_variables(state, step_id)
|
249 |
+
sub_components = self._render_step(step_data, step_ui_state, available_variables, i, ui_state.n_steps)
|
250 |
step_objects.append(sub_components)
|
251 |
|
252 |
components.append(step_objects)
|
src/components/model_pipeline/state_manager.py
CHANGED
@@ -3,6 +3,7 @@ from typing import Any, Literal
|
|
3 |
|
4 |
import gradio as gr
|
5 |
import yaml
|
|
|
6 |
from pydantic import BaseModel, Field
|
7 |
|
8 |
from components import utils
|
@@ -10,17 +11,25 @@ from workflows.factory import create_new_llm_step
|
|
10 |
from workflows.structs import ModelStep, Workflow
|
11 |
|
12 |
|
13 |
-
def make_step_id(
|
14 |
"""Make a step id from a step name."""
|
15 |
-
if
|
16 |
-
return chr(ord("A") +
|
17 |
else:
|
18 |
# For more than 26 steps, use AA, AB, AC, etc.
|
19 |
-
first_char = chr(ord("A") + (
|
20 |
-
second_char = chr(ord("A") + (
|
21 |
return f"{first_char}{second_char}"
|
22 |
|
23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
class ModelStepUIState(BaseModel):
|
25 |
"""Represents the UI state for a model step component."""
|
26 |
|
@@ -48,6 +57,11 @@ class PipelineUIState(BaseModel):
|
|
48 |
"""Get the position of a step in the pipeline."""
|
49 |
return next((i for i, step in enumerate(self.step_ids) if step == step_id), None)
|
50 |
|
|
|
|
|
|
|
|
|
|
|
51 |
@classmethod
|
52 |
def from_workflow(cls, workflow: Workflow):
|
53 |
"""Create a pipeline UI state from a workflow."""
|
@@ -63,7 +77,7 @@ class PipelineState(BaseModel):
|
|
63 |
workflow: Workflow
|
64 |
ui_state: PipelineUIState
|
65 |
|
66 |
-
def insert_step(self, position: int, step: ModelStep):
|
67 |
if step.id in self.workflow.steps:
|
68 |
raise ValueError(f"Step {step.id} already exists in pipeline")
|
69 |
|
@@ -81,14 +95,15 @@ class PipelineState(BaseModel):
|
|
81 |
self.ui_state.step_ids.insert(position, step.id)
|
82 |
return self
|
83 |
|
84 |
-
def remove_step(self, position: int):
|
85 |
step_id = self.ui_state.step_ids.pop(position)
|
86 |
self.workflow.steps.pop(step_id)
|
87 |
self.ui_state = self.ui_state.model_copy()
|
88 |
self.ui_state.steps.pop(step_id)
|
89 |
self.update_output_variables_mapping()
|
|
|
90 |
|
91 |
-
def update_output_variables_mapping(self):
|
92 |
available_variables = set(self.available_variables)
|
93 |
for output_field in self.workflow.outputs:
|
94 |
if self.workflow.outputs[output_field] not in available_variables:
|
@@ -96,13 +111,21 @@ class PipelineState(BaseModel):
|
|
96 |
return self
|
97 |
|
98 |
@property
|
99 |
-
def available_variables(self):
|
100 |
return self.workflow.get_available_variables()
|
101 |
|
102 |
@property
|
103 |
-
def n_steps(self):
|
104 |
return len(self.workflow.steps)
|
105 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
|
107 |
class PipelineStateManager:
|
108 |
"""Manages a pipeline of multiple steps."""
|
@@ -120,7 +143,7 @@ class PipelineStateManager:
|
|
120 |
|
121 |
def add_step(self, state: PipelineState, position: int = -1, name=""):
|
122 |
"""Create a new step and return its state."""
|
123 |
-
step_id =
|
124 |
step_name = name or f"Step {state.n_steps + 1}"
|
125 |
new_step = create_new_llm_step(step_id=step_id, name=step_name)
|
126 |
state = state.insert_step(position, new_step)
|
|
|
3 |
|
4 |
import gradio as gr
|
5 |
import yaml
|
6 |
+
from loguru import logger
|
7 |
from pydantic import BaseModel, Field
|
8 |
|
9 |
from components import utils
|
|
|
11 |
from workflows.structs import ModelStep, Workflow
|
12 |
|
13 |
|
14 |
+
def make_step_id(step_number: int):
|
15 |
"""Make a step id from a step name."""
|
16 |
+
if step_number < 26:
|
17 |
+
return chr(ord("A") + step_number)
|
18 |
else:
|
19 |
# For more than 26 steps, use AA, AB, AC, etc.
|
20 |
+
first_char = chr(ord("A") + (step_number // 26) - 1)
|
21 |
+
second_char = chr(ord("A") + (step_number % 26))
|
22 |
return f"{first_char}{second_char}"
|
23 |
|
24 |
|
25 |
+
def make_step_number(step_id: str):
|
26 |
+
"""Make a step number from a step id."""
|
27 |
+
if len(step_id) == 1:
|
28 |
+
return ord(step_id) - ord("A")
|
29 |
+
else:
|
30 |
+
return (ord(step_id[0]) - ord("A")) * 26 + (ord(step_id[1]) - ord("A")) + 1
|
31 |
+
|
32 |
+
|
33 |
class ModelStepUIState(BaseModel):
|
34 |
"""Represents the UI state for a model step component."""
|
35 |
|
|
|
57 |
"""Get the position of a step in the pipeline."""
|
58 |
return next((i for i, step in enumerate(self.step_ids) if step == step_id), None)
|
59 |
|
60 |
+
@property
|
61 |
+
def n_steps(self) -> int:
|
62 |
+
"""Get the number of steps in the pipeline."""
|
63 |
+
return len(self.step_ids)
|
64 |
+
|
65 |
@classmethod
|
66 |
def from_workflow(cls, workflow: Workflow):
|
67 |
"""Create a pipeline UI state from a workflow."""
|
|
|
77 |
workflow: Workflow
|
78 |
ui_state: PipelineUIState
|
79 |
|
80 |
+
def insert_step(self, position: int, step: ModelStep) -> "PipelineState":
|
81 |
if step.id in self.workflow.steps:
|
82 |
raise ValueError(f"Step {step.id} already exists in pipeline")
|
83 |
|
|
|
95 |
self.ui_state.step_ids.insert(position, step.id)
|
96 |
return self
|
97 |
|
98 |
+
def remove_step(self, position: int) -> "PipelineState":
|
99 |
step_id = self.ui_state.step_ids.pop(position)
|
100 |
self.workflow.steps.pop(step_id)
|
101 |
self.ui_state = self.ui_state.model_copy()
|
102 |
self.ui_state.steps.pop(step_id)
|
103 |
self.update_output_variables_mapping()
|
104 |
+
return self
|
105 |
|
106 |
+
def update_output_variables_mapping(self) -> "PipelineState":
|
107 |
available_variables = set(self.available_variables)
|
108 |
for output_field in self.workflow.outputs:
|
109 |
if self.workflow.outputs[output_field] not in available_variables:
|
|
|
111 |
return self
|
112 |
|
113 |
@property
|
114 |
+
def available_variables(self) -> list[str]:
|
115 |
return self.workflow.get_available_variables()
|
116 |
|
117 |
@property
|
118 |
+
def n_steps(self) -> int:
|
119 |
return len(self.workflow.steps)
|
120 |
|
121 |
+
def get_new_step_id(self) -> str:
|
122 |
+
"""Get a step ID for a new step."""
|
123 |
+
if not self.workflow.steps:
|
124 |
+
return "A"
|
125 |
+
else:
|
126 |
+
last_step_number = max(map(make_step_number, self.workflow.steps.keys()))
|
127 |
+
return make_step_id(last_step_number + 1)
|
128 |
+
|
129 |
|
130 |
class PipelineStateManager:
|
131 |
"""Manages a pipeline of multiple steps."""
|
|
|
143 |
|
144 |
def add_step(self, state: PipelineState, position: int = -1, name=""):
|
145 |
"""Create a new step and return its state."""
|
146 |
+
step_id = state.get_new_step_id()
|
147 |
step_name = name or f"Step {state.n_steps + 1}"
|
148 |
new_step = create_new_llm_step(step_id=step_id, name=step_name)
|
149 |
state = state.insert_step(position, new_step)
|
src/workflows/structs.py
CHANGED
@@ -193,7 +193,8 @@ class Workflow(BaseModel):
|
|
193 |
|
194 |
def model_dump(self, *args, **kwargs):
|
195 |
data = super().model_dump(*args, **kwargs)
|
196 |
-
|
|
|
197 |
return data
|
198 |
|
199 |
@model_validator(mode="before")
|
|
|
193 |
|
194 |
def model_dump(self, *args, **kwargs):
|
195 |
data = super().model_dump(*args, **kwargs)
|
196 |
+
if "steps" in data:
|
197 |
+
data["steps"] = list(data["steps"].values())
|
198 |
return data
|
199 |
|
200 |
@model_validator(mode="before")
|