Benedikt Droste Claude Opus 4.5 commited on
Commit
5741599
·
1 Parent(s): 22ed911

Restyle app with elluminate design system

Browse files

- Remove text input field, PDF-only mode
- Set default language to German
- Light theme with cream background and purple accents
- Clean, minimal UI without emojis
- Improved responsive design
- Add .gitignore for styling reference files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Files changed (2) hide show
  1. .gitignore +2 -0
  2. app.py +193 -196
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Ignore styling reference files
2
+ styling_files_elluminate/
app.py CHANGED
@@ -360,72 +360,67 @@ def format_output(summary: str, structure: str) -> str:
360
  """Format the summary with thinking section if available."""
361
  if not summary and not structure:
362
  return "*Your summary will appear here...*"
363
-
364
  parts = []
365
-
366
  if structure:
367
- parts.append(f'<div class="thinking-section">\n\n💭 **Thinking**\n\n*{structure}*\n\n</div>')
368
-
369
  if summary:
370
  if structure:
371
  parts.append('<div class="summary-divider"></div>')
372
  parts.append(f'<div class="summary-section">\n\n{summary}\n\n</div>')
373
-
374
  return "\n".join(parts)
375
 
376
 
377
  def summarize(
378
  pdf_file: str | None,
379
- text_input: str | None,
380
  language: str,
381
  words: int,
382
  custom_instruction: str,
383
  progress=gr.Progress(),
384
  ):
385
  """Main entry point for summarization."""
386
- page_ranges = None
387
- lang_code = LANGUAGES.get(language, "en")
388
-
389
- # Determine input source
390
- if pdf_file:
391
- progress(0.1, desc="📄 Extracting text from PDF...")
392
- try:
393
- text, page_ranges = extract_pdf_text(pdf_file)
394
- except Exception as e:
395
- yield (
396
- f"❌ **Error extracting PDF:** {str(e)}",
397
- "Please check that MISTRAL_API_KEY is set correctly.",
398
- gr.update(visible=False),
399
- )
400
- return
401
- elif text_input and text_input.strip():
402
- text = text_input.strip()
403
- else:
404
  yield (
405
- "⚠️ Please provide a PDF file or paste some text to summarize.",
406
  "",
407
  gr.update(visible=False),
408
  )
409
  return
410
-
 
 
 
 
 
 
 
 
 
 
 
411
  if not text.strip():
412
  yield (
413
- "⚠️ No text content found in the document.",
414
  "",
415
  gr.update(visible=False),
416
  )
417
  return
418
-
419
- progress(0.2, desc="🤖 Generating summary...")
420
-
421
  for summary, structure, sources, _ in generate_summary(
422
  text, lang_code, language, words, custom_instruction, page_ranges
423
  ):
424
  formatted_output = format_output(summary, structure)
425
  sources_md = format_sources(sources, page_ranges is not None) if sources else "*Identifying sources...*"
426
  yield formatted_output, sources_md, gr.update(visible=True)
427
-
428
- progress(1.0, desc="✅ Complete!")
429
 
430
 
431
  # ============================================================================
