MalikShehram commited on
Commit
7bbf56e
Β·
verified Β·
1 Parent(s): 79b585a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +376 -323
app.py CHANGED
@@ -23,9 +23,9 @@ def get_whisper():
23
  whisper_model = WhisperModel("base", compute_type="int8")
24
  return whisper_model
25
 
26
- GROQ_API_KEY = os.environ.get("YOUR_GROQ_API_KEY", "")
27
  if not GROQ_API_KEY:
28
- raise ValueError("YOUR_GROQ_API_KEY secret is not set. Add it in HF Space Settings β†’ Secrets.")
29
 
30
  client = Groq(api_key=GROQ_API_KEY)
31
  MODEL_NAME = "llama-3.3-70b-versatile"
@@ -283,444 +283,497 @@ def voice_chat(audio, history):
283
  return history, ""
284
 
285
  # =========================
286
- # CSS β€” Dark Academic / Premium Research Theme
 
 
287
  # =========================
288
 
289
  CSS = """
290
- @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,300&family=DM+Mono:wght@400;500&display=swap');
291
 
 
292
  :root {
293
- --bg-0: #0a0c10;
294
- --bg-1: #0f1117;
295
- --bg-2: #151821;
296
- --bg-3: #1b1f2c;
297
- --bg-4: #222638;
298
- --border: #252a3a;
299
- --border-hi: #303650;
300
- --gold: #c9a96e;
301
- --gold-dim: #9e7845;
302
- --gold-glow: rgba(201,169,110,0.10);
303
- --gold-glow-hi: rgba(201,169,110,0.20);
304
- --blue: #5b8dee;
305
- --green: #56c490;
306
- --red: #e05c5c;
307
- --tx-1: #eae6dc;
308
- --tx-2: #9b9588;
309
- --tx-3: #5a5650;
310
- --tx-4: #333030;
311
- --r: 14px;
312
- --r-sm: 9px;
313
- --sh: 0 4px 28px rgba(0,0,0,.45);
314
- --sh-lg: 0 8px 56px rgba(0,0,0,.65);
315
- --sh-gold: 0 0 0 3px rgba(201,169,110,0.18);
316
- }
317
-
318
- *, *::before, *::after { box-sizing: border-box; }
319
-
320
- /* Page background with subtle grid */
 
 
 
 
 
 
 
321
  body, .gradio-container {
322
  background: var(--bg-0) !important;
323
- font-family: 'DM Sans', sans-serif !important;
324
  color: var(--tx-1) !important;
325
  min-height: 100vh;
 
 
 
 
 
 
 
 
326
  }
327
 
328
- .gradio-container::after {
 
329
  content: '';
330
- position: fixed;
331
- inset: 0;
332
- background-image:
333
- linear-gradient(rgba(201,169,110,0.025) 1px, transparent 1px),
334
- linear-gradient(90deg, rgba(201,169,110,0.025) 1px, transparent 1px);
335
- background-size: 48px 48px;
336
- pointer-events: none;
337
- z-index: 0;
338
  }
339
 
340
- /* ── HEADER ─────────────────────────────── */
341
- #app-header {
342
- background: linear-gradient(160deg, #13161f 0%, #181c28 60%, #111420 100%);
343
- border: 1px solid var(--border-hi);
344
- border-radius: 20px;
345
- padding: 52px 44px 40px;
346
- text-align: center;
347
  position: relative;
 
 
 
 
 
348
  overflow: hidden;
349
- box-shadow: var(--sh-lg);
350
- margin-bottom: 4px;
351
  }
352
 
353
- #app-header::before {
354
  content: '';
355
  position: absolute;
356
- top: -80px; left: 50%;
357
- transform: translateX(-50%);
358
- width: 440px; height: 340px;
359
- background: radial-gradient(ellipse, rgba(201,169,110,0.09) 0%, transparent 68%);
360
- pointer-events: none;
361
  }
362
 
363
- #app-header::after {
364
- content: '';
365
- position: absolute;
366
- bottom: 0; left: 10%; right: 10%;
367
- height: 1px;
368
- background: linear-gradient(90deg, transparent, var(--border-hi), transparent);
369
- }
370
-
371
- .hdr-icon {
372
- font-size: 2.8rem;
373
- margin-bottom: 14px;
374
- display: block;
375
- filter: drop-shadow(0 0 18px rgba(201,169,110,0.4));
376
- }
377
-
378
- .hdr-title {
379
- font-family: 'Playfair Display', serif !important;
380
- font-size: 3rem !important;
381
- font-weight: 700 !important;
382
- color: var(--gold) !important;
383
- letter-spacing: -1px;
384
- line-height: 1.1;
385
- margin: 0 0 12px !important;
386
- text-shadow: 0 2px 32px rgba(201,169,110,0.25);
387
- }
388
-
389
- .hdr-sub {
390
- font-family: 'DM Sans', sans-serif;
391
- font-size: 1.02rem;
392
- color: var(--tx-2);
393
- font-weight: 300;
394
- letter-spacing: 0.4px;
395
- margin-bottom: 24px;
396
- }
397
-
398
- .badge-row {
399
- display: flex;
400
- gap: 8px;
401
- justify-content: center;
402
- flex-wrap: wrap;
403
- margin-top: 6px;
404
- }
405
-
406
- .badge {
407
- display: inline-flex;
408
- align-items: center;
409
- gap: 5px;
410
- background: rgba(201,169,110,0.07);
411
- border: 1px solid rgba(201,169,110,0.18);
412
- border-radius: 99px;
413
- padding: 5px 13px;
414
- font-family: 'DM Mono', monospace;
415
- font-size: 0.72rem;
416
- color: var(--gold);
417
- letter-spacing: 0.3px;
418
- transition: background 0.2s;
419
- }
420
-
421
- .badge:hover { background: rgba(201,169,110,0.13); }
422
-
423
- /* ── PANEL CARDS ─────────────────────────── */
424
- .gr-group {
425
- background: var(--bg-2) !important;
426
- border: 1px solid var(--border) !important;
427
- border-radius: var(--r) !important;
428
- padding: 26px 28px !important;
429
- box-shadow: var(--sh) !important;
430
- transition: border-color 0.25s;
431
- position: relative;
432
  }
433
 
434
- .gr-group:hover {
435
- border-color: var(--border-hi) !important;
 
 
436
  }
437
 
438
- /* ── SECTION LABELS ─────────────────────── */
439
- .sec-label {
440
- font-family: 'DM Mono', monospace;
441
- font-size: 0.67rem;
442
- font-weight: 500;
443
- letter-spacing: 2.5px;
444
- text-transform: uppercase;
445
- color: var(--gold);
446
- margin-bottom: 18px;
447
- display: flex;
448
- align-items: center;
449
- gap: 10px;
 
450
  }
451
 
452
- .sec-label::before {
453
- content: '';
454
- display: block;
455
- width: 22px; height: 1px;
456
- background: linear-gradient(90deg, var(--gold), transparent);
457
  }
458
 
459
- .sec-label::after {
460
- content: '';
461
- flex: 1; height: 1px;
462
- background: linear-gradient(90deg, var(--border), transparent);
463
  }
464
 
465
- /* ── FORM ELEMENTS ──────────────────────── */
466
- label span {
467
- font-family: 'DM Sans', sans-serif !important;
468
- font-size: 0.78rem !important;
469
- font-weight: 500 !important;
470
- color: var(--tx-2) !important;
471
- letter-spacing: 0.5px !important;
472
- text-transform: uppercase !important;
473
  }
474
 
475
- textarea, input[type="text"], .gr-textbox textarea {
476
- background: var(--bg-3) !important;
477
- border: 1px solid var(--border) !important;
478
- border-radius: var(--r-sm) !important;
479
- color: var(--tx-1) !important;
480
- font-family: 'DM Mono', monospace !important;
481
- font-size: 0.9rem !important;
482
- padding: 13px 16px !important;
483
- transition: border-color 0.2s, box-shadow 0.2s !important;
484
- resize: none !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  }
486
 
487
  textarea:focus, input[type="text"]:focus {
488
- border-color: var(--gold) !important;
489
- box-shadow: var(--sh-gold) !important;
490
- outline: none !important;
491
  }
492
 
493
  textarea::placeholder, input::placeholder {
494
- color: var(--tx-3) !important;
495
- font-style: italic;
496
  }
497
 
498
  select, .gr-dropdown select {
499
- background: var(--bg-3) !important;
500
- border: 1px solid var(--border) !important;
501
- border-radius: var(--r-sm) !important;
502
- color: var(--tx-1) !important;
503
- font-family: 'DM Sans', sans-serif !important;
504
- font-size: 0.88rem !important;
505
- padding: 13px 16px !important;
506
- transition: border-color 0.2s !important;
507
  }
508
 
509
- select:focus { border-color: var(--gold) !important; outline: none !important; }
510
 
511
- /* ── BUTTONS ────────────────────────────── */
512
  .gr-button {
513
- font-family: 'DM Sans', sans-serif !important;
514
- font-size: 0.86rem !important;
515
- font-weight: 600 !important;
516
- letter-spacing: 0.2px !important;
517
- border-radius: var(--r-sm) !important;
518
- cursor: pointer !important;
519
- transition: all 0.2s ease !important;
520
- padding: 12px 22px !important;
521
- border: none !important;
 
 
 
522
  }
 
523
 
524
  .gr-button-primary {
525
- background: linear-gradient(135deg, #c9a96e 0%, #a87c3a 100%) !important;
526
- color: #0a0c10 !important;
527
- box-shadow: 0 2px 14px rgba(201,169,110,0.28) !important;
528
  }
529
 
530
  .gr-button-primary:hover {
531
- filter: brightness(1.1) !important;
532
- transform: translateY(-2px) !important;
533
- box-shadow: 0 6px 22px rgba(201,169,110,0.38) !important;
534
  }
535
 
536
- .gr-button-primary:active { transform: translateY(0) !important; }
537
 
538
  .gr-button-secondary {
539
- background: var(--bg-4) !important;
540
- color: var(--tx-1) !important;
541
- border: 1px solid var(--border-hi) !important;
542
  }
543
 
544
  .gr-button-secondary:hover {
545
- border-color: var(--gold) !important;
546
- color: var(--gold) !important;
547
- background: var(--gold-glow) !important;
548
- transform: translateY(-1px) !important;
549
  }
550
 
551
- /* ── STATUS ─────────────────────────────── */
552
  #status-box .prose p, #status-box p {
553
- font-family: 'DM Mono', monospace !important;
554
- font-size: 0.82rem !important;
555
- color: var(--tx-2) !important;
556
- background: var(--bg-3) !important;
557
- border-left: 3px solid var(--gold) !important;
558
- border-radius: 0 var(--r-sm) var(--r-sm) 0 !important;
559
- padding: 10px 16px !important;
560
- margin: 0 !important;
561
- }
562
-
563
- /* ── CHATBOT ─────────────────────────────── */
564
- .gr-chatbot {
565
- background: var(--bg-1) !important;
566
- border: 1px solid var(--border) !important;
567
- border-radius: var(--r) !important;
568
- padding: 12px !important;
569
- }
570
-
571
- /* ── SUMMARY ────────────────────────────── */
572
- #summary-out .prose {
573
- background: var(--bg-3) !important;
574
- border: 1px solid var(--border) !important;
575
- border-radius: var(--r) !important;
576
- padding: 22px 26px !important;
577
- font-family: 'DM Sans', sans-serif !important;
578
- font-size: 0.93rem !important;
579
- line-height: 1.78 !important;
580
- color: var(--tx-1) !important;
581
  }
582
 
583
- #summary-out strong { color: var(--gold) !important; }
584
- #summary-out em { color: var(--tx-2) !important; }
585
- #summary-out ul { padding-left: 20px !important; }
586
- #summary-out li { margin-bottom: 6px !important; }
 
 
 
 
 
 
 
 
587
 
588
- /* ── AUDIO ──────────────────────────────── */
589
- .gr-audio {
590
- background: var(--bg-3) !important;
591
- border: 1px solid var(--border) !important;
592
- border-radius: var(--r-sm) !important;
593
  }
594
 
595
- /* ── FOOTER ─────────────────────────────── */
596
- #footer .prose p {
597
- text-align: center !important;
598
- font-family: 'DM Mono', monospace !important;
599
- font-size: 0.7rem !important;
600
- color: var(--tx-4) !important;
601
- letter-spacing: 0.5px !important;
602
- padding: 4px !important;
603
  }
604
 
605
- /* ── SCROLLBAR ──────────────────────────── */
606
- ::-webkit-scrollbar { width: 5px; height: 5px; }
607
- ::-webkit-scrollbar-track { background: var(--bg-1); }
608
- ::-webkit-scrollbar-thumb { background: var(--border-hi); border-radius: 99px; }
609
- ::-webkit-scrollbar-thumb:hover { background: var(--gold-dim); }
 
 
 
 
 
 
 
 
 
610
 
611
- /* ── ANIMATIONS ─────────────────────────── */
612
- @keyframes fadeUp {
613
- from { opacity: 0; transform: translateY(14px); }
614
- to { opacity: 1; transform: translateY(0); }
 
615
  }
616
 
617
- .gradio-container > .gr-group,
618
- .gradio-container > div > .gr-group {
619
- animation: fadeUp 0.45s ease both;
 
 
 
620
  }
621
 
622
- .gradio-container > div > *:nth-child(1) { animation-delay: 0.05s; }
623
- .gradio-container > div > *:nth-child(2) { animation-delay: 0.12s; }
624
- .gradio-container > div > *:nth-child(3) { animation-delay: 0.19s; }
625
- .gradio-container > div > *:nth-child(4) { animation-delay: 0.26s; }
626
- .gradio-container > div > *:nth-child(5) { animation-delay: 0.33s; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
627
  """
