Download server/utils/presentbench/scoring.py from Berlm/ppt_agent: direct link, hf CLI and curl.
- Browser
- Download file 9.53 kB
-
https://huggingface.co/spaces/Berlm/ppt_agent/resolve/main/server/utils/presentbench/scoring.py
- Command line
-
hf download hf://spaces/Berlm/ppt_agent/server/utils/presentbench/scoring.py
-
curl -L -o scoring.py https://huggingface.co/spaces/Berlm/ppt_agent/resolve/main/server/utils/presentbench/scoring.py
9.53 kB
| from __future__ import annotations | |
| from typing import Any | |
| from .metrics import ( | |
| compute_aesthetics_scores, | |
| compute_presentation_diagnostics, | |
| compute_slide_staleness_penalty, | |
| mean_scores_by_dimension, | |
| redundancy_score, | |
| score_checklist_item, | |
| score_generic_slide_checklist_items, | |
| score_slide_checklist_item, | |
| ) | |
| from ..reward_metrics import ( | |
| clamp_reward, | |
| compute_overlap_ratio, | |
| is_blank_or_title_only, | |
| ) | |
| from ..reward_models import ( | |
| IntermediateSlideRewardResult, | |
| PresentBenchEvalSpec, | |
| PresentBenchScoreResult, | |
| ExtractedPresentation, | |
| ExtractedSlide, | |
| TaskSpec, | |
| ) | |
| def score_presentbench( | |
| task_spec: TaskSpec, | |
| presentation_extraction: ExtractedPresentation, | |
| eval_spec: PresentBenchEvalSpec, | |
| *, | |
| aesthetics_service: Any | None = None, | |
| ) -> PresentBenchScoreResult: | |
| diagnostics = compute_presentation_diagnostics(presentation_extraction, task_spec) | |
| checklist_results = [ | |
| score_checklist_item(item, presentation_extraction, task_spec, diagnostics) | |
| for item in eval_spec.checklist | |
| ] | |
| dimension_scores = mean_scores_by_dimension(checklist_results) | |
| aesthetics_scores = ( | |
| aesthetics_service.score_presentation(presentation_extraction) | |
| if aesthetics_service and hasattr(aesthetics_service, "score_presentation") | |
| else compute_aesthetics_scores(presentation_extraction) | |
| ) | |
| s_fund = dimension_scores.get("fundamentals", 0.0) | |
| s_visual = dimension_scores.get("visual_layout", 0.0) | |
| s_complete = dimension_scores.get("completeness", 0.0) | |
| s_correct = dimension_scores.get("correctness", 0.0) | |
| s_fidelity = dimension_scores.get("fidelity", 0.0) | |
| dimension_weights = eval_spec.scoring_config["dimension_weights"] | |
| r_pb = ( | |
| dimension_weights["fundamentals"] * s_fund | |
| + dimension_weights["visual_layout"] * s_visual | |
| + dimension_weights["completeness"] * s_complete | |
| + dimension_weights["correctness"] * s_correct | |
| + dimension_weights["fidelity"] * s_fidelity | |
| ) | |
| c_fidelity_critical = ( | |
| 0.5 | |
| if any( | |
| r["dimension"] == "fidelity" and r["verdict"] == "no" | |
| for r in checklist_results | |
| ) | |
| else 1.0 | |
| ) | |
| blankness_threshold = eval_spec.scoring_config["hard_caps"][ | |
| "blank_title_only_ratio_threshold" | |
| ] | |
| c_blankness = ( | |
| 0.6 if diagnostics["blank_title_only_ratio"] > blankness_threshold else 1.0 | |
| ) | |
| c_hard = min(c_fidelity_critical, c_blankness) | |
| penalty_config = eval_spec.scoring_config["soft_penalties"] | |
| soft_penalties = { | |
| "slide_count_violation": penalty_config["slide_count_violation"] | |
| * diagnostics["slide_count_violation"], | |
| "overlap": penalty_config["overlap"] * diagnostics["max_overlap_ratio"], | |
| "tiny_text": penalty_config["tiny_text"] | |
| * ( | |
| 1.0 | |
| if diagnostics["min_font_size_pt"] is not None | |
| and diagnostics["min_font_size_pt"] < 10 | |
| else 0.0 | |
| ), | |
| "staleness": penalty_config["staleness"] | |
| * diagnostics["mean_staleness_penalty"], | |
| } | |
| p_soft = sum(soft_penalties.values()) | |
| aesthetic_weight = eval_spec.scoring_config.get("aesthetic_weight", 0.15) | |
| reward_total = clamp_reward( | |
| c_hard | |
| * ( | |
| (1.0 - aesthetic_weight) * r_pb | |
| + aesthetic_weight * aesthetics_scores["aesthetic"] | |
| ) | |
| - p_soft | |
| ) | |
| return PresentBenchScoreResult( | |
| reward_total=reward_total, | |
| reward_breakdown={ | |
| "R_pb": reward_total, | |
| "S_fundamentals": s_fund, | |
| "S_visual_layout": s_visual, | |
| "S_completeness": s_complete, | |
| "S_correctness": s_correct, | |
| "S_fidelity": s_fidelity, | |
| "S_aesthetic": aesthetics_scores["aesthetic"], | |
| "S_harmony": aesthetics_scores["harmony"], | |
| "S_engagement": aesthetics_scores["engagement"], | |
| "S_usability": aesthetics_scores["usability"], | |
| "S_rhythm": aesthetics_scores["rhythm"], | |
| }, | |
| hard_caps={ | |
| "C_fidelity_critical": c_fidelity_critical, | |
| "C_blankness": c_blankness, | |
| "C_hard": c_hard, | |
| }, | |
| soft_penalties=soft_penalties, | |
| checklist_results=checklist_results, | |
| aesthetics_results=aesthetics_scores, | |
| metadata={ | |
| "task_id": eval_spec.task_spec.task_id, | |
| "item_count": len(eval_spec.checklist), | |
| "slide_count": presentation_extraction.slide_count, | |
| "spec_hash": eval_spec.spec_hash, | |
| }, | |
| ) | |
| def score_presentbench_slide( | |
| task_spec: TaskSpec, | |
| eval_spec: PresentBenchEvalSpec, | |
| slide_index: int, | |
| slide_extraction: ExtractedSlide, | |
| *, | |
| previous_slide_extractions: list[ExtractedSlide] | None = None, | |
| use_mllm: bool = False, | |
| mode: str = "eval", | |
| ) -> IntermediateSlideRewardResult: | |
| target_slides = { | |
| slide.slide_index: slide for slide in task_spec.required_slides or [] | |
| } | |
| target_slide = target_slides.get(slide_index) | |
| target_mode = "required_slide" if target_slide is not None else "fallback_generic" | |
| if target_slide is None: | |
| checklist_results = score_generic_slide_checklist_items( | |
| slide_extraction, task_spec | |
| ) | |
| else: | |
| slide_checklist = eval_spec.slide_checklists.get(slide_index, []) | |
| checklist_results = [ | |
| score_slide_checklist_item( | |
| item, | |
| slide_extraction, | |
| target_slide.slide_role, | |
| target_slide.title_hint, | |
| target_slide.required_shape_kinds, | |
| task_spec, | |
| ) | |
| for item in slide_checklist | |
| ] | |
| dimension_scores = mean_scores_by_dimension(checklist_results) | |
| s_prompt_alignment = dimension_scores.get("prompt_alignment", 0.0) | |
| s_local_completeness = dimension_scores.get("local_completeness", 0.0) | |
| s_local_correctness = dimension_scores.get("local_correctness", 0.0) | |
| s_local_fidelity = dimension_scores.get("local_fidelity", 0.0) | |
| s_local_usability = dimension_scores.get("local_usability", 0.0) | |
| c_slide_fidelity_critical = ( | |
| 0.5 | |
| if ( | |
| target_slide is not None | |
| and s_local_fidelity < 1.0 | |
| and target_slide.required_exact_values | |
| ) | |
| else 1.0 | |
| ) | |
| c_slide_blankness = ( | |
| 0.4 | |
| if is_blank_or_title_only(slide_extraction) | |
| and ( | |
| (target_slide is not None and target_slide.required_points) | |
| or target_mode == "fallback_generic" | |
| ) | |
| else 1.0 | |
| ) | |
| c_slide_hard = min(c_slide_fidelity_critical, c_slide_blankness) | |
| penalty_config = eval_spec.scoring_config["soft_penalties"] | |
| overlap = compute_overlap_ratio(slide_extraction) | |
| min_font = slide_extraction.text_metrics.get("min_font_size_pt") | |
| redundancy = redundancy_score(slide_extraction, previous_slide_extractions) | |
| staleness = compute_slide_staleness_penalty( | |
| slide_extraction, | |
| role=target_slide.slide_role if target_slide is not None else None, | |
| ) | |
| wrong_slot_behavior = ( | |
| 0.0 if target_mode == "fallback_generic" or s_prompt_alignment >= 1.0 else 1.0 | |
| ) | |
| soft_penalties = { | |
| "redundancy": penalty_config["redundancy"] * redundancy, | |
| "wrong_slot_behavior": penalty_config["wrong_slot_behavior"] | |
| * wrong_slot_behavior, | |
| "tiny_text": penalty_config["tiny_text"] | |
| * (1.0 if min_font is not None and min_font < 10 else 0.0), | |
| "overlap": penalty_config["overlap"] * overlap, | |
| "staleness": penalty_config["staleness"] * float(staleness["penalty"]), | |
| } | |
| p_slide_soft = sum(soft_penalties.values()) | |
| reward_total = clamp_reward( | |
| c_slide_hard | |
| * ( | |
| 0.35 * s_prompt_alignment | |
| + 0.20 * s_local_completeness | |
| + 0.15 * s_local_correctness | |
| + 0.20 * s_local_fidelity | |
| + 0.10 * s_local_usability | |
| ) | |
| - p_slide_soft | |
| ) | |
| return IntermediateSlideRewardResult( | |
| slide_index=slide_index, | |
| reward_total=reward_total, | |
| reward_breakdown={ | |
| "R_slide": reward_total, | |
| "S_prompt_alignment": s_prompt_alignment, | |
| "S_local_completeness": s_local_completeness, | |
| "S_local_correctness": s_local_correctness, | |
| "S_local_fidelity": s_local_fidelity, | |
| "S_local_usability": s_local_usability, | |
| }, | |
| hard_caps={ | |
| "C_slide_fidelity_critical": c_slide_fidelity_critical, | |
| "C_slide_blankness": c_slide_blankness, | |
| "C_slide_hard": c_slide_hard, | |
| }, | |
| soft_penalties=soft_penalties, | |
| checklist_results=checklist_results, | |
| metadata={ | |
| "slide_index": slide_index, | |
| "slide_id": slide_extraction.slide_id, | |
| "target_mode": target_mode, | |
| "target_slide_role": target_slide.slide_role if target_slide else None, | |
| "target_title_hint": target_slide.title_hint if target_slide else None, | |
| "required_points": target_slide.required_points if target_slide else [], | |
| "judge_call_count": 0, | |
| "used_previous_slide_context": previous_slide_extractions is not None, | |
| "staleness": staleness, | |
| "spec_hash": eval_spec.spec_hash, | |
| "mode": mode, | |
| }, | |
| ) | |
| __all__ = ["score_presentbench", "score_presentbench_slide"] | |