PearlIsa commited on
Commit
f6923bc
β€’
1 Parent(s): e49dc64

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +257 -238
app.py CHANGED
@@ -42,10 +42,12 @@ from langchain.vectorstores import FAISS
42
  from langchain.text_splitter import RecursiveCharacterTextSplitter
43
  from langchain.embeddings import HuggingFaceEmbeddings
44
  from langchain.document_loaders import TextLoader
45
- from google.colab import output
46
  import IPython.display as display
47
  from peft import get_peft_model, LoraConfig, prepare_model_for_kbit_training
48
-
 
 
 
49
 
50
  # Ensure Hugging Face login
51
  try:
@@ -67,34 +69,85 @@ os.environ['CUDA_LAUNCH_BLOCKING'] = '1'
67
  logging.basicConfig(level=logging.INFO)
68
  logger = logging.getLogger(__name__)
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  class PearlyBot:
71
- def __init__(self):
72
- self.setup_model()
73
  self.setup_rag()
74
  self.conversation_history = []
 
 
75
 
76
- def setup_model(self):
 
77
  try:
78
- logger.info("Loading local checkpoint...")
79
- # Load from the local checkpoint in your Space
80
- checkpoint_path = "checkpoint-500.zip" # Path to your uploaded checkpoint
81
- base_model_id = "google/gemma-2b" # Your base model
82
 
83
- # Load tokenizer from base model
84
- self.tokenizer = AutoTokenizer.from_pretrained(base_model_id)
 
85
 
86
- # Load model with checkpoint
87
- self.model = AutoModelForCausalLM.from_pretrained(
88
- checkpoint_path,
89
- device_map="auto",
90
- load_in_8bit=True,
91
- torch_dtype=torch.float16,
92
- low_cpu_mem_usage=True
93
- )
94
- self.model.eval()
95
- logger.info("Model loaded successfully")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  except Exception as e:
97
- logger.error(f"Error loading model: {str(e)}")
98
  raise
99
 
100
  def setup_rag(self):
@@ -413,7 +466,16 @@ PROFESSIONAL CONDUCT:
413
 
414
  @torch.inference_mode()
415
  def generate_response(self, message: str, history: list) -> str:
 
416
  try:
 
 
 
 
 
 
 
 
417
  # Get RAG context
418
  context = self.get_relevant_context(message)
419
 