628
 
629
  # =========================
630
  # BUILD UI
631
  # =========================
632
 
633
- with gr.Blocks(title="ArXiv Research Assistant") as demo:
634
 
635
- # ─── HEADER ───────────────────────────────────────────────────────
636
  gr.HTML("""
637
- <div id="app-header">
638
- <span class="hdr-icon">πŸ“–</span>
639
- <div class="hdr-title">ArXiv Research Assistant</div>
640
- <div class="hdr-sub">Load any research paper Β· Generate AI summaries Β· Chat with the content Β· Ask via voice</div>
641
- <div class="badge-row">
642
- <span class="badge">⚑ RAG-Powered</span>
643
- <span class="badge">🧠 LLaMA 3.3 70B</span>
644
- <span class="badge">πŸŽ™οΈ Whisper ASR</span>
645
- <span class="badge">πŸ” FAISS Semantic Search</span>
646
- <span class="badge">πŸ”— DOI Resolver</span>
 
 
 
 
 
 
 
 
 
 
 
647
  </div>
648
  </div>
649
  """)
650
 
651
- # ─── 01 LOAD PAPER ────────────────────────────────────────────────
652
  with gr.Group():
653
- gr.HTML('<div class="sec-label">01 &nbsp; Load Paper</div>')
 
 
 
 
 
 
 
