Ali2206 commited on
Commit
2cbc57b
·
verified ·
1 Parent(s): 6caaa86

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +226 -160
app.py CHANGED
@@ -53,6 +53,9 @@ sys.path.insert(0, src_path)
53
 
54
  from txagent.txagent import TxAgent
55
 
 
 
 
56
  # ==================== UTILITY FUNCTIONS ====================
57
  def sanitize_text(text: str) -> str:
58
  """Clean and sanitize text input"""
@@ -303,9 +306,11 @@ class ClinicalOversightApp:
303
 
304
  def cleanup_resources(self):
305
  """Clean up GPU memory and collect garbage"""
 
306
  torch.cuda.empty_cache()
307
  gc.collect()
308
  if torch.distributed.is_initialized():
 
309
  torch.distributed.destroy_process_group()
310
 
311
  def process_response_stream(self, prompt: str, history: List[dict]) -> Generator[dict, None, None]:
@@ -453,6 +458,7 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
453
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
454
  background: var(--background);
455
  color: var(--text-color);
 
456
  }
457
  .gradio-container {
458
  max-width: 800px;
@@ -514,7 +520,9 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
514
  color: var(--text-color);
515
  outline: none;
516
  font-size: 1em;
517
- placeholder-opacity: 0.6;
 
 
518
  }
