aikacl commited on
Commit
ce59f44
Β·
verified Β·
1 Parent(s): 0131d69

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +409 -82
app.py CHANGED
@@ -42,6 +42,286 @@ EXAMPLES = [
42
  },
43
  ]
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
  def _make_vis_updates(count: int):
47
  return [gr.update(visible=(i < count)) for i in range(MAX_DOCS)]
@@ -96,7 +376,7 @@ def rerank(query: str, instruction: str, chunk_size: int, *doc_texts: str):
96
  chunk_size=chunk_size,
97
  )
98
 
99
- # query = query.strip()
100
  instruction = instruction.strip() or DEFAULT_INSTRUCTION
101
 
102
  try:
@@ -114,8 +394,9 @@ def rerank(query: str, instruction: str, chunk_size: int, *doc_texts: str):
114
  table.append([rank_idx, corpus_id, round(score, 6), doc])
115
 
116
  summary = (
117
- f"Reranked {len(docs)} documents with "
118
- f"`{MODEL_ID}` (chunk_size={chunk_size}). Higher score means more relevant."
 
119
  )
120
  return table, summary
121
  except Exception as error:
@@ -124,72 +405,138 @@ def rerank(query: str, instruction: str, chunk_size: int, *doc_texts: str):
124
 
125
  # ── UI ──────────────────���───────────────────────────────────────────────────
126
 
127
- with gr.Blocks(title="KaLM-Reranker-V1 Demo") as demo:
128
- gr.Markdown(
129
- """
130
- # KaLM-Reranker-V1 Demo
131
- **KaLM-Reranker-V1** is a fast but not late-interaction reranker for compressed document reranking.
132
- Input a query and several candidate documents. The demo returns relevance scores and reranked results.
133
- """
134
- )
135
-
136
- with gr.Row():
 
 
 
 
 
 
 
137
  # ── Left column: inputs ──
138
  with gr.Column(scale=1):
139
- query_input = gr.Textbox(
140
- label="Query",
141
- value="",
142
- lines=2,
143
- )
144
- instruction_input = gr.Textbox(
145
- label="Instruction",
146
- value=DEFAULT_INSTRUCTION,
147
- lines=2,
148
- )
149
- chunk_size_input = gr.Dropdown(
150
- label="Chunk Size",
151
- choices=[2, 4, 8, 16],
152
- value=2,
153
- interactive=True,
154
- )
155
-
156
- # Example selector
157
- example_selector = gr.Dropdown(
158
- label="Load Example",
159
- choices=[ex["label"] for ex in EXAMPLES],
160
- value=None,
161
- interactive=True,
162
- )
163
-
164
- gr.Markdown("### Candidate Documents")
165
- doc_count = gr.State(value=INIT_DOCS)
166
- doc_textboxes: List[gr.Textbox] = []
167
-
168
- with gr.Column() as doc_list:
169
- for i in range(MAX_DOCS):
170
- visible = i < INIT_DOCS
171
- tb = gr.Textbox(
172
- label=f"Document {i + 1}",
173
- lines=2,
174
- placeholder=f"Enter document {i + 1}...",
175
- visible=visible,
176
- )
177
- doc_textboxes.append(tb)
178
 
179
- with gr.Row():
180
- add_btn = gr.Button("+ Add Document", size="sm")
181
- remove_btn = gr.Button("- Remove Last", size="sm")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
 
183
- submit = gr.Button("Rerank", variant="primary")
 
 
 
 
 
 
184
 
185
  # ── Right column: outputs ──
186
  with gr.Column(scale=1):
187
- output_table = gr.Dataframe(
188
- headers=["Rank", "Corpus ID", "Score", "Document"],
189
- label="Reranking Results",
190
- wrap=True,
191
- )
192
- output_summary = gr.Markdown()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
  # ── Events ──
195
  add_btn.click(
@@ -213,26 +560,6 @@ Input a query and several candidate documents. The demo returns relevance scores
213
  outputs=[output_table, output_summary],
214
  )
215
 