654
  with gr.Row(equal_height=True):
655
  arxiv_input = gr.Textbox(
656
  label="Paper DOI",
657
- placeholder="e.g. 10.1038/s41586-021-03819-2 or https://doi.org/10.48550/arXiv.1706.03762",
658
  scale=5,
659
  )
660
- load_btn = gr.Button("πŸš€ Load Paper", variant="primary", scale=1, min_width=150)
661
-
662
  status = gr.Markdown(
663
- value="*Enter a paper DOI above and click **Load Paper** to begin.*",
664
  elem_id="status-box",
665
  )
666
 
667
- # ─── 02 SECTION SUMMARY ──���────────────────────────────────────────
668
  with gr.Group():
669
- gr.HTML('<div class="sec-label">02 &nbsp; Section Summary</div>')
 
 
 
 
 
 
 
670
  with gr.Row(equal_height=True):
671
  section_dropdown = gr.Dropdown(
672
- label="Select Section",
673
- choices=[],
674
- scale=5,
675
- interactive=True,
676
  )
677
- summarize_btn = gr.Button("✨ Summarize", variant="secondary", scale=1, min_width=150)
678
-
679
  summary_output = gr.Markdown(
680
- value="*Select a section above and click Summarize to get an AI-powered breakdown.*",
681
  elem_id="summary-out",
682
  )
683
 
684
- # ─── 03 CHAT ──────────────────────────────────────────────────────
685
  with gr.Group():
686
- gr.HTML('<div class="sec-label">03 &nbsp; Chat with Paper</div>')
687
- chatbot = gr.Chatbot(
688
- value=[],
689
- height=430,
690
- show_label=False,
691
- )
 
 
 
692
  with gr.Row(equal_height=True):
