ragunath-ravi commited on
Commit
4134b9e
Β·
verified Β·
1 Parent(s): d3caa9a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +341 -207
app.py CHANGED
@@ -419,320 +419,454 @@ llm_response_agent = LLMResponseAgent(message_bus)
419
  coordinator_agent = CoordinatorAgent(message_bus)
420
 
421
  def create_interface():
422
- """Create ChatGPT-style Gradio interface"""
423
 
424
  with gr.Blocks(
425
  theme=gr.themes.Base(),
426
  css="""
427
- /* Dark theme styling */
428
  .gradio-container {
429
- background-color: #1a1a1a !important;
430
  color: #ffffff !important;
431
  height: 100vh !important;
432
  max-width: none !important;
433
  padding: 0 !important;
 
434
  }
435
 
436
- /* Main container */
437
  .main-container {
438
  display: flex;
439
  flex-direction: column;
440
  height: 100vh;
441
- background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
 
 
442
  }
443
 
444
- /* Header */
445
  .header {
446
- background: rgba(255, 193, 7, 0.1);
447
- border-bottom: 1px solid rgba(255, 193, 7, 0.2);
448
  padding: 1rem 2rem;
449
- backdrop-filter: blur(10px);
450
  }
451
 
452
  .header h1 {
453
- color: #ffc107;
454
  margin: 0;
455
- font-size: 1.5rem;
456
- font-weight: 600;
457
  }
458
 
459
- .header p {
460
- color: #cccccc;
461
- margin: 0.25rem 0 0 0;
462
- font-size: 0.9rem;
463
- }
464
-
465
- /* Chat area - REDUCED HEIGHT */
466
  .chat-container {
467
  flex: 1;
468
  display: flex;
469
  flex-direction: column;
470
- max-width: 1000px;
471
- margin: 0 auto;
472
- width: 100%;
473
- padding: 1rem;
474
- height: calc(100vh - 200px) !important; /* Reduced height */
475
  }
476
 
477
- /* Chatbot styling - SMALLER */
478
  .gradio-chatbot {
479
- height: 300px !important; /* Reduced from 500px */
480
- max-height: 300px !important;
481
- background: transparent !important;
 
482
  border: none !important;
483
- margin-bottom: 1rem;
484
  overflow-y: auto !important;
485
- box-shadow: 0 0 12px rgba(255, 193, 7, 0.1);
486
-
487
  }
488
 
489
- /* Input area */
490
- .input-area {
491
- background: rgba(45, 45, 45, 0.6);
492
- border-radius: 16px;
493
- padding: 1rem;
494
- border: 1px solid rgba(255, 193, 7, 0.2);
495
- backdrop-filter: blur(10px);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
  position: sticky;
497
  bottom: 0;
 
 
 
498
  }
499
 
500
- /* File upload */
501
- .upload-area {
502
- background: rgba(255, 193, 7, 0.05);
503
- border: 2px dashed rgba(255, 193, 7, 0.3);
504
- border-radius: 12px;
505
- padding: 1rem;
506
- margin-bottom: 1rem;
507
- transition: all 0.3s ease;
 
508
  }
509
 
510
- /* Buttons - YELLOW SEND BUTTON */
511
- .send-btn {
512
- background: linear-gradient(135deg, #ffc107 0%, #ff8f00 100%) !important;
513
- color: #000000 !important;
 
 
 
514
  border: none !important;
515
- border-radius: 8px !important;
516
- font-weight: 600 !important;
517
- min-height: 40px !important;
 
 
 
 
 
 
 
 
 
 
 
 
518
  }
519
 
520
- .primary-btn {
521
- background: linear-gradient(135deg, #ffc107 0%, #ff8f00 100%) !important;
522
- color: #000000 !important;
 
 
 
 
523
  border: none !important;
524
- border-radius: 8px !important;
525
- font-weight: 600 !important;
 
 
 
 
 
 
 
 
 
 
526
  }
527
 
528
- /* Text inputs */
529
- .gradio-textbox input, .gradio-textbox textarea {
530
- background: rgba(45, 45, 45, 0.8) !important;
 
 
531
  color: #ffffff !important;
532
- border: 1px solid rgba(255, 193, 7, 0.2) !important;
533
- border-radius: 8px !important;
 
 
 
 
 
 
534
  }
535
 
536
- /* Processing indicator */
537
- .processing-indicator {
538
- background: rgba(255, 193, 7, 0.1);
539
- border: 1px solid rgba(255, 193, 7, 0.3);
540
- border-radius: 8px;
541
- padding: 0.75rem;
542
- margin: 0.5rem 0;
543
- color: #ffc107;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
544
  text-align: center;
545
  }
546
 
547
- /* Input row styling */
548
- .input-row {
549
- display: flex !important;
550
- gap: 10px !important;
551
- align-items: end !important;
552
  }
553
 
554
- /* Message input */
555
- .message-input {
556
- flex: 1 !important;
557
- min-height: 40px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
558
  }
559
  """,
560
  title="Agentic RAG Assistant"
561
  ) as iface:
562
 
563
- # Header
564
- with gr.Row():
565
- with gr.Column():
566
- gr.HTML("""
567
- <div class="header">
568
- <h1>Agentic RAG Assistant</h1>
569
- <p>Upload documents and ask questions - powered by Multi-Agent Architecture</p>
570
- </div>
571
- """)
572
 
573
- # Main layout with sidebar and chat
574
  with gr.Row():
575
- # Left sidebar for file upload
576
- with gr.Column(scale=1):
577
- gr.Markdown("### πŸ“ Document Upload")
578
-
579
- file_upload = gr.File(
580
- file_count="multiple",
581
- file_types=[".pdf", ".pptx", ".csv", ".docx", ".txt", ".md"],
582
- label="Upload Documents",
583
- elem_classes=["upload-area"]
584
- )
585
-
586
- processing_status = gr.HTML(visible=False)
587
-
588
- process_btn = gr.Button(
589
- "Process Documents",
590
- variant="primary",
591
- elem_classes=["primary-btn"]
592
- )
593
-
594
- # gr.Markdown("### ℹ️ Architecture")
595
- # gr.Markdown("""
596
- # **Multi-Agent System:**
597
- # - πŸ“„ **IngestionAgent**: Document parsing
598
- # - πŸ” **RetrievalAgent**: Semantic search
599
- # - πŸ€– **LLMAgent**: Response generation
600
- # - 🎯 **CoordinatorAgent**: Workflow orchestration
601
-
602
- # **Features:**
603
- # - Streaming responses
604
- # - Multi-format support
605
- # - Context-aware answers
606
- # """)
607
-
608
- # Right side - Chat interface
609
- with gr.Column(scale=2):
610
- gr.Markdown("### πŸ’¬ Chat Interface")
611
 
612
- # Chatbot with reduced height
613
  chatbot = gr.Chatbot(
614
- height=300, # Reduced height
615
  elem_classes=["gradio-chatbot"],
616
  show_copy_button=True,
617
  type="messages",
618
- placeholder="Upload documents first, then start chatting!"
 
 
619
  )
620
 