216
- gr.Markdown(
217
- """
218
- ## Citation
219
-
220
- If you find this demo useful, please cite:
221
-
222
- ```bibtex
223
- @misc{zhao2026kalmrerankerv1,
224
- title={KaLM-Reranker-V1: Fast but Not Late Interaction for Compressed Document Reranking},
225
- author={Xinping Zhao and Jiaxin Xu and Ziqi Dai and Xin Zhang and Shouzheng Huang and Danyu Tang and Xinshuo Hu and Meishan Zhang and Baotian Hu and Min Zhang},
226
- year={2026},
227
- eprint={2606.22807},
228
- archivePrefix={arXiv},
229
- primaryClass={cs.CL},
230
- url={https://arxiv.org/abs/2606.22807},
231
- }
232
- ```
233
- """
234
- )
235
-
236
 
237
  if __name__ == "__main__":
238
  demo.launch()
 
42
  },
43
  ]
44
 
45
+ # ── Custom CSS ──────────────────────────────────────────────────────────────
46
+
47
+ CUSTOM_CSS = """
48
+ /* ── Global ──────────────────────────────────────── */
49
+ .gradio-container {
50
+ max-width: 1200px !important;
51
+ font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif !important;
52
+ }
53
+
54
+ /* ── Header Banner ───────────────────────────────── */
55
+ .header-banner {
56
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 40%, #0f3460 100%);
57
+ border-radius: 16px;
58
+ padding: 32px 36px;
59
+ margin-bottom: 24px;
60
+ color: #fff;
61
+ position: relative;
62
+ overflow: hidden;
63
+ }
64
+ .header-banner::before {
65
+ content: '';
66
+ position: absolute;
67
+ top: -50%;
68
+ right: -20%;
69
+ width: 400px;
70
+ height: 400px;
71
+ background: radial-gradient(circle, rgba(99, 179, 237, 0.15) 0%, transparent 70%);
72
+ pointer-events: none;
73
+ }
74
+ .header-banner h1 {
75
+ margin: 0 0 8px 0 !important;
76
+ font-size: 28px !important;
77
+ font-weight: 700 !important;
78
+ letter-spacing: -0.5px;
79
+ background: linear-gradient(90deg, #ffffff, #a8d8ea);
80
+ -webkit-background-clip: text;
81
+ -webkit-text-fill-color: transparent;
82
+ background-clip: text;
83
+ }
84
+ .header-banner p {
85
+ margin: 0 !important;
86
+ font-size: 14px !important;
87
+ color: rgba(255, 255, 255, 0.7) !important;
88
+ line-height: 1.6;
89
+ }
90
+ .header-badge {
91
+ display: inline-block;
92
+ background: rgba(99, 179, 237, 0.2);
93
+ color: #a8d8ea;
94
+ font-size: 11px;
95
+ font-weight: 600;
96
+ padding: 3px 10px;
97
+ border-radius: 20px;
98
+ margin-bottom: 12px;
99
+ border: 1px solid rgba(99, 179, 237, 0.3);
100
+ letter-spacing: 0.5px;
101
+ text-transform: uppercase;
102
+ }
103
+
104
+ /* ── Section Cards ───────────────────────────────── */
105
+ .section-card {
106
+ background: #ffffff;
107
+ border: 1px solid #e8ecf1;
108
+ border-radius: 12px;
109
+ padding: 20px;
110
+ margin-bottom: 16px;
111
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
112
+ transition: box-shadow 0.2s ease;
113
+ }
114
+ .section-card:hover {
115
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
116
+ }
117
+ .section-title {
118
+ font-size: 13px !important;
119
+ font-weight: 600 !important;
120
+ color: #64748b !important;
121
+ text-transform: uppercase !important;
122
+ letter-spacing: 0.8px !important;
123
+ margin-bottom: 12px !important;
124
+ padding-bottom: 8px !important;
125
+ border-bottom: 1px solid #f1f5f9 !important;
126
+ }
127
+
128
+ /* ── Form Controls ───────────────────────────────── */
129
+ .gr-textbox, .gr-dropdown {
130
+ border-radius: 8px !important;
131
+ border: 1px solid #e2e8f0 !important;
132
+ transition: border-color 0.2s ease, box-shadow 0.2s ease !important;
133
+ }
134
+ .gr-textbox:focus-within, .gr-dropdown:focus-within {
135
+ border-color: #63b3ed !important;
136
+ box-shadow: 0 0 0 3px rgba(99, 179, 237, 0.12) !important;
137
+ }
138
+ textarea {
139
+ font-size: 13.5px !important;
140
+ line-height: 1.6 !important;
141
+ }
142
+
143
+ /* ── Document List ───────────────────────────────── */
144
+ .doc-list-container .gr-textbox {
145
+ border-left: 3px solid #63b3ed !important;
146
+ margin-bottom: 8px !important;
147
+ }
148
+
149
+ /* ── Buttons ─────────────────────────────────────── */
150
+ .doc-btn {
151
+ border-radius: 8px !important;
152
+ font-weight: 500 !important;
153
+ font-size: 13px !important;
154
+ padding: 8px 16px !important;
155
+ transition: all 0.2s ease !important;
156
+ }
157
+ .btn-add {
158
+ background: #f0f7ff !important;
159
+ color: #2b6cb0 !important;
160
+ border: 1px solid #bee3f8 !important;
161
+ }
162
+ .btn-add:hover {
163
+ background: #dbeafe !important;
164
+ border-color: #90cdf4 !important;
165
+ }
166
+ .btn-remove {
167
+ background: #fff5f5 !important;
168
+ color: #c53030 !important;
169
+ border: 1px solid #fed7d7 !important;
170
+ }
171
+ .btn-remove:hover {
172
+ background: #fee2e2 !important;
173
+ border-color: #feb2b2 !important;
174
+ }
175
+
176
+ /* ── Submit Button Override ──────────────────────── */
177
+ .submit-row .primary-btn {
178
+ width: 100%;
179
+ padding: 12px !important;
180
+ font-size: 15px !important;
181
+ font-weight: 600 !important;
182
+ border-radius: 10px !important;
183
+ background: linear-gradient(135deg, #2b6cb0, #3182ce) !important;
184
+ border: none !important;
185
+ letter-spacing: 0.3px;
186
+ transition: all 0.25s ease !important;
187
+ }
188
+ .submit-row .primary-btn:hover {
189
+ background: linear-gradient(135deg, #2c5282, #2b6cb0) !important;
190
+ box-shadow: 0 4px 14px rgba(43, 108, 176, 0.35) !important;
191
+ transform: translateY(-1px);
192
+ }
193
+
194
+ /* ── Results Panel ──────────���────────────────────── */
195
+ .result-panel {
196
+ background: #fafbfc;
197
+ border: 1px solid #e8ecf1;
198
+ border-radius: 12px;
199
+ padding: 20px;
200
+ min-height: 200px;
201
+ }
202
+ .result-panel table {
203
+ border-collapse: separate !important;
204
+ border-spacing: 0 !important;
205
+ width: 100% !important;
206
+ font-size: 13px !important;
207
+ }
208
+ .result-panel thead th {
209
+ background: #f1f5f9 !important;
210
+ color: #475569 !important;
211
+ font-weight: 600 !important;
212
+ font-size: 11px !important;
213
+ text-transform: uppercase !important;
214
+ letter-spacing: 0.5px !important;
215
+ padding: 10px 12px !important;
216
+ border-bottom: 2px solid #e2e8f0 !important;
217
+ }
218
+ .result-panel thead th:first-child {
219
+ border-radius: 8px 0 0 0 !important;
220
+ }
221
+ .result-panel thead th:last-child {
222
+ border-radius: 0 8px 0 0 !important;
223
+ }
224
+ .result-panel tbody td {
225
+ padding: 10px 12px !important;
226
+ border-bottom: 1px solid #f1f5f9 !important;
227
+ vertical-align: top !important;
228
+ color: #334155 !important;
229
+ }
230
+ .result-panel tbody tr:hover {
231
+ background: #f8fafc !important;
232
+ }
233
+ .result-panel tbody tr:last-child td {
234
+ border-bottom: none !important;
235
+ }
236
+
237
+ /* ── Summary Badge ───────────────────────────────── */
238
+ .summary-badge {
239
+ background: linear-gradient(135deg, #f0fff4, #e6fffa);
240
+ border: 1px solid #c6f6d5;
241
+ border-radius: 10px;
242
+ padding: 12px 16px;
243
+ margin-top: 12px;
244
+ font-size: 13px;
245
+ color: #276749;
246
+ }
247
+
248
+ /* ── Citation Accordion ──────────────────────────── */
249
+ .citation-box {
250
+ background: #f8fafc;
251
+ border: 1px solid #e2e8f0;
252
+ border-radius: 10px;
253
+ padding: 16px 20px;
254
+ margin-top: 20px;
255
+ }
256
+ .citation-box pre {
257
+ background: #1e293b !important;
258
+ border-radius: 8px !important;
259
+ padding: 14px !important;
260
+ font-size: 11.5px !important;
261
+ line-height: 1.6 !important;
262
+ color: #e2e8f0 !important;
263
+ overflow-x: auto;
264
+ }
265
+ .citation-box h3 {
266
+ font-size: 14px !important;
267
+ color: #64748b !important;
268
+ margin: 0 0 10px 0 !important;
269
+ }
270
+
271
+ /* ── Config Row (Instruction + ChunkSize + Example) */
272
+ .config-row {
273
+ display: flex;
274
+ gap: 12px;
275
+ align-items: flex-end;
276
+ }
277
+ .config-row > div {
278
+ flex: 1;
279
+ }
280
+
281
+ /* ── Scrollbar ───────────────────────────────────── */
282
+ .doc-scroll::-webkit-scrollbar {
283
+ width: 5px;
284
+ }
285
+ .doc-scroll::-webkit-scrollbar-track {
286
+ background: transparent;
287
+ }
288
+ .doc-scroll::-webkit-scrollbar-thumb {
289
+ background: #cbd5e1;
290
+ border-radius: 10px;
291
+ }
292
+ .doc-scroll::-webkit-scrollbar-thumb:hover {
293
+ background: #94a3b8;
294
+ }
295
+
296
+ /* ── Label tweaks ────────────────────────────────── */
297
+ .label-query label span {
298
+ font-size: 14px !important;
299
+ font-weight: 600 !important;
300
+ color: #1e293b !important;
301
+ }
302
+ """
303
+
304
+ # ── Theme ───────────────────────────────────────────────────────────────────
305
+
306
+ theme = gr.themes.Soft(
307
+ primary_hue="blue",
308
+ secondary_hue="slate",
309
+ neutral_hue="slate",
310
+ font=gr.themes.GoogleFont("Inter"),
311
+ ).set(
312
+ body_background_fill="#f8fafc",
313
+ body_background_fill_dark="#0f172a",
314
+ background_fill_primary="#ffffff",
315
+ background_fill_secondary="#f1f5f9",
316
+ border_color_primary="#e2e8f0",
317
+ text_primary="#1e293b",
318
+ text_secondary="#64748b",
319
+ radius_quarter="8px",
320
+ radius_half="10px",
321
+ )
322
+
323
+ # ── Logic helpers ───────────────────────────────────────────────────────────
324
+
325
 