693
  msg = gr.Textbox(
694
- label="Your Question",
695
  placeholder="What is the main contribution? Β· How does the method work? Β· What datasets were used?",
696
- scale=5,
697
- lines=1,
698
- max_lines=3,
699
  )
700
- send_btn = gr.Button("Send β†’", variant="primary", scale=1, min_width=120)
701
 
702
- # ─── 04 VOICE ─────────────────────────────────────────────────────
703
  with gr.Group():
704
- gr.HTML('<div class="sec-label">04 &nbsp; Voice Query</div>')
705
  gr.HTML("""
706
- <p style="font-family:'DM Sans',sans-serif;font-size:0.85rem;
707
- color:#9b9588;margin:0 0 18px;line-height:1.6;">
708
- Record or upload your question β€” Whisper will transcribe it and search the paper automatically.
709
- </p>
 
 
 
 
 
710
  """)
711
  with gr.Row(equal_height=True):
712
- audio = gr.Audio(
713
- type="filepath",
714
- label="Record or Upload Audio",
715
- scale=5,
716
- )
717
- voice_btn = gr.Button("πŸŽ™οΈ Transcribe & Ask", variant="secondary", scale=1, min_width=160)
718
 
719
  # ─── FOOTER ───────────────────────────────────────────────────────
720
- gr.Markdown(
721
- "Powered by Β· Gradio Β· Groq LLaMA 3.3 Β· FAISS Β· Sentence Transformers Β· faster-whisper Β· PyMuPDF",
722
- elem_id="footer",
723
- )
 
 
 
 
 
 
 
 
 
 
724
 
725
  # ─── BINDINGS ─────────────────────────────────────────────────────
726
  load_btn.click(load_paper, inputs=arxiv_input, outputs=[section_dropdown, status])
 
23
  whisper_model = WhisperModel("base", compute_type="int8")
24
  return whisper_model
25
 
26
+ GROQ_API_KEY = os.environ.get("GROQ_API_KEY", "")
27
  if not GROQ_API_KEY:
28
+ raise ValueError("GROQ_API_KEY secret is not set. Add it in HF Space Settings β†’ Secrets.")
29
 
30
  client = Groq(api_key=GROQ_API_KEY)
31
  MODEL_NAME = "llama-3.3-70b-versatile"
 
283
  return history, ""
284
 
285
  # =========================
286
+ # CSS β€” "Obsidian Intelligence" Premium 2026 Research Platform
287
+ # Ethos: High-Density Functionalism meets Dark Luxury
288
+ # Trends: Bento Grid Β· Glassmorphism Β· Kinetic borders Β· Layered depth
289
  # =========================
290
 
