from __future__ import annotations from typing import Iterable try: from models import AppObservation except ImportError: from app.models import AppObservation def _clamp_score(value): return max(0.0, min(1.0, float(value))) def _safe_ratio(numerator, denominator): if denominator <= 0: return 0.0 return _clamp_score(numerator / denominator) def _attempt_quality(rewards): rewards = list(rewards) if not rewards: return 0.0 positive_attempts = sum(1 for reward in rewards if reward > 0) return _safe_ratio(positive_attempts, len(rewards)) def feedback(score, category): if score >= 0.9: return f"{category} performance is excellent and highly reliable." if score >= 0.7: return f"{category} performance is solid with minor room for improvement." if score >= 0.4: return f"{category} performance is partial and needs more consistency." return f"{category} performance is weak and needs significant improvement." def grade_segmentation(app_obs: AppObservation): total_objects = len(app_obs.objectsFound) + len(app_obs.objectsLeft) progress_score = _safe_ratio(len(app_obs.objectsFound), total_objects) quality_score = _attempt_quality(app_obs.rewardListSegment) score = _clamp_score((progress_score * 0.7) + (quality_score * 0.3)) return score, feedback(score, "Segmentation") def grade_placement(app_obs: AppObservation): total_objects = len(app_obs.objectsFound) + len(app_obs.objectsLeft) progress_score = _safe_ratio(app_obs.numberPlaced, total_objects) quality_score = _attempt_quality(app_obs.rewardListPlace) score = _clamp_score((progress_score * 0.7) + (quality_score * 0.3)) return score, feedback(score, "Placement") def grade_adjustment(app_obs: AppObservation): rewards = list(app_obs.rewardListAdjust) if not rewards: return 0.0, "Adjustment was not attempted." score = _attempt_quality(rewards) return score, feedback(score, "Adjustment")