from __future__ import annotations import html import json from typing import Any # ========================================== # HELPER: ENTERPRISE REPORT RENDERER # ========================================== def render_plan_html(result: Any) -> str: """ Renders the analysis payload into a High-Contrast Enterprise Grid. """ # --- INTERNAL CSS FOR THE REPORT --- # (CSS remains unchanged to preserve the requested theme) css = """ """ if result is None: return f"{css}
// WAITING FOR ANALYSIS DATA
" # Ensure data is dict; handle string inputs gracefully data = result if not isinstance(data, dict): try: data = json.loads(str(result)) except (json.JSONDecodeError, TypeError): # Fallback for non-JSON strings return f"{css}
{html.escape(str(result))}
" project_name = html.escape(str(data.get("project_name", "UNDEFINED PROJECT")).upper()) team = data.get("team", []) # --- CALCULATE AGGREGATE STATS --- total_cost = 0.0 max_duration = 0.0 for member in team: member_cost = 0.0 member_duration = 0.0 for plan in member.get("training_plan", []): try: member_cost += float(plan.get("cost", 0)) member_duration += float(plan.get("duration_hours", 0)) except (ValueError, TypeError): continue total_cost += member_cost # Parallel training assumption: Project duration is limited by the person with the longest plan if member_duration > max_duration: max_duration = member_duration # --- BUILD HTML --- html_parts = [css, "
"] # --- MAIN HEADER --- html_parts.append(f"""

CAPABILITY ANALYSIS REPORT

PROJECT: {project_name}
STATUS: ACTIVE
HEADCOUNT: {len(team)}
""") # --- OVERALL STATS BAR --- html_parts.append(f"""
Total Budget
${total_cost:,.2f}
Est. Timeline
{max_duration:.0f} HRS (CONCURRENT)
Team Size
{len(team)}
""") html_parts.append("
") for member in team: name = html.escape(str(member.get("employee_name", "UNKNOWN")).upper()) role = html.escape(str(member.get("role", "UNASSIGNED")).upper()) # --- SKILL GAPS --- skills_html = "" gaps_list = member.get("skills_gaps", []) if gaps_list: skill_tags = "" for gap_data in gaps_list: skill_name = html.escape(gap_data.get("skill", "GENERIC")) skill_tags += f"""
{skill_name}
""" skills_html = f"""
⚠ SKILL GAP IDENTIFIED
{skill_tags}
""" else: skills_html = """
SKILLS VERIFIED. NO GAPS.
""" # --- TRAINING PLAN --- training_html = "" for plan in member.get("training_plan", []): title = html.escape(plan.get("title", "Training Module")) cost = float(plan.get("cost", 0)) hours = float(plan.get("duration_hours", 0)) # Investment Level Logic inv_class = "inv-low" if cost > 50: inv_class = "inv-med" if cost > 200: inv_class = "inv-high" training_html += f"""
{title}
COST: ${cost} | DURATION: {hours} HRS
""" if not training_html and gaps_list: training_html = "
PENDING: CURRICULUM GENERATION REQUIRED
" elif not training_html: training_html = "
NO ACTION REQUIRED
" # Assemble Card # Create a faux Employee ID emp_hash = f"EMP-{hash(name) % 99999:05d}" card_html = f"""
{role}
{name}
{emp_hash}
{skills_html}
RECOMMENDED TRAINING
{training_html}
""" html_parts.append(card_html) html_parts.append("
") html_parts.append("
") # Close sec-report-wrapper return "".join(html_parts)