from typing import Dict, List, Optional import pandas as pd def dataframe_to_html( df: pd.DataFrame, column_label_map: Optional[Dict[str, str]] = None, dimension_metrics: Optional[List[str]] = None, primary_metric: Optional[str] = None, ) -> str: if df.empty: return "
No data available
" column_label_map = column_label_map or {} dimension_metrics = dimension_metrics or [] headers = df.columns.tolist() html = """
""" for header in headers: display_header = column_label_map.get(header, header) if header == "Model": html += f'' elif header == "entry_type": html += f'' elif header == "Rank": html += f'' elif primary_metric and header == primary_metric: html += f'' elif header in dimension_metrics: html += f'' else: html += f"" html += """ """ for row_idx, (_, row) in enumerate(df.iterrows()): row_class = "even-row" if row_idx % 2 == 0 else "odd-row" html += f'' for col in headers: cell_value = row[col] if col == "Model": cell_class = "model-cell" elif col == "entry_type": cell_class = "entry-type-cell" elif col == "Rank": cell_class = "rank-cell" elif primary_metric and col == primary_metric: cell_class = "primary-metric-cell" elif col in dimension_metrics: cell_class = "dimension-metric-cell" else: cell_class = "regular-cell" cell_content = str(cell_value) if col == "Rank": rank_class = "" if cell_content == "1": rank_class = " rank-1" elif cell_content == "2": rank_class = " rank-2" elif cell_content == "3": rank_class = " rank-3" html += f'' elif col == "entry_type": entry_class = "" entry_lower = cell_content.lower() if "baseline" in entry_lower: entry_class = " baseline-entry" elif "submission" in entry_lower: entry_class = " competition-entry" html += f'' elif "**" in cell_content: html += f'' elif "" in cell_content: html += f'' else: html += f'' html += "" html += """
{display_header}{display_header}{display_header}{display_header}{display_header}{display_header}
{cell_content}{cell_content}{cell_content.replace("**", "")}{cell_content.replace("", "").replace("", "")}{cell_content}
""" return html def get_academic_css() -> str: return """ /* 艺术化标题样式 */ #title, .wa-title { text-align: center; font-size: 3.25em !important; margin-bottom: 40px !important; font-family: 'Segoe UI', 'Arial', sans-serif; font-weight: 900; letter-spacing: -0.5px; line-height: 1.06; padding: 36px 30px; border-radius: 15px; background: linear-gradient(145deg, #ffffff, #f5f7fa); box-shadow: 0 10px 40px rgba(41, 128, 185, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.8); position: relative; overflow: hidden; transition: all 0.3s ease; } #title:hover, .wa-title:hover { box-shadow: 0 15px 50px rgba(41, 128, 185, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.9); } #title h1, .wa-title h1 { margin: 0; padding: 0; background: linear-gradient( 90deg, #3498db 0%, #2ecc71 25%, #f1c40f 50%, #e74c3c 75%, #9b59b6 100% ); background-size: 400% 100%; -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; text-fill-color: transparent; animation: gradientShift 8s ease infinite; position: relative; z-index: 2; text-shadow: 2px 2px 0px rgba(0, 0, 0, 0.05), 4px 4px 0px rgba(0, 0, 0, 0.03); filter: drop-shadow(0 5px 15px rgba(52, 152, 219, 0.3)); } @keyframes gradientShift { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } } #title .subtitle, .wa-title .subtitle { font-size: 0.9em !important; color: #34495e; margin-top: 18px; font-weight: 600; display: block; line-height: 1.45; font-style: normal; max-width: 1080px; margin-left: auto; margin-right: auto; background: linear-gradient( 90deg, #e74c3c 0%, #f39c12 20%, #2ecc71 40%, #3498db 60%, #9b59b6 80%, #e74c3c 100% ); background-size: 300% 100%; -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; text-fill-color: transparent; animation: subtitleShift 10s ease infinite; padding: 12px 24px; border-radius: 8px; background-color: rgba(255, 255, 255, 0.9); box-shadow: inset 0 0 0 1px rgba(52, 152, 219, 0.1), 0 4px 12px rgba(0, 0, 0, 0.05); font-family: 'Georgia', 'Times New Roman', serif; text-transform: none; letter-spacing: 0.5px; } @keyframes subtitleShift { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } } #title::before, .wa-title::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 8px; background: linear-gradient(90deg, #3498db, #2ecc71, #f1c40f, #e74c3c, #9b59b6, #3498db); background-size: 400% 100%; animation: gradientShift 12s linear infinite; } #title::after, .wa-title::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: radial-gradient(circle at 10% 20%, rgba(52, 152, 219, 0.08) 0%, transparent 50%), radial-gradient(circle at 90% 80%, rgba(46, 204, 113, 0.08) 0%, transparent 50%), radial-gradient(circle at 50% 50%, rgba(155, 89, 182, 0.05) 0%, transparent 50%); pointer-events: none; z-index: 1; } #title .emoji, .wa-title .emoji { font-size: 1.2em; vertical-align: middle; margin-right: 15px; display: inline-block; background: linear-gradient( 90deg, #3498db 0%, #2ecc71 25%, #f1c40f 50%, #e74c3c 75%, #9b59b6 100% ); background-size: 400% 100%; -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; text-fill-color: transparent; animation: gradientShift 8s ease infinite, float 3s ease-in-out infinite; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1)); position: relative; z-index: 2; } @keyframes float { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-5px); } } .academic-table-container { margin: 20px 0; overflow-x: auto; border-radius: 12px; box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08); background: white; } .academic-table { width: 100%; border-collapse: collapse; font-family: 'Segoe UI', Arial, sans-serif; font-size: 14px; background: white; } .academic-table thead { background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); } .academic-table th { padding: 15px 12px; text-align: center; font-weight: 700; color: #2c3e50; border-bottom: 2px solid #dee2e6; border-right: 1px solid #e9ecef; white-space: nowrap; } .academic-table th:last-child { border-right: none; } .academic-table td { padding: 12px 10px; text-align: center; border-bottom: 1px solid #f1f3f4; border-right: 1px solid #f8f9fa; transition: background-color 0.2s ease; } .academic-table td:last-child { border-right: none; } .academic-table tbody tr:hover { background-color: #f8f9ff !important; } .academic-table tbody tr.even-row { background-color: #ffffff; } .academic-table tbody tr.odd-row { background-color: #fafbfc; } .model-header, .model-cell { text-align: left !important; min-width: 200px; font-weight: 600; } .entry-type-header, .entry-type-cell { min-width: 160px; text-align: center !important; white-space: nowrap; } .entry-type-cell { font-weight: 700; } .entry-type-cell.baseline-entry { color: #8e5a00; background-color: #fff7e6; } .entry-type-cell.competition-entry { color: #0b5d3b; background-color: #eafaf1; } .rank-header, .rank-cell { width: 80px; font-weight: 700; color: #495057; } .rank-cell.rank-1 { color: #e67e22; font-weight: 800; font-size: 15px; } .rank-cell.rank-2 { color: #95a5a6; font-weight: 700; font-size: 14px; } .rank-cell.rank-3 { color: #d35400; font-weight: 700; font-size: 14px; } .primary-metric { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; color: white !important; font-weight: 800; } .primary-metric-cell { background-color: rgba(102, 126, 234, 0.06); font-weight: 700; color: #5a67d8; } .dimension-metric-header { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%) !important; color: white !important; font-weight: 700; } .dimension-metric-cell { background-color: rgba(79, 172, 254, 0.05); color: #3182ce; font-weight: 600; } .best-score { font-weight: 800 !important; color: #27ae60 !important; background-color: #eafaf1 !important; position: relative; } .best-score::after { content: "🏆"; position: absolute; right: 5px; top: 50%; transform: translateY(-50%); font-size: 10px; } .second-best { color: #f39c12 !important; background-color: #fef9e7 !important; font-weight: 700 !important; text-decoration: underline; text-decoration-color: #f39c12; text-decoration-thickness: 2px; text-underline-offset: 2px; } .no-data, .placeholder { padding: 40px; text-align: center; color: #6c757d; font-size: 16px; font-style: italic; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 12px; border: 2px dashed #dee2e6; } @media (max-width: 1200px) { #title, .wa-title { font-size: 2.7em !important; padding: 30px 24px; } #title .subtitle, .wa-title .subtitle { font-size: 0.8em !important; } } @media (max-width: 768px) { #title, .wa-title { font-size: 2.1em !important; padding: 24px 18px; } #title .subtitle, .wa-title .subtitle { font-size: 0.72em !important; padding: 10px 16px; } } """