Skip to content

Commit 1c0ac5d

Browse files
committed
Merge develop
2 parents b08c69e + f727dce commit 1c0ac5d

File tree

11 files changed

+175
-79
lines changed

11 files changed

+175
-79
lines changed

examples/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@
109109
<td><a href="https://github.com/Labelbox/labelbox-python/tree/develop/examples/project_configuration/queue_management.ipynb" target="_blank"><img src="https://img.shields.io/badge/GitHub-100000?logo=github&logoColor=white" alt="Open In Github"></a></td>
110110
<td><a href="https://colab.research.google.com/github/Labelbox/labelbox-python/blob/develop/examples/project_configuration/queue_management.ipynb" target="_blank"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></td>
111111
</tr>
112+
<tr>
113+
<td>Multimodal Chat Project</td>
114+
<td><a href="https://github.com/Labelbox/labelbox-python/tree/develop/examples/project_configuration/multimodal_chat_project.ipynb" target="_blank"><img src="https://img.shields.io/badge/GitHub-100000?logo=github&logoColor=white" alt="Open In Github"></a></td>
115+
<td><a href="https://colab.research.google.com/github/Labelbox/labelbox-python/blob/develop/examples/project_configuration/multimodal_chat_project.ipynb" target="_blank"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></td>
116+
</tr>
112117
<tr>
113118
<td>Project Setup</td>
114119
<td><a href="https://github.com/Labelbox/labelbox-python/tree/develop/examples/project_configuration/project_setup.ipynb" target="_blank"><img src="https://img.shields.io/badge/GitHub-100000?logo=github&logoColor=white" alt="Open In Github"></a></td>