291
  CSS = """
292
+ @import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@300;400;500;600;700&family=Geist+Mono:wght@400;500&display=swap');
293
 
294
+ /* ═══════════ DESIGN TOKENS ═══════════ */
295
  :root {
296
+ --void: #07080c;
297
+ --bg-0: #0b0d13;
298
+ --bg-1: #0f1119;
299
+ --bg-2: #13161f;
300
+ --bg-3: #181c28;
301
+ --bg-4: #1e2333;
302
+ --bg-5: #242840;
303
+ --b-0: #1c2030;
304
+ --b-1: #252a3c;
305
+ --b-2: #303650;
306
+ --b-hi: #404868;
307
+ --gold: #d4a853;
308
+ --gold-lt: #e8c47a;
309
+ --gold-dk: #9e7535;
310
+ --gold-muted: rgba(212,168,83,0.08);
311
+ --gold-glow: rgba(212,168,83,0.16);
312
+ --gold-ring: 0 0 0 2.5px rgba(212,168,83,0.22);
313
+ --green: #3ecf8e;
314
+ --blue: #4d94ff;
315
+ --red: #f06565;
316
+ --amber: #f0a443;
317
+ --tx-1: #f0ece2;
318
+ --tx-2: #8a8578;
319
+ --tx-3: #4a4740;
320
+ --r-xs: 6px; --r-sm: 10px; --r: 16px; --r-lg: 22px; --r-xl: 28px;
321
+ --sh-sm: 0 2px 12px rgba(0,0,0,.4);
322
+ --sh: 0 4px 32px rgba(0,0,0,.55);
323
+ --sh-lg: 0 8px 64px rgba(0,0,0,.7);
324
+ --sh-xl: 0 16px 80px rgba(0,0,0,.8);
325
+ --sh-gold: 0 4px 28px rgba(212,168,83,0.2);
326
+ }
327
+
328
+ *, *::before, *::after { box-sizing: border-box; margin: 0; }
329
+ html { scroll-behavior: smooth; }
330
+
331
  body, .gradio-container {
332
  background: var(--bg-0) !important;
333
+ font-family: 'Geist', system-ui, sans-serif !important;
334
  color: var(--tx-1) !important;
335
  min-height: 100vh;
336
+ -webkit-font-smoothing: antialiased;
337
+ }
338
+
339
+ /* Dot-matrix background */
340
+ .gradio-container {
341
+ background-image: radial-gradient(circle, rgba(212,168,83,0.05) 1px, transparent 1px) !important;
342
+ background-size: 28px 28px !important;
343
+ background-attachment: fixed !important;
344
  }
345
 
346
+ /* Vignette overlay */
347
+ .gradio-container::before {
348
  content: '';
349
+ position: fixed; inset: 0;
350
+ background: radial-gradient(ellipse 80% 60% at 50% 0%, transparent 40%, rgba(7,8,12,0.75) 100%);
351
+ pointer-events: none; z-index: 0;
 
 
 
 
 
352
  }
353
 
354
+ /* ═══════════ HERO HEADER ═══════════ */
355
+ #hero {
 
 
 
 
 
356
  position: relative;
357
+ background: linear-gradient(145deg, #0f1220 0%, #131828 45%, #0c0f1a 100%);
358
+ border: 1px solid var(--b-2);
359
+ border-radius: var(--r-xl);
360
+ padding: 56px 48px 44px;
361
+ text-align: center;
362
  overflow: hidden;
363
+ box-shadow: var(--sh-xl);
364
+ margin-bottom: 2px;
365
  }
366
 
367
+ #hero::before {
368
  content: '';
369
  position: absolute;
370
+ top: -120px; left: 50%; transform: translateX(-50%);
371
+ width: 600px; height: 400px;
372
+ background: conic-gradient(from 180deg at 50% 50%, rgba(212,168,83,0) 0deg, rgba(212,168,83,0.07) 60deg, rgba(77,148,255,0.04) 120deg, rgba(212,168,83,0) 180deg, rgba(212,168,83,0.06) 240deg, rgba(77,148,255,0.03) 300deg, rgba(212,168,83,0) 360deg);
373
+ animation: aurora 12s linear infinite;
374
+ pointer-events: none; border-radius: 50%;
375
  }
376
 
377
+ @keyframes aurora {
378
+ from { transform: translateX(-50%) rotate(0deg); }
379
+ to { transform: translateX(-50%) rotate(360deg); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
380
  }
381
 
382
+ #hero::after {
383
+ content: ''; position: absolute;
384
+ bottom: 0; left: 8%; right: 8%; height: 1px;
385
+ background: linear-gradient(90deg, transparent, var(--b-2) 30%, var(--b-hi) 50%, var(--b-2) 70%, transparent);
386
  }
387
 
388
+ .hero-corner { position: absolute; width: 36px; height: 36px; opacity: 0.35; }
389
+ .hero-corner-tl { top: 18px; left: 18px; border-top: 1.5px solid var(--gold); border-left: 1.5px solid var(--gold); border-radius: 4px 0 0 0; }
390
+ .hero-corner-tr { top: 18px; right: 18px; border-top: 1.5px solid var(--gold); border-right: 1.5px solid var(--gold); border-radius: 0 4px 0 0; }
391
+ .hero-corner-bl { bottom: 18px; left: 18px; border-bottom: 1.5px solid var(--gold); border-left: 1.5px solid var(--gold); border-radius: 0 0 0 4px; }
392
+ .hero-corner-br { bottom: 18px; right: 18px; border-bottom: 1.5px solid var(--gold); border-right: 1.5px solid var(--gold); border-radius: 0 0 4px 0; }
393
+
394
+ .hero-eyebrow {
395
+ display: inline-flex; align-items: center; gap: 8px;
396
+ background: rgba(212,168,83,0.07); border: 1px solid rgba(212,168,83,0.2);
397
+ border-radius: 99px; padding: 5px 14px;
398
+ font-family: 'Geist Mono', monospace; font-size: 0.67rem;
399
+ color: var(--gold); letter-spacing: 2px; text-transform: uppercase;
400
+ margin-bottom: 20px; animation: fadeDown 0.6s ease both;
401
  }
402
 
403
+ .hero-eyebrow::before {
404
+ content: ''; width: 5px; height: 5px; background: var(--gold);
405
+ border-radius: 50%; box-shadow: 0 0 6px var(--gold);
406
+ animation: pulse-dot 2s ease-in-out infinite;
 
407
  }
408
 
409
+ @keyframes pulse-dot {
410
+ 0%, 100% { opacity: 1; transform: scale(1); }
411
+ 50% { opacity: 0.4; transform: scale(0.65); }
 
412
  }
413
 
414
+ .hero-title {
415
+ font-family: 'Instrument Serif', Georgia, serif !important;
416
+ font-size: 3.4rem !important; font-weight: 400 !important;
417
+ color: var(--tx-1) !important; letter-spacing: -1.5px;
418
+ line-height: 1.05; margin-bottom: 16px !important;
419
+ animation: fadeDown 0.6s 0.1s ease both;
 
 
420
  }
421
 
422
+ .hero-title em {
423
+ font-style: italic; color: var(--gold);
424
+ text-shadow: 0 0 40px rgba(212,168,83,0.3);
425
+ }
426
+
427
+ .hero-sub {
428
+ font-size: 1rem; color: var(--tx-2); font-weight: 300;
429
+ letter-spacing: 0.2px; max-width: 560px; margin: 0 auto 28px;
430
+ line-height: 1.6; animation: fadeDown 0.6s 0.2s ease both;
431
+ }
432
+
433
+ .pill-row {
434
+ display: flex; gap: 8px; justify-content: center;
435
+ flex-wrap: wrap; animation: fadeDown 0.6s 0.3s ease both;
436
+ }
437
+
438
+ .pill {
439
+ display: inline-flex; align-items: center; gap: 6px;
440
+ background: rgba(255,255,255,0.03); border: 1px solid var(--b-2);
441
+ border-radius: 99px; padding: 6px 14px;
442
+ font-size: 0.76rem; font-weight: 500;
443
+ color: var(--tx-2); letter-spacing: 0.2px;
444
+ transition: all 0.2s; cursor: default;
445
+ }
446
+
447
+ .pill:hover { border-color: var(--gold); color: var(--gold-lt); background: var(--gold-muted); transform: translateY(-1px); }
448
+ .pill-dot { width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; }
449
+
450
+ /* ═══════════ PANEL CARDS ═══════════ */
451
+ .gr-group {
452
+ background: rgba(19,22,31,0.88) !important;
453
+ backdrop-filter: blur(20px) saturate(140%) !important;
454
+ -webkit-backdrop-filter: blur(20px) saturate(140%) !important;
455
+ border: 1px solid var(--b-1) !important;
456
+ border-radius: var(--r-lg) !important;
457
+ padding: 28px 32px !important;
458
+ box-shadow: var(--sh) !important;
459
+ transition: border-color 0.3s, box-shadow 0.3s !important;
460
+ position: relative; overflow: hidden;
461
+ }
462
+
463
+ .gr-group::before {
464
+ content: ''; position: absolute;
465
+ top: 0; left: 0; right: 0; height: 1px;
466
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.05) 40%, rgba(255,255,255,0.05) 60%, transparent);
467
+ pointer-events: none;
468
+ }
469
+
470
+ .gr-group:hover { border-color: var(--b-2) !important; box-shadow: var(--sh-lg) !important; }
471
+
472
+ /* ═══════════ STEP HEADERS ═══════════ */
473
+ .step-header { display: flex; align-items: center; gap: 14px; margin-bottom: 20px; }
474
+
475
+ .step-num {
476
+ width: 30px; height: 30px; background: var(--gold-muted);
477
+ border: 1px solid rgba(212,168,83,0.25); border-radius: 8px;
478
+ display: flex; align-items: center; justify-content: center;
479
+ font-family: 'Geist Mono', monospace; font-size: 0.72rem;
480
+ font-weight: 500; color: var(--gold); flex-shrink: 0;
481
+ }
482
+
483
+ .step-title { font-size: 0.95rem; font-weight: 600; color: var(--tx-1); letter-spacing: -0.2px; }
484
+ .step-desc { font-size: 0.76rem; color: var(--tx-3); margin-left: auto; }
485
+ .step-divider { height: 1px; background: linear-gradient(90deg, var(--b-1), transparent); margin-bottom: 20px; }
486
+
487
+ /* ═══════════ FORM CONTROLS ═══════════ */
488
+ label span, .block label span {
489
+ font-family: 'Geist', sans-serif !important; font-size: 0.73rem !important;
490
+ font-weight: 600 !important; color: var(--tx-3) !important;
491
+ letter-spacing: 0.8px !important; text-transform: uppercase !important;
492
+ }
493
+
494
+ textarea, input[type="text"], .gr-textbox textarea, .gr-textbox input {
495
+ background: var(--bg-3) !important; border: 1px solid var(--b-1) !important;
496
+ border-radius: var(--r-sm) !important; color: var(--tx-1) !important;
497
+ font-family: 'Geist Mono', monospace !important; font-size: 0.88rem !important;
498
+ padding: 14px 18px !important;
499
+ transition: border-color 0.2s, box-shadow 0.2s, background 0.2s !important;
500
+ resize: none !important; line-height: 1.5 !important;
501
  }
502
 
503
  textarea:focus, input[type="text"]:focus {
504
+ border-color: var(--gold) !important; box-shadow: var(--gold-ring) !important;
505
+ background: var(--bg-4) !important; outline: none !important;
 
506
  }
507
 
508
  textarea::placeholder, input::placeholder {
509
+ color: var(--tx-3) !important; font-style: italic;
510
+ font-family: 'Geist', sans-serif !important; font-size: 0.84rem !important;
511
  }
512
 
513
  select, .gr-dropdown select {
514
+ background: var(--bg-3) !important; border: 1px solid var(--b-1) !important;
515
+ border-radius: var(--r-sm) !important; color: var(--tx-1) !important;
516
+ font-family: 'Geist', sans-serif !important; font-size: 0.88rem !important;
517
+ padding: 14px 18px !important; transition: border-color 0.2s, box-shadow 0.2s !important;
 
 
 
 
518
  }
519
 
520
+ select:focus { border-color: var(--gold) !important; box-shadow: var(--gold-ring) !important; outline: none !important; }
521
 
522
+ /* ═══════════ BUTTONS ═══════════ */
523
  .gr-button {
524
+ font-family: 'Geist', sans-serif !important; font-size: 0.85rem !important;
525
+ font-weight: 600 !important; letter-spacing: 0.1px !important;
526
+ border-radius: var(--r-sm) !important; cursor: pointer !important;
527
+ transition: all 0.18s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
528
+ padding: 13px 24px !important; position: relative; overflow: hidden;
529
+ }
530
+
531
+ .gr-button-primary::after {
532
+ content: ''; position: absolute;
533
+ top: 0; left: -100%; width: 100%; height: 100%;
534
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.12), transparent);
535
+ transition: left 0.45s ease;
536
  }
537
+ .gr-button-primary:hover::after { left: 100%; }
538
 
539
  .gr-button-primary {
540
+ background: linear-gradient(135deg, #d4a853 0%, #b8893a 60%, #9e7535 100%) !important;
541
+ color: #070810 !important; border: none !important;
542
+ box-shadow: 0 2px 16px rgba(212,168,83,0.3), inset 0 1px 0 rgba(255,255,255,0.15) !important;
543
  }
544
 
545
  .gr-button-primary:hover {
546
+ transform: translateY(-2px) scale(1.01) !important;
547
+ box-shadow: 0 8px 28px rgba(212,168,83,0.42), inset 0 1px 0 rgba(255,255,255,0.2) !important;
548
+ filter: brightness(1.06) !important;
549
  }
550
 
551
+ .gr-button-primary:active { transform: translateY(0) scale(0.99) !important; }
552
 
553
  .gr-button-secondary {
554
+ background: var(--bg-4) !important; color: var(--tx-2) !important;
555
+ border: 1px solid var(--b-2) !important;
 
556
  }
557
 
558
  .gr-button-secondary:hover {
559
+ border-color: var(--gold) !important; color: var(--gold-lt) !important;
560
+ background: var(--gold-muted) !important; transform: translateY(-1px) !important;
561
+ box-shadow: var(--sh-gold) !important;
 
562
  }
563
 
564
+ /* ═══════════ STATUS BOX ═══════════ */
565
  #status-box .prose p, #status-box p {
566
+ font-family: 'Geist Mono', monospace !important; font-size: 0.8rem !important;
567
+ color: var(--tx-2) !important; background: var(--bg-3) !important;
568
+ border: 1px solid var(--b-1) !important; border-left: 3px solid var(--gold) !important;
569
+ border-radius: 0 var(--r-xs) var(--r-xs) 0 !important;
570
+ padding: 11px 16px !important; margin: 0 !important; line-height: 1.55 !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
571
  }
572
 
573
+ /* ═══════════ SUMMARY OUTPUT ═══════════ */
574
+ #summary-out .prose strong, #summary-out strong { color: var(--gold-lt) !important; font-weight: 600 !important; }
575
+ #summary-out .prose p { margin-bottom: 10px !important; }
576
+ #summary-out .prose ul { padding-left: 20px !important; }
577
+ #summary-out .prose li { margin-bottom: 5px !important; color: var(--tx-1) !important; }
578
+ #summary-out .prose em { color: var(--tx-2) !important; }
579
+
580
+ /* ═══════════ CHATBOT ═══════════ */
581
+ .gr-chatbot, [data-testid="chatbot"] {
582
+ background: var(--bg-1) !important; border: 1px solid var(--b-1) !important;
583
+ border-radius: var(--r) !important; padding: 12px !important;
584
+ }
585
 
586
+ .gr-chatbot .message {
587
+ font-family: 'Geist', sans-serif !important; font-size: 0.9rem !important;
588
+ line-height: 1.7 !important; padding: 13px 18px !important;
589
+ border-radius: 12px !important; max-width: 82% !important;
590
+ animation: msgIn 0.25s cubic-bezier(0.34,1.56,0.64,1) both;
591
  }
592
 
593
+ @keyframes msgIn {
594
+ from { opacity: 0; transform: translateY(8px) scale(0.97); }
595
+ to { opacity: 1; transform: translateY(0) scale(1); }
 
 
 
 
 
596
  }
597
 
598
+ .gr-chatbot .message.user {
599
+ background: linear-gradient(135deg, var(--bg-4), var(--bg-5)) !important;
600
+ border: 1px solid var(--b-2) !important; color: var(--tx-1) !important; margin-left: auto !important;
601
+ }
602
+
603
+ .gr-chatbot .message.bot {
604
+ background: var(--bg-2) !important; border: 1px solid var(--b-1) !important; color: var(--tx-1) !important;
605
+ }
606
+
607
+ /* ═══════════ AUDIO ═══════════ */
608
+ .gr-audio, [data-testid="audio"] {
609
+ background: var(--bg-3) !important; border: 1px solid var(--b-1) !important;
610
+ border-radius: var(--r-sm) !important; padding: 8px !important;
611
+ }
612
 
613
+ /* ═══════════ VOICE DESC ═══════════ */
614
+ .voice-desc {
615
+ font-size: 0.84rem; color: var(--tx-2); margin: 0 0 16px; line-height: 1.6;
616
+ padding: 10px 14px; background: var(--bg-3); border-radius: var(--r-xs);
617
+ border-left: 2px solid var(--b-2);
618
  }
619
 
620
+ /* ═══════════ FOOTER ═══════════ */
621
+ #footer-bar {
622
+ display: flex; align-items: center; justify-content: space-between;
623
+ padding: 14px 20px; background: rgba(15,17,25,0.6);
624
+ border: 1px solid var(--b-0); border-radius: var(--r); margin-top: 4px;
625
+ flex-wrap: wrap; gap: 10px;
626
  }
627
 
628
+ .footer-copy { font-family: 'Geist Mono', monospace; font-size: 0.68rem; color: var(--tx-3); }
629
+ .footer-stack { display: flex; gap: 6px; flex-wrap: wrap; }
630
+ .footer-tag {
631
+ font-family: 'Geist Mono', monospace; font-size: 0.64rem; color: var(--tx-3);
632
+ background: var(--bg-2); border: 1px solid var(--b-0); border-radius: 4px; padding: 2px 7px;
633
+ }
634
+
635
+ /* ═══════════ SCROLLBAR ═══════════ */
636
+ ::-webkit-scrollbar { width: 4px; height: 4px; }
637
+ ::-webkit-scrollbar-track { background: transparent; }
638
+ ::-webkit-scrollbar-thumb { background: var(--b-2); border-radius: 99px; }
639
+ ::-webkit-scrollbar-thumb:hover { background: var(--gold-dk); }
640
+
641
+ /* ═══════════ ANIMATIONS ═══════════ */
642
+ @keyframes fadeDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
643
+ @keyframes fadeUp { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }
644
+ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
645
+
646
+ .gradio-container .gr-group { animation: fadeUp 0.5s cubic-bezier(0.22, 1, 0.36, 1) both; }
647
+
648
+ ::selection { background: rgba(212,168,83,0.25); color: var(--tx-1); }
649
  """
