""" 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"
Errore nella conversione: {str(e)}
" # 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 "Sezione non disponibile
" 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:** {dp.deviation:+.1f}%\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 = ''' ? Cos'è l'Affidabilità ? Indica quanto sono attendibili i dati: