uumerrr684 commited on
Commit
010f6d4
·
verified ·
1 Parent(s): fceb8a5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +271 -91
app.py CHANGED
@@ -1,7 +1,7 @@
1
  #!/usr/bin/env python3
2
  """
3
  Hybrid AI Assistant - General Purpose + Healthcare Billing Expert
4
- A ChatGPT-style assistant using Gradio ChatInterface for simplicity
5
  """
6
 
7
  import os
@@ -9,7 +9,7 @@ import sys
9
  import json
10
  import logging
11
  import re
12
- from typing import Dict, Optional, Tuple, List, Any, Iterator
13
  from dataclasses import dataclass, field
14
  from enum import Enum
15
  import requests
@@ -40,6 +40,19 @@ class ConversationContext:
40
  messages: List[Dict[str, str]] = field(default_factory=list)
41
  detected_codes: List[str] = field(default_factory=list)
42
  last_topic: Optional[str] = None
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  # ============= Healthcare Billing Database =============
45
 
@@ -181,12 +194,50 @@ class BillingCodesDB:
181
 
182
  return found_codes
183
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  # ============= AI Assistant Class =============
185
 
186
  class HybridAIAssistant:
187
  def __init__(self):
188
  self.api_key = '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'
189
  self.billing_db = BillingCodesDB()
 
190
  self.context = ConversationContext()
191
 
