Spaces:
Running
Running
File size: 5,769 Bytes
38f9c15 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | """
Utility per convertire StructuredPlan in markdown formattato per webapp
"""
import logging
from typing import Dict
from data_models import StructuredPlan, StructuredSection, DataPoint
logger = logging.getLogger(__name__)
def structured_plan_to_markdown(structured_plan: StructuredPlan) -> Dict[str, str]:
"""
Converte un StructuredPlan object in dictionary di sezioni markdown.
Returns:
Dict con chiavi: technical_sporting, youth_development, infrastructure, etc.
"""
sections_markdown = {}
for section_key, section in structured_plan.sections.items():
try:
markdown = _section_to_markdown(section)
sections_markdown[section_key] = markdown
logger.info(f"Converted section {section_key} to markdown ({len(markdown)} chars)")
except Exception as e:
logger.error(f"Error converting section {section_key}: {e}", exc_info=True)
sections_markdown[section_key] = f"<p class='empty-section'>Errore nella conversione: {str(e)}</p>"
# Aggiungi executive summary se presente
if structured_plan.executive_summary:
sections_markdown['executive_summary'] = structured_plan.executive_summary
logger.info(f"Converted {len(sections_markdown)} sections to markdown")
return sections_markdown
def _section_to_markdown(section: StructuredSection) -> str:
"""Converte una StructuredSection in markdown formattato"""
if not section.data_points:
return "<p class='empty-section'>Sezione non disponibile</p>"
md = f"# {section.title}\n\n"
# Aggiungi data points organizzati
md += "## Indicatori Chiave\n\n"
for dp in section.data_points:
# Header del data point con badge
md += f"### {dp.label}\n\n"
# Valore principale con units
if dp.value is not None:
md += f"**Valore:** {_format_value(dp.value, dp.unit)}\n\n"
# Benchmark se disponibile
if dp.benchmark and dp.benchmark.value is not None:
md += f"**Benchmark {dp.benchmark.category}:** {_format_value(dp.benchmark.value, dp.unit)}\n\n"
# Deviazione con colore
if dp.deviation is not None:
deviation_class = "success" if dp.deviation >= 0 else "warning"
md += f"**Scostamento:** <span class='badge-{deviation_class}'>{dp.deviation:+.1f}%</span>\n\n"
# Fonte
if dp.source:
# Gestisci source.type che potrebbe essere un enum o una stringa
if hasattr(dp.source.type, 'value'):
source_type = dp.source.type.value
elif dp.source.type:
source_type = str(dp.source.type)
else:
source_type = "unknown"
source_desc = dp.source.description if dp.source.description else "N/A"
md += f"📌 **Fonte:** {source_desc} ({source_type})\n\n"
# Confidenza (gestisce sia float che ConfidenceLevel object)
if hasattr(dp.confidence, 'value'):
# E' un ConfidenceLevel object
confidence_value = dp.confidence.value
else:
# E' un float diretto - converti in stringa
if isinstance(dp.confidence, float):
if dp.confidence >= 0.8:
confidence_value = "high"
elif dp.confidence >= 0.5:
confidence_value = "medium"
else:
confidence_value = "low"
else:
confidence_value = str(dp.confidence)
confidence_emoji = _confidence_emoji(confidence_value)
# Aggiungi tooltip di aiuto per spiegare l'affidabilità
tooltip_html = '''<span class="confidence-tooltip">
<span class="confidence-help">?</span>
<span class="tooltip-content">
<strong>Cos'è l'Affidabilità?</strong>
Indica quanto sono attendibili i dati:<br><br>
<ul>
<li><strong>✅ High (80-100%):</strong> Dati verificati da fonti ufficiali (bilanci certificati, FIGC)</li>
<li><strong>⚠️ Medium (50-80%):</strong> Stime basate su dati parziali o medie di categoria</li>
<li><strong>❗ Low (<50%):</strong> Stime approssimative che richiedono verifica dal club</li>
</ul>
Per migliorare l'affidabilità, fornire dati ufficiali del club.
</span>
</span>'''
md += f"{confidence_emoji} **Affidabilità:** {confidence_value.title()} {tooltip_html}\n\n"
md += "---\n\n"
# Aggiungi insights se presenti (attributo opzionale)
if hasattr(section, 'insights') and section.insights:
md += "\n## 💡 Insights Strategici\n\n"
for insight in section.insights:
md += f"- {insight}\n"
md += "\n"
return md
def _format_value(value: float, unit: str) -> str:
"""Formatta valore con unit appropriate"""
if unit == "EUR":
if value >= 1_000_000:
return f"€{value/1_000_000:.2f}M"
elif value >= 1_000:
return f"€{value/1_000:.1f}K"
else:
return f"€{value:.0f}"
elif unit == "%":
return f"{value:.1f}%"
elif unit in ["anni", "giocatori", "atleti", "squadre", "campi", "posti", "abbonati", "followers", "progetti", "persone", "FTE", "membri"]:
return f"{int(value)} {unit}"
else:
return f"{value} {unit}"
def _confidence_emoji(confidence_level: str) -> str:
"""Emoji per livello di confidenza"""
mapping = {
"high": "✅",
"medium": "⚠️",
"low": "❗",
"estimated": "📊"
}
return mapping.get(confidence_level.lower(), "❓")
|