650
 
651
  # =========================
652
  # BUILD UI
653
  # =========================
654
 
655
+ with gr.Blocks(title="Research Intelligence Platform") as demo:
656
 
657
+ # ─── HERO HEADER ──────────────────────────────────────────────────
658
  gr.HTML("""
659
+ <div id="hero">
660
+ <div class="hero-corner hero-corner-tl"></div>
661
+ <div class="hero-corner hero-corner-tr"></div>
662
+ <div class="hero-corner hero-corner-bl"></div>
663
+ <div class="hero-corner hero-corner-br"></div>
664
+
665
+ <div class="hero-eyebrow">Research Intelligence Platform</div>
666
+
667
+ <div class="hero-title">Your <em>AI Research</em> Partner</div>
668
+
669
+ <div class="hero-sub">
670
+ Paste any paper DOI β€” instantly fetch, index, summarize, and interrogate
671
+ research literature with LLaMA 3.3 and semantic search.
672
+ </div>
673
+
674
+ <div class="pill-row">
675
+ <span class="pill"><span class="pill-dot" style="background:#3ecf8e"></span>RAG Architecture</span>
676
+ <span class="pill"><span class="pill-dot" style="background:#d4a853"></span>LLaMA 3.3 Β· 70B</span>
677
+ <span class="pill"><span class="pill-dot" style="background:#4d94ff"></span>Whisper ASR</span>
678
+ <span class="pill"><span class="pill-dot" style="background:#f0a443"></span>FAISS Semantic Index</span>
679
+ <span class="pill"><span class="pill-dot" style="background:#c084fc"></span>DOI Resolver</span>
680
  </div>
681
  </div>
682
  """)