@@ -433,101 +428,126 @@ def summarize(
433
  # ============================================================================
434
 
435
  THEME = gr.themes.Soft(
436
- primary_hue="indigo",
437
- secondary_hue="blue",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
  neutral_hue="slate",
439
- font=gr.themes.GoogleFont("Inter"),
440
  ).set(
441
- body_background_fill="linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
442
- body_background_fill_dark="linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)",
443
- block_background_fill="white",
444
- block_background_fill_dark="#1e1e2e",
445
- block_radius="12px",
446
- block_shadow="0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
 
 
 
 
 
 
 
 
447
  )
448
 
449
  CSS = """
450
- /* Full width layout */
451
  .gradio-container {
452
- max-width: 100% !important;
453
- padding: 0 3rem !important;
 
454
  }
455
 
456
  /* Header styling */
457
  .main-header {
458
  text-align: center;
459
- padding: 2.5rem 2rem;
460
- background: rgba(30, 30, 46, 0.6);
461
- backdrop-filter: blur(10px);
462
- border-radius: 16px;
463
- margin-bottom: 2rem;
464
- border: 1px solid rgba(255, 255, 255, 0.1);
465
  }
466
 
467
  .main-header h1 {
468
- font-size: 2.75rem;
469
- font-weight: 700;
470
- background: linear-gradient(135deg, #a5b4fc 0%, #c4b5fd 100%);
471
- -webkit-background-clip: text;
472
- -webkit-text-fill-color: transparent;
473
- background-clip: text;
474
- margin-bottom: 0.75rem;
475
  }
476
 
477
  .main-header p {
478
- color: #94a3b8;
479
- font-size: 1.15rem;
480
  margin: 0;
481
  }
482
 
483
- /* Card styling */
484
- .input-card, .output-card {
485
- background: rgba(30, 30, 46, 0.8) !important;
486
- border: 1px solid rgba(255, 255, 255, 0.08) !important;
487
- border-radius: 16px !important;
488
- padding: 1.5rem !important;
489
- }
490
-
491
  /* Section headers */
492
  .section-title {
493
- color: #e2e8f0 !important;
494
- font-size: 1.1rem !important;
495
  font-weight: 600 !important;
496
- margin-bottom: 1rem !important;
497
- display: flex;
498
- align-items: center;
499
- gap: 0.5rem;
 
 
500
  }
501
 
502
  /* Summary output */
503
  .summary-text {
504
- font-size: 1.05rem !important;
505
- line-height: 1.85 !important;
506
- color: #e2e8f0 !important;
507
  background: transparent !important;
508
  }
509
 
510
  /* Thinking section */
511
  .thinking-section {
512
- background: rgba(99, 102, 241, 0.08);
513
- border-left: 3px solid #6366f1;
514
- border-radius: 0 8px 8px 0;
515
  padding: 1rem 1.25rem;
516
  margin-bottom: 0;
517
  }
518
 
519
  .thinking-section p {
520
- color: #a5b4fc !important;
521
- font-size: 0.95rem !important;
522
- line-height: 1.7 !important;
523
  margin: 0 !important;
 
524
  }
525
 
526
  /* Summary divider */
527
  .summary-divider {
528
  height: 1px;
529
- background: linear-gradient(90deg, transparent, rgba(99, 102, 241, 0.3), transparent);
530
- margin: 1.5rem 0;
531
  }
532
 
533
  /* Summary section */
@@ -535,23 +555,23 @@ CSS = """
535
  padding-top: 0.5rem;
536
  }
537
 
538
- /* Sources panel - fixed styling */
539
  .sources-panel {
540
- background: #252536 !important;
541
- border-radius: 12px !important;
542
- padding: 1.25rem !important;
543
- font-size: 0.95rem !important;
544
  max-height: 400px !important;
545
  overflow-y: auto !important;
546
- color: #cbd5e1 !important;
547
- border: 1px solid rgba(255, 255, 255, 0.06) !important;
548
  }
549
 
550
  .sources-panel p {
551
- color: #cbd5e1 !important;
552
- margin-bottom: 0.75rem !important;
553
  padding: 0.5rem 0 !important;
554
- border-bottom: 1px solid rgba(255, 255, 255, 0.05) !important;
555
  }
556
 
