Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| from typing import Any, Dict, List, Tuple | |
| from catalog_text_templates import ( | |
| RECOMMENDATION_TEMPLATES, | |
| STRENGTH_TEMPLATES, | |
| VERDICT_LEVELS, | |
| WEAKNESS_TEMPLATES, | |
| ) | |
| def clamp(v: float, lo: float, hi: float) -> float: | |
| return max(lo, min(hi, v)) | |
| def pick_top_unique(items: List[str], limit: int = 3) -> List[str]: | |
| out: List[str] = [] | |
| seen = set() | |
| for item in items: | |
| if item and item not in seen: | |
| out.append(item) | |
| seen.add(item) | |
| if len(out) >= limit: | |
| break | |
| return out | |
| def build_strength_keys( | |
| official_scores: Dict[str, float], | |
| diagnostic_metrics: Dict[str, int], | |
| ) -> List[str]: | |
| keys: List[str] = [] | |
| if official_scores.get("composition", 0.0) >= 4.2: | |
| keys.append("strong_composition") | |
| if diagnostic_metrics.get("hierarchy_strength", 0) >= 4: | |
| keys.append("clear_hierarchy") | |
| if diagnostic_metrics.get("focal_clarity", 0) >= 4: | |
| keys.append("clear_focal_point") | |
| if diagnostic_metrics.get("palette_control", 0) >= 4: | |
| keys.append("controlled_palette") | |
| if diagnostic_metrics.get("visual_impact", 0) >= 4: | |
| keys.append("strong_impact") | |
| if diagnostic_metrics.get("technical_quality", 0) >= 4: | |
| keys.append("good_technical_quality") | |
| if diagnostic_metrics.get("visual_clutter", 0) <= 2: | |
| keys.append("clean_presentation") | |
| if official_scores.get("typography", 0.0) >= 4.0: | |
| keys.append("readable_typography") | |
| if official_scores.get("message_clarity", 0.0) >= 4.0: | |
| keys.append("good_message_clarity") | |
| return pick_top_unique(keys, 3) | |
| def build_weakness_keys( | |
| official_scores: Dict[str, float], | |
| diagnostic_metrics: Dict[str, int], | |
| ) -> List[str]: | |
| keys: List[str] = [] | |
| if official_scores.get("composition", 0.0) <= 2.8: | |
| keys.append("weak_composition") | |
| if diagnostic_metrics.get("hierarchy_strength", 0) <= 2: | |
| keys.append("weak_hierarchy") | |
| if diagnostic_metrics.get("focal_clarity", 0) <= 2: | |
| keys.append("weak_focal_point") | |
| if diagnostic_metrics.get("palette_control", 0) <= 2: | |
| keys.append("weak_palette_control") | |
| if diagnostic_metrics.get("visual_impact", 0) <= 2: | |
| keys.append("low_visual_impact") | |
| if diagnostic_metrics.get("technical_quality", 0) <= 2: | |
| keys.append("low_technical_quality") | |
| if diagnostic_metrics.get("visual_clutter", 0) >= 4: | |
| keys.append("high_clutter") | |
| if official_scores.get("typography", 0.0) <= 3.0: | |
| keys.append("weak_typography") | |
| if official_scores.get("message_clarity", 0.0) <= 3.0: | |
| keys.append("weak_message_clarity") | |
| return pick_top_unique(keys, 3) | |
| def build_recommendation_keys( | |
| official_scores: Dict[str, float], | |
| diagnostic_metrics: Dict[str, int], | |
| pins: List[str], | |
| ) -> List[str]: | |
| keys: List[str] = [] | |
| if diagnostic_metrics.get("hierarchy_strength", 0) <= 3: | |
| keys.append("improve_hierarchy") | |
| if diagnostic_metrics.get("visual_clutter", 0) >= 4: | |
| keys.append("reduce_clutter") | |
| if diagnostic_metrics.get("focal_clarity", 0) <= 3: | |
| keys.append("improve_focal_point") | |
| if official_scores.get("typography", 0.0) <= 3.3: | |
| keys.append("improve_typography") | |
| if official_scores.get("color", 0.0) <= 3.2: | |
| keys.append("improve_palette") | |
| if official_scores.get("message_clarity", 0.0) <= 3.5: | |
| keys.append("improve_message_clarity") | |
| if official_scores.get("quality", 0.0) <= 3.3: | |
| keys.append("improve_technical_quality") | |
| if "credits_box" in pins or "small_footer_info" in pins: | |
| keys.append("improve_footer_block") | |
| return pick_top_unique(keys, 3) | |
| def render_texts_from_keys( | |
| keys: List[str], | |
| template_map: Dict[str, str], | |
| ) -> List[str]: | |
| return [template_map[k] for k in keys if k in template_map] | |
| def compute_verdict_level( | |
| primary_label: str, | |
| primary_confidence: str, | |
| diagnostic_score: float, | |
| ) -> str: | |
| if primary_label == "good" and diagnostic_score >= 4.3: | |
| return "strong" | |
| if primary_label == "good" and diagnostic_score >= 3.5: | |
| return "good" | |
| if primary_label == "uncertain": | |
| return "uncertain" | |
| if primary_label == "bad" and diagnostic_score <= 2.7: | |
| return "weak" | |
| return "mixed" | |
| def build_verdict_summary( | |
| *, | |
| verdict_level: str, | |
| primary_label: str, | |
| diagnostic_score: float, | |
| tags: List[str], | |
| strengths: List[str], | |
| weaknesses: List[str], | |
| ) -> str: | |
| level_text = VERDICT_LEVELS.get(verdict_level, "Смешанный") | |
| tone_bits: List[str] = [] | |
| if "minimal" in tags: | |
| tone_bits.append("минималистичной подачей") | |
| if "clean" in tags: | |
| tone_bits.append("чистой подачей") | |
| if "cinematic" in tags: | |
| tone_bits.append("атмосферной подачей") | |
| if "editorial" in tags: | |
| tone_bits.append("редакционной структурой") | |
| tone_text = "" | |
| if tone_bits: | |
| tone_text = " с " + ", ".join(tone_bits[:2]) | |
| if primary_label == "good": | |
| return f"{level_text} постер{tone_text}, который в целом производит положительное визуальное впечатление." | |
| if primary_label == "bad": | |
| return f"{level_text} постер, которому пока не хватает ясности и собранности восприятия." | |
| return f"{level_text} постер: в нем есть сильные стороны, но общий сигнал пока неоднозначен." | |
| def build_verdict_takeaway( | |
| strengths: List[str], | |
| weaknesses: List[str], | |
| recommendations: List[str], | |
| ) -> str: | |
| if recommendations: | |
| first = recommendations[0] | |
| if first.endswith("."): | |
| return first | |
| return first + "." | |
| if weaknesses: | |
| return "Основной резерв роста связан с улучшением читаемости и структуры." | |
| if strengths: | |
| return "Текущую визуальную логику стоит сохранить и доработать точечно." | |
| return "Нужна дополнительная проверка композиции, ясности сообщения и визуальной иерархии." | |
| def build_structured_report( | |
| *, | |
| official_scores: Dict[str, float], | |
| diagnostic_metrics: Dict[str, int], | |
| tags: List[str], | |
| pins: List[str], | |
| primary_label: str, | |
| primary_confidence: str, | |
| diagnostic_score: float, | |
| ) -> Dict[str, Any]: | |
| strength_keys = build_strength_keys(official_scores, diagnostic_metrics) | |
| weakness_keys = build_weakness_keys(official_scores, diagnostic_metrics) | |
| recommendation_keys = build_recommendation_keys(official_scores, diagnostic_metrics, pins) | |
| strengths = render_texts_from_keys(strength_keys, STRENGTH_TEMPLATES) | |
| weaknesses = render_texts_from_keys(weakness_keys, WEAKNESS_TEMPLATES) | |
| recommendations = render_texts_from_keys(recommendation_keys, RECOMMENDATION_TEMPLATES) | |
| verdict_level = compute_verdict_level( | |
| primary_label=primary_label, | |
| primary_confidence=primary_confidence, | |
| diagnostic_score=diagnostic_score, | |
| ) | |
| verdict_summary = build_verdict_summary( | |
| verdict_level=verdict_level, | |
| primary_label=primary_label, | |
| diagnostic_score=diagnostic_score, | |
| tags=tags, | |
| strengths=strengths, | |
| weaknesses=weaknesses, | |
| ) | |
| verdict_takeaway = build_verdict_takeaway( | |
| strengths=strengths, | |
| weaknesses=weaknesses, | |
| recommendations=recommendations, | |
| ) | |
| return { | |
| "tags": tags, | |
| "pins": pins, | |
| "strengths": strengths, | |
| "weaknesses": weaknesses, | |
| "recommendations": recommendations, | |
| "verdict": { | |
| "level": verdict_level, | |
| "summary": verdict_summary, | |
| "takeaway": verdict_takeaway, | |
| }, | |
| "debug_keys": { | |
| "strength_keys": strength_keys, | |
| "weakness_keys": weakness_keys, | |
| "recommendation_keys": recommendation_keys, | |
| }, | |
| } |