@@ -445,107 +507,143 @@ Guidelines:
445
  <start_of_turn>assistant"""
446
 
447
  # Generate response
448
- inputs = self.tokenizer(
449
- prompt,
450
- return_tensors="pt",
451
- truncation=True,
452
- max_length=512
453
- ).to(self.model.device)
454
-
455
- outputs = self.model.generate(
456
- **inputs,
457
- max_new_tokens=256,
458
- min_new_tokens=20,
459
- do_sample=True,
460
- temperature=0.7,
461
- top_p=0.9,
462
- repetition_penalty=1.2
463
- )
464
-
465
- response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
466
- response = response.split("<start_of_turn>assistant")[-1].strip()
467
- if "<end_of_turn>" in response:
468
- response = response.split("<end_of_turn>")[0].strip()
 
 
 
 
 
 
 
 
 
 
469
 
470
- return response
471
-
472
  except Exception as e:
473
  logger.error(f"Error generating response: {str(e)}")
474
  return "I apologize, but I encountered an error. Please try again."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
476
 
477
  def create_demo():
478
  """Set up Gradio interface for the chatbot with enhanced styling and functionality."""
479
  try:
480
- # Health check
481
- @gr.routes.get("/health")
482
- def health_check():
483
- return {"status": "healthy"}
484
- bot = PearlyBot() # βœ…
485
 
486
- def chat(message: str, history: list): # βœ…
 
487
  try:
488
  if not message.strip():
489
  return history
490
-
491
- bot_response = bot.generate_response(message)
492
 
493
- # Add user message
 
 
 
494
  history.append({
495
  "role": "user",
496
  "content": message
497
  })
498
-
499
- # Add bot response
500
  history.append({
501
  "role": "assistant",
502
- "content": bot_response['response']
503
  })
504
-
505
  return history
506
 
507
  except Exception as e:
508
  logger.error(f"Chat error: {e}")
509
- history.append({
510
- "role": "user",
511
- "content": message
512
- })
513
- history.append({
514
  "role": "assistant",
515
  "content": "I apologize, but I'm experiencing technical difficulties. For emergencies, please call 999."
516
- })
517
- return history
518
-
519
- def process_feedback(is_positive: bool, comment: str, history: List[Dict[str, str]]):
520
- try:
521
- if not history:
522
- return
523
-
524
- last_interaction = history[-2:] # Get last user message and bot response
525
- if len(last_interaction) == 2:
526
- user_msg = last_interaction[0]["content"]
527
- bot_msg = last_interaction[1]["content"]
528
-
529
- feedback_data = {
530
- "user_message": user_msg,
531
- "bot_response": bot_msg,
532
- "feedback": 1 if is_positive else -1,
533
- "comment": comment,
534
- "timestamp": datetime.now().isoformat()
535
- }
536
-
537
- bot.handle_feedback(
538
- message=user_msg,
539
- response=bot_msg,
540
- feedback=1 if is_positive else -1
541
- )
542
-
543
- # Clear feedback inputs
544
- return gr.update(value="")
545
-
546
- except Exception as e:
547
- logger.error(f"Error processing feedback: {e}")
548
-
549
  # Create enhanced Gradio interface
550
  with gr.Blocks(theme=gr.themes.Soft(
551
  primary_hue="blue",
@@ -574,32 +672,38 @@ def create_demo():
574
  color: white;
575
  font-weight: bold;
576
  }
577
- /* Specific backgrounds for each emoji card */
578
- .feature-card:nth-child(1) {
579
- background: linear-gradient(135deg, #2193b0, #6dd5ed); /* Hospital emoji */
580
- }
581
- .feature-card:nth-child(2) {
582
- background: linear-gradient(135deg, #834d9b, #d04ed6); /* Magnifying glass emoji */
583
- }
584
- .feature-card:nth-child(3) {
585
- background: linear-gradient(135deg, #ff4b1f, #ff9068); /* Emergency emoji */
586
- }
587
- .feature-card:nth-child(4) {
588
- background: linear-gradient(135deg, #38ef7d, #11998e); /* Medical advice emoji */
589
- }
590
- /* Hover effect */
591
  .feature-card:hover {
592
  transform: translateY(-5px);
593
  box-shadow: 0 5px 15px rgba(0,0,0,0.2);
594
  }
595
- }
596
-
597
- /* Make emojis larger and more visible */
598
  .feature-card span.emoji {
599
  font-size: 2em;
600
  display: block;
601
  margin-bottom: 10px;
602
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  </style>
604
  """)
605
 
@@ -614,7 +718,6 @@ def create_demo():
614
  with gr.Row(elem_classes="header"):
615
  gr.Markdown("""
616
  # GP Medical Triage Assistant - Pearly
617
-
618
  Welcome to your personal medical triage assistant. I'm here to help assess your symptoms and guide you to appropriate care.
619
  """)
620
 
@@ -638,42 +741,6 @@ def create_demo():
638
  <div>Medical Advice</div>
639
  </div>
640
  </div>
641
- <style>
642
- /* Enable Enter key submission */
643
- .message-textbox textarea {
644
- resize: none;
645
- }
646
-
647
- /* Improve feedback buttons */
648
- #thumb-up, #thumb-down {
649
- min-width: 60px;
650
- padding: 8px;
651
- margin: 5px;
652
- }
653
-
654
- /* Improve chat messages */
655
- .chatbot-message {
656
- padding: 12px;
657
- margin: 8px 0;
658
- border-radius: 8px;
659
- }
660
-
661
- .user-message {
662
- background-color: #e3f2fd;
663
- }
664
-
665
- .assistant-message {
666
- background-color: #f5f5f5;
667
- }
668
-
669
- /* Feedback section */
670
- .feedback-section {
671
- margin-top: 20px;
672
- padding: 15px;
673
- border-radius: 8px;
674
- background-color: #f8f9fa;
675
- }
676
- </style>
677
  """)
678
 
679
  # Chat Interface
@@ -696,8 +763,8 @@ def create_demo():
696
  placeholder="Type your message here...",
697
  lines=2,
698
  scale=4,
699
- autofocus=True,
700
- submit_on_enter=True
701
  )
702
  submit = gr.Button("Send", variant="primary", scale=1)
703
 
@@ -708,37 +775,33 @@ def create_demo():
708
  nhs_111_btn = gr.Button("πŸ“ž NHS 111 Info", variant="secondary")
709
  booking_btn = gr.Button("πŸ“… GP Booking", variant="secondary")
710
 
711
- # Conversation Controls
712
  gr.Markdown("### Controls")
713
  clear = gr.Button("πŸ—‘οΈ Clear Chat")
714
 
715
- # Feedback Section
716
  gr.Markdown("### Feedback")
717
  with gr.Row():
718
  feedback_positive = gr.Button("πŸ‘", elem_id="thumb-up")
719
  feedback_negative = gr.Button("πŸ‘Ž", elem_id="thumb-down")
720
 
721
  feedback_text = gr.Textbox(
722
- label="Additional comments (optional)",
723
- placeholder="Tell us more about your experience...",
724
  lines=2,
725
- visible=True
726
  )
727
  feedback_submit = gr.Button("Submit Feedback", visible=True)
728
- # Examples Section
 
729
  with gr.Accordion("Example Messages", open=False):
730
- gr.Examples(
731
- examples=[
732
- ["I've been having severe headaches for the past week"],
733
- ["I need to book a routine checkup"],
734
- ["I'm feeling very anxious lately and need help"],
735
- ["My child has had a fever for 2 days"],
736
- ["I need information about COVID-19 testing"]
737
- ],
738
- inputs=msg
739
- )
740
 
741
- # Information Accordions
742
  with gr.Accordion("NHS Services Guide", open=False):
743
  gr.Markdown("""
