Spaces:
Sleeping
Sleeping
File size: 6,503 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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | """
Rooting Future - Content Formatter v1.0
Converts markdown content to styled HTML for webapp viewer
"""
import re
import markdown
from typing import Dict, Any
import logging
logger = logging.getLogger(__name__)
class ContentFormatter:
"""Formatta contenuti piano strategico per webapp"""
@staticmethod
def format_section_content(content: str) -> str:
"""
Converte markdown in HTML formattato con:
- Headers con anchor links
- Bullet points stilizzati
- Callout boxes per info importanti
- Code blocks con syntax highlighting
- Keyword badges
"""
if not content:
return '<p class="empty-section">Sezione non disponibile</p>'
# Strip whitespace
content = content.strip()
if len(content) < 20:
return '<p class="empty-section">Sezione non disponibile</p>'
try:
# Convert markdown to HTML with extensions
html = markdown.markdown(
content,
extensions=[
'extra', # Tables, fenced code, etc.
'codehilite', # Syntax highlighting
'toc', # Table of contents
'tables', # GitHub-style tables
'nl2br', # Newline to <br>
]
)
# Add custom styling enhancements
html = ContentFormatter._enhance_html(html)
logger.debug(f"[FORMATTER] Formatted content: {len(content)} chars -> {len(html)} chars HTML")
return html
except Exception as e:
logger.error(f"[FORMATTER] Error formatting content: {e}")
# Fallback: wrap in paragraph tags
return f'<p>{content}</p>'
@staticmethod
def _enhance_html(html: str) -> str:
"""Aggiunge classi CSS custom per styling avanzato"""
# 1. Highlight priority headers (### PRIORITÀ, ### OBIETTIVI, etc.)
html = re.sub(
r'<h3>(PRIORITÀ|OBIETTIVI|QUICK WINS|TOP \d+|MACRO \d+|STRATEGIA|PILASTRI|AZIONI)(.*?)</h3>',
r'<h3 class="priority-header"><span class="badge-priority">\1</span>\2</h3>',
html,
flags=re.IGNORECASE
)
# 2. Style all bullet lists
html = html.replace('<ul>', '<ul class="styled-list">')
# 3. Style ordered lists
html = html.replace('<ol>', '<ol class="styled-ordered-list">')
# 4. Add emoji icons to specific keywords
html = ContentFormatter._add_emoji_icons(html)
# 5. Create callout boxes for h4 subsections
html = re.sub(
r'<h4>(.*?)</h4>',
r'<h4 class="subsection-header">\1</h4>',
html
)
# 6. Enhance h2 headers
html = re.sub(
r'<h2>(.*?)</h2>',
r'<h2 class="section-h2">\1</h2>',
html
)
# 7. Create callout boxes for important notes
# Match patterns like "NOTA:", "IMPORTANTE:", "ATTENZIONE:"
html = re.sub(
r'<p>(NOTA|IMPORTANTE|ATTENZIONE|NOTA BENE|NB):\s*(.*?)</p>',
r'<div class="callout">\1: \2</div>',
html,
flags=re.IGNORECASE
)
return html
@staticmethod
def _add_emoji_icons(html: str) -> str:
"""Aggiunge emoji icons a keyword specifiche"""
replacements = {
# Categorie principali
'SPORTIVI': '⚽',
'STRUTTURALI': '🏗️',
'MARKETING': '📢',
'COMMERCIALE': '💼',
'SOCIALI': '🤝',
'FINANZIARI': '💰',
'TECNICI': '⚙️',
# Timeline
'ANNO 1': '1️⃣',
'ANNO 2': '2️⃣',
'ANNO 3': '3️⃣',
'BREVE TERMINE': '⚡',
'MEDIO TERMINE': '📅',
'LUNGO TERMINE': '🎯',
# Priorità
'QUICK WINS': '⚡',
'PRIORITÀ': '🎯',
'URGENTE': '🚨',
'ALTA': '🔴',
'MEDIA': '🟡',
'BASSA': '🟢',
# Settori
'GIOVANILE': '🌱',
'PRIMA SQUADRA': '⭐',
'INFRASTRUTTURE': '🏗️',
'GOVERNANCE': '⚖️',
}
for keyword, emoji in replacements.items():
# Replace in strong tags
html = re.sub(
rf'<strong>({keyword})</strong>',
rf'<span class="keyword-badge">{emoji} <strong>\1</strong></span>',
html,
flags=re.IGNORECASE
)
# Replace in plain text at start of paragraphs
html = re.sub(
rf'<p>({keyword}):',
rf'<p><span class="keyword-badge">{emoji} <strong>\1</strong></span>:',
html,
flags=re.IGNORECASE
)
return html
@staticmethod
def extract_key_metrics(content: str) -> Dict[str, Any]:
"""Estrae metriche chiave dal contenuto per dashboard"""
if not content:
return {}
metrics = {}
try:
# Estrai percentuali (es. "97.5%", "20%")
percentages = re.findall(r'(\d+(?:\.\d+)?%)', content)
if percentages:
metrics['percentages'] = percentages[:5]
# Estrai valori monetari (es. "€50K", "€1.2M")
money = re.findall(r'€\s?(\d+(?:\.\d+)?[KM]?)', content, re.IGNORECASE)
if money:
metrics['financial'] = money[:5]
# Conta priorità/obiettivi
priorities = len(re.findall(r'MACRO \d+|PRIORITÀ \d+|OBIETTIVO \d+', content, re.IGNORECASE))
if priorities:
metrics['priorities_count'] = priorities
# Estrai numeri importanti (es. "15 progetti", "3 anni")
numbers = re.findall(r'\b(\d+)\s+(progetti|obiettivi|anni|mesi|settimane)', content, re.IGNORECASE)
if numbers:
metrics['key_numbers'] = [(num, unit) for num, unit in numbers[:5]]
except Exception as e:
logger.error(f"[FORMATTER] Error extracting metrics: {e}")
return metrics
# Utility function for quick formatting
def format_plan_section(content: str) -> str:
"""Quick utility to format a single section"""
formatter = ContentFormatter()
return formatter.format_section_content(content)
|