557
  .sources-panel p:last-child {
@@ -560,105 +580,91 @@ CSS = """
560
  }
561
 
562
  .sources-panel strong {
563
- color: #a5b4fc !important;
564
  }
565
 
566
  /* Accordion styling */
567
  .accordion {
568
  background: transparent !important;
569
- border: none !important;
 
570
  }
571
 
572
  .accordion > .label-wrap {
573
- background: rgba(37, 37, 54, 0.6) !important;
574
- border-radius: 10px !important;
575
  padding: 0.75rem 1rem !important;
576
- border: 1px solid rgba(255, 255, 255, 0.06) !important;
577
  }
578
 
579
  /* Generate button */
580
  .generate-btn {
581
- background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%) !important;
582
  border: none !important;
583
- font-weight: 600 !important;
584
- font-size: 1.05rem !important;
585
- padding: 0.875rem 2rem !important;
586
- border-radius: 10px !important;
587
- transition: all 0.2s ease !important;
588
- box-shadow: 0 4px 14px rgba(99, 102, 241, 0.4) !important;
589
  }
590
 
591
  .generate-btn:hover {
592
- transform: translateY(-2px) !important;
593
- box-shadow: 0 6px 20px rgba(99, 102, 241, 0.5) !important;
594
  }
595
 
596
- /* Input fields */
597
- .dark input, .dark textarea {
598
- background: #252536 !important;
599
- border: 1px solid rgba(255, 255, 255, 0.1) !important;
600
- color: #e2e8f0 !important;
601
- border-radius: 8px !important;
602
- }
603
-
604
- .dark input:focus, .dark textarea:focus {
605
- border-color: #6366f1 !important;
606
- box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2) !important;
607
  }
608
 
609
- /* Dropdown */
610
- .dark select {
611
- background: #252536 !important;
612
- border: 1px solid rgba(255, 255, 255, 0.1) !important;
613
- color: #e2e8f0 !important;
 
614
  }
615
 
616
- /* Slider */
617
- .dark .slider {
618
- background: #252536 !important;
 
619
  }
620
 
621
  /* File upload */
622
- .dark .upload-button {
623
- background: #252536 !important;
624
- border: 2px dashed rgba(255, 255, 255, 0.15) !important;
625
- border-radius: 12px !important;
 
626
  }
627
 
628
- .dark .upload-button:hover {
629
- border-color: #6366f1 !important;
630
- background: rgba(99, 102, 241, 0.1) !important;
631
- }
632
-
633
- /* Divider */
634
- .divider {
635
- color: #64748b !important;
636
- text-align: center;
637
- margin: 1rem 0;
638
  }
639
 
640
  /* Footer */
641
  .footer {
642
  text-align: center;
643
  padding: 1.5rem;
644
- margin-top: 2rem;
645
- color: #94a3b8;
646
- font-size: 0.9rem;
647
  }
648
 
649
  .footer a {
650
- color: #a5b4fc;
651
  text-decoration: none;
652
- transition: color 0.2s;
653
  }
654
 
655
  .footer a:hover {
656
- color: #c4b5fd;
657
- text-decoration: underline;
658
  }
659
 
660
  .footer-divider {
661
- color: #475569;
662
  margin: 0 0.5rem;
663
  }
664
 
@@ -670,13 +676,23 @@ footer {
670
  /* Responsive adjustments */
671
  @media (max-width: 768px) {
672
  .gradio-container {
673
- padding: 0 1rem !important;
674
  }
675
-
676
  .main-header h1 {
677
- font-size: 2rem;
 
 
 
 
678
  }
679
  }
 
 
 
 
 
 
680
  """
681
 
682
 
@@ -684,54 +700,37 @@ footer {
684
  # Gradio Interface
685
  # ============================================================================
686
 
687
- FORCE_DARK_MODE_JS = """
688
- () => {
689
- document.body.classList.remove('light');
690
- document.body.classList.add('dark');
691
- }
692
- """
693
-
694
-
695
  def create_app() -> gr.Blocks:
696
  """Create the Gradio application."""
697
- with gr.Blocks(title="sui-1 Summarizer", theme=THEME, css=CSS, js=FORCE_DARK_MODE_JS) as app:
698
 
699
  # Header
700
  gr.HTML("""
701
  <div class="main-header">
702
- <h1>📄 sui-1 Summarizer</h1>
703
  <p>Generate grounded summaries with verifiable source citations</p>
704
  </div>
705
  """)
706
-
707
  with gr.Row(equal_height=False):
708
  # Left column: Inputs
709
  with gr.Column(scale=1):
710
- gr.Markdown("### 📥 Input", elem_classes=["section-title"])
711
-
712
  pdf_input = gr.File(
713
- label="Upload PDF",
714
  file_types=[".pdf"],
715
  type="filepath",
716
  )
717
-
718
- gr.Markdown("<div class='divider'>— or —</div>")
719
-
720
- text_input = gr.Textbox(
721
- label="Paste Text",
722
- placeholder="Paste your document text here...",
723
- lines=8,
724
- max_lines=15,
725
- )
726
-
727
- gr.Markdown("### ⚙️ Settings", elem_classes=["section-title"])
728
-
729
  language = gr.Dropdown(
730
  choices=list(LANGUAGES.keys()),
731
- value="English",
732
  label="Output Language",
733
  )
734
-
735
  words = gr.Slider(
736
  minimum=100,
737
  maximum=800,
@@ -740,51 +739,49 @@ def create_app() -> gr.Blocks:
740
  label="Target Word Count",
741
  info="Longer summaries include more citations",
742
  )
743
-
744
  custom_instruction = gr.Textbox(
745
  label="Custom Instructions (Optional)",
746
- placeholder="e.g., 'Focus on methodology' or 'Use bullet points'",
747
  lines=2,
748
  )
749
-
750
  generate_btn = gr.Button(
751
- "✨ Generate Summary",
752
  variant="primary",
753
  size="lg",
754
  elem_classes=["generate-btn"],
755
  )
756
-
757
  # Right column: Output
758
  with gr.Column(scale=1):
759
- gr.Markdown("### 📋 Summary", elem_classes=["section-title"])
760
 
761
  summary_output = gr.Markdown(
762
  value="*Your summary will appear here...*",
763
  elem_classes=["summary-text"],
764
  )
765
-
766
  with gr.Accordion(
767
- "📚 Source Citations",
768
  open=False,
769
  visible=False,
770
  ) as sources_accordion:
771
  sources_output = gr.Markdown(elem_classes=["sources-panel"])
772
-
773
  # Event handlers
774
  generate_btn.click(
775
  fn=summarize,
776
- inputs=[pdf_input, text_input, language, words, custom_instruction],
777
  outputs=[summary_output, sources_output, sources_accordion],
778
  )
779
-
780
  # Footer
781
  gr.HTML("""
782
  <div class="footer">
783
- <strong>Model:</strong> <a href="https://huggingface.co/ellamind/sui-1-24b" target="_blank">ellamind/sui-1-24b</a>
784
- <span class="footer-divider">•</span>
785
- <strong>PDF OCR:</strong> <a href="https://docs.mistral.ai/capabilities/document_ai" target="_blank">Mistral OCR</a>
786
- <span class="footer-divider">•</span>
787
- Made with 💜 by <a href="https://huggingface.co/ellamind" target="_blank">ellamind</a>
788
  </div>
789
  """)
790
 
 
360
  """Format the summary with thinking section if available."""
361
  if not summary and not structure:
362
  return "*Your summary will appear here...*"
363
+
364
  parts = []
365
+
366
  if structure:
367
+ parts.append(f'<div class="thinking-section">\n\n**Reasoning**\n\n*{structure}*\n\n</div>')
368
+
369
  if summary:
370
  if structure:
371
  parts.append('<div class="summary-divider"></div>')
372
  parts.append(f'<div class="summary-section">\n\n{summary}\n\n</div>')
373
+
374
  return "\n".join(parts)
375
 
376
 
377
  def summarize(
378
  pdf_file: str | None,
 
379
  language: str,
380
  words: int,
381
  custom_instruction: str,
382
  progress=gr.Progress(),
383
  ):
384
  """Main entry point for summarization."""
385
+ lang_code = LANGUAGES.get(language, "de")
386
+
387
+ if not pdf_file:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  yield (
389
+ "Please upload a PDF document to summarize.",
390
  "",
391
  gr.update(visible=False),
392
  )
393
  return
394
+
395
+ progress(0.1, desc="Extracting text from PDF...")
396
+ try:
397
+ text, page_ranges = extract_pdf_text(pdf_file)
398
+ except Exception as e:
399
+ yield (
400
+ f"**Error extracting PDF:** {str(e)}",
401
+ "Please check that MISTRAL_API_KEY is set correctly.",
402
+ gr.update(visible=False),
403
+ )
404
+ return
405
+
406
  if not text.strip():
407
  yield (
408
+ "No text content found in the document.",
409
  "",
410
  gr.update(visible=False),
411
  )
412
  return
413
+
414
+ progress(0.2, desc="Generating summary...")
415
+
416
  for summary, structure, sources, _ in generate_summary(
417
  text, lang_code, language, words, custom_instruction, page_ranges
418
  ):
419
  formatted_output = format_output(summary, structure)
420
  sources_md = format_sources(sources, page_ranges is not None) if sources else "*Identifying sources...*"
421
  yield formatted_output, sources_md, gr.update(visible=True)
422
+
423
+ progress(1.0, desc="Complete!")
424
 
425
 
426
  # ============================================================================
 
428
  # ============================================================================
429
 
430
  THEME = gr.themes.Soft(
431
+ primary_hue=gr.themes.Color(
432
+ c50="#f5f3ff",
433
+ c100="#ede9fe",
434
+ c200="#ddd6fe",
435
+ c300="#c4b5fd",
436
+ c400="#a78bfa",
437
+ c500="#8b5cf6",
438
+ c600="#7c3aed",
439
+ c700="#220475",
440
+ c800="#1a0359",
441
+ c900="#130242",
442
+ c950="#0a0124",
443
+ ),
444
+ secondary_hue=gr.themes.Color(
445
+ c50="#fdfcfa",
446
+ c100="#f9f7f2",
447
+ c200="#f5f0e5",
448
+ c300="#ebe4d4",
449
+ c400="#ddd4c0",
450
+ c500="#c9bda6",
451
+ c600="#b5a78c",
452
+ c700="#9a8e73",
453
+ c800="#7f755f",
454
+ c900="#665e4d",
455
+ c950="#4d4639",
456
+ ),
457
  neutral_hue="slate",
458
+ font=gr.themes.GoogleFont("General Sans"),
459
  ).set(
460
+ body_background_fill="#f5f2ea",
461
+ body_background_fill_dark="#f5f2ea",
462
+ block_background_fill="#ffffff",
463
+ block_background_fill_dark="#ffffff",
464
+ block_radius="0.5rem",
465
+ block_shadow="0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
466
+ block_border_width="1px",
467
+ block_border_color="#e2e8f0",
468
+ button_primary_background_fill="#220475",
469
+ button_primary_background_fill_hover="#1a0359",
470
+ button_primary_text_color="#ffffff",
471
+ input_background_fill="#ffffff",
472
+ input_border_color="#e2e8f0",
473
+ input_border_width="1px",
474
  )
475
 
476
  CSS = """
477
+ /* Base layout */
478
  .gradio-container {
479
+ max-width: 1400px !important;
480
+ margin: 0 auto !important;
481
+ padding: 2rem !important;
482
  }
483
 
484
  /* Header styling */
485
  .main-header {
486
  text-align: center;
487
+ padding: 2rem 1.5rem;
488
+ background: #ffffff;
489
+ border-radius: 0.5rem;
490
+ margin-bottom: 1.5rem;
491
+ border: 1px solid #e2e8f0;
492
+ box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
493
  }
494
 
495
  .main-header h1 {
496
+ font-size: 2rem;
497
+ font-weight: 600;
498
+ color: #220475;
499
+ margin-bottom: 0.5rem;
 
 
 
500
  }
501
 
502
  .main-header p {
503
+ color: #64748b;
504
+ font-size: 1rem;
505
  margin: 0;
506
  }
507
 
 
 
 
 
 
 
 
 
508
  /* Section headers */
509
  .section-title {
510
+ color: #220475 !important;
511
+ font-size: 1rem !important;
512
  font-weight: 600 !important;
513
+ margin-bottom: 0.75rem !important;
514
+ }
515
+
516
+ .section-title h3 {
517
+ color: #220475 !important;
518
+ margin: 0 !important;
519
  }
520
 
521
  /* Summary output */
522
  .summary-text {
523
+ font-size: 1rem !important;
524
+ line-height: 1.75 !important;
525
+ color: #020817 !important;
526
  background: transparent !important;
527
  }
528
 
529
  /* Thinking section */
530
  .thinking-section {
531
+ background: #f5f0e5;
532
+ border-left: 3px solid #220475;
533
+ border-radius: 0 0.5rem 0.5rem 0;
534
  padding: 1rem 1.25rem;
535
  margin-bottom: 0;
536
  }
537
 
538
  .thinking-section p {
539
+ color: #220475 !important;
540
+ font-size: 0.9rem !important;
541
+ line-height: 1.6 !important;
542
  margin: 0 !important;
543
+ opacity: 0.85;
544
  }
545
 
546
  /* Summary divider */
547
  .summary-divider {
548
  height: 1px;
549
+ background: linear-gradient(90deg, transparent, #e2e8f0, transparent);
550
+ margin: 1.25rem 0;
551
  }
552
 
553
  /* Summary section */
 
555
  padding-top: 0.5rem;
556
  }
557
 
558
+ /* Sources panel */
559
  .sources-panel {
560
+ background: #f9f7f2 !important;
561
+ border-radius: 0.5rem !important;
562
+ padding: 1rem !important;
563
+ font-size: 0.9rem !important;
564
  max-height: 400px !important;
565
  overflow-y: auto !important;
566
+ color: #020817 !important;
567
+ border: 1px solid #e2e8f0 !important;
568
  }
569
 
570
  .sources-panel p {
571
+ color: #020817 !important;
572
+ margin-bottom: 0.5rem !important;
573
  padding: 0.5rem 0 !important;
574
+ border-bottom: 1px solid #e2e8f0 !important;
575
  }
576
 
577
  .sources-panel p:last-child {
 
580
  }
581
 
582
  .sources-panel strong {
583
+ color: #220475 !important;
584
  }
585
 
586
  /* Accordion styling */
587
  .accordion {
588
  background: transparent !important;
589
+ border: 1px solid #e2e8f0 !important;
590
+ border-radius: 0.5rem !important;
591
  }
592
 
593
  .accordion > .label-wrap {
594
+ background: #f9f7f2 !important;
595
+ border-radius: 0.5rem !important;
596
  padding: 0.75rem 1rem !important;
 
597
  }
598
 
599
  /* Generate button */
600
  .generate-btn {
601
+ background: #220475 !important;
602
  border: none !important;
603
+ font-weight: 500 !important;
604
+ font-size: 1rem !important;
605
+ padding: 0.75rem 1.5rem !important;
606
+ border-radius: 0.5rem !important;
607
+ transition: all 0.15s ease !important;
608
+ color: #ffffff !important;
609
  }
610
 
611
  .generate-btn:hover {
612
+ background: #1a0359 !important;
613
+ transform: translateY(-1px) !important;
614
  }
615
 
616
+ .generate-btn:disabled {
617
+ background: #9ca3af !important;
 
 
 
 
 
 
 
 
 
618
  }
619
 
620
+ /* Input fields */
621
+ input, textarea {
622
+ background: #ffffff !important;
623
+ border: 1px solid #e2e8f0 !important;
624
+ color: #020817 !important;
625
+ border-radius: 0.5rem !important;
626
  }
627
 
628
+ input:focus, textarea:focus {
629
+ border-color: #220475 !important;
630
+ box-shadow: 0 0 0 2px rgba(34, 4, 117, 0.1) !important;
631
+ outline: none !important;
632
  }
633
 
634
  /* File upload */
635
+ .upload-button {
636
+ background: #ffffff !important;
637
+ border: 2px dashed #d5d6ef !important;
638
+ border-radius: 0.5rem !important;
639
+ transition: all 0.15s ease !important;
640
  }
641
 
642
+ .upload-button:hover {
643
+ border-color: #220475 !important;
644
+ background: #f5f0e5 !important;
 
 
 
 
 
 
 
645
  }
646
 
647
  /* Footer */
648
  .footer {
649
  text-align: center;
650
  padding: 1.5rem;
651
+ margin-top: 1.5rem;
652
+ color: #64748b;
653
+ font-size: 0.875rem;
654
  }
655
 
656
  .footer a {
657
+ color: #220475;
658
  text-decoration: none;
659
+ transition: opacity 0.15s;
660
  }
661
 
662
  .footer a:hover {
663
+ opacity: 0.7;
 
664
  }
665
 
666
  .footer-divider {
667
+ color: #cbd5e1;
668
  margin: 0 0.5rem;
669
  }
670
 
 
676
  /* Responsive adjustments */
677
  @media (max-width: 768px) {
678
  .gradio-container {
679
+ padding: 1rem !important;
680
  }
681
+
682
  .main-header h1 {
683
+ font-size: 1.5rem;
684
+ }
685
+
686
+ .main-header {
687
+ padding: 1.5rem 1rem;
688
  }
689
  }
690
+
691
+ /* Loading state */
692
+ .generating {
693
+ opacity: 0.7;
694
+ pointer-events: none;
695
+ }
696
  """
697
 
698
 
 
700
  # Gradio Interface
701
  # ============================================================================
702
 
 
 
 
 
 
 
 
 
703
  def create_app() -> gr.Blocks:
704
  """Create the Gradio application."""
705
+ with gr.Blocks(title="sui-1 Summarizer", theme=THEME, css=CSS) as app:
706
 
707
  # Header
708
  gr.HTML("""
709
  <div class="main-header">
710
+ <h1>sui-1 Summarizer</h1>
711
  <p>Generate grounded summaries with verifiable source citations</p>
712
  </div>
713
  """)
714
+
715
  with gr.Row(equal_height=False):
716
  # Left column: Inputs
717
  with gr.Column(scale=1):
718
+ gr.Markdown("### Upload Document", elem_classes=["section-title"])
719
+
720
  pdf_input = gr.File(
721
+ label="PDF Document",
722
  file_types=[".pdf"],
723
  type="filepath",
724
  )
725
+
726
+ gr.Markdown("### Settings", elem_classes=["section-title"])
727
+
 
 
 
 
 
 
 
 
 
728
  language = gr.Dropdown(
729
  choices=list(LANGUAGES.keys()),
730
+ value="German",
731
  label="Output Language",
732
  )
733
+
734
  words = gr.Slider(
735
  minimum=100,
736
  maximum=800,
 
739
  label="Target Word Count",
740
  info="Longer summaries include more citations",
741
  )
742
+
743
  custom_instruction = gr.Textbox(
744
  label="Custom Instructions (Optional)",
745
+ placeholder="e.g., Focus on methodology, Use bullet points",
746
  lines=2,
747
  )
748
+
749
  generate_btn = gr.Button(
750
+ "Generate Summary",
751
  variant="primary",
752
  size="lg",
753
  elem_classes=["generate-btn"],
754
  )
755
+
756
  # Right column: Output
757
  with gr.Column(scale=1):
758
+ gr.Markdown("### Summary", elem_classes=["section-title"])
759
 
760
  summary_output = gr.Markdown(
761
  value="*Your summary will appear here...*",
762
  elem_classes=["summary-text"],
763
  )
764
+
765
  with gr.Accordion(
766
+ "Source Citations",
767
  open=False,
768
  visible=False,
769
  ) as sources_accordion:
770
  sources_output = gr.Markdown(elem_classes=["sources-panel"])
771
+
772
  # Event handlers
773
  generate_btn.click(
774
  fn=summarize,
775
+ inputs=[pdf_input, language, words, custom_instruction],
776
  outputs=[summary_output, sources_output, sources_accordion],
777
  )
778
+
779
  # Footer
780
  gr.HTML("""
781
  <div class="footer">
782
+ <a href="https://huggingface.co/ellamind/sui-1-24b" target="_blank">sui-1-24b</a>
783
+ <span class="footer-divider">|</span>
784
+ <a href="https://huggingface.co/ellamind" target="_blank">ellamind</a>
 
 
785
  </div>
786
  """)
787