744
  ### Emergency Services (999)
@@ -758,74 +821,16 @@ def create_demo():
758
  """)
759
 
760
  # Event Handlers
761
- # Message submission handlers
762
- msg.submit(
763
- chat,
764
- inputs=[msg, chatbot],
765
- outputs=[chatbot]
766
- ).then(
767
- lambda: gr.update(value=""),
768
- None,
769
- [msg]
770
- )
771
-
772
- submit.click(
773
- chat,
774
- inputs=[msg, chatbot],
775
- outputs=[chatbot]
776
- ).then(
777
- lambda: gr.update(value=""),
778
- None,
779
- [msg]
780
- )
781
-
782
- # Feedback handlers
783
- feedback_positive.click(
784
- lambda history: process_feedback(True, feedback_text.value, history),
785
- inputs=[chatbot],
786
- outputs=[feedback_text]
787
- )
788
-
789
- feedback_negative.click(
790
- lambda history: process_feedback(False, feedback_text.value, history),
791
- inputs=[chatbot],
792
- outputs=[feedback_text]
793
  )
794
 
795
- feedback_submit.click(
796
- lambda: gr.update(value=""),
797
- outputs=[feedback_text]
798
  )
799
-
800
- # Quick Action Button Handlers
801
- def show_emergency_info():
802
- return """🚨 Emergency Services (999)
803
- - For life-threatening emergencies
804
- - Severe chest pain
805
- - Difficulty breathing
806
- - Severe bleeding
807
- - Loss of consciousness
808
- """
809
-
810
- def show_nhs_111_info():
811
- return """πŸ“ž NHS 111 Service
812
- - Available 24/7
813
- - Medical advice
814
- - Local service information
815
- - Urgent care guidance
816
- """
817
-
818
- def show_booking_info():
819
- return """πŸ“… GP Booking Options
820
- - Online booking
821
- - Phone booking
822
- - Routine appointments
823
- - Urgent appointments
824
- """
825
-
826
- emergency_btn.click(lambda: show_emergency_info(), outputs=[msg])
827
- nhs_111_btn.click(lambda: show_nhs_111_info(), outputs=[msg])
828
- booking_btn.click(lambda: show_booking_info(), outputs=[msg])
829
 
830
  return demo
831
 
@@ -834,9 +839,23 @@ def create_demo():
834
  raise
835
 
836
  if __name__ == "__main__":
837
- load_dotenv() # Load environment variables
838
- demo = create_demo() # Launch the Gradio app
839
- demo.launch(share=True)
840
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
841
 
842
 
 
42
  from langchain.text_splitter import RecursiveCharacterTextSplitter
43
  from langchain.embeddings import HuggingFaceEmbeddings
44
  from langchain.document_loaders import TextLoader
 
45
  import IPython.display as display
46
  from peft import get_peft_model, LoraConfig, prepare_model_for_kbit_training
47
+ import warnings
48
+ import re
49
+ from dotenv import load_dotenv
50
+ warnings.filterwarnings('ignore')
51
 
52
  # Ensure Hugging Face login
53
  try:
 
69
  logging.basicConfig(level=logging.INFO)
70
  logger = logging.getLogger(__name__)
71
 
72
+ class ModelManager:
73
+ """Handles model loading and resource management"""
74
+
75
+ @staticmethod
76
+ def verify_model_path(checkpoint_path: str) -> str:
77
+ """Verify and return valid model path"""
78
+ if os.path.exists(checkpoint_path):
79
+ return checkpoint_path
80
+
81
+ alternate_paths = [
82
+ f"{os.getcwd()}/checkpoint-500.zip",
83
+ "./checkpoint-500.zip",
84
+ "../checkpoint-500.zip"
85
+ ]
86
+
87
+ for path in alternate_paths:
88
+ if os.path.exists(path):
89
+ return path
90
+
91
+ raise FileNotFoundError(
92
+ f"Model checkpoint not found in any of these locations: "
93
+ f"{[checkpoint_path] + alternate_paths}"
94
+ )
95
+
96
+ @staticmethod
97
+ def clear_gpu_memory():
98
+ """Clear GPU memory cache"""
99
+ if torch.cuda.is_available():
100
+ torch.cuda.empty_cache()
101
+ gc.collect()
102
+
103
  class PearlyBot:
104
+ def __init__(self, model_path: str = "./checkpoint-500.zip"):
105
+ self.setup_model(model_path)
106
  self.setup_rag()
107
  self.conversation_history = []
108
+ self.last_interaction_time = time.time()
109
+ self.interaction_cooldown = 1.0 # seconds
110
 
111
+ def setup_model(self, model_path: str):
112
+ """Initialize the model with proper error handling"""
113
  try:
114
+ logger.info("Starting model initialization...")
115
+ ModelManager.clear_gpu_memory()
 
 
116
 
117
+ # Verify model path
118
+ verified_path = ModelManager.verify_model_path(model_path)
119
+ logger.info(f"Using model checkpoint from: {verified_path}")
120
 
121
+ # Base model configuration
122
+ base_model_id = "google/gemma-2b"
123
+ logger.info(f"Loading base model: {base_model_id}")
124
+
125
+ # Load tokenizer
126
+ try:
127
+ self.tokenizer = AutoTokenizer.from_pretrained(base_model_id)
128
+ self.tokenizer.pad_token = self.tokenizer.eos_token
129
+ logger.info("Tokenizer loaded successfully")
130
+ except Exception as e:
131
+ logger.error(f"Failed to load tokenizer: {str(e)}")
132
+ raise
133
+
134
+ # Load model
135
+ try:
136
+ self.model = AutoModelForCausalLM.from_pretrained(
137
+ verified_path,
138
+ device_map="auto",
139
+ load_in_8bit=True,
140
+ torch_dtype=torch.float16,
141
+ low_cpu_mem_usage=True
142
+ )
143
+ self.model.eval()
144
+ logger.info("Model loaded successfully")
145
+ except Exception as e:
146
+ logger.error(f"Failed to load model: {str(e)}")
147
+ raise
148
+
149
  except Exception as e:
150
+ logger.error(f"Error in model setup: {str(e)}")
151
  raise
152
 
153
  def setup_rag(self):
 
466
 
467
  @torch.inference_mode()
468
  def generate_response(self, message: str, history: list) -> str:
469
+ """Generate response using both fine-tuned model and RAG"""
470
  try:
471
+ # Rate limiting
472
+ current_time = time.time()
473
+ if current_time - self.last_interaction_time < self.interaction_cooldown:
474
+ time.sleep(self.interaction_cooldown)
475
+
476
+ # Clear GPU memory before generation
477
+ ModelManager.clear_gpu_memory()
478
+
479
  # Get RAG context
480
  context = self.get_relevant_context(message)
481
 
 
507
  <start_of_turn>assistant"""