519
  .send-btn {
520
  background: linear-gradient(135deg, #007bff, #0056b3);
@@ -529,7 +537,7 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
529
  transform: scale(1.05);
530
  }
531
  .send-btn:active {
532
- animation: pulse 0.3s ease;
533
  }
534
  .sidebar {
535
  background: var(--sidebar-bg);
@@ -544,6 +552,8 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
544
  top: 100px;
545
  width: 300px;
546
  z-index: 1000;
 
 
547
  }
548
  .sidebar-hidden {
549
  transform: translateX(100%);
@@ -578,13 +588,31 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
578
  align-items: center;
579
  gap: 8px;
580
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
  .loading-spinner {
582
  position: absolute;
583
  bottom: 80px;
584
  left: 50%;
585
  transform: translateX(-50%);
586
  font-size: 1.2em;
587
- animation: pulse 1.5s ease infinite;
588
  }
589
  .typing-indicator {
590
  display: none;
@@ -597,20 +625,46 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
597
  display: block;
598
  animation: blink 1s step-end infinite;
599
  }
600
- @keyframes pulse {
601
- 0%, 100% { transform: translateX(-50%) scale(1); opacity: 1; }
602
- 50% { transform: translateX(-50%) scale(1.2); opacity: 0.7; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  }
604
  @keyframes blink {
605
  50% { opacity: 0.3; }
606
  }
 
 
 
 
 
 
 
 
 
607
  :root {
608
  --background: #ffffff;
609
  --text-color: #333333;
610
  --chat-bg: #f9fafb;
611
  --message-bg: #e5e5ea;
612
  --sidebar-bg: #f1f3f5;
613
- transition: background 0.3s ease, color 0.3s ease;
614
  }
615
  [data-theme="dark"] {
616
  --background: #1e2a44;
@@ -655,6 +709,13 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
655
  function toggleSidebar() {
656
  const sidebar = document.querySelector('.sidebar');
657
  sidebar.classList.toggle('sidebar-hidden');
 
 
 
 
 
 
 
658
  }
659
 
660
  document.addEventListener('DOMContentLoaded', () => {
@@ -665,165 +726,170 @@ Patient Record (Chunk {chunk_idx}/{len(chunks)}):
665
  """
666
 
667
  with gr.Blocks(theme=gr.themes.Default(), css=css, js=js, title="Clinical Oversight Assistant") as app:
668
- theme_state = gr.State(value="light")
669
- sidebar_state = gr.State(value=False)
670
-
671
- gr.HTML("""
672
- <div class='header'>
673
- <h1 style='color: var(--text-color);'>🩺 Clinical Oversight Assistant</h1>
674
- <p style='color: var(--text-color); opacity: 0.7;'>
675
- AI-powered analysis of patient records for missed diagnoses
676
- </p>
677
- </div>
678
- <div class='sidebar-backdrop'></div>
679
- """)
680
-
681
- theme_button = gr.Button("🌙 Dark Mode", elem_classes="theme-toggle")
682
-
683
- with gr.Column(elem_classes="chat-container"):
684
- chatbot = gr.Chatbot(
685
- label="Clinical Analysis",
686
- height="100%",
687
- show_copy_button=True,
688
- type="messages",
689
- elem_classes="chatbot",
690
- render_markdown=True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
691
  )
692
- gr.HTML("<div class='loading-spinner'>⏳</div>")
693
- gr.HTML("<div class='typing-indicator'>Typing...</div>")
694
-
695
- with gr.Row():
696
- tools_button = gr.Button("📂 Tools", variant="secondary")
697
-
698
- with gr.Column(elem_classes="sidebar"):
699
- gr.Markdown("### 📎 Upload Records", elem_classes="tooltip", elem_id="upload-tooltip")
700
- file_upload = gr.File(
701
- file_types=[".pdf", ".csv", ".xls", ".xlsx"],
702
- file_count="multiple",
703
- label="Patient Records",
704
- elem_classes="tooltip",
705
- elem_id="upload-input"
 
 
 
 
 
706
  )
707
- gr.Markdown("### 📝 Analysis Summary", elem_classes="tooltip", elem_id="summary-tooltip")
708
- final_summary = gr.Markdown(
709
- "Analysis results will appear here...",
710
- elem_classes="tooltip",
711
- elem_id="summary-output"
 
 
712
  )
713
- gr.Markdown("### 📄 Full Report", elem_classes="tooltip", elem_id="report-tooltip")
714
- download_output = gr.File(
715
- label="Download Report",
716
- visible=False,
717
- interactive=False,
718
- elem_classes="tooltip",
719
- elem_id="download-output"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
720
  )
721
-
722
- with gr.Row(elem_classes="input-container"):
723
- msg_input = gr.Textbox(
724
- placeholder="Ask about potential oversights or upload files...",
725
- show_label=False,
726
- container=False,
727
- elem_classes="input-textbox",
728
- autofocus=True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
729
  )
730
- send_btn = gr.Button(
731
- "Analyze",
732
- variant="primary",
733
- elem_classes="send-btn"
 
 
 
734
  )
735
-
736
- progress_text = gr.Textbox(
737
- label="Progress Status",
738
- visible=False,
739
- interactive=False,
740
- elem_classes="progress-text"
741
- )
742
-
743
- def show_loading(state: bool) -> dict:
744
- return {
745
- "value": "<div class='loading-spinner'>⏳</div>" if state else "<div class='loading-spinner' style='display: none;'>⏳</div>",
746
- "visible": state
747
- }
748
-
749
- def show_typing(state: bool) -> dict:
750
- return {
751
- "value": f"<div class='typing-indicator{' active' if state else ''}'>Typing...</div>",
752
- "visible": state
753
- }
754
-
755
- # Theme toggle handler
756
- theme_button.click(
757
- self.toggle_theme,
758
- inputs=[theme_state],
759
- outputs=[theme_state, theme_button],
760
- _js="theme => applyTheme(theme)"
761
- )
762
-
763
- # Sidebar toggle handler
764
- tools_button.click(
765
- self.toggle_sidebar,
766
- inputs=[sidebar_state],
767
- outputs=[sidebar_state],
768
- _js="() => toggleSidebar()"
769
- )
770
-
771
- # Analysis handlers
772
- send_btn.click(
773
- show_loading,
774
- inputs=[gr.State(value=True)],
775
- outputs=[chatbot]
776
- ).then(
777
- show_typing,
778
- inputs=[gr.State(value=True)],
779
- outputs=[chatbot]
780
- ).then(
781
- self.analyze,
782
- inputs=[msg_input, chatbot, file_upload],
783
- outputs=[chatbot, download_output, final_summary, progress_text],
784
- show_progress="hidden"
785
- ).then(
786
- show_loading,
787
- inputs=[gr.State(value=False)],
788
- outputs=[chatbot]
789
- ).then(
790
- show_typing,
791
- inputs=[gr.State(value=False)],
792
- outputs=[chatbot]
793
- )
794
-
795
- msg_input.submit(
796
- show_loading,
797
- inputs=[gr.State(value=True)],
798
- outputs=[chatbot]
799
- ).then(
800
- show_typing,
801
- inputs=[gr.State(value=True)],
802
- outputs=[chatbot]
803
- ).then(
804
- self.analyze,
805
- inputs=[msg_input, chatbot, file_upload],
806
- outputs=[chatbot, download_output, final_summary, progress_text],
807
- show_progress="hidden"
808
- ).then(
809
- show_loading,
810
- inputs=[gr.State(value=False)],
811
- outputs=[chatbot]
812
- ).then(
813
- show_typing,
814
- inputs=[gr.State(value=False)],
815
- outputs=[chatbot]
816
- )
817
-
818
- app.load(
819
- lambda: [
820
- [], None, "", "", None, {"visible": False}, "light", False, "🌙 Dark Mode"
821
- ],
822
- outputs=[chatbot, download_output, final_summary, msg_input, file_upload, progress_text, theme_state, sidebar_state, theme_button],
823
- queue=False
824
- )
825
-
826
- return app
827
 
828
  # ==================== APPLICATION ENTRY POINT ====================
829
  if __name__ == "__main__":
 
53
 
54
  from txagent.txagent import TxAgent
55
 
56
+ # Log Gradio version for debugging
57
+ logger.info(f"Gradio version: {gr.__version__}")
58
+
59
  # ==================== UTILITY FUNCTIONS ====================
60
  def sanitize_text(text: str) -> str:
61
  """Clean and sanitize text input"""
 
306
 
307
  def cleanup_resources(self):
308
  """Clean up GPU memory and collect garbage"""
309
+ logger.info("Cleaning up resources...")
310
  torch.cuda.empty_cache()
311
  gc.collect()
312
  if torch.distributed.is_initialized():
313
+ logger.info("Destroying PyTorch distributed process group...")
314
  torch.distributed.destroy_process_group()
315
 
316
  def process_response_stream(self, prompt: str, history: List[dict]) -> Generator[dict, None, None]:
 
458
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
459
  background: var(--background);
460
  color: var(--text-color);
461
+ transition: all 0.4s ease;
462
  }
463
  .gradio-container {
464
  max-width: 800px;
 
520
  color: var(--text-color);
521
  outline: none;
522
  font-size: 1em;
523
+ }
524
+ .input-textbox:focus {
525
+ border-bottom: 2px solid #007bff;
526
  }
527
  .send-btn {
528
  background: linear-gradient(135deg, #007bff, #0056b3);
 
537
  transform: scale(1.05);
538
  }
539
  .send-btn:active {
540
+ animation: glow 0.3s ease;
541
  }
542
  .sidebar {
543
  background: var(--sidebar-bg);
 
552
  top: 100px;
553
  width: 300px;
554
  z-index: 1000;
555
+ backdrop-filter: blur(10px);
556
+ background: rgba(241, 243, 245, 0.8);
557
  }
558
  .sidebar-hidden {
559
  transform: translateX(100%);
 
588
  align-items: center;
589
  gap: 8px;
590
  }
591
+ .tooltip {
592
+ position: relative;
593
+ }
594
+ .tooltip:hover::after {
595
+ content: attr(data-tooltip);
596
+ position: absolute;
597
+ bottom: 100%;
598
+ left: 50%;
599
+ transform: translateX(-50%);
600
+ background: #333;
601
+ color: white;
602
+ padding: 6px 12px;
603
+ border-radius: 6px;
604
+ font-size: 0.85em;
605
+ white-space: nowrap;
606
+ z-index: 1000;
607
+ animation: fadeIn 0.3s ease;
608
+ }
609
  .loading-spinner {
610
  position: absolute;
611
  bottom: 80px;
612
  left: 50%;
613
  transform: translateX(-50%);
614
  font-size: 1.2em;
615
+ animation: glow 1.5s ease infinite;
616
  }
617
  .typing-indicator {
618
  display: none;
 
625
  display: block;
626
  animation: blink 1s step-end infinite;
627
  }
628
+ .progress-text {
629
+ position: relative;
630
+ padding: 8px;
631
+ background: var(--message-bg);
632
+ border-radius: 8px;
633
+ margin-top: 12px;
634
+ }
635
+ .progress-text::before {
636
+ content: '';
637
+ position: absolute;
638
+ top: 0;
639
+ left: 0;
640
+ height: 100%;
641
+ width: 0;
642
+ background: #007bff;
643
+ opacity: 0.2;
644
+ animation: progress 2s linear infinite;
645
+ }
646
+ @keyframes glow {
647
+ 0%, 100% { transform: translateX(-50%) scale(1); opacity: 1; color: #007bff; }
648
+ 50% { transform: translateX(-50%) scale(1.2); opacity: 0.7; color: #0056b3; }
649
  }
650
  @keyframes blink {
651
  50% { opacity: 0.3; }
652
  }
653
+ @keyframes fadeIn {
654
+ from { opacity: 0; }
655
+ to { opacity: 1; }
656
+ }
657
+ @keyframes progress {
658
+ 0% { width: 0; }
659
+ 50% { width: 50%; }
660
+ 100% { width: 0; }
661
+ }
662
  :root {
663
  --background: #ffffff;
664
  --text-color: #333333;
665
  --chat-bg: #f9fafb;
666
  --message-bg: #e5e5ea;
667
  --sidebar-bg: #f1f3f5;
 
668
  }
669
  [data-theme="dark"] {
670
  --background: #1e2a44;
 
709
  function toggleSidebar() {
710
  const sidebar = document.querySelector('.sidebar');
711
  sidebar.classList.toggle('sidebar-hidden');
712
+ if (!sidebar.classList.contains('sidebar-hidden')) {
713
+ setTimeout(() => {
714
+ if (window.innerWidth <= 600) {
715
+ sidebar.classList.add('sidebar-hidden');
716
+ }
717
+ }, 5000);
718
+ }
719
  }
720
 
721
  document.addEventListener('DOMContentLoaded', () => {
 
726
  """
727
 
728
  with gr.Blocks(theme=gr.themes.Default(), css=css, js=js, title="Clinical Oversight Assistant") as app:
729
+ try:
730
+ theme_state = gr.State(value="light")
731
+ sidebar_state = gr.State(value=False)
732
+
733
+ gr.HTML("""
734
+ <div class='header'>
735
+ <h1 style='color: var(--text-color);'>🩺 Clinical Oversight Assistant</h1>
736
+ <p style='color: var(--text-color); opacity: 0.7;'>
737
+ AI-powered analysis of patient records for missed diagnoses
738
+ </p>
739
+ </div>
740
+ <div class='sidebar-backdrop'></div>
741
+ """)
742
+
743
+ theme_button = gr.Button("🌙 Dark Mode", elem_classes="theme-toggle")
744
+
745
+ with gr.Column(elem_classes="chat-container"):
746
+ chatbot = gr.Chatbot(
747
+ label="Clinical Analysis",
748
+ height="100%",
749
+ show_copy_button=True,
750
+ type="messages",
751
+ elem_classes="chatbot",
752
+ render_markdown=True
753
+ )
754
+ gr.HTML("<div class='loading-spinner' style='display: none;'>⏳</div>")
755
+ gr.HTML("<div class='typing-indicator'>Typing...</div>")
756
+
757
+ with gr.Row():
758
+ tools_button = gr.Button("📂 Tools", variant="secondary")
759
+
760
+ with gr.Column(elem_classes="sidebar"):
761
+ gr.Markdown("### 📎 Upload Records", elem_classes="tooltip", data_tooltip="Upload patient records")
762
+ file_upload = gr.File(
763
+ file_types=[".pdf", ".csv", ".xls", ".xlsx"],
764
+ file_count="multiple",
765
+ label="Patient Records",
766
+ elem_classes="tooltip",
767
+ data_tooltip="Select PDF, CSV, or Excel files"
768
+ )
769
+ gr.Markdown("### 📝 Analysis Summary", elem_classes="tooltip", data_tooltip="Summary of findings")
770
+ final_summary = gr.Markdown(
771
+ "Analysis results will appear here...",
772
+ elem_classes="tooltip",
773
+ data_tooltip="View analysis results"
774
+ )
775
+ gr.Markdown("### 📄 Full Report", elem_classes="tooltip", data_tooltip="Download full report")
776
+ download_output = gr.File(
777
+ label="Download Report",
778
+ visible=False,
779
+ interactive=False,
780
+ elem_classes="tooltip",
781
+ data_tooltip="Download analysis report"
782
+ )
783
+
784
+ with gr.Row(elem_classes="input-container"):
785
+ msg_input = gr.Textbox(
786
+ placeholder="Ask about potential oversights or upload files...",
787
+ show_label=False,
788
+ container=False,
789
+ elem_classes="input-textbox",
790
+ autofocus=True
791
+ )
792
+ send_btn = gr.Button(
793
+ "Analyze",
794
+ variant="primary",
795
+ elem_classes="send-btn"
796
+ )
797
+
798
+ progress_text = gr.Textbox(
799
+ label="Progress Status",
800
+ visible=False,
801
+ interactive=False,
802
+ elem_classes="progress-text"
803
  )
804
+
805
+ def show_loading(state: bool) -> dict:
806
+ return {
807
+ "value": "<div class='loading-spinner'>⏳</div>" if state else "<div class='loading-spinner' style='display: none;'>⏳</div>",
808
+ "visible": state
809
+ }
810
+
811
+ def show_typing(state: bool) -> dict:
812
+ return {
813
+ "value": f"<div class='typing-indicator{' active' if state else ''}'>Typing...</div>",
814
+ "visible": state
815
+ }
816
+
817
+ # Theme toggle handler
818
+ theme_button.click(
819
+ fn=self.toggle_theme,
820
+ inputs=[theme_state],
821
+ outputs=[theme_state, theme_button],
822
+ _js="function(theme) { applyTheme(theme); }"
823
  )
824
+
825
+ # Sidebar toggle handler
826
+ tools_button.click(
827
+ fn=self.toggle_sidebar,
828
+ inputs=[sidebar_state],
829
+ outputs=[sidebar_state],
830
+ _js="toggleSidebar"
831
  )
832
+
833
+ # Analysis handlers
834
+ send_btn.click(
835
+ fn=show_loading,
836
+ inputs=[gr.State(value=True)],
837
+ outputs=[chatbot]
838
+ ).then(
839
+ fn=show_typing,
840
+ inputs=[gr.State(value=True)],
841
+ outputs=[chatbot]
842
+ ).then(
843
+ fn=self.analyze,
844
+ inputs=[msg_input, chatbot, file_upload],
845
+ outputs=[chatbot, download_output, final_summary, progress_text],
846
+ show_progress="hidden"
847
+ ).then(
848
+ fn=show_loading,
849
+ inputs=[gr.State(value=False)],
850
+ outputs=[chatbot]
851
+ ).then(
852
+ fn=show_typing,
853
+ inputs=[gr.State(value=False)],
854
+ outputs=[chatbot]
855
  )
856
+
857
+ msg_input.submit(
858
+ fn=show_loading,
859
+ inputs=[gr.State(value=True)],
860
+ outputs=[chatbot]
861
+ ).then(
862
+ fn=show_typing,
863
+ inputs=[gr.State(value=True)],
864
+ outputs=[chatbot]
865
+ ).then(
866
+ fn=self.analyze,
867
+ inputs=[msg_input, chatbot, file_upload],
868
+ outputs=[chatbot, download_output, final_summary, progress_text],
869
+ show_progress="hidden"
870
+ ).then(
871
+ fn=show_loading,
872
+ inputs=[gr.State(value=False)],
873
+ outputs=[chatbot]
874
+ ).then(
875
+ fn=show_typing,
876
+ inputs=[gr.State(value=False)],
877
+ outputs=[chatbot]
878
  )
879
+
880
+ app.load(
881
+ fn=lambda: [
882
+ [], None, "", "", None, {"visible": False}, "light", False, "🌙 Dark Mode"
883
+ ],
884
+ outputs=[chatbot, download_output, final_summary, msg_input, file_upload, progress_text, theme_state, sidebar_state, theme_button],
885
+ queue=False
886
  )
887
+
888
+ except Exception as e:
889
+ logger.error(f"Interface creation failed: {e}")
890
+ self.cleanup_resources()
891
+ raise
892
+ return app
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
893
 
894
  # ==================== APPLICATION ENTRY POINT ====================
895
  if __name__ == "__main__":