192
  self.headers = {
@@ -239,15 +290,39 @@ class HybridAIAssistant:
239
  else:
240
  return self.get_general_response(message, billing_context=True)
241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  def get_general_response(self, message: str, billing_context: bool = False) -> str:
243
  """Get response from OpenRouter API for general queries"""
244
 
245
- # Prepare system prompt
246
- system_prompt = """You are a helpful, friendly AI assistant with expertise in healthcare billing codes.
 
 
 
 
 
 
 
 
 
247
  You can assist with any topic - from casual conversation to complex questions.
248
  When discussing medical billing codes, you provide accurate, detailed information.
249
- Be conversational, helpful, and engaging. Use emojis occasionally to be friendly.
250
- Keep responses concise but informative."""
251
 
252
  if billing_context:
253
  system_prompt += "\nThe user is asking about medical billing. Provide helpful information even if you don't have specific code details."
@@ -280,6 +355,11 @@ class HybridAIAssistant:
280
  result = response.json()
281
  ai_response = result['choices'][0]['message']['content']
282
 
 
 
 
 
 
283
  # Update context
284
  self.context.messages.append({'role': 'user', 'content': message})
285
  self.context.messages.append({'role': 'assistant', 'content': ai_response})
@@ -299,27 +379,32 @@ class HybridAIAssistant:
299
 
300
  def get_fallback_response(self, message: str) -> str:
301
  """Fallback responses when API fails"""
 
 
 
302
  fallbacks = [
303
  "I'm having trouble connecting right now, but I'm still here to help! Could you rephrase your question?",
304
  "Let me think about that differently. What specific aspect would you like to know more about?",
305
  "That's an interesting question! While I process that, is there anything specific you'd like to explore?",
306
  "I'm here to help! Could you provide a bit more detail about what you're looking for?"
307
  ]
308
- return random.choice(fallbacks)
309
 
310
- def process_message(self, message: str) -> str:
311
- """Main method to process any message"""
312
  if not message.strip():
313
- return "Feel free to ask me anything! I can help with general questions or healthcare billing codes. 😊"
314
 
315
  # Detect intent
316
  intent = self.detect_intent(message)
317
 
318
  # Route to appropriate handler
319
  if intent['is_billing'] and intent['codes_found']:
320
- return self.handle_billing_query(message, intent['codes_found'])
321
  else:
322
- return self.get_general_response(message, billing_context=intent['is_billing'])
 
 
323
 
324
  def reset_context(self):
325
  """Reset conversation context"""
@@ -335,10 +420,21 @@ def respond(message, history):
335
  if not message.strip():
336
  return "Feel free to ask me anything! I can help with general questions or healthcare billing codes. 😊"
337
 
338
- # Process message
339
- response = assistant.process_message(message)
 
 
340
  return response
341
 
 
 
 
 
 
 
 
 
 
342
  def reset_chat():
343
  """Reset the conversation context"""
344
  assistant.reset_context()
@@ -348,22 +444,22 @@ def reset_chat():
348
 
349
  examples = [
350
  "What is healthcare billing code A0429?",
351
- "Can you explain CPT code 99213 in detail?",
352
  "Tell me about DRG 470",
 
 
 
353
  "How does artificial intelligence work?",
354
  "Give me a simple pasta recipe",
355
- "Teach me Python basics",
356
- "Write a short poem about nature",
357
- "Help me write a professional email template",
358
- "Give me creative story ideas"
359
  ]
360
 
361
  # ============= Create Interface =============
362
 
363
  def create_interface():
364
- """Create the Gradio ChatInterface"""
365
 
366
- # Enhanced CSS with modern design improvements
367
  custom_css = """
368
  /* Global Styles */
369
  .gradio-container {
@@ -373,9 +469,20 @@ def create_interface():
373
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%) !important;
374
  min-height: 100vh !important;
375
  padding: 1rem !important;
 
376
  }
377
 
378
- /* Enhanced Header */
 
 
 
 
 
 
 
 
 
 
379
  .header-text {
380
  text-align: center;
381
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
@@ -386,6 +493,7 @@ def create_interface():
386
  box-shadow: 0 20px 40px rgba(102, 126, 234, 0.3);
387
  position: relative;
388
  overflow: hidden;
 
389
  }
390
 
391
  .header-text::before {
@@ -404,6 +512,34 @@ def create_interface():
404
  50% { opacity: 0.6; }
405
  }
406
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
407
  .header-text h1 {
408
  margin: 0;
409
  font-size: 3rem;
@@ -438,7 +574,39 @@ def create_interface():
438
  to { box-shadow: 0 0 20px rgba(255,255,255,0.6); }
439
  }
440
 
441
- /* Chat Interface Styling */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
  .gradio-chatinterface {
443
  background: white !important;
444
  border-radius: 20px !important;
@@ -446,6 +614,17 @@ def create_interface():
446
  padding: 2rem !important;
447
  margin: 1rem 0 !important;
448
  backdrop-filter: blur(10px) !important;
 
 
 
 
 
 
 
 
 
 
 
449
  }
450
 
451
  /* Enhanced Buttons */
@@ -539,6 +718,40 @@ def create_interface():
539
  letter-spacing: 1px;
540
  }
541
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
  /* Enhanced Accordion */
543
  .gradio-accordion {
544
  background: rgba(255,255,255,0.9) !important;
@@ -564,6 +777,12 @@ def create_interface():
564
  padding: 1.5rem;
565
  border: 1px solid rgba(255,255,255,0.3);
566
  box-shadow: 0 8px 25px rgba(0,0,0,0.1);
 
 
 
 
 
 
567
  }
568
 
569
  .feature-icon {
@@ -612,6 +831,18 @@ def create_interface():
612
  grid-template-columns: 1fr;
613
  gap: 1rem;
614
  }
 
 
 
 
 
 
 
 
 
 
 
 
615
  }
616
 
617
  /* Loading Animation */
@@ -625,71 +856,20 @@ def create_interface():
625
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
626
  background-size: 400% 100%;
627
  }
628
- """
629
-
630
- with gr.Blocks(css=custom_css, title="AI Assistant + Healthcare Billing Expert") as demo:
631
- # Header
632
- gr.HTML("""
633
- <div class="header-text">
634
- <h1>🤖 AI Assistant <span style="font-size: 0.6em; background: rgba(255,255,255,0.2); padding: 4px 12px; border-radius: 16px;">PLUS</span></h1>
635
- <p>Your intelligent companion for any question + Healthcare Billing Expert</p>
636
- </div>
637
- """)
638
-
639
- # Main Chat Interface
640
- chat_interface = gr.ChatInterface(
641
- fn=respond,
642
- examples=examples,
643
- cache_examples=False
644
- )
645
-
646
- # Additional controls
647
- with gr.Row():
648
- with gr.Column(scale=1):
649
- reset_context_btn = gr.Button("🔄 Reset Context", elem_classes="reset-btn", size="sm")
650
- with gr.Column(scale=3):
651
- gr.HTML("") # Spacer
652
- with gr.Column(scale=1):
653
- gr.HTML("""
654
- <div style='text-align: right; color: #718096; font-size: 12px; margin-top: 0.5rem;'>
655
- Powered by GPT-3.5 Turbo<br>
656
- Healthcare Billing Database
657
- </div>
658
- """)
659
-
660
- # Info section
661
- with gr.Accordion("ℹ️ About This Assistant", open=False):
662
- gr.HTML("""
663
- <div style="padding: 1rem; background: #f7fafc; border-radius: 8px; margin: 0.5rem 0;">
664
- <h4 style="color: #2d3748; margin-top: 0;">🏥 Healthcare Billing Expert</h4>
665
- <p style="color: #4a5568; margin-bottom: 1rem;">I'm specialized in healthcare billing codes including:</p>
666
- <ul style="color: #4a5568; margin: 0.5rem 0;">
667
- <li><strong>CPT Codes</strong> - Current Procedural Terminology</li>
668
- <li><strong>HCPCS</strong> - Healthcare Common Procedure Coding System</li>
669
- <li><strong>ICD-10</strong> - International Classification of Diseases</li>
670
- <li><strong>DRG</strong> - Diagnosis-Related Groups</li>
671
- </ul>
672
-
673
- <h4 style="color: #2d3748;">💬 General AI Assistant</h4>
674
- <p style="color: #4a5568; margin: 0;">I can also help with general questions, writing, coding, learning, and creative tasks!</p>
675
- </div>
676
- """)
677
-
678
- # Connect reset button
679
- reset_context_btn.click(
680
- fn=reset_chat,
681
- outputs=chat_interface.chatbot
682
- )
683
-
684
- return demo
685
-
686
- # ============= Launch =============
687
-
688
- if __name__ == "__main__":
689
- app = create_interface()
690
- app.launch(
691
- server_name="0.0.0.0",
692
- server_port=7860,
693
- share=False,
694
- show_error=True
695
- )
 
1
  #!/usr/bin/env python3
2
  """
3
  Hybrid AI Assistant - General Purpose + Healthcare Billing Expert
4
+ Enhanced with Emotional UI and Voice Input
5
  """
6
 
7
  import os
 
9
  import json
10
  import logging
11
  import re
12
+ from typing import Dict, Optional, Tuple, List, Any
13
  from dataclasses import dataclass, field
14
  from enum import Enum
15
  import requests
 
40
  messages: List[Dict[str, str]] = field(default_factory=list)
41
  detected_codes: List[str] = field(default_factory=list)
42
  last_topic: Optional[str] = None
43
+ current_sentiment: str = "neutral"
44
+ sentiment_history: List[str] = field(default_factory=list)
45
+
46
+ class SentimentType(Enum):
47
+ VERY_POSITIVE = "very_positive"
48
+ POSITIVE = "positive"
49
+ NEUTRAL = "neutral"
50
+ NEGATIVE = "negative"
51
+ VERY_NEGATIVE = "very_negative"
52
+ ANXIOUS = "anxious"
53
+ FRUSTRATED = "frustrated"
54
+ EXCITED = "excited"
55
+ CONFUSED = "confused"
56
 
57
  # ============= Healthcare Billing Database =============
58
 
 
194
 
195
  return found_codes
196
 
197
+ # ============= Sentiment Analysis =============
198
+
199
+ class SentimentAnalyzer:
200
+ def __init__(self):
201
+ self.positive_words = ['great', 'awesome', 'excellent', 'fantastic', 'wonderful', 'amazing', 'perfect', 'love', 'happy', 'excited', 'thank', 'thanks', 'good', 'nice', 'brilliant', 'outstanding']
202
+ self.negative_words = ['terrible', 'awful', 'horrible', 'bad', 'worst', 'hate', 'frustrated', 'angry', 'sad', 'disappointed', 'upset', 'confused', 'difficult', 'problem', 'issue', 'error', 'wrong']
203
+ self.anxious_words = ['worried', 'concerned', 'nervous', 'anxious', 'scared', 'afraid', 'stress', 'panic', 'uncertain', 'unsure']
204
+ self.excited_words = ['excited', 'thrilled', 'amazing', 'wow', 'incredible', 'fantastic', 'brilliant', 'awesome']
205
+
206
+ def analyze_sentiment(self, text: str) -> SentimentType:
207
+ text_lower = text.lower()
208
+
209
+ positive_count = sum(1 for word in self.positive_words if word in text_lower)
210
+ negative_count = sum(1 for word in self.negative_words if word in text_lower)
211
+ anxious_count = sum(1 for word in self.anxious_words if word in text_lower)
212
+ excited_count = sum(1 for word in self.excited_words if word in text_lower)
213
+
214
+ # Check for question marks (confusion indicator)
215
+ question_marks = text.count('?')
216
+ exclamation_marks = text.count('!')
217
+
218
+ # Determine sentiment
219
+ if excited_count > 0 or exclamation_marks > 1:
220
+ return SentimentType.EXCITED
221
+ elif anxious_count > 0:
222
+ return SentimentType.ANXIOUS
223
+ elif question_marks > 1 and negative_count > 0:
224
+ return SentimentType.CONFUSED
225
+ elif negative_count > positive_count and negative_count > 1:
226
+ return SentimentType.VERY_NEGATIVE if negative_count > 2 else SentimentType.NEGATIVE
227
+ elif positive_count > negative_count and positive_count > 1:
228
+ return SentimentType.VERY_POSITIVE if positive_count > 2 else SentimentType.POSITIVE
229
+ elif 'frustrated' in text_lower or 'frustrating' in text_lower:
230
+ return SentimentType.FRUSTRATED
231
+ else:
232
+ return SentimentType.NEUTRAL
233
+
234
  # ============= AI Assistant Class =============
235
 
236
  class HybridAIAssistant:
237
  def __init__(self):
238
  self.api_key = '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'
239
  self.billing_db = BillingCodesDB()
240
+ self.sentiment_analyzer = SentimentAnalyzer()
241
  self.context = ConversationContext()
242
 
243
  self.headers = {
 
290
  else:
291
  return self.get_general_response(message, billing_context=True)
292
 
293
+ def get_empathetic_response_prefix(self, sentiment: SentimentType) -> str:
294
+ """Generate empathetic response based on sentiment"""
295
+ prefixes = {
296
+ SentimentType.VERY_POSITIVE: "I'm so glad to hear your enthusiasm! 🌟 ",
297
+ SentimentType.POSITIVE: "That's wonderful! 😊 ",
298
+ SentimentType.EXCITED: "I can feel your excitement! 🎉 ",
299
+ SentimentType.ANXIOUS: "I understand this might be causing some concern. Let me help ease your worries. 🤗 ",
300
+ SentimentType.FRUSTRATED: "I can sense your frustration, and I'm here to help make this easier for you. 💙 ",
301
+ SentimentType.CONFUSED: "No worries, I'm here to clear things up for you! 🧠 ",
302
+ SentimentType.NEGATIVE: "I hear that you're having some difficulties. Let me help you with that. 💚 ",
303
+ SentimentType.VERY_NEGATIVE: "I'm really sorry you're going through this. I'm here to support you. ❤️ ",
304
+ SentimentType.NEUTRAL: ""
305
+ }
306
+ return prefixes.get(sentiment, "")
307
+
308
  def get_general_response(self, message: str, billing_context: bool = False) -> str:
309
  """Get response from OpenRouter API for general queries"""
310
 
311
+ # Analyze sentiment
312
+ sentiment = self.sentiment_analyzer.analyze_sentiment(message)
313
+ self.context.current_sentiment = sentiment.value
314
+ self.context.sentiment_history.append(sentiment.value)
315
+
316
+ # Keep only last 10 sentiments
317
+ if len(self.context.sentiment_history) > 10:
318
+ self.context.sentiment_history = self.context.sentiment_history[-10:]
319
+
320
+ # Prepare system prompt with empathy
321
+ system_prompt = """You are a helpful, friendly, and empathetic AI assistant with expertise in healthcare billing codes.
322
  You can assist with any topic - from casual conversation to complex questions.
323
  When discussing medical billing codes, you provide accurate, detailed information.
324
+ Be conversational, helpful, and engaging. Show empathy and understanding.
325
+ Adapt your tone based on the user's emotional state - be more supportive if they seem frustrated or anxious."""
326
 
327
  if billing_context:
328
  system_prompt += "\nThe user is asking about medical billing. Provide helpful information even if you don't have specific code details."
 
355
  result = response.json()
356
  ai_response = result['choices'][0]['message']['content']
357
 
358
+ # Add empathetic prefix based on sentiment
359
+ empathy_prefix = self.get_empathetic_response_prefix(sentiment)
360
+ if empathy_prefix:
361
+ ai_response = empathy_prefix + ai_response
362
+
363
  # Update context
364
  self.context.messages.append({'role': 'user', 'content': message})
365
  self.context.messages.append({'role': 'assistant', 'content': ai_response})
 
379
 
380
  def get_fallback_response(self, message: str) -> str:
381
  """Fallback responses when API fails"""
382
+ sentiment = self.sentiment_analyzer.analyze_sentiment(message)
383
+ empathy_prefix = self.get_empathetic_response_prefix(sentiment)
384
+
385
  fallbacks = [
386
  "I'm having trouble connecting right now, but I'm still here to help! Could you rephrase your question?",
387
  "Let me think about that differently. What specific aspect would you like to know more about?",
388
  "That's an interesting question! While I process that, is there anything specific you'd like to explore?",
389
  "I'm here to help! Could you provide a bit more detail about what you're looking for?"
390
  ]
391
+ return empathy_prefix + random.choice(fallbacks)
392
 
393
+ def process_message(self, message: str) -> Tuple[str, str]:
394
+ """Main method to process any message and return response with sentiment"""
395
  if not message.strip():
396
+ return "Feel free to ask me anything! I can help with general questions or healthcare billing codes. 😊", "neutral"
397
 
398
  # Detect intent
399
  intent = self.detect_intent(message)
400
 
401
  # Route to appropriate handler
402
  if intent['is_billing'] and intent['codes_found']:
403
+ response = self.handle_billing_query(message, intent['codes_found'])
404
  else:
405
+ response = self.get_general_response(message, billing_context=intent['is_billing'])
406
+
407
+ return response, self.context.current_sentiment
408
 
409
  def reset_context(self):
410
  """Reset conversation context"""
 
420
  if not message.strip():
421
  return "Feel free to ask me anything! I can help with general questions or healthcare billing codes. 😊"
422
 
423
+ # Process message and get sentiment
424
+ response, sentiment = assistant.process_message(message)
425
+
426
+ # Update UI based on sentiment (this will be handled by JavaScript)
427
  return response
428
 
429
+ def process_voice_input(audio):
430
+ """Process voice input and return text"""
431
+ if audio is None:
432
+ return "No audio received. Please try again."
433
+
434
+ # For now, return a placeholder message
435
+ # In a real implementation, you'd use speech recognition here
436
+ return "Voice input processed! (Speech recognition would be implemented here)"
437
+
438
  def reset_chat():
439
  """Reset the conversation context"""
440
  assistant.reset_context()
 
444
 
445
  examples = [
446
  "What is healthcare billing code A0429?",
447
+ "Can you explain CPT code 99213 in detail?",
448
  "Tell me about DRG 470",
449
+ "I'm feeling frustrated with this billing issue",
450
+ "This is confusing, can you help me understand?",
451
+ "Thank you so much! This is exactly what I needed!",
452
  "How does artificial intelligence work?",
453
  "Give me a simple pasta recipe",
454
+ "Write a short poem about nature"
 
 
 
455
  ]
456
 
457
  # ============= Create Interface =============
458
 
459
  def create_interface():
460
+ """Create the Gradio ChatInterface with Emotional UI and Voice Input"""
461
 
462
+ # Enhanced CSS with emotional UI and voice features
463
  custom_css = """
464
  /* Global Styles */
465
  .gradio-container {
 
469
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%) !important;
470
  min-height: 100vh !important;
471
  padding: 1rem !important;
472
+ transition: all 0.5s ease !important;
473
  }
474
 
475
+ /* Emotional UI Color Schemes */
476
+ .sentiment-positive { background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%) !important; }
477
+ .sentiment-very-positive { background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%) !important; }
478
+ .sentiment-negative { background: linear-gradient(135deg, #d299c2 0%, #fef9d7 100%) !important; }
479
+ .sentiment-very-negative { background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%) !important; }
480
+ .sentiment-anxious { background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%) !important; }
481
+ .sentiment-frustrated { background: linear-gradient(135deg, #ff8a80 0%, #ffad80 100%) !important; }
482
+ .sentiment-excited { background: linear-gradient(135deg, #ffd89b 0%, #19547b 100%) !important; }
483
+ .sentiment-confused { background: linear-gradient(135deg, #a8caba 0%, #5d4e75 100%) !important; }
484
+
485
+ /* Enhanced Header with Mood Indicator */
486
  .header-text {
487
  text-align: center;
488
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
 
493
  box-shadow: 0 20px 40px rgba(102, 126, 234, 0.3);
494
  position: relative;
495
  overflow: hidden;
496
+ transition: all 0.5s ease;
497
  }
498
 
499
  .header-text::before {
 
512
  50% { opacity: 0.6; }
513
  }
514
 
515
+ /* Mood Indicator */
516
+ .mood-indicator {
517
+ position: absolute;
518
+ top: 1rem;
519
+ right: 1rem;
520
+ width: 60px;
521
+ height: 60px;
522
+ border-radius: 50%;
523
+ background: rgba(255,255,255,0.2);
524
+ backdrop-filter: blur(10px);
525
+ display: flex;
526
+ align-items: center;
527
+ justify-content: center;
528
+ font-size: 24px;
529
+ transition: all 0.5s ease;
530
+ animation: breathe 3s ease-in-out infinite;
531
+ }
532
+
533
+ @keyframes breathe {
534
+ 0%, 100% { transform: scale(1); }
535
+ 50% { transform: scale(1.05); }
536
+ }
537
+
538
+ .mood-positive { background: rgba(132, 250, 176, 0.3) !important; }
539
+ .mood-negative { background: rgba(255, 154, 158, 0.3) !important; }
540
+ .mood-anxious { background: rgba(255, 236, 210, 0.3) !important; }
541
+ .mood-excited { background: rgba(255, 216, 155, 0.3) !important; }
542
+
543
  .header-text h1 {
544
  margin: 0;
545
  font-size: 3rem;
 
574
  to { box-shadow: 0 0 20px rgba(255,255,255,0.6); }
575
  }
576
 
577
+ /* Voice Input Button */
578
+ .voice-btn {
579
+ background: linear-gradient(135deg, #ff6b6b 0%, #ee5a52 100%) !important;
580
+ color: white !important;
581
+ border: none !important;
582
+ border-radius: 50% !important;
583
+ width: 60px !important;
584
+ height: 60px !important;
585
+ font-size: 24px !important;
586
+ margin: 0.5rem !important;
587
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) !important;
588
+ box-shadow: 0 4px 15px rgba(255, 107, 107, 0.3) !important;
589
+ position: relative;
590
+ overflow: hidden;
591
+ }
592
+
593
+ .voice-btn:hover {
594
+ transform: scale(1.1) !important;
595
+ box-shadow: 0 8px 25px rgba(255, 107, 107, 0.5) !important;
596
+ }
597
+
598
+ .voice-btn.recording {
599
+ animation: recordPulse 1s ease-in-out infinite !important;
600
+ background: linear-gradient(135deg, #ff3030 0%, #ff1010 100%) !important;
601
+ }
602
+
603
+ @keyframes recordPulse {
604
+ 0% { box-shadow: 0 0 0 0 rgba(255, 107, 107, 0.7); }
605
+ 70% { box-shadow: 0 0 0 20px rgba(255, 107, 107, 0); }
606
+ 100% { box-shadow: 0 0 0 0 rgba(255, 107, 107, 0); }
607
+ }
608
+
609
+ /* Chat Interface Styling with Emotional Feedback */
610
  .gradio-chatinterface {
611
  background: white !important;
612
  border-radius: 20px !important;
 
614
  padding: 2rem !important;
615
  margin: 1rem 0 !important;
616
  backdrop-filter: blur(10px) !important;
617
+ transition: all 0.5s ease !important;
618
+ }
619
+
620
+ .gradio-chatinterface.emotional-positive {
621
+ border: 2px solid rgba(132, 250, 176, 0.5) !important;
622
+ box-shadow: 0 25px 50px rgba(132, 250, 176, 0.2) !important;
623
+ }
624
+
625
+ .gradio-chatinterface.emotional-negative {
626
+ border: 2px solid rgba(255, 154, 158, 0.5) !important;
627
+ box-shadow: 0 25px 50px rgba(255, 154, 158, 0.2) !important;
628
  }
629
 
630
  /* Enhanced Buttons */
 
718
  letter-spacing: 1px;
719
  }
720
 
721
+ /* Empathy Animations */
722
+ @keyframes empathyPulse {
723
+ 0%, 100% { transform: scale(1); }
724
+ 50% { transform: scale(1.02); }
725
+ }
726
+
727
+ @keyframes supportGlow {
728
+ 0%, 100% { box-shadow: 0 0 10px rgba(102, 126, 234, 0.3); }
729
+ 50% { box-shadow: 0 0 20px rgba(102, 126, 234, 0.6); }
730
+ }
731
+
732
+ .empathy-support {
733
+ animation: empathyPulse 2s ease-in-out infinite, supportGlow 3s ease-in-out infinite;
734
+ }
735
+
736
+ /* Voice Recognition Feedback */
737
+ .voice-feedback {
738
+ position: fixed;
739
+ bottom: 2rem;
740
+ right: 2rem;
741
+ background: rgba(102, 126, 234, 0.9);
742
+ color: white;
743
+ padding: 1rem 1.5rem;
744
+ border-radius: 50px;
745
+ backdrop-filter: blur(10px);
746
+ z-index: 1000;
747
+ animation: slideInRight 0.3s ease-out;
748
+ }
749
+
750
+ @keyframes slideInRight {
751
+ from { transform: translateX(100%); opacity: 0; }
752
+ to { transform: translateX(0); opacity: 1; }
753
+ }
754
+
755
  /* Enhanced Accordion */
756
  .gradio-accordion {
757
  background: rgba(255,255,255,0.9) !important;
 
777
  padding: 1.5rem;
778
  border: 1px solid rgba(255,255,255,0.3);
779
  box-shadow: 0 8px 25px rgba(0,0,0,0.1);
780
+ transition: all 0.3s ease;
781
+ }
782
+
783
+ .feature-card:hover {
784
+ transform: translateY(-5px);
785
+ box-shadow: 0 15px 35px rgba(0,0,0,0.15);
786
  }
787
 
788
  .feature-icon {
 
831
  grid-template-columns: 1fr;
832
  gap: 1rem;
833
  }
834
+
835
+ .mood-indicator {
836
+ width: 50px;
837
+ height: 50px;
838
+ font-size: 20px;
839
+ }
840
+
841
+ .voice-btn {
842
+ width: 50px !important;
843
+ height: 50px !important;
844
+ font-size: 20px !important;
845
+ }
846
  }
847
 
848
  /* Loading Animation */
 
856
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
857
  background-size: 400% 100%;
858
  }
859
+
860
+ /* Sentiment-based message styling */
861
+ .message-positive {
862
+ border-left: 4px solid #84fab0 !important;
863
+ background: linear-gradient(135deg, rgba(132, 250, 176, 0.1) 0%, rgba(143, 211, 244, 0.1) 100%) !important;
864
+ }
865
+
866
+ .message-negative {
867
+ border-left: 4px solid #ff9a9e !important;
868
+ background: linear-gradient(135deg, rgba(255, 154, 158, 0.1) 0%, rgba(254, 207, 239, 0.1) 100%) !important;
869
+ }
870
+
871
+ .message-anxious {
872
+ border-left: 4px solid #ffecd2 !important;
873
+ background: linear-gradient(135deg, rgba(255, 236, 210, 0.1) 0%, rgba(252, 182, 159, 0.1) 100%) !important;
874
+ }
875
+ """