@@ -608,6 +608,166 @@ def resume_user_activity(
608608 f"User with email { user .email } has been successfully unblocked from the specified projects: { projects } ."
609609 )
610610
611+ def get_user_scores (
612+ self ,
613+ project : Union [NotEmptyStr , Tuple [int , int ], Tuple [str , str ]],
614+ item : Union [NotEmptyStr , int ],
615+ scored_user : NotEmptyStr ,
616+ * ,
617+ score_names : Optional [List [str ]] = None ,
618+ ) -> List [Dict [str , Any ]]:
619+ """
620+ Retrieve score metadata for a user for a specific item in a specific project.
621+
622+ :param project: Project and folder as a tuple, folder is optional.
623+ :type project: Union[str, Tuple[int, int], Tuple[str, str]]
624+
625+ :param item: The unique ID or name of the item.
626+ :type item: Union[str, int]
627+
628+ :param scored_user: The email address of the project user.
629+ :type scored_user: str
630+
631+ :param score_names: A list of score names to filter by. If None, returns all scores.
632+ :type score_names: Optional[List[str]]
633+
634+ :return: A list of dictionaries containing score metadata for the user.
635+ :rtype: list of dicts
636+
637+ Request Example:
638+ ::
639+
640+ client.get_user_scores(
641+ project=("my_multimodal", "folder1"),
642+ item="item1",
643+ scored_user="example@superannotate.com",
644+ score_names=["Accuracy Score", "Speed"]
645+ )
646+
647+ Response Example:
648+ ::
649+
650+ [
651+ {
652+ "createdAt": "2024-06-01T13:00:00",
653+ "updatedAt": "2024-06-01T13:00:00",
654+ "id": 3217575,
655+ "name": "Accuracy Score",
656+ "value": 98,
657+ "weight": 4,
658+ },
659+ {
660+ "createdAt": "2024-06-01T13:00:00",
661+ "updatedAt": "2024-06-01T13:00:00",
662+ "id": 5657575,
663+ "name": "Speed",
664+ "value": 9,
665+ "weight": 0.4,
666+ },
667+ ]
668+ """
669+
670+ if isinstance (project , str ):
671+ project_name , folder_name = extract_project_folder (project )
672+ project , folder = self .controller .get_project_folder (
673+ project_name , folder_name
674+ )
675+ else :
676+ project_pk , folder_pk = project
677+ if isinstance (project_pk , int ) and isinstance (folder_pk , int ):
678+ project = self .controller .get_project_by_id (project_pk ).data
679+ folder = self .controller .get_folder_by_id (folder_pk , project .id ).data
680+ elif isinstance (project_pk , str ) and isinstance (folder_pk , str ):
681+ project = self .controller .get_project (project_pk )
682+ folder = self .controller .get_folder (project , folder_pk )
683+ else :
684+ raise AppException ("Provided project param is not valid." )
685+ response = BaseSerializer .serialize_iterable (
686+ self .controller .work_management .get_user_scores (
687+ project = project ,
688+ folder = folder ,
689+ item = item ,
690+ scored_user = scored_user ,
691+ provided_score_names = score_names ,
692+ )
693+ )
694+ return response
695+
696+ def set_user_scores (
697+ self ,
698+ project : Union [NotEmptyStr , Tuple [int , int ], Tuple [str , str ]],
699+ item : Union [NotEmptyStr , int ],
700+ scored_user : NotEmptyStr ,
701+ scores : List [Dict [str , Any ]],
702+ ):
703+ """
704+ Assign score metadata for a user in a scoring component.
705+
706+ :param project: Project and folder as a tuple, folder is optional.
707+ :type project: Union[str, Tuple[int, int], Tuple[str, str]]
708+
709+ :param item: The unique ID or name of the item.
710+ :type item: Union[str, int]
711+
712+ :param scored_user: Set the email of the user being scored.
713+ :type scored_user: str
714+
715+ :param scores: A list of dictionaries containing the following key-value pairs:
716+ * **name** (*str*): The name of the score (required).
717+ * **value** (*Any*): The score value (required).
718+ * **weight** (*Union[float, int]*, optional): The weight of the score. Defaults to `1` if not provided.
719+
720+ **Example**:
721+ ::
722+
723+ scores = [
724+ {
725+ "name": "Speed", # str (required)
726+ "value": 90, # Any (required)
727+ "weight": 1 # Union[float, int] (optional, defaults to 1.0 if not provided)
728+ }
729+ ]
730+ :type scores: List[Dict[str, Any]
731+
732+ Request Example:
733+ ::
734+
735+ client.set_user_scores(
736+ project=("my_multimodal", "folder1"),
737+ item_=12345,
738+ scored_user="example@superannotate.com",
739+ scores=[
740+ {"name": "Speed", "value": 90},
741+ {"name": "Accuracy", "value": 9, "weight": 4.0},
742+ {"name": "Attention to Detail", "value": None, "weight": None},
743+ ]
744+ )
745+
746+ """
747+ if isinstance (project , str ):
748+ project_name , folder_name = extract_project_folder (project )
749+ project , folder = self .controller .get_project_folder (
750+ project_name , folder_name
751+ )
752+ else :
753+ project_pk , folder_pk = project
754+ if isinstance (project_pk , int ) and isinstance (folder_pk , int ):
755+ project = self .controller .get_project_by_id (project_pk ).data
756+ folder = self .controller .get_folder_by_id (folder_pk , project .id ).data
757+ elif isinstance (project_pk , str ) and isinstance (folder_pk , str ):
758+ project = self .controller .get_project (project_pk )
759+ folder = self .controller .get_folder (project , folder_pk )
760+ else :
761+ raise AppException ("Provided project param is not valid." )
762+ self .controller .work_management .set_user_scores (
763+ project = project ,
764+ folder = folder ,
765+ item = item ,
766+ scored_user = scored_user ,
767+ scores = scores ,
768+ )
769+ logger .info ("Scores successfully set." )
770+
611771 def get_component_config (self , project : Union [NotEmptyStr , int ], component_id : str ):
612772 """
613773 Retrieves the configuration for a given project and component ID.
0 commit comments