21
21
from labelbox .adv_client import AdvClient
22
22
from labelbox .orm import query
23
23
from labelbox .orm .db_object import DbObject
24
- from labelbox .orm .model import Entity
24
+ from labelbox .orm .model import Entity , Field
25
25
from labelbox .pagination import PaginatedCollection
26
26
from labelbox .schema import role
27
27
from labelbox .schema .conflict_resolution_strategy import ConflictResolutionStrategy
52
52
from labelbox .schema .slice import CatalogSlice , ModelSlice
53
53
from labelbox .schema .task import Task
54
54
from labelbox .schema .user import User
55
+ from labelbox .schema .ontology_kind import (OntologyKind , EditorTaskTypeMapper ,
56
+ EditorTaskType )
55
57
56
58
logger = logging .getLogger (__name__ )
57
59
@@ -563,14 +565,16 @@ def get_labeling_frontends(self, where=None) -> List[LabelingFrontend]:
563
565
"""
564
566
return self ._get_all (Entity .LabelingFrontend , where )
565
567
566
- def _create (self , db_object_type , data ):
568
+ def _create (self , db_object_type , data , extra_params = {} ):
567
569
""" Creates an object on the server. Attribute values are
568
570
passed as keyword arguments:
569
571
570
572
Args:
571
573
db_object_type (type): A DbObjectType subtype.
572
574
data (dict): Keys are attributes or their names (in Python,
573
575
snake-case convention) and values are desired attribute values.
576
+ extra_params (dict): Additional parameters to pass to GraphQL.
577
+ These have to be Field(...): value pairs.
574
578
Returns:
575
579
A new object of the given DB object type.
576
580
Raises:
@@ -585,6 +589,7 @@ def _create(self, db_object_type, data):
585
589
for attr , value in data .items ()
586
590
}
587
591
592
+ data = {** data , ** extra_params }
588
593
query_string , params = query .create (db_object_type , data )
589
594
res = self .execute (query_string , params )
590
595
res = res ["create%s" % db_object_type .type_name ()]
@@ -699,17 +704,26 @@ def create_project(self, **kwargs) -> Project:
699
704
)
700
705
701
706
media_type = kwargs .get ("media_type" )
702
- if media_type :
703
- if MediaType .is_supported (media_type ):
704
- media_type = media_type .value
705
- else :
706
- raise TypeError (f"{ media_type } is not a valid media type. Use"
707
- f" any of { MediaType .get_supported_members ()} "
708
- " from MediaType. Example: MediaType.Image." )
707
+ if media_type and MediaType .is_supported (media_type ):
708
+ media_type_value = media_type .value
709
+ elif media_type :
710
+ raise TypeError (f"{ media_type } is not a valid media type. Use"
711
+ f" any of { MediaType .get_supported_members ()} "
712
+ " from MediaType. Example: MediaType.Image." )
709
713
else :
710
714
logger .warning (
711
715
"Creating a project without specifying media_type"
712
716
" through this method will soon no longer be supported." )
717
+ media_type_value = None
718
+
719
+ ontology_kind = kwargs .pop ("ontology_kind" , None )
720
+ if ontology_kind and OntologyKind .is_supported (ontology_kind ):
721
+ editor_task_type_value = EditorTaskTypeMapper .to_editor_task_type (
722
+ ontology_kind , media_type ).value
723
+ elif ontology_kind :
724
+ raise OntologyKind .get_ontology_kind_validation_error (ontology_kind )
725
+ else :
726
+ editor_task_type_value = None
713
727
714
728
quality_mode = kwargs .get ("quality_mode" )
715
729
if not quality_mode :
@@ -728,12 +742,47 @@ def create_project(self, **kwargs) -> Project:
728
742
else :
729
743
raise ValueError (f"{ quality_mode } is not a valid quality mode." )
730
744
731
- return self ._create (Entity .Project , {
732
- ** data ,
733
- ** ({
734
- "media_type" : media_type
735
- } if media_type else {})
736
- })
745
+ params = {** data }
746
+ if media_type_value :
747
+ params ["media_type" ] = media_type_value
748
+ if editor_task_type_value :
749
+ params ["editor_task_type" ] = editor_task_type_value
750
+
751
+ extra_params = {
752
+ Field .String ("dataset_name_or_id" ):
753
+ params .pop ("dataset_name_or_id" , None ),
754
+ Field .Boolean ("append_to_existing_dataset" ):
755
+ params .pop ("append_to_existing_dataset" , None ),
756
+ Field .Int ("data_row_count" ):
757
+ params .pop ("data_row_count" , None ),
758
+ }
759
+ extra_params = {k : v for k , v in extra_params .items () if v is not None }
760
+
761
+ return self ._create (Entity .Project , params , extra_params )
762
+
763
+ def create_model_evaluation_project (
764
+ self ,
765
+ dataset_name_or_id : str ,
766
+ append_to_existing_dataset : bool = False ,
767
+ data_row_count : int = 100 ,
768
+ ** kwargs ) -> Project :
769
+ """
770
+ Use this method exclusively to create a chat model evaluation project.
771
+ Args:
772
+ dataset_name_or_id: The name or id of the dataset to use for the project
773
+ append_to_existing_dataset: If True, the project will append assets (data rows) to the existing dataset
774
+ data_row_count: The number of data row assets to use for the project
775
+ **kwargs: Additional parameters to pass to the the create_project method
776
+ Returns:
777
+ Project: The created project
778
+ """
779
+ kwargs ["media_type" ] = MediaType .Conversational
780
+ kwargs ["ontology_kind" ] = OntologyKind .ModelEvaluation
781
+ kwargs ["dataset_name_or_id" ] = dataset_name_or_id
782
+ kwargs ["append_to_existing_dataset" ] = append_to_existing_dataset
783
+ kwargs ["data_row_count" ] = data_row_count
784
+
785
+ return self .create_project (** kwargs )
737
786
738
787
def get_roles (self ) -> List [Role ]:
739
788
"""
@@ -938,18 +987,22 @@ def rootSchemaPayloadToFeatureSchema(client, payload):
938
987
rootSchemaPayloadToFeatureSchema ,
939
988
['rootSchemaNodes' , 'nextCursor' ])
940
989
941
- def create_ontology_from_feature_schemas (self ,
942
- name ,
943
- feature_schema_ids ,
944
- media_type = None ) -> Ontology :
990
+ def create_ontology_from_feature_schemas (
991
+ self ,
992
+ name ,
993
+ feature_schema_ids ,
994
+ media_type : MediaType = None ,
995
+ ontology_kind : OntologyKind = None ) -> Ontology :
945
996
"""
946
997
Creates an ontology from a list of feature schema ids
947
998
948
999
Args:
949
1000
name (str): Name of the ontology
950
1001
feature_schema_ids (List[str]): List of feature schema ids corresponding to
951
1002
top level tools and classifications to include in the ontology
952
- media_type (MediaType or None): Media type of a new ontology
1003
+ media_type (MediaType or None): Media type of a new ontology. NOTE for chat evaluation, we currently foce media_type to Conversational
1004
+ ontology_kind (OntologyKind or None): set to OntologyKind.ModelEvaluation if the ontology is for chat evaluation,
1005
+ leave as None otherwise.
953
1006
Returns:
954
1007
The created Ontology
955
1008
"""
@@ -979,7 +1032,20 @@ def create_ontology_from_feature_schemas(self,
979
1032
"Neither `tool` or `classification` found in the normalized feature schema"
980
1033
)
981
1034
normalized = {'tools' : tools , 'classifications' : classifications }
982
- return self .create_ontology (name , normalized , media_type )
1035
+
1036
+ if ontology_kind and ontology_kind is OntologyKind .ModelEvaluation :
1037
+ if media_type is None :
1038
+ media_type = MediaType .Conversational
1039
+ else :
1040
+ if media_type is not MediaType .Conversational :
1041
+ raise ValueError (
1042
+ "For chat evaluation, media_type must be Conversational."
1043
+ )
1044
+
1045
+ return self .create_ontology (name = name ,
1046
+ normalized = normalized ,
1047
+ media_type = media_type ,
1048
+ ontology_kind = ontology_kind )
983
1049
984
1050
def delete_unused_feature_schema (self , feature_schema_id : str ) -> None :
985
1051
"""
@@ -1166,7 +1232,11 @@ def get_unused_feature_schemas(self, after: str = None) -> List[str]:
1166
1232
"Failed to get unused feature schemas, message: " +
1167
1233
str (response .json ()['message' ]))
1168
1234
1169
- def create_ontology (self , name , normalized , media_type = None ) -> Ontology :
1235
+ def create_ontology (self ,
1236
+ name ,
1237
+ normalized ,
1238
+ media_type : MediaType = None ,
1239
+ ontology_kind : OntologyKind = None ) -> Ontology :
1170
1240
"""
1171
1241
Creates an ontology from normalized data
1172
1242
>>> normalized = {"tools" : [{'tool': 'polygon', 'name': 'cat', 'color': 'black'}], "classifications" : []}
@@ -1184,26 +1254,43 @@ def create_ontology(self, name, normalized, media_type=None) -> Ontology:
1184
1254
name (str): Name of the ontology
1185
1255
normalized (dict): A normalized ontology payload. See above for details.
1186
1256
media_type (MediaType or None): Media type of a new ontology
1257
+ ontology_kind (OntologyKind or None): set to OntologyKind.ModelEvaluation if the ontology is for chat evaluation,
1258
+ leave as None otherwise.
1259
+
1187
1260
Returns:
1188
1261
The created Ontology
1262
+
1263
+ NOTE caller of this method is expected to set media_type to Conversational if ontology_kind is ModelEvaluation
1189
1264
"""
1190
1265
1266
+ media_type_value = None
1191
1267
if media_type :
1192
1268
if MediaType .is_supported (media_type ):
1193
- media_type = media_type .value
1269
+ media_type_value = media_type .value
1194
1270
else :
1195
1271
raise get_media_type_validation_error (media_type )
1196
1272
1273
+ if ontology_kind and OntologyKind .is_supported (ontology_kind ):
1274
+ editor_task_type_value = EditorTaskTypeMapper .to_editor_task_type (
1275
+ ontology_kind , media_type ).value
1276
+ elif ontology_kind :
1277
+ raise OntologyKind .get_ontology_kind_validation_error (ontology_kind )
1278
+ else :
1279
+ editor_task_type_value = None
1280
+
1197
1281
query_str = """mutation upsertRootSchemaNodePyApi($data: UpsertOntologyInput!){
1198
1282
upsertOntology(data: $data){ %s }
1199
1283
} """ % query .results_query_part (Entity .Ontology )
1200
1284
params = {
1201
1285
'data' : {
1202
1286
'name' : name ,
1203
1287
'normalized' : json .dumps (normalized ),
1204
- 'mediaType' : media_type
1288
+ 'mediaType' : media_type_value
1205
1289
}
1206
1290
}
1291
+ if editor_task_type_value :
1292
+ params ['data' ]['editorTaskType' ] = editor_task_type_value
1293
+
1207
1294
res = self .execute (query_str , params )
1208
1295
return Entity .Ontology (self , res ['upsertOntology' ])
1209
1296
0 commit comments