examples/project_configuration/live_multimodal_chat_project.ipynb renamed to examples/project_configuration/multimodal_chat_project.ipynb

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
"metadata": {},
1717
"source": [
1818
"<td>\n",
19-
"<a href=\"https://colab.research.google.com/github/Labelbox/labelbox-python/blob/develop/examples/project_configuration/live_multimodal_chat_project.ipynb\" target=\"_blank\"><img\n",
19+
"<a href=\"https://colab.research.google.com/github/Labelbox/labelbox-python/blob/develop/examples/project_configuration/multimodal_chat_project.ipynb\" target=\"_blank\"><img\n",
2020
"src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"></a>\n",
2121
"</td>\n",
2222
"\n",
2323
"<td>\n",
24-
"<a href=\"https://github.com/Labelbox/labelbox-python/tree/develop/examples/project_configuration/live_multimodal_chat_project.ipynb\" target=\"_blank\"><img\n",
24+
"<a href=\"https://github.com/Labelbox/labelbox-python/tree/develop/examples/project_configuration/multimodal_chat_project.ipynb\" target=\"_blank\"><img\n",
2525
"src=\"https://img.shields.io/badge/GitHub-100000?logo=github&logoColor=white\" alt=\"GitHub\"></a>\n",
2626
"</td>"
2727
],
@@ -30,14 +30,16 @@
3030
{
3131
"metadata": {},
3232
"source": [
33-
"# Live Multimodal Chat project setup\n",
33+
"# Multimodal chat project setup\n",
3434
"\n",
35-
"This notebook will provide an example workflow of setting up a Live Multimodal Chat (LMC) Project with the Labelbox-Python SDK.\n",
36-
"Live Multimodal Chat Projects are set up differently than other projects with its own unique method and modifications to existing methods:\n",
35+
"This notebook will provide an example workflow of setting up a multimodal Chat (MMC) Project with the Labelbox-Python SDK.\n",
36+
"Multimodal Chat Projects are set up differently than other projects with its own unique method and modifications to existing methods:\n",
3737
"\n",
38-
"- `client.create_model_evaluation_project`: The main method used to create a Live Multimodal Chat project\n",
38+
"- `client.create_model_evaluation_project`: The main method used to create a live multimodal Chat project.\n",
39+
" \n",
40+
"- `client.create_offline_model_evaluation_project`: The main method used to create a offline multimodal Chat project.\n",
3941
"\n",
40-
"- `client.create_ontology`: Methods used to create Labelbox ontologies for LMC project this requires an `ontology_kind` parameter set to `lb.OntologyKind.ModelEvaluation`\n",
42+
"- `client.create_ontology`: Methods used to create Labelbox ontologies for LMC project this requires an `ontology_kind` parameter set to `lb.OntologyKind.ModelEvaluation`.\n",
4143
"\n",
4244
"- `client.create_ontology_from_feature_schemas`: Similar to `client.create_ontology` but from a list of `feature schema ids` designed to allow you to use existing features instead of creating new features. This also requires an `ontology_kind` set to `lb.OntologyKind.ModelEvaluation`."
4345
],
@@ -68,7 +70,7 @@
6870
"metadata": {},
6971
"source": [
7072
"## API key and client\n",
71-
"Provide a valid API key below in order to properly connect to the Labelbox client. Please review [Create API key guide](https://docs.labelbox.com/reference/create-api-key) for more information."
73+
"Please provide a valid API key below to connect to the Labelbox client properly. For more information, please review the [Create API key guide](https://docs.labelbox.com/reference/create-api-key)."
7274
],
7375
"cell_type": "markdown"
7476
},
@@ -82,18 +84,18 @@
8284
{
8385
"metadata": {},
8486
"source": [
85-
"## Example: Create Live Multimodal Chat project\n",
87+
"## Example: Create multimodal Chat project\n",
8688
"\n",
87-
"The steps to creating a Live Multimodal Chat Project through the Labelbox-Python SDK are similar to creating a regular project. However, they vary slightly, and we will showcase the different methods in this example workflow."
89+
"The steps to creating a multimodal Chat Projects through the Labelbox-Python SDK are similar to creating a regular project. However, they vary slightly, and we will showcase the different methods in this example workflow."
8890
],
8991
"cell_type": "markdown"
9092
},
9193
{
9294
"metadata": {},
9395
"source": [
94-
"### Create a Live Multimodal Chat ontology\n",
96+
"### Create a multimodal chat ontology\n",
9597
"\n",
96-
"You can create ontologies for Model Evaluation projects the same way as creating ontologies for other projects with the only requirement of passing in a `ontology_kind` parameter which needs set to `lb.OntologyKind.ModelEvaluation`. You can create ontologies with two methods: `client.create_ontology` and `client.create_ontology_from_feature_schemas`."
98+
"You can create ontologies for multimodal chat projects in the same way as other project ontologies using two methods: `client.create_ontology` and `client.create_ontology_from_feature_schemas`. The only additional requirement is to pass an ontology_kind parameter, which needs to be set to `lb.OntologyKind.ModelEvaluation`."
9799
],
98100
"cell_type": "markdown"
99101
},
@@ -102,7 +104,7 @@
102104
"source": [
103105
"#### Option A: `client.create_ontology`\n",
104106
"\n",
105-
"Typically, you create ontologies and generate the associated features at the same time. Below is an example of creating an ontology for your Live Multimodal Chat project using supported tools and classifications. For information on supported annotation types visit our [Live Multimodal Chat](https://docs.labelbox.com/docs/live-multimodal-chat#supported-annotation-types) guide."
107+
"Typically, you create ontologies and generate the associated features simultaneously. Below is an example of creating an ontology for your multimodal chat project using supported tools and classifications; for information on supported annotation types, visit our [multimodal chat evaluation guide](https://docs.labelbox.com/docs/multimodal-chat#supported-annotation-types) guide."
106108
],
107109
"cell_type": "markdown"
108110
},
@@ -128,6 +130,37 @@
128130
"outputs": [],
129131
"execution_count": null
130132
},
133+
{
134+
"metadata": {},
135+
"source": [
136+
"## Creating multimodal chat evaluation projects\n",
137+
"\n",
138+
"There are two versions of a multimodal chat evaluation projects:\n",
139+
"\n",
140+
"1. Offline multimodal chat evaluation projects: Data rows will need to be imported manually and have no live model invocation.\n",
141+
"\n",
142+
"2. Live multimodal chat evaluation projects: Empty data rows are generated on project creation and are filled out with live model invocation.\n",
143+
"\n",
144+
"We will discuss creating both types of projects with the Labelbox SDK."
145+
],
146+
"cell_type": "markdown"
147+
},
148+
{
149+
"metadata": {},
150+
"source": [
151+
"## Set up offline multimodal chat evaluation project\n",
152+
"\n",
153+
"For an offline multimodal chat evaluation project, you must import conversational version 2 data rows. For more information, please visit our [import multimodal chat evaluation data](https://docs.labelbox.com/reference/import-multimodal-chat-data) guide. Offline multimodal chat evaluation projects are created through the SDK with `client.create_offline_model_evaluation_project`. This method uses the same parameters as `client.create_project` but provides better validation to ensure the project is set up correctly."
154+
],
155+
"cell_type": "markdown"
156+
},
157+
{
158+
"metadata": {},
159+
"source": "project = client.create_offline_model_evaluation_project(\n name=\"<project_name>\",\n description=\"<project_description>\", # optional\n)",
160+
"cell_type": "code",
161+
"outputs": [],
162+
"execution_count": null
163+
},
131164
{
132165
"metadata": {},
133166
"source": [
@@ -224,10 +257,21 @@
224257
{
225258
"metadata": {},
226259
"source": [
227-
"**To finish setting up your LMC project, you will need to navigate to your project overview inside the Labelbox platform and select _Complete setup_ on the left side panel**"
260+
"### Mark project setup as completed\n",
261+
"\n",
262+
"Once you have finalized your project and set up your model configs, you must mark the project setup as completed.\n",
263+
"\n",
264+
"**Once the project is marked as \"setup complete\", a user can not add, modify, or delete existing project model configs.**"
228265
],
229266
"cell_type": "markdown"
230267
},
268+
{
269+
"metadata": {},
270+
"source": "project.set_project_model_setup_complete()",
271+
"cell_type": "code",
272+
"outputs": [],
273+
"execution_count": null
274+
},
231275
{
232276
"metadata": {},
233277
"source": [

libs/labelbox/src/labelbox/schema/project.py

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ def is_chat_evaluation(self) -> bool:
149149
def is_auto_data_generation(self) -> bool:
150150
return (self.upload_type == UploadType.Auto) # type: ignore
151151

152+
# we test not only the project ontology is None, but also a default empty ontology that we create when we attach a labeling front end in createLabelingFrontendOptions
153+
def is_empty_ontology(self) -> bool:
154+
ontology = self.ontology() # type: ignore
155+
return ontology is None or (len(ontology.tools()) == 0 and
156+
len(ontology.classifications()) == 0)
157+
152158
def project_model_configs(self):
153159
query_str = """query ProjectModelConfigsPyApi($id: ID!) {
154160
project(where: {id : $id}) {
@@ -772,35 +778,27 @@ def setup_editor(self, ontology) -> None:
772778
Args:
773779
ontology (Ontology): The ontology to attach to the project
774780
"""
781+
warnings.warn("This method is deprecated use connect_ontology instead.")
782+
self.connect_ontology(ontology)
775783

776-
if self.labeling_frontend() is not None and not self.is_chat_evaluation(
777-
): # Chat evaluation projects are automatically set up via the same api that creates a project
778-
raise ResourceConflict("Editor is already set up.")
779-
780-
if not self.is_chat_evaluation():
781-
labeling_frontend = next(
782-
self.client.get_labeling_frontends(
783-
where=Entity.LabelingFrontend.name == "Editor"))
784-
self.labeling_frontend.connect(labeling_frontend)
785-
786-
LFO = Entity.LabelingFrontendOptions
787-
self.client._create(
788-
LFO, {
789-
LFO.project:
790-
self,
791-
LFO.labeling_frontend:
792-
labeling_frontend,
793-
LFO.customization_options:
794-
json.dumps({
795-
"tools": [],
796-
"classifications": []
797-
})
798-
})
799-
else:
800-
warnings.warn("""
801-
Skipping editor setup for a chat evaluation project.
802-
Editor was setup automatically.
803-
""")
784+
def connect_ontology(self, ontology) -> None:
785+
"""
786+
Connects the ontology to the project. If an editor is not setup, it will be connected as well.
787+
788+
Note: For live chat model evaluation projects, the editor setup is skipped becase it is automatically setup when the project is created.
789+
790+
Args:
791+
ontology (Ontology): The ontology to attach to the project
792+
"""
793+
if self.labeling_frontend(
794+
) is None: # Chat evaluation projects are automatically set up via the same api that creates a project
795+
self._connect_default_labeling_front_end(ontology_as_dict={
796+
"tools": [],
797+
"classifications": []
798+
})
799+
800+
if not self.is_empty_ontology():
801+
raise ValueError("Ontology already connected to project.")
804802

805803
query_str = """mutation ConnectOntologyPyApi($projectId: ID!, $ontologyId: ID!){
806804
project(where: {id: $projectId}) {connectOntology(ontologyId: $ontologyId) {id}}}"""
@@ -812,43 +810,55 @@ def setup_editor(self, ontology) -> None:
812810
self.update(setup_complete=timestamp)
813811

814812
def setup(self, labeling_frontend, labeling_frontend_options) -> None:
815-
""" Finalizes the Project setup.
813+
""" This method will associate default labeling frontend with the project and create an ontology based on labeling_frontend_options.
816814
817815
Args:
818-
labeling_frontend (LabelingFrontend): Which UI to use to label the
819-
data.
816+
labeling_frontend (LabelingFrontend): Do not use, this parameter is deprecated. We now associate the default labeling frontend with the project.
820817
labeling_frontend_options (dict or str): Labeling frontend options,
821818
a.k.a. project ontology. If given a `dict` it will be converted
822819
to `str` using `json.dumps`.
823820
"""
824821

822+
warnings.warn("This method is deprecated use connect_ontology instead.")
823+
if labeling_frontend is not None:
824+
warnings.warn(
825+
"labeling_frontend parameter will not be used to create a new labeling frontend."
826+
)
827+
825828
if self.is_chat_evaluation():
826829
warnings.warn("""
827-
This project is a chat evaluation project.
830+
This project is a live chat evaluation project.
828831
Editor was setup automatically.
829-
No need to call this method.
830832
""")
831833
return
832834

833-
if self.labeling_frontend() is not None:
834-
raise ResourceConflict("Editor is already set up.")
835+
if self.labeling_frontend(
836+
) is None: # Chat evaluation projects are automatically set up via the same api that creates a project
837+
self._connect_default_labeling_front_end(labeling_frontend_options)
835838

836-
if not isinstance(labeling_frontend_options, str):
837-
labeling_frontend_options = json.dumps(labeling_frontend_options)
839+
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
840+
self.update(setup_complete=timestamp)
838841

842+
def _connect_default_labeling_front_end(self, ontology_as_dict: dict):
843+
warnings.warn("Connecting default labeling editor for the project.")
844+
labeling_frontend = next(
845+
self.client.get_labeling_frontends(
846+
where=Entity.LabelingFrontend.name == "Editor"))
839847
self.labeling_frontend.connect(labeling_frontend)
840848

849+
if not isinstance(ontology_as_dict, str):
850+
labeling_frontend_options_str = json.dumps(ontology_as_dict)
851+
else:
852+
labeling_frontend_options_str = ontology_as_dict
853+
841854
LFO = Entity.LabelingFrontendOptions
842855
self.client._create(
843856
LFO, {
844857
LFO.project: self,
845858
LFO.labeling_frontend: labeling_frontend,
846-
LFO.customization_options: labeling_frontend_options
859+
LFO.customization_options: labeling_frontend_options_str
847860
})
848861

849-
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
850-
self.update(setup_complete=timestamp)
851-
852862
def create_batch(
853863
self,
854864
name: str,

libs/labelbox/tests/data/annotation_import/conftest.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,8 @@ def get_data_row_id(indx=0):
608608

609609
yield get_data_row_id
610610

611-
#TODO: Switch to setup_editor, setup might get removed in later releases
611+
612+
#TODO: Switch to connect_ontology, setup might get removed in later releases
612613
@pytest.fixture
613614
def configured_project(client, initial_dataset, ontology, rand_gen, image_url):
614615
dataset = initial_dataset
@@ -645,7 +646,8 @@ def configured_project(client, initial_dataset, ontology, rand_gen, image_url):
645646

646647
project.delete()
647648

648-
#TODO: Switch to setup_editor, setup might get removed in later releases
649+
650+
#TODO: Switch to connect_ontology, setup might get removed in later releases
649651
@pytest.fixture
650652
def project_with_ontology(client, configured_project, ontology, rand_gen):
651653
project = client.create_project(name=rand_gen(str),
@@ -660,7 +662,8 @@ def project_with_ontology(client, configured_project, ontology, rand_gen):
660662

661663
project.delete()
662664

663-
#TODO: Switch to setup_editor, setup might get removed in later releases
665+
666+
#TODO: Switch to connect_ontology, setup might get removed in later releases
664667
@pytest.fixture
665668
def configured_project_pdf(client, ontology, rand_gen, pdf_url):
666669
project = client.create_project(name=rand_gen(str),

libs/labelbox/tests/data/annotation_import/test_send_to_annotate_mea.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def test_send_to_annotate_from_model(client, configured_project,
1414
destination_project = project
1515
model = client.get_model(model_run.model_id)
1616
ontology = client.get_ontology(model.ontology_id)
17-
destination_project.setup_editor(ontology)
17+
destination_project.connect_ontology(ontology)
1818

1919
queues = destination_project.task_queues()
2020
initial_review_task = next(
@@ -55,13 +55,13 @@ def test_send_to_annotate_from_model(client, configured_project,
5555
# Check that the data row was sent to the new project
5656
destination_batches = list(destination_project.batches())
5757
assert len(destination_batches) == 1
58-
58+
5959
export_task = destination_project.export()
6060
export_task.wait_till_done()
6161
stream = export_task.get_buffered_stream()
62-
62+
6363
destination_data_rows = [dr.json["data_row"]["id"] for dr in stream]
64-
64+
6565
assert len(destination_data_rows) == len(data_row_ids)
6666
assert all([dr in data_row_ids for dr in destination_data_rows])
6767

libs/labelbox/tests/integration/test_chat_evaluation_ontology_project.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def test_create_chat_evaluation_ontology_project(
2828
project = live_chat_evaluation_project_with_new_dataset
2929
assert project.model_setup_complete is None
3030

31-
project.setup_editor(ontology)
31+
project.connect_ontology(ontology)
3232

3333
assert project.labeling_frontend().name == "Editor"
3434
assert project.ontology().name == ontology.name
@@ -61,7 +61,7 @@ def test_create_chat_evaluation_ontology_project_existing_dataset(
6161

6262
project = chat_evaluation_project_append_to_dataset
6363
assert project
64-
project.setup_editor(ontology)
64+
project.connect_ontology(ontology)
6565

6666
assert project.labeling_frontend().name == "Editor"
6767
assert project.ontology().name == ontology.name

libs/labelbox/tests/integration/test_offline_chat_evaluation_project.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
22

3+
34
def test_create_offline_chat_evaluation_project(client, rand_gen,
45
offline_chat_evaluation_project,
56
chat_evaluation_ontology,
@@ -9,7 +10,7 @@ def test_create_offline_chat_evaluation_project(client, rand_gen,
910
assert project
1011

1112
ontology = chat_evaluation_ontology
12-
project.setup_editor(ontology)
13+
project.connect_ontology(ontology)
1314

1415
assert project.labeling_frontend().name == "Editor"
1516
assert project.ontology().name == ontology.name

0 commit comments

Comments
 (0)