326
  def _make_vis_updates(count: int):
327
  return [gr.update(visible=(i < count)) for i in range(MAX_DOCS)]
 
376
  chunk_size=chunk_size,
377
  )
378
 
379
+ query = query.strip()
380
  instruction = instruction.strip() or DEFAULT_INSTRUCTION
381
 
382
  try:
 
394
  table.append([rank_idx, corpus_id, round(score, 6), doc])
395
 
396
  summary = (
397
+ f"Reranked **{len(docs)}** documents with "
398
+ f"`{MODEL_ID}` (chunk_size={chunk_size}). "
399
+ f"Higher score means more relevant."
400
  )
401
  return table, summary
402
  except Exception as error:
 
405
 
406
  # ── UI ──────────────────���───────────────────────────────────────────────────
407
 
408
+ with gr.Blocks(
409
+ title="KaLM-Reranker-V1 Demo",
410
+ theme=theme,
411
+ css=CUSTOM_CSS,
412
+ ) as demo:
413
+
414
+ # ── Header ──
415
+ gr.HTML("""
416
+ <div class="header-banner">
417
+ <div class="header-badge">Powered by KaLM-Embedding</div>
418
+ <h1>KaLM-Reranker-V1 Demo</h1>
419
+ <p>A fast but not late-interaction reranker for compressed document reranking. <br/>
420
+ Input a query and candidate documents to get relevance scores and reranked results.</p>
421
+ </div>
422
+ """)
423
+
424
+ with gr.Row(equal_height=False):
425
  # ── Left column: inputs ──
