Add workflow management by lb-pno · Pull Request #1975 · Labelbox/labelbox-python
This PR adds workflow management to the SDK.
Note: the verb "create" is used abusively since one doesn't create a workflow but updates it either by removing all nodes first (reset_config()) or by changing the existing configuration.
⚠️ As it is, workflow management doesn't check any data but only the validity of the workflow. This is to avoid adding even more complexity and performance issues.
⚠️ Using project.get_workflow() and project.clone_workflow_from() will raise a warning:
project.py:1714: UserWarning: Workflow Management is currently in alpha and its behavior may change in future releases.
project_target_id = "cm4vs2ic90ey0072v01e33isl" project_source_id = "cm9lfjx010ddc07432s3a0zvo" project_source = client.get_project(project_source_id) project_target = client.get_project(project_target_id) project_target.clone_workflow_from(project_source.uid)
import labelbox as lb from labelbox.schema.workflow import NodeType project_id = "cm37vxyth01fu07xu2ejc6j2f" client = lb.Client(API_KEY) project = client.get_project(project_id) workflow = project.get_workflow() workflow.reset_config() initial_labeling = workflow.add_node(type=NodeType.InitialLabeling) initial_rework = workflow.add_node(type=NodeType.InitialRework) done = workflow.add_node(type=NodeType.Done) workflow.add_edge(initial_labeling, done) workflow.add_edge(initial_rework, done) if not workflow.check_validity().get("errors"): workflow.update_config(reposition=True)
import labelbox as lb from labelbox.schema.workflow import ( NodeType, NodeOutput, ProjectWorkflowFilter, created_by, metadata, sample, labeled_at, mp_condition, m_condition, labeling_time, review_time, issue_category, batch, dataset, annotation, consensus_average, model_prediction, natural_language, feature_consensus_average ) from labelbox.schema.workflow.enums import IndividualAssignment from labelbox.schema.workflow.enums import MatchFilters from datetime import datetime client = lb.Client(API_KEY) project_id = "cm37vxyth01fu07xu2ejc6j2f" project = client.get_project(project_id) # Get workflow and reset config workflow = project.get_workflow() workflow.reset_config() # Create nodes initial_labeling = workflow.add_node( type=NodeType.InitialLabeling, instructions="This is the entry point", max_contributions_per_user=10 ) initial_rework = workflow.add_node(type=NodeType.InitialRework, individual_assignment=IndividualAssignment.LabelCreator) initial_review = workflow.add_node( type=NodeType.Review, name="Initial review task", group_assignment=["63a6a360-baa8-11ec-aedb-2592d52c761e", "b3f89430-ea3a-11ef-b2a5-e1807377f8af"] ) logic = workflow.add_node( type=NodeType.Logic, name="Logic node", match_filters=MatchFilters.Any, filters=ProjectWorkflowFilter([ created_by(["cly7gzohg07zz07v5fqs63zmx", "cl7k7a9x1764808vk6bm1hf8e", "ckruht2sob6xj0ybh7bu46mgo"]), metadata([m_condition.contains("clo8t1njt00j807zkh5wz9uyt", ["test"])]), sample(23), labeled_at.between(datetime(2024, 3, 9, 5, 5, 42), datetime(2025, 4, 28, 13, 5, 42)), labeling_time.greater_than(1000), review_time.less_than_or_equal(100), issue_category(["cmbgs41zu0k5u07y49o9p54o9"]), batch.is_one_of(["ad210540-9d58-11ef-87dd-8501c518f349"]), dataset(["cm37vyets000z072314wxgt0l"]), annotation(["cm37w0e0500lf0709ba7c42m9"]), consensus_average(0.17, 0.61), model_prediction([mp_condition.is_one_of(["cm17qumj801ll07093toq47x3"], 1), mp_condition.is_not_one_of(["cm4lbh7fv07q00709ewfk2b0o"], 2, 6), mp_condition.is_none()]), natural_language("Birds in the sky/Blue sky/clouds/0.5", 0.178, 0.768), feature_consensus_average(0.17, 0.67, ["cm37w0e0500lf0709ba7c42m9"]) ]) ) done = workflow.add_node(type=NodeType.Done) custom_rework_1 = workflow.add_node( type=NodeType.CustomRework, name="Custom Rework 1", individual_assignment=IndividualAssignment.LabelCreator, group_assignment=["63a6a360-baa8-11ec-aedb-2592d52c761e", "b3f89430-ea3a-11ef-b2a5-e1807377f8af"] ) review_2 = workflow.add_node( type=NodeType.Review, name="Review 2" ) rework = workflow.add_node( type=NodeType.Rework, name="To rework" ) custom_rework_2 = workflow.add_node( type=NodeType.CustomRework, name="Custom Rework 2", instructions="test" ) done_2 = workflow.add_node( type=NodeType.Done, name="Well done" ) # Create edges workflow.add_edge(initial_labeling, initial_review) workflow.add_edge(initial_rework, initial_review) workflow.add_edge(initial_review, logic, NodeOutput.Approved) workflow.add_edge(logic, done, NodeOutput.If) workflow.add_edge(logic, custom_rework_1, NodeOutput.Else) workflow.add_edge(initial_review, review_2, NodeOutput.Rejected) workflow.add_edge(review_2, rework, NodeOutput.Rejected) workflow.add_edge(review_2, custom_rework_2, NodeOutput.Approved) workflow.add_edge(custom_rework_2, done_2) if not (err := workflow.check_validity().get("errors")): workflow.update_config(reposition=True) else: print(err)
from labelbox.schema.workflow.enums import FilterField #from labelbox.schema.workflow.enums import WorkflowDefinitionId workflow = project.get_workflow() # Check nodes to workflow.get_nodes() # check nodes logic = workflow.get_node_by_id("0359113a-6081-4f48-83d1-175062a0259b") # logic = next( # node for node in workflow.get_nodes() # if node.definition_id == WorkflowDefinitionId.Logic # ) # Change node name (for all nodes but initial ones) logic.name = "My Logic" logic.remove_filter(FilterField.ModelPrediction) # Apply changes workflow.update_config() # re-add filter logic.add_filter( model_prediction([ mp_condition.is_none() ]) ) # Apply changes workflow.update_config()
Please delete options that are not relevant.