JiuTianDataAgent/NL2SQL
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>NL2SQL Leaderboard</title>7 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">8 <style>9 * {10 margin: 0;11 padding: 0;12 box-sizing: border-box;13 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;14 }15 16 body {17 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);18 min-height: 100vh;19 padding: 20px;20 }21 22 .container {23 max-width: 1400px;24 margin: 0 auto;25 background: #f8fafc;26 border-radius: 20px;27 box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);28 overflow: hidden;29 }30 31 header {32 background: linear-gradient(to right, #1e40af, #3b82f6);33 color: white;34 padding: 30px 40px;35 text-align: center;36 }37 38 h1 {39 font-size: 2.8rem;40 margin-bottom: 10px;41 font-weight: 800;42 }43 44 .subtitle {45 font-size: 1.2rem;46 opacity: 0.9;47 margin-bottom: 20px;48 }49 50 .tabs {51 display: flex;52 background: rgba(255, 255, 255, 0.1);53 border-radius: 12px;54 padding: 5px;55 margin: 20px auto 0;56 max-width: 800px;57 }58 59 .tab {60 flex: 1;61 padding: 15px;62 text-align: center;63 font-weight: 600;64 font-size: 1.1rem;65 cursor: pointer;66 border-radius: 8px;67 transition: all 0.3s ease;68 }69 70 .tab:hover {71 background: rgba(255, 255, 255, 0.2);72 }73 74 .tab.active {75 background: white;76 color: #3b82f6;77 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);78 }79 80 main {81 padding: 30px;82 }83 84 .controls {85 background: white;86 padding: 30px;87 border-radius: 12px;88 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);89 margin-bottom: 30px;90 }91 92 .dataset-selector {93 margin-bottom: 30px;94 padding-bottom: 30px;95 border-bottom: 1px solid #e2e8f0;96 }97 98 .metric-selector {99 margin-bottom: 20px;100 }101 102 .dataset-label, .metric-label {103 font-weight: 600;104 color: #475569;105 font-size: 1.1rem;106 margin-bottom: 15px;107 display: flex;108 align-items: center;109 gap: 10px;110 }111 112 .dataset-label i, .metric-label i {113 color: #3b82f6;114 }115 116 .dataset-buttons {117 display: flex;118 flex-wrap: wrap;119 gap: 10px;120 }121 122 .dataset-btn {123 padding: 12px 24px;124 background: white;125 border: 2px solid #cbd5e1;126 border-radius: 8px;127 font-weight: 600;128 color: #475569;129 cursor: pointer;130 transition: all 0.2s ease;131 }132 133 .dataset-btn:hover {134 background: #f1f5f9;135 transform: translateY(-2px);136 }137 138 .dataset-btn.active {139 background: #3b82f6;140 color: white;141 border-color: #3b82f6;142 box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);143 }144 145 .metric-checkboxes {146 display: grid;147 grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));148 gap: 15px;149 margin-top: 10px;150 }151 152 .metric-checkbox {153 display: flex;154 align-items: center;155 gap: 12px;156 padding: 10px 15px;157 background: #f8fafc;158 border-radius: 8px;159 transition: all 0.2s ease;160 border: 1px solid #e2e8f0;161 }162 163 .metric-checkbox:hover {164 background: #f1f5f9;165 transform: translateY(-2px);166 box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);167 }168 169 .metric-checkbox input {170 width: 18px;171 height: 18px;172 cursor: pointer;173 accent-color: #3b82f6;174 }175 176 .metric-checkbox label {177 font-weight: 500;178 color: #475569;179 cursor: pointer;180 font-size: 0.95rem;181 flex: 1;182 }183 184 .metric-hint {185 font-size: 0.85rem;186 color: #64748b;187 margin-top: 5px;188 font-style: italic;189 }190 191 .table-container {192 overflow-x: auto;193 border-radius: 12px;194 box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);195 background: white;196 margin-bottom: 30px;197 }198 199 table {200 width: 100%;201 border-collapse: collapse;202 min-width: 1200px;203 }204 205 th {206 background: linear-gradient(to right, #1e40af, #3b82f6);207 color: white;208 text-align: left;209 padding: 18px 20px;210 font-weight: 600;211 font-size: 1.1rem;212 position: sticky;213 top: 0;214 }215 216 th.algorithm-header {217 min-width: 200px;218 }219 220 td {221 padding: 16px 20px;222 border-bottom: 1px solid #e2e8f0;223 font-size: 1rem;224 }225 226 tr:hover {227 background: #f8fafc;228 }229 230 tr:nth-child(even) {231 background: #f8fafc;232 }233 234 tr:nth-child(even):hover {235 background: #f1f5f9;236 }237 238 .algorithm-name {239 font-weight: 600;240 color: #1e293b;241 font-size: 1.1rem;242 }243 244 .metric-value {245 font-weight: 600;246 color: #0f172a;247 text-align: center;248 }249 250 .highlight {251 background: linear-gradient(120deg, #f0f9ff 0%, #e0f2fe 100%);252 border-left: 4px solid #0ea5e9;253 }254 255 .best-value {256 background: linear-gradient(120deg, #dcfce7 0%, #bbf7d0 100%);257 font-weight: 700;258 color: #166534;259 position: relative;260 }261 262 .best-value::after {263 content: "🏆";264 position: absolute;265 right: 5px;266 top: 50%;267 transform: translateY(-50%);268 font-size: 0.9rem;269 }270 271 .no-data {272 text-align: center;273 padding: 60px 20px;274 color: #64748b;275 font-size: 1.2rem;276 }277 278 .no-data i {279 font-size: 3rem;280 margin-bottom: 20px;281 opacity: 0.5;282 }283 284 /* Submit Data Styles */285 .submit-container {286 padding: 40px;287 text-align: center;288 background: white;289 border-radius: 12px;290 box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);291 margin-bottom: 30px;292 }293 294 .submit-icon {295 font-size: 5rem;296 color: #cbd5e1;297 margin-bottom: 20px;298 }299 300 .submit-title {301 font-size: 2.5rem;302 color: #64748b;303 margin-bottom: 15px;304 }305 306 .submit-description {307 font-size: 1.2rem;308 color: #94a3b8;309 max-width: 600px;310 margin: 0 auto 30px;311 line-height: 1.6;312 }313 314 .coming-soon {315 display: inline-block;316 background: #f1f5f9;317 color: #64748b;318 padding: 10px 25px;319 border-radius: 30px;320 font-weight: 600;321 font-size: 1.1rem;322 }323 324 .submit-form {325 max-width: 600px;326 margin: 30px auto;327 background: #f8fafc;328 padding: 25px;329 border-radius: 12px;330 text-align: left;331 }332 333 .form-group {334 margin-bottom: 20px;335 }336 337 .form-group label {338 display: block;339 font-weight: 600;340 color: #475569;341 margin-bottom: 8px;342 }343 344 .form-group input,345 .form-group select,346 .form-group textarea {347 width: 100%;348 padding: 12px;349 border: 2px solid #cbd5e1;350 border-radius: 8px;351 font-size: 1rem;352 transition: border-color 0.2s ease;353 }354 355 .form-group input:focus,356 .form-group select:focus,357 .form-group textarea:focus {358 outline: none;359 border-color: #3b82f6;360 }361 362 .submit-btn {363 background: #3b82f6;364 color: white;365 border: none;366 padding: 12px 30px;367 border-radius: 8px;368 font-weight: 600;369 font-size: 1.1rem;370 cursor: pointer;371 transition: all 0.2s ease;372 }373 374 .submit-btn:hover {375 background: #2563eb;376 transform: translateY(-2px);377 box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);378 }379 380 /* Footer */381 footer {382 text-align: center;383 padding: 20px;384 color: #94a3b8;385 font-size: 0.9rem;386 border-top: 1px solid #e2e8f0;387 margin-top: 30px;388 }389 390 .controls-header {391 display: flex;392 justify-content: space-between;393 align-items: center;394 margin-bottom: 25px;395 padding-bottom: 15px;396 border-bottom: 1px solid #e2e8f0;397 }398 399 .controls-title {400 font-size: 1.4rem;401 color: #1e293b;402 font-weight: 700;403 }404 405 .reset-btn {406 background: #f1f5f9;407 color: #475569;408 border: 1px solid #cbd5e1;409 padding: 8px 16px;410 border-radius: 6px;411 font-weight: 500;412 cursor: pointer;413 transition: all 0.2s ease;414 }415 416 .reset-btn:hover {417 background: #e2e8f0;418 }419 420 /* Responsive */421 @media (max-width: 768px) {422 .container {423 border-radius: 10px;424 }425 426 h1 {427 font-size: 2rem;428 }429 430 .tab {431 padding: 12px 15px;432 font-size: 1rem;433 }434 435 .controls {436 padding: 20px;437 }438 439 .metric-checkboxes {440 grid-template-columns: 1fr;441 }442 443 th, td {444 padding: 12px 15px;445 }446 447 .submit-container {448 padding: 20px;449 }450 451 .submit-title {452 font-size: 1.8rem;453 }454 455 .controls-header {456 flex-direction: column;457 align-items: flex-start;458 gap: 10px;459 }460 461 .reset-btn {462 align-self: flex-end;463 }464 }465 </style>466</head>467<body>468 <div class="container">469 <header>470 <h1>NL2SQL Leaderboard</h1>471 <div class="subtitle">Benchmarking Natural Language to SQL Conversion Models and Agents</div>472 <div class="tabs">473 <div class="tab active" onclick="switchTab('leaderboard')">Leaderboard</div>474 <div class="tab" onclick="switchTab('submit')">Submit Results</div>475 <div class="tab" onclick="switchTab('about')">About</div>476 </div>477 </header>478 479 <main id="leaderboard-content">480 <div class="controls">481 <div class="controls-header">482 <div class="controls-title">483 <i class="fas fa-sliders-h"></i> Filter Controls484 </div>485 <button class="reset-btn" onclick="resetFilters()">486 <i class="fas fa-redo"></i> Reset Filters487 </button>488 </div>489 490 <div class="dataset-selector">491 <div class="dataset-label">492 <i class="fas fa-database"></i>493 Select Dataset494 </div>495 <div class="dataset-buttons" id="dataset-buttons">496 <!-- 动态生成数据集按钮 -->497 </div>498 </div>499 500 <div class="metric-selector">501 <div class="metric-label">502 <i class="fas fa-chart-bar"></i>503 Select Metrics to Display504 </div>505 <div class="metric-checkboxes" id="metric-checkboxes">506 <!-- 动态生成指标复选框 -->507 </div>508 <div class="metric-hint">509 Tip: Click on metrics to show/hide them in the table. The best value for each metric is highlighted with a 🏆. Metrics Precision/Recall/F1 are calculated only among the sqls that are executable.510 </div>511 </div>512 </div>513 514 <div class="table-container">515 <table id="leaderboard-table">516 <thead>517 <tr id="table-header">518 <!-- 动态生成表头 -->519 </tr>520 </thead>521 <tbody id="table-body">522 <!-- 动态生成表格内容 -->523 </tbody>524 </table>525 </div>526 527 <div class="no-data" id="no-data-message" style="display: none;">528 <i class="fas fa-database"></i>529 <h3>No Data Available</h3>530 <p>This dataset currently has no results. Be the first to submit!</p>531 <button class="submit-btn" onclick="switchTab('submit')" style="margin-top: 20px;">532 <i class="fas fa-cloud-upload-alt"></i> Submit Results533 </button>534 </div>535 </main>536 537 <div id="submit-content" style="display: none;">538 <div class="submit-container">539 <div class="submit-icon">540 <i class="fas fa-cloud-upload-alt"></i>541 </div>542 <h2 class="submit-title">Submit Your Results</h2>543 <p class="submit-description">544 Submit your NL2SQL model results to be included in the leaderboard. 545 Please ensure your results follow the required format.546 </p>547 <div class="coming-soon">548 <i class="fas fa-tools"></i> Submission Portal Under Development549 </div>550 551 <div class="submit-form">552 <div class="form-group">553 <label for="dataset-select"><i class="fas fa-database"></i> Select Dataset</label>554 <select id="dataset-select" class="dataset-select">555 <option value="birddev">BIRD Dev</option>556 <option value="birdtrain">BIRD Train</option>557 <option value="spider">Spider</option>558 </select>559 </div>560 561 <div class="form-group">562 <label for="algorithm-name"><i class="fas fa-robot"></i> Algorithm/Model Name</label>563 <input type="text" id="algorithm-name" placeholder="Enter your algorithm name">564 </div>565 566 <div class="form-group">567 <label for="results-json"><i class="fas fa-code"></i> Results (JSON format)</label>568 <textarea id="results-json" rows="6" placeholder='{569 "execution_ability": 0.85,570 "correct_rate": 0.78,571 "execution_efficiency_on_executable_sql": 0.92,572 "table_precision_on_executable_sql": 0.87,573 "table_recall_on_executable_sql": 0.85,574 "table_f1_on_executable_sql": 0.86,575 "column_precision_on_executable_sql": 0.83,576 "column_recall_on_executable_sql": 0.80,577 "column_f1_on_executable_sql": 0.815578}'></textarea>579 </div>580 581 <div style="text-align: center;">582 <button class="submit-btn" onclick="submitResults()">583 <i class="fas fa-paper-plane"></i> Submit Results (Demo)584 </button>585 </div>586 </div>587 </div>588 </div>589 590 <div id="about-content" style="display: none;">591 <div class="submit-container">592 <h2 class="submit-title">About NL2SQL Leaderboard</h2>593 <p class="submit-description">594 This leaderboard tracks the performance of various Natural Language to SQL (NL2SQL) models 595 across multiple benchmarks and metrics.596 </p>597 598 <div style="text-align: left; max-width: 800px; margin: 40px auto;">599 <h3 style="color: #475569; margin-bottom: 15px;">Metrics Explained:</h3>600 <ul style="list-style-type: none; padding: 0;">601 <li style="margin-bottom: 10px; padding: 10px; background: #f1f5f9; border-radius: 6px;">602 <strong>Execution Ability:</strong> Ability to generate executable SQL queries603 </li>604 <li style="margin-bottom: 10px; padding: 10px; background: #f1f5f9; border-radius: 6px;">605 <strong>Correct Rate:</strong> Percentage of correctly generated SQL queries606 </li>607 <li style="margin-bottom: 10px; padding: 10px; background: #f1f5f9; border-radius: 6px;">608 <strong>Execution Efficiency:</strong> Performance on executable SQL queries609 </li>610 <li style="margin-bottom: 10px; padding: 10px; background: #f1f5f9; border-radius: 6px;">611 <strong>Table/Column Precision/Recall/F1:</strong> Accuracy in selecting correct tables and columns when the sql is executable612 </li>613 </ul>614 615 <h3 style="color: #475569; margin-top: 30px; margin-bottom: 15px;">Supported Datasets:</h3>616 <ul style="list-style-type: none; padding: 0;">617 <li style="margin-bottom: 10px; padding: 10px; background: #f1f5f9; border-radius: 6px;">618 <strong>BIRD Dev:</strong> Benchmark for large-scale database tasks in the real world619 </li>620 <li style="margin-bottom: 10px; padding: 10px; background: #f1f5f9; border-radius: 6px;">621 <strong>BIRD Train:</strong> Training set for BIRD benchmark622 </li>623 <li style="margin-bottom: 10px; padding: 10px; background: #f1f5f9; border-radius: 6px;">624 <strong>Spider:</strong> Large-scale complex and cross-domain semantic parsing and text-to-SQL dataset625 </li>626 </ul>627 </div>628 </div>629 </div>630 631 <footer>632 <p>NL2SQL Leaderboard • Last Updated: <span id="last-updated">Loading...</span></p>633 <p style="margin-top: 5px; font-size: 0.8rem;">634 <i class="fas fa-code"></i> Built with FastAPI • 635 <i class="fas fa-server"></i> Docker Ready • 636 <i class="fas fa-chart-line"></i> Real-time Updates637 </p>638 </footer>639 </div>640 641 <script>642 let currentDataset = 'birddev';643 let datasets = {};644 let selectedMetrics = new Set();645 let datasetMetrics = {};646 647 // 页面加载时获取数据648 document.addEventListener('DOMContentLoaded', async function() {649 await loadLeaderboardData();650 updateLastUpdated();651 });652 653 // 加载排行榜数据654 async function loadLeaderboardData() {655 try {656 const response = await fetch('/api/data');657 const data = await response.json();658 datasets = data.datasets;659 660 // 为每个数据集存储指标661 for (const [key, dataset] of Object.entries(datasets)) {662 datasetMetrics[key] = dataset.metrics;663 }664 665 // 初始化数据集选择按钮666 initDatasetButtons();667 668 // 显示当前数据集669 showDataset(currentDataset);670 671 } catch (error) {672 console.error('Error loading data:', error);673 alert('Failed to load leaderboard data');674 }675 }676 677 // 更新最后更新时间678 async function updateLastUpdated() {679 try {680 const response = await fetch('/api/data');681 const data = await response.json();682 const date = new Date(data.last_updated);683 document.getElementById('last-updated').textContent = 684 date.toLocaleString();685 } catch (error) {686 console.error('Error updating timestamp:', error);687 }688 }689 690 // 初始化数据集按钮691 function initDatasetButtons() {692 const container = document.getElementById('dataset-buttons');693 container.innerHTML = '';694 695 for (const [key, dataset] of Object.entries(datasets)) {696 const button = document.createElement('button');697 button.className = `dataset-btn ${key === currentDataset ? 'active' : ''}`;698 button.textContent = dataset.name; // 移除了图标699 button.onclick = () => {700 currentDataset = key;701 showDataset(key);702 updateDatasetButtons();703 };704 container.appendChild(button);705 }706 }707 708 // 更新数据集按钮状态709 function updateDatasetButtons() {710 const buttons = document.querySelectorAll('.dataset-btn');711 buttons.forEach(button => {712 // 移除所有active类713 button.classList.remove('active');714 715 // 找到对应的数据集键716 const buttonText = button.textContent.toLowerCase().replace(/\s+/g, '');717 let foundKey = null;718 for (const [key, dataset] of Object.entries(datasets)) {719 if (dataset.name.toLowerCase().replace(/\s+/g, '').includes(buttonText.replace(/icon/g, ''))) {720 foundKey = key;721 break;722 }723 }724 if (foundKey === currentDataset) {725 button.classList.add('active');726 }727 });728 }729 730 // 显示指定数据集731 function showDataset(datasetKey) {732 const dataset = datasets[datasetKey];733 if (!dataset) return;734 735 // 初始化指标选择(如果这是第一次显示这个数据集)736 if (!selectedMetrics.size || !Array.from(selectedMetrics).some(m => dataset.metrics.includes(m))) {737 // 重置为选中所有指标738 selectedMetrics = new Set(dataset.metrics || []);739 }740 741 // 更新指标复选框742 updateMetricCheckboxes(datasetKey);743 744 // 更新表格745 updateTable(dataset);746 747 // 显示/隐藏无数据消息748 const noDataMsg = document.getElementById('no-data-message');749 if (dataset.algorithms.length === 0) {750 noDataMsg.style.display = 'block';751 document.querySelector('.table-container').style.display = 'none';752 } else {753 noDataMsg.style.display = 'none';754 document.querySelector('.table-container').style.display = 'block';755 }756 }757 758 // 更新指标复选框759 function updateMetricCheckboxes(datasetKey) {760 const container = document.getElementById('metric-checkboxes');761 container.innerHTML = '';762 763 const metrics = datasetMetrics[datasetKey] || [];764 765 metrics.forEach(metric => {766 const checkbox = document.createElement('div');767 checkbox.className = 'metric-checkbox';768 769 const inputId = `metric-${metric}`;770 const isChecked = selectedMetrics.has(metric);771 772 checkbox.innerHTML = `773 <input type="checkbox" id="${inputId}" ${isChecked ? 'checked' : ''} 774 onchange="toggleMetric('${metric}', this.checked)">775 <label for="${inputId}">${formatMetricName(metric)}</label> <!-- 移除了图标 -->776 `;777 container.appendChild(checkbox);778 });779 }780 781 // 切换指标显示782 function toggleMetric(metric, isChecked) {783 if (isChecked) {784 selectedMetrics.add(metric);785 } else {786 selectedMetrics.delete(metric);787 }788 789 // 重新显示当前数据集(会刷新表格)790 showDataset(currentDataset);791 }792 793 // 格式化指标名称794 function formatMetricName(metric) {795 // 先替换_on_executable_sql796 let name = metric.replace(/_on_executable_sql/g, '');797 // 将下划线替换为空格798 name = name.replace(/_/g, ' ');799 // 首字母大写800 name = name.replace(/\b\w/g, l => l.toUpperCase());801 return name;802 }803 804 // 重置过滤器805 function resetFilters() {806 // 重置为默认数据集807 currentDataset = 'birddev';808 809 // 重置指标选择810 const dataset = datasets[currentDataset];811 selectedMetrics = new Set(dataset.metrics || []);812 813 // 更新显示814 showDataset(currentDataset);815 updateDatasetButtons();816 }817 818 // 切换标签页(如果需要,也可以移除控制面板标题中的图标)819 function switchTab(tabName) {820 // 更新标签页状态821 document.querySelectorAll('.tab').forEach(tab => {822 tab.classList.toggle('active', tab.textContent.toLowerCase().includes(tabName));823 });824 825 // 显示对应的内容826 document.getElementById('leaderboard-content').style.display = 827 tabName === 'leaderboard' ? 'block' : 'none';828 document.getElementById('submit-content').style.display = 829 tabName === 'submit' ? 'block' : 'none';830 document.getElementById('about-content').style.display = 831 tabName === 'about' ? 'block' : 'none';832 }833 834 // 更新表格835 function updateTable(dataset) {836 const algorithms = dataset.algorithms;837 const metrics = dataset.metrics || [];838 839 // 更新表头840 updateTableHeader(metrics);841 842 // 更新表格内容843 updateTableBody(algorithms, metrics);844 }845 846 // 更新表头847 function updateTableHeader(metrics) {848 const header = document.getElementById('table-header');849 header.innerHTML = '<th class="algorithm-header">Algorithm</th>'; // 移除了图标850 851 // 只添加选中的指标852 metrics.forEach(metric => {853 if (selectedMetrics.has(metric)) {854 header.innerHTML += `<th>${formatMetricName(metric)}</th>`; // 移除了图标855 }856 });857 }858 859 // 更新表格内容860 function updateTableBody(algorithms, metrics) {861 const tbody = document.getElementById('table-body');862 tbody.innerHTML = '';863 864 if (algorithms.length === 0) return;865 866 // 计算每个指标的最佳值867 const bestValues = {};868 metrics.forEach(metric => {869 if (selectedMetrics.has(metric)) {870 const values = algorithms.map(a => a[metric] || 0);871 bestValues[metric] = Math.max(...values);872 }873 });874 875 // 填充数据行876 algorithms.forEach(algorithm => {877 const row = document.createElement('tr');878 let rowHtml = `<td class="algorithm-name">${algorithm.name}</td>`; // 移除了图标879 880 metrics.forEach(metric => {881 if (selectedMetrics.has(metric)) {882 const value = algorithm[metric];883 const isBest = value === bestValues[metric] && value !== undefined;884 const cellClass = isBest ? 'metric-value best-value' : 'metric-value';885 const displayValue = value !== undefined ? value.toFixed(3) : 'N/A';886 rowHtml += `<td class="${cellClass}">${displayValue}</td>`;887 }888 });889 890 row.innerHTML = rowHtml;891 tbody.appendChild(row);892 });893 }894 895 // 每30秒刷新数据896 setInterval(updateLastUpdated, 30000);897 </script>898</body>899</html>