Hasarindu Perera commited on
Commit
ade80c1
·
unverified ·
1 Parent(s): d42eca0

demo: replace plain-text outputs with HTML cards in Recommend and Compare tabs

Browse files
Files changed (1) hide show
  1. app.py +148 -25
app.py CHANGED
@@ -239,7 +239,7 @@ def run_recommend(csv_file, sample_name: str, task: str, n_qubits: int) -> str:
239
  try:
240
  import quprep as qd
241
  except ImportError:
242
- return "❌ quprep is not installed in this Space."
243
 
244
  try:
245
  if csv_file is not None:
@@ -248,11 +248,11 @@ def run_recommend(csv_file, sample_name: str, task: str, n_qubits: int) -> str:
248
  elif sample_name and sample_name in SAMPLES:
249
  df = pd.read_csv(io.StringIO(SAMPLES[sample_name]()))
250
  else:
251
- return "⚠️ Please upload a CSV or select a sample dataset."
252
 
253
  df = df.select_dtypes(include="number").dropna()
254
  if df.empty:
255
- return "⚠️ No numeric columns found."
256
 
257
  import tempfile, os
258
  with tempfile.NamedTemporaryFile(
@@ -263,10 +263,56 @@ def run_recommend(csv_file, sample_name: str, task: str, n_qubits: int) -> str:
263
 
264
  qubits_arg = n_qubits if n_qubits > 0 else None
265
  rec = qd.recommend(tmp_path, task=task, qubits=qubits_arg)
266
- return str(rec)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
 
268
  except Exception as exc:
269
- return f"❌ {exc}"
270
  finally:
271
  try:
272
  os.unlink(tmp_path)
@@ -282,7 +328,7 @@ def run_compare(csv_file, sample_name: str, task: str, n_qubits: int) -> str:
282
  try:
283
  import quprep as qd
284
  except ImportError:
285
- return "❌ quprep is not installed in this Space."
286
 
287
  try:
288
  if csv_file is not None:
@@ -291,11 +337,11 @@ def run_compare(csv_file, sample_name: str, task: str, n_qubits: int) -> str:
291
  elif sample_name and sample_name in SAMPLES:
292
  df = pd.read_csv(io.StringIO(SAMPLES[sample_name]()))
293
  else:
294
- return "⚠️ Please upload a CSV or select a sample dataset."
295
 
296
  df = df.select_dtypes(include="number").dropna()
297
  if df.empty:
298
- return "⚠️ No numeric columns found."
299
 
300
  import tempfile, os
301
  with tempfile.NamedTemporaryFile(
@@ -306,10 +352,50 @@ def run_compare(csv_file, sample_name: str, task: str, n_qubits: int) -> str:
306
 
307
  qubits_arg = n_qubits if n_qubits > 0 else None
308
  result = qd.compare_encodings(tmp_path, task=task, qubits=qubits_arg)
309
- return str(result)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
  except Exception as exc:
312
- return f"❌ {exc}"
313
  finally:
314
  try:
315
  os.unlink(tmp_path)
@@ -323,40 +409,63 @@ def run_compare(csv_file, sample_name: str, task: str, n_qubits: int) -> str:
323
 
324
  THEME = gr.themes.Soft(primary_hue="violet", secondary_hue="blue")
325
 
326
- with gr.Blocks(theme=THEME, title="QuPrep — Quantum Data Preparation") as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
327
 
328
  with gr.Row(equal_height=True):
329
  # ── Left: package info ─────────────────────────────────────────────
330
- with gr.Column(scale=1):
331
  gr.HTML("""
332
- <div style="height:100%;display:flex;flex-direction:column;justify-content:center;padding:16px 24px;border-radius:12px;border:1px solid #334155">
333
- <p style="margin:0 0 4px;font-size:1.4rem;font-weight:700;color:#e2e8f0">⚛️ QuPrep</p>
334
- <p style="margin:0 0 12px;font-size:0.9rem;font-weight:500;color:#a78bfa">Quantum Data Preparation</p>
335
- <p style="margin:0 0 16px;font-size:0.85rem;color:#94a3b8;line-height:1.5">
336
  The missing preprocessing layer between classical datasets and quantum computing.
337
  Framework-agnostic: Qiskit · PennyLane · Cirq · TKET · Braket · Q# · IQM · OpenQASM 3.0.
338
  </p>
339
  <div style="display:flex;flex-direction:column;gap:8px;font-size:0.85rem">
340
- <div>📦 <code style="background:#1e293b;padding:2px 6px;border-radius:4px">pip install quprep</code></div>
341
  <div>📖 <a href="https://docs.quprep.org" target="_blank" style="color:#818cf8">docs.quprep.org</a></div>
342
  <div>💻 <a href="https://github.com/quprep/quprep" target="_blank" style="color:#818cf8">github.com/quprep/quprep</a></div>
343
  <div>🌐 <a href="https://quprep.org" target="_blank" style="color:#818cf8">quprep.org</a></div>
344
  </div>
345
- <p style="margin:16px 0 0;font-size:0.75rem;color:#475569">
346
  11 encodings · 8 export frameworks · Apache 2.0 · Python ≥ 3.10
347
  </p>
348
  </div>
349
  """)
350
 
351
  # ── Right: data inputs ─────────────────────────────────────────────
352
- with gr.Column(scale=1):
353
- csv_upload = gr.File(label="Upload CSV", file_types=[".csv", ".tsv"])
 
 
 
 
 
 
 
 
354
  sample_dd = gr.Dropdown(
355
  choices=[""] + list(SAMPLES.keys()),
356
  value="Iris (150 samples, 4 features)",
357
- label="Or use a sample dataset",
358
  )
359
- gr.Markdown("*Uploaded file takes priority over the sample selector.*")
 
 
360
 
361
  with gr.Tabs():
362
 
@@ -441,7 +550,14 @@ with gr.Blocks(theme=THEME, title="QuPrep — Quantum Data Preparation") as demo
441
  )
442
  rec_btn = gr.Button("Recommend →", variant="primary")
443
  with gr.Column(scale=2):
444
- rec_out = gr.Textbox(label="Recommendation", lines=15, interactive=False)
 
 
 
 
 
 
 
445
 
446
  rec_btn.click(
447
  fn=run_recommend,
@@ -464,7 +580,14 @@ with gr.Blocks(theme=THEME, title="QuPrep — Quantum Data Preparation") as demo
464
  )
465
  cmp_btn = gr.Button("Compare →", variant="primary")
466
  with gr.Column(scale=2):
467
- cmp_out = gr.Textbox(label="Comparison table", lines=20, interactive=False)
 
 
 
 
 
 
 
468
 
469
  cmp_btn.click(
470
  fn=run_compare,
@@ -525,4 +648,4 @@ Apache 2.0 license · Python ≥ 3.10
525
  )
526
 
527
  if __name__ == "__main__":
528
- demo.launch()
 
239
  try:
240
  import quprep as qd
241
  except ImportError:
242
+ return "<p>❌ quprep is not installed in this Space.</p>"
243
 
244
  try:
245
  if csv_file is not None:
 
248
  elif sample_name and sample_name in SAMPLES:
249
  df = pd.read_csv(io.StringIO(SAMPLES[sample_name]()))
250
  else:
251
+ return "<p>⚠️ Please upload a CSV or select a sample dataset.</p>"
252
 
253
  df = df.select_dtypes(include="number").dropna()
254
  if df.empty:
255
+ return "<p>⚠️ No numeric columns found.</p>"
256
 
257
  import tempfile, os
258
  with tempfile.NamedTemporaryFile(
 
263
 
264
  qubits_arg = n_qubits if n_qubits > 0 else None
265
  rec = qd.recommend(tmp_path, task=task, qubits=qubits_arg)
266
+
267
+ nisq_badge = (
268
+ '<span style="color:#4ade80;font-weight:600">✓ Yes</span>'
269
+ if rec.nisq_safe else
270
+ '<span style="color:#f87171;font-weight:600">✗ No</span>'
271
+ )
272
+
273
+ alt_rows = "".join(
274
+ f"""<tr>
275
+ <td style="padding:6px 12px">{a.method}</td>
276
+ <td style="padding:6px 12px;text-align:center">{a.score:.0f}</td>
277
+ <td style="padding:6px 12px;color:#94a3b8">{a.depth}</td>
278
+ </tr>"""
279
+ for a in rec.alternatives
280
+ )
281
+ alt_html = f"""
282
+ <div style="margin-top:20px">
283
+ <p style="margin:0 0 8px;font-size:0.8rem;font-weight:600;color:#94a3b8;text-transform:uppercase;letter-spacing:.05em">Alternatives</p>
284
+ <table style="width:100%;border-collapse:collapse;font-size:0.85rem">
285
+ <thead>
286
+ <tr style="border-bottom:1px solid #334155">
287
+ <th style="padding:6px 12px;text-align:left;color:#64748b;font-weight:500">Encoding</th>
288
+ <th style="padding:6px 12px;text-align:center;color:#64748b;font-weight:500">Score</th>
289
+ <th style="padding:6px 12px;text-align:left;color:#64748b;font-weight:500">Depth</th>
290
+ </tr>
291
+ </thead>
292
+ <tbody>{alt_rows}</tbody>
293
+ </table>
294
+ </div>""" if rec.alternatives else ""
295
+
296
+ return f"""
297
+ <div style="font-family:sans-serif;font-size:0.9rem;line-height:1.6">
298
+ <div style="display:flex;align-items:baseline;gap:12px;margin-bottom:16px">
299
+ <span style="font-size:1.6rem;font-weight:700;color:#e2e8f0">{rec.method}</span>
300
+ <span style="font-size:0.8rem;color:#a78bfa;font-weight:600">recommended</span>
301
+ </div>
302
+ <div style="display:grid;grid-template-columns:auto 1fr;gap:4px 24px;margin-bottom:16px">
303
+ <span style="color:#64748b">Qubits needed</span> <span>{rec.qubits}</span>
304
+ <span style="color:#64748b">Circuit depth</span> <span style="font-family:monospace">{rec.depth}</span>
305
+ <span style="color:#64748b">NISQ safe</span> <span>{nisq_badge}</span>
306
+ <span style="color:#64748b">Score</span> <span>{rec.score:.0f}</span>
307
+ </div>
308
+ <div style="padding:12px 16px;background:#1e293b;border-radius:8px;color:#cbd5e1;font-size:0.85rem;line-height:1.6">
309
+ {rec.reason}
310
+ </div>
311
+ {alt_html}
312
+ </div>"""
313
 
314
  except Exception as exc:
315
+ return f"<p>❌ {exc}</p>"
316
  finally:
317
  try:
318
  os.unlink(tmp_path)
 
328
  try:
329
  import quprep as qd
330
  except ImportError:
331
+ return "<p>❌ quprep is not installed in this Space.</p>"
332
 
333
  try:
334
  if csv_file is not None:
 
337
  elif sample_name and sample_name in SAMPLES:
338
  df = pd.read_csv(io.StringIO(SAMPLES[sample_name]()))
339
  else:
340
+ return "<p>⚠️ Please upload a CSV or select a sample dataset.</p>"
341
 
342
  df = df.select_dtypes(include="number").dropna()
343
  if df.empty:
344
+ return "<p>⚠️ No numeric columns found.</p>"
345
 
346
  import tempfile, os
347
  with tempfile.NamedTemporaryFile(
 
352
 
353
  qubits_arg = n_qubits if n_qubits > 0 else None
354
  result = qd.compare_encodings(tmp_path, task=task, qubits=qubits_arg)
355
+
356
+ rows_html = ""
357
+ for r in result.rows:
358
+ nisq = '<span style="color:#4ade80">Yes</span>' if r.nisq_safe else '<span style="color:#f87171">No</span>'
359
+ name = f"{r.encoding} ★" if r.encoding == result.recommended else r.encoding
360
+ style = "background:#1e293b" if r.encoding == result.recommended else ""
361
+ rows_html += f"""<tr style="{style}">
362
+ <td style="padding:8px 14px;font-weight:{'600' if r.encoding == result.recommended else '400'}">{name}</td>
363
+ <td style="padding:8px 14px;text-align:center">{r.n_qubits}</td>
364
+ <td style="padding:8px 14px;text-align:center">{r.gate_count}</td>
365
+ <td style="padding:8px 14px;text-align:center">{r.circuit_depth}</td>
366
+ <td style="padding:8px 14px;text-align:center">{r.two_qubit_gates}</td>
367
+ <td style="padding:8px 14px;text-align:center">{nisq}</td>
368
+ </tr>"""
369
+
370
+ footnote = "<p style='margin:12px 0 0;font-size:0.78rem;color:#475569'>★ recommended for the specified task / budget</p>" if result.recommended else ""
371
+
372
+ warnings = [r for r in result.rows if r.warning]
373
+ warn_html = "".join(
374
+ f"<p style='margin:4px 0;font-size:0.78rem;color:#fbbf24'>⚠️ [{r.encoding}] {r.warning}</p>"
375
+ for r in warnings
376
+ )
377
+
378
+ return f"""
379
+ <div style="font-family:sans-serif;font-size:0.88rem">
380
+ <table style="width:100%;border-collapse:collapse">
381
+ <thead>
382
+ <tr style="border-bottom:1px solid #334155">
383
+ <th style="padding:8px 14px;text-align:left;color:#64748b;font-weight:500">Encoding</th>
384
+ <th style="padding:8px 14px;text-align:center;color:#64748b;font-weight:500">Qubits</th>
385
+ <th style="padding:8px 14px;text-align:center;color:#64748b;font-weight:500">Gate Count</th>
386
+ <th style="padding:8px 14px;text-align:center;color:#64748b;font-weight:500">Depth</th>
387
+ <th style="padding:8px 14px;text-align:center;color:#64748b;font-weight:500">2Q Gates</th>
388
+ <th style="padding:8px 14px;text-align:center;color:#64748b;font-weight:500">NISQ Safe</th>
389
+ </tr>
390
+ </thead>
391
+ <tbody>{rows_html}</tbody>
392
+ </table>
393
+ {footnote}
394
+ {warn_html}
395
+ </div>"""
396
 
397
  except Exception as exc:
398
+ return f"<p>❌ {exc}</p>"
399
  finally:
400
  try:
401
  os.unlink(tmp_path)
 
409
 
410
  THEME = gr.themes.Soft(primary_hue="violet", secondary_hue="blue")
411
 
412
+ CSS = """
413
+ #info-panel, #data-panel {
414
+ border: 1px solid #334155 !important;
415
+ border-radius: 12px !important;
416
+ padding: 20px 24px !important;
417
+ box-sizing: border-box;
418
+ min-height: 320px !important;
419
+ }
420
+ #data-panel {
421
+ gap: 12px !important;
422
+ }
423
+ """
424
+
425
+ with gr.Blocks(title="QuPrep — Quantum Data Preparation", css=CSS) as demo:
426
 
427
  with gr.Row(equal_height=True):
428
  # ── Left: package info ─────────────────────────────────────────────
429
+ with gr.Column(scale=1, elem_id="info-panel"):
430
  gr.HTML("""
431
+ <div style="display:flex;flex-direction:column;justify-content:center">
432
+ <p style="margin:0 0 2px;font-size:1.5rem;font-weight:700;color:#e2e8f0">⚛️ QuPrep</p>
433
+ <p style="margin:0 0 14px;font-size:0.9rem;font-weight:500;color:#a78bfa">Quantum Data Preparation</p>
434
+ <p style="margin:0 0 14px;font-size:0.85rem;color:#94a3b8;line-height:1.6">
435
  The missing preprocessing layer between classical datasets and quantum computing.
436
  Framework-agnostic: Qiskit · PennyLane · Cirq · TKET · Braket · Q# · IQM · OpenQASM 3.0.
437
  </p>
438
  <div style="display:flex;flex-direction:column;gap:8px;font-size:0.85rem">
439
+ <div>📦 <code style="background:#1e293b;padding:2px 8px;border-radius:4px">pip install quprep</code></div>
440
  <div>📖 <a href="https://docs.quprep.org" target="_blank" style="color:#818cf8">docs.quprep.org</a></div>
441
  <div>💻 <a href="https://github.com/quprep/quprep" target="_blank" style="color:#818cf8">github.com/quprep/quprep</a></div>
442
  <div>🌐 <a href="https://quprep.org" target="_blank" style="color:#818cf8">quprep.org</a></div>
443
  </div>
444
+ <p style="margin:14px 0 0;font-size:0.75rem;color:#475569">
445
  11 encodings · 8 export frameworks · Apache 2.0 · Python ≥ 3.10
446
  </p>
447
  </div>
448
  """)
449
 
450
  # ── Right: data inputs ─────────────────────────────────────────────
451
+ with gr.Column(scale=1, elem_id="data-panel"):
452
+ gr.HTML("""
453
+ <p style="margin:0 0 2px;font-size:1.5rem;font-weight:700;color:#e2e8f0">📂 Load Dataset</p>
454
+ <p style="margin:0 0 4px;font-size:0.9rem;font-weight:500;color:#a78bfa">Upload a CSV or pick a sample</p>
455
+ """)
456
+ csv_upload = gr.File(
457
+ label="Upload CSV (.csv / .tsv)",
458
+ file_types=[".csv", ".tsv"],
459
+ height=150,
460
+ )
461
  sample_dd = gr.Dropdown(
462
  choices=[""] + list(SAMPLES.keys()),
463
  value="Iris (150 samples, 4 features)",
464
+ label="Or use a built-in sample dataset",
465
  )
466
+ gr.HTML("""
467
+ <p style="margin:0;font-size:0.75rem;color:#475569">Uploaded file takes priority over the sample selector.</p>
468
+ """)
469
 
470
  with gr.Tabs():
471
 
 
550
  )
551
  rec_btn = gr.Button("Recommend →", variant="primary")
552
  with gr.Column(scale=2):
553
+ rec_out = gr.HTML(
554
+ label="Recommendation",
555
+ value="""
556
+ <div style="font-family:sans-serif;color:#475569;font-size:0.9rem;padding:24px 0">
557
+ <p style="margin:0 0 8px;font-size:1rem;font-weight:600;color:#64748b">No recommendation yet</p>
558
+ <p style="margin:0;line-height:1.6">Select a task, set an optional qubit budget, and click <strong>Recommend →</strong> to get a dataset-aware encoding suggestion with ranked alternatives.</p>
559
+ </div>""",
560
+ )
561
 
562
  rec_btn.click(
563
  fn=run_recommend,
 
580
  )
581
  cmp_btn = gr.Button("Compare →", variant="primary")
582
  with gr.Column(scale=2):
583
+ cmp_out = gr.HTML(
584
+ label="Comparison table",
585
+ value="""
586
+ <div style="font-family:sans-serif;color:#475569;font-size:0.9rem;padding:24px 0">
587
+ <p style="margin:0 0 8px;font-size:1rem;font-weight:600;color:#64748b">No comparison yet</p>
588
+ <p style="margin:0;line-height:1.6">Select a task, set an optional qubit budget, and click <strong>Compare →</strong> to see a side-by-side cost breakdown for all encoders.</p>
589
+ </div>""",
590
+ )
591
 
592
  cmp_btn.click(
593
  fn=run_compare,
 
648
  )
649
 
650
  if __name__ == "__main__":
651
+ demo.launch(theme=THEME)