Skip to content

fix: RND-101: Fix ML backend compatibility with sdk>=1 #570

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion label_studio_ml/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def _predict():
else:
response.update_predictions_version()

response = response.serialize()
response = response.model_dump()

res = response
if res is None:
Expand Down
3 changes: 2 additions & 1 deletion label_studio_ml/examples/easyocr/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
easyocr==1.7.1
boto3==1.28.58
opencv-python-headless==4.9.0.80
opencv-python-headless==4.9.0.80
numpy<2
2 changes: 1 addition & 1 deletion label_studio_ml/examples/huggingface_ner/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def predict(self, tasks: List[Dict], context: Optional[Dict] = None, **kwargs) -
entities = list(group)
start = entities[0]['start']
end = entities[-1]['end']
score = sum([entity['score'] for entity in entities]) / len(entities)
score = float(sum([entity['score'] for entity in entities]) / len(entities))
results.append({
'from_name': from_name,
'to_name': to_name,
Expand Down
1 change: 1 addition & 0 deletions label_studio_ml/examples/mmdetection-3/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
boto3>=1.26.103,<2.0.0
openmim~=0.3.9
numpy~=1.26
1 change: 1 addition & 0 deletions label_studio_ml/examples/nemo_asr/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
nemo-toolkit[all]
numpy<2
1 change: 1 addition & 0 deletions label_studio_ml/examples/spacy/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
gunicorn==22.0.0
spacy~=3.6
label-studio-ml @ git+https://github.com/HumanSignal/label-studio-ml-backend.git@master
numpy~=1.26
4 changes: 2 additions & 2 deletions label_studio_ml/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
from colorama import Fore

from label_studio_sdk.label_interface import LabelInterface
from label_studio_tools.core.label_config import parse_config
from label_studio_tools.core.utils.io import get_local_path
from label_studio_sdk._extensions.label_studio_tools.core.label_config import parse_config
from label_studio_sdk._extensions.label_studio_tools.core.utils.io import get_local_path
from .response import ModelResponse
from .utils import is_preload_needed
from .cache import create_cache
Expand Down
25 changes: 12 additions & 13 deletions label_studio_ml/response.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@

from typing import Type, Dict, Optional, List, Tuple, Any, Union
from pydantic import BaseModel, confloat
from pydantic import BaseModel, confloat, Field
from label_studio_sdk.label_interface.objects import PredictionValue
from typing import Union, List

from label_studio_sdk.objects import PredictionValue

# one or multiple predictions per task
SingleTaskPredictions = Union[List[PredictionValue], PredictionValue]


class ModelResponse(BaseModel):
"""
"""
model_version: Optional[str] = None
predictions: List[PredictionValue]
predictions: List[SingleTaskPredictions]

def has_model_version(self) -> bool:
return bool(self.model_version)
Expand All @@ -18,21 +22,16 @@ def update_predictions_version(self) -> None:
"""
"""
for prediction in self.predictions:
if not prediction.model_version:
prediction.model_version = self.model_version
if isinstance(prediction, PredictionValue):
prediction = [prediction]
for p in prediction:
if not p.model_version:
p.model_version = self.model_version

def set_version(self, version: str) -> None:
"""
"""
self.model_version = version
# Set the version for each prediction
self.update_predictions_version()

def serialize(self):
"""
"""
return {
"model_version": self.model_version,
"predictions": [ p.serialize() for p in self.predictions ]
}

5 changes: 2 additions & 3 deletions label_studio_ml/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
from typing import List
from urllib.parse import urlparse

from label_studio_tools.core.utils.params import get_env
from label_studio_tools.core.utils.io import get_local_path
from label_studio_sdk.label_interface import LabelInterface
from label_studio_sdk._extensions.label_studio_tools.core.utils.params import get_env
from label_studio_sdk._extensions.label_studio_tools.core.utils.io import get_local_path

DATA_UNDEFINED_NAME = '$undefined$'

Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ colorama~=0.4
requests~=2.31
semver~=3.0.2
pillow~=10.3
label_studio_tools @ git+https://github.com/HumanSignal/label-studio-tools.git@master
label-studio-sdk==0.0.34
label-studio-sdk==1.0.2
# label-studio-sdk @ git+https://github.com/HumanSignal/label-studio-sdk.git
37 changes: 31 additions & 6 deletions tests/test_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@
from typing import Optional

from label_studio_ml.response import ModelResponse
from label_studio_sdk.objects import PredictionValue
from label_studio_sdk.label_interface.objects import PredictionValue

MODEL_VERSION = 0.1
MODEL_VERSION = "0.1"

@pytest.fixture
def predictions():
# Replace 'Example Prediction' with real Predictions
return [PredictionValue(model_version=MODEL_VERSION, score=0.1, result=[{}]),
PredictionValue(score=0.1, result=[{}])]
return [
PredictionValue(model_version=MODEL_VERSION, score=0.1, result=[{}]),
PredictionValue(score=0.1, result=[{}]),
[
PredictionValue(model_version='prediction_1', score=0.2, result=[{}]),
PredictionValue(score=0.3, result=[{}]),
]
]

def test_has_model_version(predictions):
res = ModelResponse(predictions=predictions)
Expand Down Expand Up @@ -45,8 +51,27 @@ def test_set_version(predictions):
def test_serialize(predictions):
# Assuming PredictionValue has method .serialize() which returns a dict
res = ModelResponse(model_version="1.0", predictions=predictions)
serialized_res = res.serialize()
serialized_res = res.model_dump()

assert serialized_res['model_version'] == "1.0"
assert serialized_res['predictions'] == [
p.serialize() for p in predictions]
{'model_version': MODEL_VERSION, 'score': 0.1, 'result': [{}]},
{'model_version': None, 'score': 0.1, 'result': [{}]},
[
{'model_version': 'prediction_1', 'score': 0.2, 'result': [{}]},
{'model_version': None, 'score': 0.3, 'result': [{}]},
]
]

# update model_version
res.update_predictions_version()
serialized_res = res.model_dump()

assert serialized_res['predictions'] == [
{'model_version': "0.1", 'score': 0.1, 'result': [{}]},
{'model_version': "1.0", 'score': 0.1, 'result': [{}]},
[
{'model_version': 'prediction_1', 'score': 0.2, 'result': [{}]},
{'model_version': '1.0', 'score': 0.3, 'result': [{}]},
]
]