683
 
684
+ # ─── STEP 01 β€” LOAD PAPER ─────────────────────────────────────────
685
  with gr.Group():
686
+ gr.HTML("""
687
+ <div class="step-header">
688
+ <div class="step-num">01</div>
689
+ <div><div class="step-title">Load Paper</div></div>
690
+ <div class="step-desc">Paste DOI &rarr; fetch &rarr; index</div>
691
+ </div>
692
+ <div class="step-divider"></div>
693
+ """)
694
  with gr.Row(equal_height=True):
695
  arxiv_input = gr.Textbox(
696
  label="Paper DOI",
697
+ placeholder="10.1038/s41586-021-03819-2 Β· https://doi.org/10.48550/arXiv.1706.03762",
698
  scale=5,
699
  )
700
+ load_btn = gr.Button("Load Paper β†’", variant="primary", scale=1, min_width=160)
 
701
  status = gr.Markdown(
702
+ value="*Paste a DOI above and click **Load Paper** β€” the full text will be fetched and indexed automatically.*",
703
  elem_id="status-box",
704
  )
705
 
706
+ # ─── STEP 02 β€” SECTION SUMMARY ────────────────────────────────────
707
  with gr.Group():
708
+ gr.HTML("""
709
+ <div class="step-header">
710
+ <div class="step-num">02</div>
711
+ <div><div class="step-title">Section Summary</div></div>
712
+ <div class="step-desc">AI-powered breakdown</div>
713
+ </div>
714
+ <div class="step-divider"></div>
715
+ """)
716
  with gr.Row(equal_height=True):
