atc-tts-mos / frontend /utils /validation.py
aether-raider
tested and completed mos form
653a3eb
# frontend/validation.py
"""
Validation logic for MOS evaluation form data.
"""
import json
import gradio as gr
from typing import Dict, Any, Tuple
def validate_mos_completion(mos_data_json: str, expected_clips: int) -> Tuple[bool, str]:
"""
Validate that all MOS clips have been rated.
Returns:
(is_valid, error_message)
"""
if not mos_data_json or mos_data_json == "None":
return False, "⚠️ Please rate at least one dimension for each clip before continuing!"
try:
ratings_data = json.loads(mos_data_json)
# Check that each clip is completed
# Clip is complete if: all 5 ratings are filled OR gender_mismatch is checked
clips_with_ratings = 0
for clip_id, ratings in ratings_data.items():
rating_dims = ["clarity", "pronunciation", "prosody", "naturalness", "overall"]
filled_ratings = [dim for dim in rating_dims if ratings.get(dim)]
all_ratings_filled = len(filled_ratings) == 5
has_gender_mismatch = ratings.get("gender_mismatch", False)
if all_ratings_filled or has_gender_mismatch:
clips_with_ratings += 1
if clips_with_ratings < expected_clips:
return False, f"⚠️ Please complete all clips before continuing! Each clip needs either all 5 ratings, or a gender flag. ({clips_with_ratings}/{expected_clips} completed)"
return True, ""
except json.JSONDecodeError:
return False, "⚠️ Error reading ratings. Please try again!"
def validate_ab_completion(ab_data_json: str, expected_comparisons: int, comparison_type: str = "comparisons") -> Tuple[bool, str]:
"""
Validate that all A/B comparisons have been completed.
A comparison is considered complete if either:
- A choice is selected (A, B, or tie), OR
- At least one gender mismatch checkbox is checked
Args:
ab_data_json: JSON string containing comparison data
expected_comparisons: Number of comparisons expected
comparison_type: Type of comparison for error message (e.g., "model comparisons", "gender comparisons")
Returns:
(is_valid, error_message)
"""
if not ab_data_json or ab_data_json == "None":
return False, f"⚠️ Please make a choice for each {comparison_type} before continuing!"
try:
comparisons_data = json.loads(ab_data_json)
# Check that each comparison is completed
# Complete if: has a choice OR has gender mismatch checked
completed_comparisons = 0
for comp_id, comparison in comparisons_data.items():
has_choice = bool(comparison.get("choice"))
has_gender_mismatch = (
comparison.get("gender_mismatch_a", False) or
comparison.get("gender_mismatch_b", False) or
comparison.get("gender_mismatch_male", False) or
comparison.get("gender_mismatch_female", False)
)
if has_choice or has_gender_mismatch:
completed_comparisons += 1
if completed_comparisons < expected_comparisons:
return False, f"⚠️ Please complete all {comparison_type} before continuing! Each needs either a choice or gender flag. ({completed_comparisons}/{expected_comparisons} completed)"
return True, ""
except json.JSONDecodeError:
return False, f"⚠️ Error reading {comparison_type}. Please try again!"
def validate_overall_feedback(overall_preference: str) -> Tuple[bool, str]:
"""
Validate that overall feedback has been selected.
Returns:
(is_valid, error_message)
"""
if not overall_preference or overall_preference == "None" or overall_preference == "":
return False, "⚠️ Please select an overall preference before submitting!"
return True, ""
def validate_final_submission(overall_preference: str) -> Tuple[bool, str]:
"""
Validate final submission - only checks that overall preference is selected.
Returns:
(is_valid, error_message)
"""
# Only check that overall feedback is selected
return validate_overall_feedback(overall_preference)