Skip to content

Commit 97fd09f

Browse files
authored
[MODEL-1448] Upsert label feedback method (#1684)
2 parents de47ca3 + a859280 commit 97fd09f

File tree

6 files changed

+96
-9
lines changed

6 files changed

+96
-9
lines changed

docs/labelbox/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Labelbox Python SDK Documentation
2525
identifiable
2626
identifiables
2727
label
28+
label-score
2829
labeling-frontend
2930
labeling-frontend-options
3031
labeling-parameter-override

docs/labelbox/label-score.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Label Score
2+
===============================================================================================
3+
4+
.. automodule:: labelbox.schema.label_score
5+
:members:
6+
:show-inheritance:

libs/labelbox/src/labelbox/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from labelbox.schema.slice import Slice, CatalogSlice, ModelSlice
3737
from labelbox.schema.queue_mode import QueueMode
3838
from labelbox.schema.task_queue import TaskQueue
39+
from labelbox.schema.label_score import LabelScore
3940
from labelbox.schema.identifiables import UniqueIds, GlobalKeys, DataRowIds
4041
from labelbox.schema.identifiable import UniqueId, GlobalKey
4142
from labelbox.schema.ontology_kind import OntologyKind

libs/labelbox/src/labelbox/client.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
from labelbox.schema.slice import CatalogSlice, ModelSlice
5454
from labelbox.schema.task import Task
5555
from labelbox.schema.user import User
56+
from labelbox.schema.label_score import LabelScore
5657
from labelbox.schema.ontology_kind import (OntologyKind, EditorTaskTypeMapper,
5758
EditorTaskType)
5859

@@ -2197,3 +2198,53 @@ def get_embedding_by_name(self, name: str) -> Embedding:
21972198
return e
21982199
raise labelbox.exceptions.ResourceNotFoundError(Embedding,
21992200
dict(name=name))
2201+
2202+
def upsert_label_feedback(
2203+
self, label_id: str, feedback: str,
2204+
scores: Dict[str, float]) -> List[LabelScore]:
2205+
"""
2206+
Submits the label feedback which is a free-form text and numeric
2207+
label scores.
2208+
2209+
Args:
2210+
label_id: Target label ID
2211+
feedback: Free text comment regarding the label
2212+
scores: A dict of scores, the key is a score name and the value is
2213+
the score value
2214+
2215+
Returns:
2216+
A list of LabelScore instances
2217+
"""
2218+
mutation_str = """
2219+
mutation UpsertAutoQaLabelFeedbackPyApi(
2220+
$labelId: ID!
2221+
$feedback: String!
2222+
$scores: Json!
2223+
) {
2224+
upsertAutoQaLabelFeedback(
2225+
input: {
2226+
labelId: $labelId,
2227+
feedback: $feedback,
2228+
scores: $scores
2229+
}
2230+
) {
2231+
id
2232+
scores {
2233+
id
2234+
name
2235+
score
2236+
}
2237+
}
2238+
}
2239+
"""
2240+
res = self.execute(mutation_str, {
2241+
"labelId": label_id,
2242+
"feedback": feedback,
2243+
"scores": scores
2244+
})
2245+
scores_raw = res["upsertAutoQaLabelFeedback"]["scores"]
2246+
2247+
return [
2248+
labelbox.LabelScore(name=x['name'], score=x['score'])
2249+
for x in scores_raw
2250+
]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from labelbox import pydantic_compat
2+
3+
4+
class LabelScore(pydantic_compat.BaseModel):
5+
"""
6+
A label score.
7+
8+
Attributes:
9+
name (str)
10+
score (float)
11+
12+
"""
13+
14+
name: str
15+
score: float

libs/labelbox/tests/integration/test_label.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1+
import os
12
import time
23

34
import pytest
4-
import requests
5-
import os
65

7-
from labelbox import Label
6+
from labelbox import Client, Label
87

98

109
def test_labels(configured_project_with_label):
@@ -29,11 +28,13 @@ def test_labels(configured_project_with_label):
2928

3029

3130
# TODO: Skipping this test in staging due to label not updating
32-
@pytest.mark.skipif(condition=os.environ['LABELBOX_TEST_ENVIRON'] == "onprem" or
33-
os.environ['LABELBOX_TEST_ENVIRON'] == "staging" or
34-
os.environ['LABELBOX_TEST_ENVIRON'] == "local" or
35-
os.environ['LABELBOX_TEST_ENVIRON'] == "custom",
36-
reason="does not work for onprem")
31+
@pytest.mark.skipif(
32+
condition=os.environ["LABELBOX_TEST_ENVIRON"] == "onprem" or
33+
os.environ["LABELBOX_TEST_ENVIRON"] == "staging" or
34+
os.environ["LABELBOX_TEST_ENVIRON"] == "local" or
35+
os.environ["LABELBOX_TEST_ENVIRON"] == "custom",
36+
reason="does not work for onprem",
37+
)
3738
def test_label_update(configured_project_with_label):
3839
_, _, _, label = configured_project_with_label
3940
label.update(label="something else")
@@ -57,7 +58,7 @@ def test_label_bulk_deletion(configured_project_with_label):
5758
project, _, _, _ = configured_project_with_label
5859

5960
for _ in range(2):
60-
#only run twice, already have one label in the fixture
61+
# only run twice, already have one label in the fixture
6162
project.create_label()
6263
labels = project.labels()
6364
l1 = next(labels)
@@ -74,3 +75,15 @@ def test_label_bulk_deletion(configured_project_with_label):
7475
time.sleep(5)
7576

7677
assert set(project.labels()) == {l2}
78+
79+
80+
def test_upsert_label_scores(configured_project_with_label, client: Client):
81+
project, _, _, _ = configured_project_with_label
82+
83+
label = next(project.labels())
84+
85+
scores = client.upsert_label_feedback(label_id=label.uid,
86+
feedback="That's a great label!",
87+
scores={"overall": 5})
88+
assert len(scores) == 1
89+
assert scores[0].score == 5

0 commit comments

Comments
 (0)