508
 
509
  # Generate response
510
+ try:
511
+ inputs = self.tokenizer(
512
+ prompt,
513
+ return_tensors="pt",
514
+ truncation=True,
515
+ max_length=512
516
+ ).to(self.model.device)
517
+
518
+ outputs = self.model.generate(
519
+ **inputs,
520
+ max_new_tokens=256,
521
+ min_new_tokens=20,
522
+ do_sample=True,
523
+ temperature=0.7,
524
+ top_p=0.9,
525
+ repetition_penalty=1.2,
526
+ no_repeat_ngram_size=3
527
+ )
528
+
529
+ response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
530
+ response = response.split("<start_of_turn>assistant")[-1].strip()
531
+ if "<end_of_turn>" in response:
532
+ response = response.split("<end_of_turn>")[0].strip()
533
+
534
+ self.last_interaction_time = time.time()
535
+ return response
536
+
537
+ except torch.cuda.OutOfMemoryError:
538
+ ModelManager.clear_gpu_memory()
539
+ logger.error("GPU out of memory, cleared cache and retrying...")
540
+ return "I apologize, but I'm experiencing technical difficulties. Please try again."
541
 
 
 
542
  except Exception as e:
543
  logger.error(f"Error generating response: {str(e)}")
544
  return "I apologize, but I encountered an error. Please try again."
