Skip to content

Commit 07fd531

Browse files
authored
[PLT-1305] Vb/start labeling service plt 1305 (#1749)
1 parent 8dc150d commit 07fd531

File tree

5 files changed

+133
-1
lines changed

5 files changed

+133
-1
lines changed

docs/labelbox/labeling-service.rst

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Project Labeling Service
2+
===============================================================================================
3+
4+
.. automodule:: labelbox.schema.labeling_service
5+
:members:
6+
:show-inheritance:

libs/labelbox/src/labelbox/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@
4343
from labelbox.schema.identifiable import UniqueId, GlobalKey
4444
from labelbox.schema.ontology_kind import OntologyKind
4545
from labelbox.schema.project_overview import ProjectOverview, ProjectOverviewDetailed
46+
from labelbox.schema.labeling_service import LabelingService, LabelingServiceStatus
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
from datetime import datetime
2+
from enum import Enum
3+
from typing import Any
4+
5+
from labelbox.exceptions import ResourceNotFoundError
6+
7+
from labelbox.data.annotation_types.types import Cuid
8+
from labelbox.pydantic_compat import BaseModel
9+
from labelbox.utils import _CamelCaseMixin
10+
11+
12+
class LabelingServiceStatus(Enum):
13+
Accepted = 'ACCEPTED',
14+
Calibration = 'CALIBRATION',
15+
Complete = 'COMPLETE',
16+
Production = 'PRODUCTION',
17+
Requested = 'REQUESTED',
18+
SetUp = 'SET_UP'
19+
20+
21+
class LabelingService(BaseModel):
22+
id: Cuid
23+
project_id: Cuid
24+
created_at: datetime
25+
updated_at: datetime
26+
created_by_id: Cuid
27+
status: LabelingServiceStatus
28+
client: Any # type Any to avoid circular import from client
29+
30+
def __init__(self, **kwargs):
31+
super().__init__(**kwargs)
32+
if not self.client.enable_experimental:
33+
raise RuntimeError(
34+
"Please enable experimental in client to use LabelingService")
35+
36+
class Config(_CamelCaseMixin.Config):
37+
...
38+
39+
@classmethod
40+
def start(cls, client, project_id: Cuid) -> 'LabelingService':
41+
"""
42+
Starts the labeling service for the project. This is equivalent to a UI acction to Request Specialized Labelers
43+
44+
Returns:
45+
LabelingService: The labeling service for the project.
46+
Raises:
47+
Exception: If the service fails to start.
48+
"""
49+
query_str = """mutation CreateProjectBoostWorkforcePyApi($projectId: ID!) {
50+
upsertProjectBoostWorkforce(data: { projectId: $projectId }) {
51+
success
52+
}
53+
}"""
54+
result = client.execute(query_str, {"projectId": project_id})
55+
success = result["upsertProjectBoostWorkforce"]["success"]
56+
if not success:
57+
raise Exception("Failed to start labeling service")
58+
return cls.get(client, project_id)
59+
60+
@classmethod
61+
def get(cls, client, project_id: Cuid) -> 'LabelingService':
62+
"""
63+
Returns the labeling service associated with the project.
64+
65+
Raises:
66+
ResourceNotFoundError: If the project does not have a labeling service.
67+
"""
68+
query = """
69+
query GetProjectBoostWorkforcePyApi($projectId: ID!) {
70+
projectBoostWorkforce(data: { projectId: $projectId }) {
71+
id
72+
projectId
73+
createdAt
74+
updatedAt
75+
createdById
76+
status
77+
}
78+
}
79+
"""
80+
result = client.execute(query, {"projectId": project_id})
81+
if result["projectBoostWorkforce"] is None:
82+
raise ResourceNotFoundError(
83+
message="The project does not have a labeling service.")
84+
data = result["projectBoostWorkforce"]
85+
data["client"] = client
86+
return LabelingService(**data)

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

+20-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple, TypeVar, Union, overload
1010
from urllib.parse import urlparse
1111

12+
from labelbox.schema.labeling_service import LabelingService
1213
import requests
1314

1415
from labelbox import parser
@@ -149,7 +150,7 @@ def is_chat_evaluation(self) -> bool:
149150
True if this project is a live chat evaluation project, False otherwise
150151
"""
151152
return self.media_type == MediaType.Conversational and self.editor_task_type == EditorTaskType.ModelChatEvaluation
152-
153+
153154
def is_prompt_response(self) -> bool:
154155
"""
155156
Returns:
@@ -1915,6 +1916,24 @@ def clone(self) -> "Project":
19151916
result = self.client.execute(mutation, {"projectId": self.uid})
19161917
return self.client.get_project(result["cloneProject"]["id"])
19171918

1919+
@experimental
1920+
def get_labeling_service(self) -> LabelingService:
1921+
"""Get the labeling service for this project.
1922+
1923+
Returns:
1924+
LabelingService: The labeling service for this project.
1925+
"""
1926+
return LabelingService.get(self.client, self.uid) # type: ignore
1927+
1928+
@experimental
1929+
def request_labeling_service(self) -> LabelingService:
1930+
"""Get the labeling service for this project.
1931+
1932+
Returns:
1933+
LabelingService: The labeling service for this project.
1934+
"""
1935+
return LabelingService.start(self.client, self.uid) # type: ignore
1936+
19181937

19191938
class ProjectMember(DbObject):
19201939
user = Relationship.ToOne("User", cache=True)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import pytest
2+
3+
from labelbox.exceptions import ResourceNotFoundError
4+
from labelbox.schema.labeling_service import LabelingServiceStatus
5+
6+
7+
def test_get_labeling_service_throws_exception(project):
8+
with pytest.raises(ResourceNotFoundError): # No labeling service by default
9+
project.get_labeling_service()
10+
11+
12+
def test_start_labeling_service(project):
13+
labeling_service = project.request_labeling_service()
14+
assert labeling_service.status == LabelingServiceStatus.SetUp
15+
assert labeling_service.project_id == project.uid
16+
17+
# Check that the labeling service is now available
18+
labeling_service = project.get_labeling_service()
19+
assert labeling_service.status == LabelingServiceStatus.SetUp
20+
assert labeling_service.project_id == project.uid

0 commit comments

Comments
 (0)