426
  with gr.Column(scale=1):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
427
 
428
+ # Query
429
+ with gr.Group(elem_classes=["section-card"]):
430
+ gr.Markdown('<div class="section-title">Query</div>', elem_classes="label-query")
431
+ query_input = gr.Textbox(
432
+ show_label=False,
433
+ value="What is the capital of China?",
434
+ lines=3,
435
+ placeholder="Enter your query here...",
436
+ )
437
+
438
+ # Config row: Instruction Β· Chunk Size Β· Load Example
439
+ with gr.Group(elem_classes=["section-card"]):
440
+ gr.Markdown('<div class="section-title">Configuration</div>', elem_classes="label-query")
441
+ with gr.Row():
442
+ with gr.Column(scale=2):
443
+ instruction_input = gr.Textbox(
444
+ label="Instruction",
445
+ value=DEFAULT_INSTRUCTION,
446
+ lines=2,
447
+ show_copy_button=True,
448
+ )
449
+ with gr.Column(scale=1):
450
+ chunk_size_input = gr.Dropdown(
451
+ label="Chunk Size",
452
+ choices=[2, 4, 8, 16],
453
+ value=4,
454
+ interactive=True,
455
+ )
456
+ example_selector = gr.Dropdown(
457
+ label="Quick Example",
458
+ choices=[""] + [ex["label"] for ex in EXAMPLES],
459
+ value="",
460
+ interactive=True,
461
+ allow_custom_value=False,
462
+ )
463
+
464
+ # Candidate Documents
465
+ with gr.Group(elem_classes=["section-card"]):
466
+ gr.Markdown(
467
+ '<div class="section-title">Candidate Documents '
468
+ '<span style="float:right;font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:#94a3b8">'
469
+ f'Max {MAX_DOCS} docs</span></div>',
470
+ elem_classes="label-query",
471
+ )
472
+ doc_count = gr.State(value=INIT_DOCS)
473
+ doc_textboxes: List[gr.Textbox] = []
474
+
475
+ with gr.Column(elem_classes=["doc-list-container", "doc-scroll"]) as doc_list:
476
+ for i in range(MAX_DOCS):
477
+ visible = i < INIT_DOCS
478
+ tb = gr.Textbox(
479
+ label=f" {i + 1}",
480
+ lines=2,
481
+ placeholder=f"Enter document {i + 1}...",
482
+ visible=visible,
483
+ show_label=True,
484
+ )
485
+ doc_textboxes.append(tb)
486
+
487
+ with gr.Row():
488
+ add_btn = gr.Button(
489
+ "+ Add Document",
490
+ size="sm",
491
+ elem_classes=["doc-btn", "btn-add"],
492
+ )
493
+ remove_btn = gr.Button(
494
+ "- Remove Last",
495
+ size="sm",
496
+ elem_classes=["doc-btn", "btn-remove"],
497
+ )
498
 
