Lyyyy1818 commited on
Commit
ad0d245
·
verified ·
1 Parent(s): 1870e89

Upload 7 files

Browse files
Files changed (7) hide show
  1. .gitignore +1 -0
  2. Dockerfile +36 -0
  3. README.md +9 -13
  4. data.json +88 -0
  5. index.html +899 -0
  6. requirements.txt +8 -0
  7. server.py +225 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ __pycache__
Dockerfile ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # --- Base image ---
2
+ FROM python:3.11-slim
3
+
4
+ ENV PYTHONDONTWRITEBYTECODE=1 \
5
+ PYTHONUNBUFFERED=1 \
6
+ PIP_NO_CACHE_DIR=on
7
+
8
+ # OS deps (git useful for HF repos; curl for HEALTHCHECK)
9
+ RUN apt-get update && apt-get install -y --no-install-recommends \
10
+ git curl && \
11
+ rm -rf /var/lib/apt/lists/*
12
+
13
+ # Non-root user
14
+ RUN useradd -m -u 1000 user
15
+ USER user
16
+ ENV PATH="/home/user/.local/bin:$PATH"
17
+
18
+ WORKDIR /app
19
+
20
+ # Python deps
21
+ COPY --chown=user ./requirements.txt requirements.txt
22
+ RUN pip install --upgrade pip && pip install -r requirements.txt
23
+
24
+ # App source
25
+ COPY --chown=user . /app
26
+
27
+ EXPOSE 7860
28
+
29
+ # Healthcheck pings your FastAPI health endpoint
30
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
31
+ CMD curl -fsS http://localhost:7860/api/health || exit 1
32
+
33
+ # Production server (Gunicorn + Uvicorn worker)
34
+ #CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
35
+
36
+ CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "-w", "2", "-b", "0.0.0.0:7860", "server:app"]
README.md CHANGED
@@ -1,13 +1,9 @@
1
- ---
2
- title: NL2SQL
3
- emoji:
4
- colorFrom: yellow
5
- colorTo: red
6
- sdk: gradio
7
- sdk_version: 6.2.0
8
- app_file: app.py
9
- pinned: false
10
- license: apache-2.0
11
- ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ ---
2
+ title: Table_discovery
3
+ emoji: 📈
4
+ colorFrom: red
5
+ colorTo: blue
6
+ sdk: docker
7
+ pinned: false
8
+ ---
9
+
 
 
 
 
data.json ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "datasets": {
3
+ "birddev": {
4
+ "name": "BIRD Dev",
5
+ "metrics": [
6
+ "execution_ability",
7
+ "correct_rate",
8
+ "execution_efficiency_on_executable_sql",
9
+ "table_precision_on_executable_sql",
10
+ "table_recall_on_executable_sql",
11
+ "table_f1_on_executable_sql",
12
+ "column_precision_on_executable_sql",
13
+ "column_recall_on_executable_sql",
14
+ "column_f1_on_executable_sql"
15
+ ],
16
+ "algorithms": [
17
+ {
18
+ "name": "Ferry Qwen3-4B",
19
+ "execution_ability": 0.3123,
20
+ "correct_rate": 0.146,
21
+ "execution_efficiency_on_executable_sql": 1.0454,
22
+ "table_precision_on_executable_sql": 0.9426,
23
+ "table_recall_on_executable_sql": 0.8432,
24
+ "table_f1_on_executable_sql": 0.8959,
25
+ "column_precision_on_executable_sql": 0.8524,
26
+ "column_recall_on_executable_sql": 0.7012,
27
+ "column_f1_on_executable_sql": 0.7878
28
+ },
29
+ {
30
+ "name": "Ferry Qwen3-8B",
31
+ "execution_ability": 0.0632,
32
+ "correct_rate": 0.0332,
33
+ "execution_efficiency_on_executable_sql": 0.9659,
34
+ "table_precision_on_executable_sql": 1,
35
+ "table_recall_on_executable_sql": 0.9485,
36
+ "table_f1_on_executable_sql": 0.9656,
37
+ "column_precision_on_executable_sql": 0.9273,
38
+ "column_recall_on_executable_sql": 0.7618,
39
+ "column_f1_on_executable_sql": 0.8387
40
+ },
41
+ {
42
+ "name": "Ferry Qwen3-30B",
43
+ "execution_ability": 0.8598,
44
+ "correct_rate": 0.4993,
45
+ "execution_efficiency_on_executable_sql": 0.9939,
46
+ "table_precision_on_executable_sql": 0.9644,
47
+ "table_recall_on_executable_sql": 0.9325,
48
+ "table_f1_on_executable_sql": 0.9476,
49
+ "column_precision_on_executable_sql": 0.8959,
50
+ "column_recall_on_executable_sql": 0.8386,
51
+ "column_f1_on_executable_sql": 0.8734
52
+ }
53
+ ]
54
+ },
55
+ "birdtrain": {
56
+ "name": "BIRD Train",
57
+ "metrics": [
58
+ "execution_ability",
59
+ "correct_rate",
60
+ "execution_efficiency_on_executable_sql",
61
+ "table_precision_on_executable_sql",
62
+ "table_recall_on_executable_sql",
63
+ "table_f1_on_executable_sql",
64
+ "column_precision_on_executable_sql",
65
+ "column_recall_on_executable_sql",
66
+ "column_f1_on_executable_sql"
67
+ ],
68
+ "algorithms": []
69
+ },
70
+ "spider": {
71
+ "name": "Spider",
72
+ "metrics": [
73
+ "execution_ability",
74
+ "correct_rate",
75
+ "execution_efficiency_on_executable_sql",
76
+ "table_precision_on_executable_sql",
77
+ "table_recall_on_executable_sql",
78
+ "table_f1_on_executable_sql",
79
+ "column_precision_on_executable_sql",
80
+ "column_recall_on_executable_sql",
81
+ "column_f1_on_executable_sql"
82
+ ],
83
+ "algorithms": [
84
+ ]
85
+ }
86
+ },
87
+ "last_updated": "2025-12-23T00:00:00"
88
+ }
index.html ADDED
@@ -0,0 +1,899 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 Controls
484
+ </div>
485
+ <button class="reset-btn" onclick="resetFilters()">
486
+ <i class="fas fa-redo"></i> Reset Filters
487
+ </button>
488
+ </div>
489
+
490
+ <div class="dataset-selector">
491
+ <div class="dataset-label">
492
+ <i class="fas fa-database"></i>
493
+ Select Dataset
494
+ </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 Display
504
+ </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 Results
533
+ </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 Development
549
+ </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.815
578
+ }'></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 queries
603
+ </li>
604
+ <li style="margin-bottom: 10px; padding: 10px; background: #f1f5f9; border-radius: 6px;">
605
+ <strong>Correct Rate:</strong> Percentage of correctly generated SQL queries
606
+ </li>
607
+ <li style="margin-bottom: 10px; padding: 10px; background: #f1f5f9; border-radius: 6px;">
608
+ <strong>Execution Efficiency:</strong> Performance on executable SQL queries
609
+ </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 executable
612
+ </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 world
619
+ </li>
620
+ <li style="margin-bottom: 10px; padding: 10px; background: #f1f5f9; border-radius: 6px;">
621
+ <strong>BIRD Train:</strong> Training set for BIRD benchmark
622
+ </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 dataset
625
+ </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 &bull;
635
+ <i class="fas fa-server"></i> Docker Ready &bull;
636
+ <i class="fas fa-chart-line"></i> Real-time Updates
637
+ </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_sql
796
+ 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>
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn[standard]==0.24.0
3
+ gunicorn==21.2.0
4
+ python-multipart==0.0.6
5
+ pydantic==2.5.0
6
+ pydantic-settings==2.1.0
7
+ aiofiles==23.2.1
8
+ Jinja2==3.1.3
server.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, Request, HTTPException, UploadFile, File
2
+ from fastapi.responses import HTMLResponse, JSONResponse
3
+ from fastapi.staticfiles import StaticFiles
4
+ from fastapi.templating import Jinja2Templates
5
+ import json
6
+ import os
7
+ from pathlib import Path
8
+ from typing import Dict, List, Optional
9
+ import logging
10
+ from datetime import datetime
11
+
12
+ # 设置日志
13
+ logging.basicConfig(level=logging.INFO)
14
+ logger = logging.getLogger(__name__)
15
+
16
+ app = FastAPI(title="NL2SQL Leaderboard", version="1.0.0")
17
+
18
+ # 创建必要的目录
19
+ Path("static").mkdir(exist_ok=True)
20
+
21
+ # 挂载静态文件
22
+ app.mount("/static", StaticFiles(directory="static"), name="static")
23
+
24
+ # 模板
25
+ templates = Jinja2Templates(directory=".")
26
+
27
+ # 数据文件路径
28
+ DATA_FILE = "data.json"
29
+
30
+ def load_data() -> Dict:
31
+ """加载排行榜数据"""
32
+ try:
33
+ with open(DATA_FILE, "r", encoding="utf-8") as f:
34
+ return json.load(f)
35
+ except FileNotFoundError:
36
+ # 返回默认数据结构
37
+ return {
38
+ "datasets": {
39
+ "birddev": {
40
+ "name": "BIRD Dev",
41
+ "metrics": [
42
+ "execution_ability",
43
+ "correct_rate",
44
+ "execution_efficiency_on_executable_sql",
45
+ "table_precision_on_executable_sql",
46
+ "table_recall_on_executable_sql",
47
+ "table_f1_on_executable_sql",
48
+ "column_precision_on_executable_sql",
49
+ "column_recall_on_executable_sql",
50
+ "column_f1_on_executable_sql"
51
+ ],
52
+ "algorithms": [
53
+ {
54
+ "name": "Algorithm A",
55
+ "execution_ability": 0.85,
56
+ "correct_rate": 0.78,
57
+ "execution_efficiency_on_executable_sql": 0.92,
58
+ "table_precision_on_executable_sql": 0.87,
59
+ "table_recall_on_executable_sql": 0.85,
60
+ "table_f1_on_executable_sql": 0.86,
61
+ "column_precision_on_executable_sql": 0.83,
62
+ "column_recall_on_executable_sql": 0.80,
63
+ "column_f1_on_executable_sql": 0.815
64
+ },
65
+ {
66
+ "name": "Algorithm B",
67
+ "execution_ability": 0.82,
68
+ "correct_rate": 0.75,
69
+ "execution_efficiency_on_executable_sql": 0.90,
70
+ "table_precision_on_executable_sql": 0.85,
71
+ "table_recall_on_executable_sql": 0.82,
72
+ "table_f1_on_executable_sql": 0.835,
73
+ "column_precision_on_executable_sql": 0.80,
74
+ "column_recall_on_executable_sql": 0.78,
75
+ "column_f1_on_executable_sql": 0.79
76
+ },
77
+ {
78
+ "name": "Algorithm C",
79
+ "execution_ability": 0.88,
80
+ "correct_rate": 0.81,
81
+ "execution_efficiency_on_executable_sql": 0.94,
82
+ "table_precision_on_executable_sql": 0.89,
83
+ "table_recall_on_executable_sql": 0.87,
84
+ "table_f1_on_executable_sql": 0.88,
85
+ "column_precision_on_executable_sql": 0.85,
86
+ "column_recall_on_executable_sql": 0.83,
87
+ "column_f1_on_executable_sql": 0.84
88
+ }
89
+ ]
90
+ },
91
+ "birdtrain": {
92
+ "name": "BIRD Train",
93
+ "metrics": [
94
+ "execution_ability",
95
+ "correct_rate",
96
+ "execution_efficiency_on_executable_sql",
97
+ "table_precision_on_executable_sql",
98
+ "table_recall_on_executable_sql",
99
+ "table_f1_on_executable_sql",
100
+ "column_precision_on_executable_sql",
101
+ "column_recall_on_executable_sql",
102
+ "column_f1_on_executable_sql"
103
+ ],
104
+ "algorithms": [] # 空数据,只有架子
105
+ },
106
+ "spider": {
107
+ "name": "Spider",
108
+ "metrics": [
109
+ "execution_ability",
110
+ "correct_rate"
111
+ ],
112
+ "algorithms": [
113
+ {
114
+ "name": "Model X",
115
+ "execution_ability": 0.91,
116
+ "correct_rate": 0.85
117
+ },
118
+ {
119
+ "name": "Model Y",
120
+ "execution_ability": 0.89,
121
+ "correct_rate": 0.83
122
+ }
123
+ ]
124
+ }
125
+ },
126
+ "last_updated": datetime.now().isoformat()
127
+ }
128
+
129
+ def save_data(data: Dict):
130
+ """保存数据到文件"""
131
+ data["last_updated"] = datetime.now().isoformat()
132
+ with open(DATA_FILE, "w", encoding="utf-8") as f:
133
+ json.dump(data, f, indent=2, ensure_ascii=False)
134
+
135
+ @app.get("/", response_class=HTMLResponse)
136
+ async def read_root(request: Request):
137
+ """渲染主页面"""
138
+ data = load_data()
139
+ return templates.TemplateResponse(
140
+ "index.html",
141
+ {"request": request, "datasets": data["datasets"]}
142
+ )
143
+
144
+ @app.get("/api/data")
145
+ async def get_data():
146
+ """获取排行榜数据"""
147
+ return load_data()
148
+
149
+ @app.get("/api/health")
150
+ async def health_check():
151
+ """健康检查端点"""
152
+ return {"status": "healthy", "timestamp": datetime.now().isoformat()}
153
+
154
+ @app.post("/api/submit")
155
+ async def submit_results(
156
+ dataset: str,
157
+ algorithm_name: str,
158
+ results: str # JSON字符串
159
+ ):
160
+ """
161
+ 提交新结果的端点(架子功能)
162
+ 实际使用时应该验证和解析results
163
+ """
164
+ try:
165
+ # 这里只是架子,实际应该验证和存储数据
166
+ results_data = json.loads(results)
167
+ logger.info(f"Received submission for {dataset} - {algorithm_name}")
168
+
169
+ # 在实际实现中,这里应该:
170
+ # 1. 验证数据格式
171
+ # 2. 存储到数据库或文件
172
+ # 3. 更新排行榜
173
+
174
+ return {
175
+ "status": "success",
176
+ "message": "Submission received (demo mode - not actually saved)",
177
+ "dataset": dataset,
178
+ "algorithm": algorithm_name,
179
+ "received_results": results_data
180
+ }
181
+ except json.JSONDecodeError:
182
+ raise HTTPException(status_code=400, detail="Invalid JSON format")
183
+ except Exception as e:
184
+ raise HTTPException(status_code=500, detail=str(e))
185
+
186
+ @app.post("/api/submit/file")
187
+ async def submit_results_file(
188
+ dataset: str,
189
+ algorithm_name: str,
190
+ file: UploadFile = File(...)
191
+ ):
192
+ """
193
+ 通过文件提交结果的端点
194
+ """
195
+ try:
196
+ # 读取文件内容
197
+ content = await file.read()
198
+ results = json.loads(content)
199
+
200
+ logger.info(f"Received file submission for {dataset} - {algorithm_name}")
201
+
202
+ return {
203
+ "status": "success",
204
+ "message": "File submission received (demo mode)",
205
+ "dataset": dataset,
206
+ "algorithm": algorithm_name,
207
+ "filename": file.filename,
208
+ "file_size": len(content)
209
+ }
210
+ except Exception as e:
211
+ raise HTTPException(status_code=500, detail=str(e))
212
+
213
+ @app.get("/api/datasets")
214
+ async def get_datasets():
215
+ """获取所有数据集信息"""
216
+ data = load_data()
217
+ return {
218
+ "datasets": list(data["datasets"].keys()),
219
+ "details": {k: {"name": v["name"], "count": len(v["algorithms"])}
220
+ for k, v in data["datasets"].items()}
221
+ }
222
+
223
+ if __name__ == "__main__":
224
+ import uvicorn
225
+ uvicorn.run("server:app", host="0.0.0.0", port=7860, reload=True)