621
- # Input area with improved layout
622
- with gr.Row(elem_classes=["input-row"]):
623
- msg_input = gr.Textbox(
624
- placeholder="Ask about your documents...",
625
- label="Message",
626
- scale=4,
627
- elem_classes=["message-input"],
628
- show_label=False,
629
- autofocus=True
630
- )
631
- send_btn = gr.Button(
632
- "Send",
633
- scale=1,
634
- elem_classes=["send-btn"],
635
- size="sm"
636
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
637
 
638
- # Examples
639
- gr.Examples(
640
- examples=[
641
- "What are the main topics discussed?",
642
- "Summarize the key findings",
643
- "What metrics are mentioned?",
644
- "What are the recommendations?"
645
- ],
646
- inputs=msg_input,
647
- label="Example Questions"
648
- )
649
-
650
- # State to track document processing
651
  doc_processed = gr.State(False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
652
 
653
  # Event handlers
654
- def handle_file_upload_and_process(files):
 
655
  if not files:
656
- return gr.update(visible=False), False
 
 
 
 
 
 
 
 
 
657
 
658
- # Show processing indicator
659
- processing_html = f"""
660
- <div class="processing-indicator">
661
- πŸ“„ Processing {len(files)} documents... Please wait.
662
- </div>
663
- """
664
 
665
- # Process files
666
  try:
 
667
  result = coordinator_agent.process_files(files)
668
 
669
- # Wait a moment for processing to complete
670
  import time
671
  time.sleep(3)
672
 
673
- success_html = """
674
- <div style="background: rgba(76, 175, 80, 0.1); border: 1px solid rgba(76, 175, 80, 0.3);
675
- border-radius: 8px; padding: 0.75rem; color: #4caf50; text-align: center;">
676
- Documents processed successfully! You can now ask questions.
677
- </div>
678
- """
679
- return gr.update(value=success_html, visible=True), True
680
 
681
  except Exception as e:
682
- error_html = f"""
683
- <div style="background: rgba(244, 67, 54, 0.1); border: 1px solid rgba(244, 67, 54, 0.3);
684
- border-radius: 8px; padding: 0.75rem; color: #f44336; text-align: center;">
685
- ❌ Error processing documents: {str(e)}
686
- </div>
687
- """
688
- return gr.update(value=error_html, visible=True), False
689
 
690
- def respond(message, history, doc_ready):
691
- if not doc_ready:
692
- # Show error message
693
- history.append({"role": "user", "content": message})
694
- history.append({"role": "assistant", "content": " Please upload and process documents first."})
695
- return history, ""
696
-
697
  if not message.strip():
698
- return history, message
699
 
700
  # Add user message
701
  history.append({"role": "user", "content": message})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
702
  history.append({"role": "assistant", "content": ""})
703
 
704
  # Stream response
705
  try:
706
  for token in coordinator_agent.handle_query(message, history):
707
- history[-1]["content"] += token
708
- yield history, ""
 
709
  except Exception as e:
710
- history[-1]["content"] = f"❌ Error: {str(e)}"
711
  yield history, ""
712
-
713
  # Event bindings
714
- process_btn.click(
715
- handle_file_upload_and_process,
716
- inputs=[file_upload],
717
- outputs=[processing_status, doc_processed]
 
 
718
  )
719
-
 
 
 
 
 
 
 
 
720
  send_btn.click(
721
  respond,
722
- inputs=[msg_input, chatbot, doc_processed],
723
- outputs=[chatbot, msg_input],
724
- show_progress=True
725
  )
726
-
 
727
  msg_input.submit(
728
  respond,
729
- inputs=[msg_input, chatbot, doc_processed],
730
- outputs=[chatbot, msg_input],
731
- show_progress=True
732
  )
733
 
734
  return iface
735
-
736
  # Launch the application
737
  if __name__ == "__main__":
738
  demo = create_interface()
 
419
  coordinator_agent = CoordinatorAgent(message_bus)
420
 
421
  def create_interface():
422
+ """Create Claude-style Gradio interface with integrated file upload"""
423
 
424
  with gr.Blocks(
425
  theme=gr.themes.Base(),
426
  css="""
427
+ /* Claude-inspired dark theme */
428
  .gradio-container {
429
+ background-color: #0f0f0f !important;
430
  color: #ffffff !important;
431
  height: 100vh !important;
432
  max-width: none !important;
433
  padding: 0 !important;
434
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif !important;
435
  }
436
 
437
+ /* Main layout */
438
  .main-container {
439
  display: flex;
440
  flex-direction: column;
441
  height: 100vh;
442
+ background: #0f0f0f;
443
+ max-width: 800px;
444
+ margin: 0 auto;
445
  }
446
 
447
+ /* Header - minimal like Claude */
448
  .header {
449
+ background: #0f0f0f;
450
+ border-bottom: 1px solid #2a2a2a;
451
  padding: 1rem 2rem;
452
+ text-align: center;
453
  }
454
 
455
  .header h1 {
456
+ color: #ffffff;
457
  margin: 0;
458
+ font-size: 1.25rem;
459
+ font-weight: 500;
460
  }
461
 
462
+ /* Chat container - full height like Claude */
 
 
 
 
 
 
463
  .chat-container {
464
  flex: 1;
465
  display: flex;
466
  flex-direction: column;
467
+ padding: 0;
468
+ background: #0f0f0f;
 
 
 
469
  }
470
 
471
+ /* Chatbot area - Claude style */
472
  .gradio-chatbot {
473
+ flex: 1 !important;
474
+ height: calc(100vh - 200px) !important;
475
+ max-height: none !important;
476
+ background: #0f0f0f !important;
477
  border: none !important;
478
+ padding: 1rem !important;
479
  overflow-y: auto !important;
 
 
480
  }
481
 
482
+ /* Messages styling - Claude-like bubbles */
483
+ .message.user {
484
+ background: #2a2a2a !important;
485
+ border-radius: 16px !important;
486
+ padding: 12px 16px !important;
487
+ margin: 8px 0 !important;
488
+ color: #ffffff !important;
489
+ }
490
+
491
+ .message.bot {
492
+ background: transparent !important;
493
+ border-radius: 16px !important;
494
+ padding: 12px 16px !important;
495
+ margin: 8px 0 !important;
496
+ color: #ffffff !important;
497
+ border-left: 3px solid #ff6b35 !important;
498
+ padding-left: 16px !important;
499
+ }
500
+
501
+ /* Input area - fixed at bottom like Claude */
502
+ .input-container {
503
  position: sticky;
504
  bottom: 0;
505
+ background: #0f0f0f;
506
+ border-top: 1px solid #2a2a2a;
507
+ padding: 1rem 2rem 2rem 2rem;
508
  }
509
 
510
+ .input-wrapper {
511
+ background: #2a2a2a;
512
+ border-radius: 24px;
513
+ border: 1px solid #404040;
514
+ padding: 4px;
515
+ display: flex;
516
+ align-items: end;
517
+ gap: 8px;
518
+ transition: border-color 0.2s;
519
  }
520
 
521
+ .input-wrapper:focus-within {
522
+ border-color: #ff6b35 !important;
523
+ }
524
+
525
+ /* File upload button - integrated like Claude */
526
+ .file-btn {
527
+ background: transparent !important;
528
  border: none !important;
529
+ color: #999999 !important;
530
+ padding: 8px !important;
531
+ border-radius: 20px !important;
532
+ cursor: pointer !important;
533
+ display: flex !important;
534
+ align-items: center !important;
535
+ justify-content: center !important;
536
+ min-width: 36px !important;
537
+ height: 36px !important;
538
+ transition: all 0.2s !important;
539
+ }
540
+
541
+ .file-btn:hover {
542
+ background: #404040 !important;
543
+ color: #ffffff !important;
544
  }
545
 
546
+ /* Text input - Claude style */
547
+ .gradio-textbox {
548
+ flex: 1 !important;
549
+ }
550
+
551
+ .gradio-textbox textarea, .gradio-textbox input {
552
+ background: transparent !important;
553
  border: none !important;
554
+ color: #ffffff !important;
555
+ resize: none !important;
556
+ padding: 12px 16px !important;
557
+ font-size: 16px !important;
558
+ line-height: 1.5 !important;
559
+ max-height: 200px !important;
560
+ min-height: 24px !important;
561
+ }
562
+
563
+ .gradio-textbox textarea:focus, .gradio-textbox input:focus {
564
+ outline: none !important;
565
+ box-shadow: none !important;
566
  }
567
 
568
+ /* Send button - Claude style */
569
+ .send-btn {
570
+ background: #ff6b35 !important;
571
+ border: none !important;
572
+ border-radius: 20px !important;
573
  color: #ffffff !important;
574
+ padding: 8px !important;
575
+ min-width: 36px !important;
576
+ height: 36px !important;
577
+ display: flex !important;
578
+ align-items: center !important;
579
+ justify-content: center !important;
580
+ cursor: pointer !important;
581
+ transition: all 0.2s !important;
582
  }
583
 
584
+ .send-btn:hover {
585
+ background: #e55a2b !important;
586
+ }
587
+
588
+ .send-btn:disabled {
589
+ background: #404040 !important;
590
+ cursor: not-allowed !important;
591
+ }
592
+
593
+ /* File upload area - hidden by default */
594
+ .file-upload {
595
+ display: none !important;
596
+ }
597
+
598
+ /* Status messages */
599
+ .status-message {
600
+ background: #1a1a1a;
601
+ border: 1px solid #404040;
602
+ border-radius: 12px;
603
+ padding: 12px 16px;
604
+ margin: 8px 0;
605
+ color: #cccccc;
606
+ font-size: 14px;
607
  text-align: center;
608
  }
609
 
610
+ .status-success {
611
+ border-color: #22c55e !important;
612
+ color: #22c55e !important;
613
+ background: rgba(34, 197, 94, 0.1) !important;
 
614
  }
615
 
616
+ .status-error {
617
+ border-color: #ef4444 !important;
618
+ color: #ef4444 !important;
619
+ background: rgba(239, 68, 68, 0.1) !important;
620
+ }
621
+
622
+ .status-processing {
623
+ border-color: #ff6b35 !important;
624
+ color: #ff6b35 !important;
625
+ background: rgba(255, 107, 53, 0.1) !important;
626
+ }
627
+
628
+ /* File list styling */
629
+ .file-list {
630
+ background: #1a1a1a;
631
+ border-radius: 8px;
632
+ padding: 8px 12px;
633
+ margin: 4px 0;
634
+ font-size: 14px;
635
+ color: #cccccc;
636
+ border-left: 3px solid #ff6b35;
637
+ }
638
+
639
+ /* Hide Gradio elements we don't want */
640
+ .gradio-file {
641
+ display: none !important;
642
+ }
643
+
644
+ /* Scrollbar styling */
645
+ ::-webkit-scrollbar {
646
+ width: 6px;
647
+ }
648
+
649
+ ::-webkit-scrollbar-track {
650
+ background: transparent;
651
+ }
652
+
653
+ ::-webkit-scrollbar-thumb {
654
+ background: #404040;
655
+ border-radius: 3px;
656
+ }
657
+
658
+ ::-webkit-scrollbar-thumb:hover {
659
+ background: #555555;
660
  }
661
  """,
662
  title="Agentic RAG Assistant"
663
  ) as iface:
664
 
665
+ # Header - minimal like Claude
666
+ gr.HTML("""
667
+ <div class="header">
668
+ <h1>Agentic RAG Assistant</h1>
669
+ </div>
670
+ """)
 
 
 
671
 
672
+ # Main chat container
673
  with gr.Row():
674
+ with gr.Column(scale=1, elem_classes=["main-container"]):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
675
 
676
+ # Chat area
677
  chatbot = gr.Chatbot(
 
678
  elem_classes=["gradio-chatbot"],
679
  show_copy_button=True,
680
  type="messages",
681
+ placeholder="Hello! Upload documents using the πŸ“Ž button below, then ask me anything about them.",
682
+ avatar_images=(None, None),
683
+ bubble_full_width=False
684
  )
685
 
686
+ # Input area - Claude style with integrated file upload
687
+ with gr.Row(elem_classes=["input-container"]):
688
+ with gr.Column():
689
+ with gr.Row(elem_classes=["input-wrapper"]):
690
+
691
+ # Hidden file upload
692
+ file_upload = gr.File(
693
+ file_count="multiple",
694
+ file_types=[".pdf", ".pptx", ".csv", ".docx", ".txt", ".md"],
695
+ elem_classes=["file-upload"],
696
+ visible=False
697
+ )
698
+
699
+ # File upload button (πŸ“Ž icon)
700
+ file_btn = gr.Button(
701
+ "πŸ“Ž",
702
+ elem_classes=["file-btn"],
703
+ size="sm",
704
+ scale=0
705
+ )
706
+
707
+ # Message input
708
+ msg_input = gr.Textbox(
709
+ placeholder="Message Agentic RAG Assistant...",
710
+ show_label=False,
711
+ elem_classes=["message-input"],
712
+ scale=1,
713
+ container=False,
714
+ autofocus=True,
715
+ lines=1,
716
+ max_lines=10
717
+ )
718
+
719
+ # Send button
720
+ send_btn = gr.Button(
721
+ "↑",
722
+ elem_classes=["send-btn"],
723
+ size="sm",
724
+ scale=0
725
+ )
726
 
727
+ # State management
 
 
 
 
 
 
 
 
 
 
 
 
728
  doc_processed = gr.State(False)
729
+ uploaded_files = gr.State([])
730
+
731
+ # JavaScript for file upload integration
732
+ gr.HTML("""
733
+ <script>
734
+ document.addEventListener('DOMContentLoaded', function() {
735
+ // Make file button trigger file upload
736
+ const fileBtn = document.querySelector('.file-btn');
737
+ const fileInput = document.querySelector('.file-upload input[type="file"]');
738
+
739
+ if (fileBtn && fileInput) {
740
+ fileBtn.addEventListener('click', function(e) {
741
+ e.preventDefault();
742
+ e.stopPropagation();
743
+ fileInput.click();
744
+ });
745
+ }
746
+
747
+ // Auto-resize textarea
748
+ const textarea = document.querySelector('.message-input textarea');
749
+ if (textarea) {
750
+ textarea.addEventListener('input', function() {
751
+ this.style.height = 'auto';
752
+ this.style.height = Math.min(this.scrollHeight, 200) + 'px';
753
+ });
754
+ }
755
+ });
756
+ </script>
757
+ """)
758
 
759
  # Event handlers
760
+ def handle_file_upload(files, history):
761
+ """Handle file uploads and show in chat"""
762
  if not files:
763
+ return history, [], False, gr.update()
764
+
765
+ # Add file upload message to chat
766
+ file_names = [f.name.split('/')[-1] if hasattr(f, 'name') else str(f) for f in files]
767
+ file_list = "\n".join([f"πŸ“„ {name}" for name in file_names])
768
+
769
+ history.append({
770
+ "role": "user",
771
+ "content": f"πŸ“Ž Uploaded {len(files)} file(s):\n{file_list}"
772
+ })
773
 
774
+ # Show processing message
775
+ history.append({
776
+ "role": "assistant",
777
+ "content": "πŸ“„ Processing documents... This may take a moment."
778
+ })
 
779
 
 
780
  try:
781
+ # Process files
782
  result = coordinator_agent.process_files(files)
783
 
784
+ # Wait for processing
785
  import time
786
  time.sleep(3)
787
 
788
+ # Update last message with success
789
+ history[-1]["content"] = f"βœ… Successfully processed {len(files)} document(s)! You can now ask questions about your documents."
790
+
791
+ return history, files, True, gr.update(value=None)
 
 
 
792
 
793
  except Exception as e:
794
+ history[-1]["content"] = f"❌ Error processing documents: {str(e)}"
795
+ return history, [], False, gr.update(value=None)
 
 
 
 
 
796
 
797
+ def respond(message, history, doc_ready, files):
798
+ """Handle user messages"""
 
 
 
 
 
799
  if not message.strip():
800
+ return history, ""
801
 
802
  # Add user message
803
  history.append({"role": "user", "content": message})
804
+
805
+ if not doc_ready and not any(cmd in message.lower() for cmd in ['hello', 'hi', 'help']):
806
+ history.append({
807
+ "role": "assistant",
808
+ "content": "πŸ‘‹ Hello! I'm your RAG assistant. Please upload some documents first using the πŸ“Ž button, then I can help you analyze and answer questions about them."
809
+ })
810
+ return history, ""
811
+
812
+ # Handle general queries without documents
813
+ if not doc_ready:
814
+ if any(cmd in message.lower() for cmd in ['hello', 'hi', 'help']):
815
+ history.append({
816
+ "role": "assistant",
817
+ "content": "πŸ‘‹ Hello! I'm an AI assistant specialized in document analysis. Upload documents using the πŸ“Ž button above, and I'll help you:\n\nβ€’ Summarize content\nβ€’ Answer questions\nβ€’ Extract key insights\nβ€’ Find specific information\n\nSupported formats: PDF, DOCX, PPTX, CSV, TXT, MD"
818
+ })
819
+ else:
820
+ history.append({
821
+ "role": "assistant",
822
+ "content": "Please upload documents first using the πŸ“Ž button above, then I can help answer questions about them."
823
+ })
824
+ return history, ""
825
+
826
+ # Add assistant message placeholder
827
  history.append({"role": "assistant", "content": ""})
828
 
829
  # Stream response
830
  try:
831
  for token in coordinator_agent.handle_query(message, history):
832
+ if token:
833
+ history[-1]["content"] += token
834
+ yield history, ""
835
  except Exception as e:
836
+ history[-1]["content"] = f"❌ Sorry, I encountered an error: {str(e)}"
837
  yield history, ""
838
+
839
  # Event bindings
840
+
841
+ # File upload handling
842
+ file_upload.upload(
843
+ handle_file_upload,
844
+ inputs=[file_upload, chatbot],
845
+ outputs=[chatbot, uploaded_files, doc_processed, file_upload]
846
  )
847
+
848
+ # File button click (handled by JavaScript)
849
+ file_btn.click(None, None, None, js="""
850
+ function() {
851
+ document.querySelector('.file-upload input[type="file"]').click();
852
+ }
853
+ """)
854
+
855
+ # Send button click
856
  send_btn.click(
857
  respond,
858
+ inputs=[msg_input, chatbot, doc_processed, uploaded_files],
859
+ outputs=[chatbot, msg_input]
 
860
  )
861
+
862
+ # Enter key submit
863
  msg_input.submit(
864
  respond,
865
+ inputs=[msg_input, chatbot, doc_processed, uploaded_files],
866
+ outputs=[chatbot, msg_input]
 
867
  )
868
 
869
  return iface
 
870
  # Launch the application
871
  if __name__ == "__main__":
872
  demo = create_interface()