717
  section_dropdown = gr.Dropdown(
718
+ label="Select Section", choices=[], scale=5, interactive=True,
 
 
 
719
  )
720
+ summarize_btn = gr.Button("✦ Summarize", variant="secondary", scale=1, min_width=150)
 
721
  summary_output = gr.Markdown(
722
+ value="*Select a section from the dropdown, then click **Summarize** for a structured AI breakdown.*",
723
  elem_id="summary-out",
724
  )
725
 
726
+ # ─── STEP 03 β€” CHAT ───────────────────────────────────────────────
727
  with gr.Group():
728
+ gr.HTML("""
729
+ <div class="step-header">
730
+ <div class="step-num">03</div>
731
+ <div><div class="step-title">Chat with Paper</div></div>
732
+ <div class="step-desc">Context-aware Q&A</div>
733
+ </div>
734
+ <div class="step-divider"></div>
735
+ """)
736
+ chatbot = gr.Chatbot(value=[], height=440, show_label=False)
737
  with gr.Row(equal_height=True):
738
  msg = gr.Textbox(
739
+ label="Ask a Question",
740
  placeholder="What is the main contribution? Β· How does the method work? Β· What datasets were used?",
741
+ scale=5, lines=1, max_lines=4,
 
 
742
  )
743
+ send_btn = gr.Button("Send β†’", variant="primary", scale=1, min_width=120)
744
 
745
+ # ─── STEP 04 β€” VOICE ──────────────────────────────────────────────
746
  with gr.Group():
 
747
  gr.HTML("""
748
+ <div class="step-header">
749
+ <div class="step-num">04</div>
750
+ <div><div class="step-title">Voice Query</div></div>
751
+ <div class="step-desc">Speak &rarr; transcribe &rarr; search</div>
752
+ </div>
753
+ <div class="step-divider"></div>
754
+ <p class="voice-desc">
755
+ Record or upload an audio question β€” Whisper ASR transcribes it and runs semantic search automatically.
756
+ </p>
757
  """)
758
  with gr.Row(equal_height=True):
759
+ audio = gr.Audio(type="filepath", label="Record or Upload Audio", scale=5)
760
+ voice_btn = gr.Button("πŸŽ™ Transcribe & Ask", variant="secondary", scale=1, min_width=170)
 
 
 
 
761
 
762
  # ─── FOOTER ───────────────────────────────────────────────────────
763
+ gr.HTML("""
764
+ <div id="footer-bar">
765
+ <span class="footer-copy">Research Intelligence Platform &middot; 2026</span>
766
+ <div class="footer-stack">
767
+ <span class="footer-tag">Gradio</span>
768
+ <span class="footer-tag">Groq LLaMA 3.3</span>
769
+ <span class="footer-tag">FAISS</span>
770
+ <span class="footer-tag">Sentence Transformers</span>
771
+ <span class="footer-tag">faster-whisper</span>
772
+ <span class="footer-tag">PyMuPDF</span>
773
+ <span class="footer-tag">Unpaywall</span>
774
+ </div>
775
+ </div>
776
+ """)
777
 
778
  # ─── BINDINGS ─────────────────────────────────────────────────────
779
  load_btn.click(load_paper, inputs=arxiv_input, outputs=[section_dropdown, status])