499
+ # Submit
500
+ with gr.Row(elem_classes=["submit-row"]):
501
+ submit = gr.Button(
502
+ "Rerank",
503
+ variant="primary",
504
+ elem_classes=["primary-btn"],
505
+ )
506
 
507
  # ── Right column: outputs ──
508
  with gr.Column(scale=1):
509
+ with gr.Group(elem_classes=["result-panel"]):
510
+ gr.Markdown(
511
+ '<div class="section-title">Reranking Results</div>',
512
+ elem_classes="label-query",
513
+ )
514
+ output_table = gr.Dataframe(
515
+ headers=["Rank", "Corpus ID", "Score", "Document"],
516
+ label=None,
517
+ wrap=True,
518
+ interactive=False,
519
+ )
520
+ output_summary = gr.HTML()
521
+
522
+ # ── Citation ──
523
+ gr.HTML("""
524
+ <details class="citation-box">
525
+ <summary style="cursor:pointer;font-weight:600;font-size:14px;color:#64748b;">
526
+ Cite this work
527
+ </summary>
528
+ <pre><code>@misc{zhao2026kalmrerankerv1,
529
+ title={KaLM-Reranker-V1: Fast but Not Late Interaction for Compressed Document Reranking},
530
+ author={Xinping Zhao and Jiaxin Xu and Ziqi Dai and Xin Zhang and Shouzheng Huang
531
+ and Danyu Tang and Xinshuo Hu and Meishan Zhang and Baotian Hu and Min Zhang},
532
+ year={2026},
533
+ eprint={2606.22807},
534
+ archivePrefix={arXiv},
535
+ primaryClass={cs.CL},
536
+ url={https://arxiv.org/abs/2606.22807},
537
+ }</code></pre>
538
+ </details>
539
+ """)
540
 
541
  # ── Events ──
542
  add_btn.click(
 
560
  outputs=[output_table, output_summary],
561
  )
562
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
563
 
564
  if __name__ == "__main__":
565
  demo.launch()