545
+
546
+ def handle_feedback(self, message: str, response: str, feedback: int):
547
+ """Handle user feedback for responses"""
548
+ try:
549
+ timestamp = datetime.now().isoformat()
550
+ feedback_data = {
551
+ "message": message,
552
+ "response": response,
553
+ "feedback": feedback,
554
+ "timestamp": timestamp
555
+ }
556
+
557
+ # Log feedback
558
+ logger.info(f"Feedback received: {feedback_data}")
559
+
560
+ # Here you could:
561
+ # 1. Store feedback in a database
562
+ # 2. Send to monitoring system
563
+ # 3. Use for model improvements
564
+
565
+ return True
566
+ except Exception as e:
567
+ logger.error(f"Error handling feedback: {e}")
568
+ return False
569
+
570
+ def __del__(self):
571
+ """Cleanup resources"""
572
+ try:
573
+ if hasattr(self, 'model'):
574
+ del self.model
575
+ ModelManager.clear_gpu_memory()
576
+ except Exception as e:
577
+ logger.error(f"Error in cleanup: {e}")
578
 
579
+ def process_feedback(positive: bool, comment: str, history: List[Dict[str, str]]):
580
+ try:
581
+ if not history or len(history) < 2:
582
+ return gr.update(value="")
583
+
584
+ last_user_msg = history[-2]["content"] if isinstance(history[-2], dict) else history[-2][0]
585
+ last_bot_msg = history[-1]["content"] if isinstance(history[-1], dict) else history[-1][1]
586
+
587
+ bot.handle_feedback(
588
+ message=last_user_msg,
589
+ response=last_bot_msg,
590
+ feedback=1 if positive else -1
591
+ )
592
+
593
+ return gr.update(value="")
594
+
595
+ except Exception as e:
596
+ logger.error(f"Error processing feedback: {e}")
597
+ return gr.update(value="")
598
 
599
  def create_demo():
600
  """Set up Gradio interface for the chatbot with enhanced styling and functionality."""
601
  try:
602
+ # Initialize bot
603
+ bot = PearlyBot()
 
 
 
604
 
605
+ def chat(message: str, history: list):
606
+ """Handle chat interactions"""
607
  try:
608
  if not message.strip():
609
  return history
 
 
610
 
611
+ # Generate response
612
+ response = bot.generate_response(message, history)
613
+
614
+ # Update history with proper formatting
615
  history.append({
616
  "role": "user",
617
  "content": message
618
  })
 
 
619
  history.append({
620
  "role": "assistant",
621
+ "content": response
622
  })
 
623
  return history
624
 
625
  except Exception as e:
626
  logger.error(f"Chat error: {e}")
627
+ return history + [{
 
 
 
 
628
  "role": "assistant",
629
  "content": "I apologize, but I'm experiencing technical difficulties. For emergencies, please call 999."
630
+ }]
631
+
632
+ # Add these event handlers
633
+ feedback_positive.click(
634
+ lambda history: process_feedback(True, feedback_text.value, history),
635
+ inputs=[chatbot],
636
+ outputs=[feedback_text]
637
+ )
638
+
639
+ feedback_negative.click(
640
+ lambda history: process_feedback(False, feedback_text.value, history),
641
+ inputs=[chatbot],
642
+ outputs=[feedback_text]
643
+ )
644
+
645
+ # Add clear chat functionality
646
+ clear.click(lambda: None, None, chatbot)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
647
  # Create enhanced Gradio interface
