Poster_Analyzer / app /src /report_builder.py
DatsuNTOYOTA's picture
init app
ec4da21 verified
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,
},
}