648
  with gr.Blocks(theme=gr.themes.Soft(
649
  primary_hue="blue",
 
672
  color: white;
673
  font-weight: bold;
674
  }
675
+ .feature-card:nth-child(1) { background: linear-gradient(135deg, #2193b0, #6dd5ed); }
676
+ .feature-card:nth-child(2) { background: linear-gradient(135deg, #834d9b, #d04ed6); }
677
+ .feature-card:nth-child(3) { background: linear-gradient(135deg, #ff4b1f, #ff9068); }
678
+ .feature-card:nth-child(4) { background: linear-gradient(135deg, #38ef7d, #11998e); }
 
 
 
 
 
 
 
 
 
 
679
  .feature-card:hover {
680
  transform: translateY(-5px);
681
  box-shadow: 0 5px 15px rgba(0,0,0,0.2);
682
  }
 
 
 
683
  .feature-card span.emoji {
684
  font-size: 2em;
685
  display: block;
686
  margin-bottom: 10px;
687
  }
688
+ .message-textbox textarea { resize: none; }
689
+ #thumb-up, #thumb-down {
690
+ min-width: 60px;
691
+ padding: 8px;
692
+ margin: 5px;
693
+ }
694
+ .chatbot-message {
695
+ padding: 12px;
696
+ margin: 8px 0;
697
+ border-radius: 8px;
698
+ }
699
+ .user-message { background-color: #e3f2fd; }
700
+ .assistant-message { background-color: #f5f5f5; }
701
+ .feedback-section {
702
+ margin-top: 20px;
703
+ padding: 15px;
704
+ border-radius: 8px;
705
+ background-color: #f8f9fa;
706
+ }
707
  </style>
708
  """)
709
 
 
718
  with gr.Row(elem_classes="header"):
719
  gr.Markdown("""
720
  # GP Medical Triage Assistant - Pearly
 
721
  Welcome to your personal medical triage assistant. I'm here to help assess your symptoms and guide you to appropriate care.
722
  """)
723
 
 
741
  <div>Medical Advice</div>
742
  </div>
743
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
744
  """)
745
 
746
  # Chat Interface
 
763
  placeholder="Type your message here...",
764
  lines=2,
765
  scale=4,
766
+ autofocus=True,
767
+ submit_on_enter=True
768
  )
769
  submit = gr.Button("Send", variant="primary", scale=1)
770
 
 
775
  nhs_111_btn = gr.Button("πŸ“ž NHS 111 Info", variant="secondary")
776
  booking_btn = gr.Button("πŸ“… GP Booking", variant="secondary")
777
 
778
+ # Controls and Feedback
779
  gr.Markdown("### Controls")
780
  clear = gr.Button("πŸ—‘οΈ Clear Chat")
781
 
 
782
  gr.Markdown("### Feedback")
783
  with gr.Row():
784
  feedback_positive = gr.Button("πŸ‘", elem_id="thumb-up")
785
  feedback_negative = gr.Button("πŸ‘Ž", elem_id="thumb-down")
786
 
787
  feedback_text = gr.Textbox(
788
+ label="Additional comments",
789
+ placeholder="Tell us more...",
790
  lines=2,
791
+ visible=True
792
  )
793
  feedback_submit = gr.Button("Submit Feedback", visible=True)
794
+
795
+ # Examples and Information
796
  with gr.Accordion("Example Messages", open=False):
797
+ gr.Examples([
798
+ ["I've been having severe headaches for the past week"],
799
+ ["I need to book a routine checkup"],
800
+ ["I'm feeling very anxious lately and need help"],
801
+ ["My child has had a fever for 2 days"],
802
+ ["I need information about COVID-19 testing"]
803
+ ], inputs=msg)
 
 
 
804
 
 
805
  with gr.Accordion("NHS Services Guide", open=False):
806
  gr.Markdown("""
807
  ### Emergency Services (999)
 
821
  """)
822
 
823
  # Event Handlers
824
+ msg.submit(chat, [msg, chatbot], [chatbot]).then(
825
+ lambda: gr.update(value=""), None, [msg]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
826
  )
827
 
828
+ submit.click(chat, [msg, chatbot], [chatbot]).then(
829
+ lambda: gr.update(value=""), None, [msg]
 
830
  )
831
+
832
+ # Add queue for handling multiple users
833
+ demo.queue(concurrency_count=1, max_size=10)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
834
 
835
  return demo
836
 
 
839
  raise
840
 
841
  if __name__ == "__main__":
842
+ try:
843
+ # Initialize logging
844
+ logging.basicConfig(level=logging.INFO)
845
+
846
+ # Load environment variables
847
+ load_dotenv()
848
+
849
+ # Create and launch demo
850
+ demo = create_demo()
851
+ demo.launch(
852
+ server_name="0.0.0.0",
853
+ server_port=7860,
854
+ show_error=True
855
+ )
856
+
857
+ except Exception as e:
858
+ logger.error(f"Application startup failed: {e}")
859
+ raise
860
 
861