import streamlit as st import pandas as pd import json import os from typing import Union, List, Dict, Optional, Tuple from groq import Groq from duckduckgo_search import DDGS from datetime import datetime, timedelta import time import numpy as np import pickle from dataclasses import dataclass, asdict import hashlib from collections import defaultdict # Set page configuration st.set_page_config( page_title="MedAssist - AI Medical Preconsultation", layout="wide", initial_sidebar_state="expanded", page_icon="š„" ) # Enhanced CSS for medical theme st.markdown(""" """, unsafe_allow_html=True) @dataclass class ConversationEntry: """Data structure for storing conversation entries""" timestamp: str user_input: str assistant_response: str symptoms: List[str] severity_score: float confidence_score: float search_queries_used: List[str] user_feedback: Optional[int] = None # 1-5 rating was_helpful: Optional[bool] = None @dataclass class AgentPerformance: """Track agent performance metrics""" agent_name: str total_queries: int = 0 successful_responses: int = 0 average_confidence: float = 0.0 user_satisfaction: float = 0.0 learning_rate: float = 0.01 expertise_areas: Dict[str, float] = None def __post_init__(self): if self.expertise_areas is None: self.expertise_areas = defaultdict(float) class MedicalSearchTool: """Enhanced medical search tool with domain-specific optimization""" def __init__(self): self.ddgs = DDGS() self.medical_sources = [ "mayoclinic.org", "webmd.com", "healthline.com", "medlineplus.gov", "nih.gov", "who.int", "cdc.gov", "ncbi.nlm.nih.gov" ] def search_medical_info(self, query: str, search_type: str = "symptoms") -> str: """Search for medical information with safety considerations""" try: # Add medical context to search medical_queries = { "symptoms": f"medical symptoms {query} causes diagnosis", "treatment": f"medical treatment {query} therapy options", "prevention": f"disease prevention {query} health tips", "general": f"medical information {query} health facts" } enhanced_query = medical_queries.get(search_type, medical_queries["general"]) # Perform search with medical focus search_results = list(self.ddgs.text( enhanced_query, max_results=5, region='wt-wt', safesearch='on' )) if not search_results: return "No relevant medical information found. Please consult with a healthcare professional." # Filter and format results with medical authority preference formatted_results = [] for idx, result in enumerate(search_results, 1): title = result.get('title', 'No title') snippet = result.get('body', 'No description') url = result.get('href', 'No URL') # Prioritize trusted medical sources source_trust = "ā" if any(source in url for source in self.medical_sources) else "" formatted_results.append( f"{idx}. {source_trust} {title}\n" f" Information: {snippet}\n" f" Source: {url}\n" ) return "\n".join(formatted_results) except Exception as e: return f"Search temporarily unavailable: {str(e)}" class GroqLLM: """Medical-optimized LLM client""" def __init__(self, model_name="openai/gpt-oss-20b"): self.client = Groq(api_key=os.environ.get("GROQ_API_KEY")) self.model_name = model_name self.medical_context = """ You are a medical AI assistant for preconsultation guidance. IMPORTANT: Always remind users that this is not a substitute for professional medical advice. Provide helpful information while emphasizing the need for proper medical consultation. """ def generate_response(self, prompt: str, conversation_history: List[str] = None) -> Tuple[str, float]: """Generate response with confidence scoring""" try: # Build context with conversation history context = self.medical_context if conversation_history: context += f"\n\nConversation History:\n{chr(10).join(conversation_history[-5:])}" full_prompt = f"{context}\n\nUser Query: {prompt}\n\nPlease provide helpful medical guidance while emphasizing the importance of professional medical consultation." completion = self.client.chat.completions.create( model=self.model_name, messages=[{"role": "user", "content": full_prompt}], temperature=0.3, # Lower temperature for medical accuracy max_tokens=1500, stream=False ) response = completion.choices[0].message.content if completion.choices else "Unable to generate response" # Calculate confidence score based on response characteristics confidence = self._calculate_confidence(response, prompt) return response, confidence except Exception as e: return f"LLM temporarily unavailable: {str(e)}", 0.0 def _calculate_confidence(self, response: str, query: str) -> float: """Calculate confidence score based on response quality""" confidence_factors = 0.0 # Check for medical disclaimers (increases confidence in safety) if any(phrase in response.lower() for phrase in ["consult", "doctor", "medical professional", "healthcare provider"]): confidence_factors += 0.3 # Check response length (adequate detail) if 200 <= len(response) <= 1000: confidence_factors += 0.2 # Check for structured information if any(marker in response for marker in ["1.", "ā¢", "-", "**"]): confidence_factors += 0.2 # Check for balanced information (not overly certain) if any(phrase in response.lower() for phrase in ["may", "might", "could", "possible", "typically"]): confidence_factors += 0.3 return min(confidence_factors, 1.0) class EvolutionaryMedicalAgent: """Evolutionary agent with reinforcement learning capabilities""" def __init__(self, agent_id: str, specialization: str): self.agent_id = agent_id self.specialization = specialization self.performance = AgentPerformance(agent_name=agent_id) self.knowledge_base = defaultdict(float) self.response_patterns = {} self.learning_memory = [] def process_query(self, query: str, context: str, search_results: str) -> Tuple[str, float]: """Process query and adapt based on specialization""" # Update query count self.performance.total_queries += 1 # Extract key terms for learning key_terms = self._extract_medical_terms(query) # Build specialized response based on agent's expertise specialized_prompt = f""" As a {self.specialization} specialist, analyze this medical query: Query: {query} Context: {context} Search Results: {search_results} Provide specialized insights based on your expertise in {self.specialization}. Always emphasize the need for professional medical consultation. """ # Simulate processing (in real implementation, this would use the LLM) response = f"Based on my specialization in {self.specialization}, {query.lower()} suggests several considerations. However, please consult with a healthcare professional for proper diagnosis and treatment." confidence = 0.7 + (self.performance.average_confidence * 0.3) # Update expertise in relevant areas for term in key_terms: self.knowledge_base[term] += 0.1 return response, confidence def update_from_feedback(self, query: str, response: str, feedback_score: int, was_helpful: bool): """Update agent based on user feedback (reinforcement learning)""" # Calculate reward signal reward = (feedback_score - 3) / 2 # Convert 1-5 scale to -1 to 1 if was_helpful: reward += 0.2 # Update performance metrics if feedback_score >= 3: self.performance.successful_responses += 1 # Update satisfaction and confidence self.performance.user_satisfaction = ( (self.performance.user_satisfaction * (self.performance.total_queries - 1) + feedback_score) / self.performance.total_queries ) # Store learning memory self.learning_memory.append({ 'query': query, 'response': response, 'reward': reward, 'timestamp': datetime.now().isoformat() }) # Adapt learning rate based on performance if self.performance.user_satisfaction > 4.0: self.performance.learning_rate *= 0.95 # Slow down learning when performing well elif self.performance.user_satisfaction < 3.0: self.performance.learning_rate *= 1.1 # Speed up learning when performing poorly # Update expertise areas based on feedback terms = self._extract_medical_terms(query) for term in terms: self.knowledge_base[term] += reward * self.performance.learning_rate def _extract_medical_terms(self, text: str) -> List[str]: """Extract medical terms from text for learning""" medical_keywords = [ 'pain', 'fever', 'headache', 'nausea', 'fatigue', 'cough', 'cold', 'flu', 'diabetes', 'hypertension', 'infection', 'allergy', 'asthma', 'arthritis', 'anxiety', 'depression', 'insomnia', 'migraine', 'rash', 'swelling' ] found_terms = [] text_lower = text.lower() for term in medical_keywords: if term in text_lower: found_terms.append(term) return found_terms def get_expertise_summary(self) -> Dict: """Get summary of agent's learned expertise""" return { 'specialization': self.specialization, 'total_queries': self.performance.total_queries, 'success_rate': (self.performance.successful_responses / max(1, self.performance.total_queries)) * 100, 'user_satisfaction': self.performance.user_satisfaction, 'learning_rate': self.performance.learning_rate, 'top_expertise_areas': dict(sorted(self.knowledge_base.items(), key=lambda x: x[1], reverse=True)[:5]) } class MedicalConsultationSystem: """Main medical consultation system with evolutionary agents""" def __init__(self): self.llm = GroqLLM() self.search_tool = MedicalSearchTool() self.agents = self._initialize_agents() self.conversation_history = [] self.conversation_data = [] def _initialize_agents(self) -> Dict[str, EvolutionaryMedicalAgent]: """Initialize specialized medical agents""" return { "general_practitioner": EvolutionaryMedicalAgent("gp", "General Practice Medicine"), "symptom_analyzer": EvolutionaryMedicalAgent("symptom", "Symptom Analysis and Triage"), "wellness_advisor": EvolutionaryMedicalAgent("wellness", "Preventive Care and Wellness"), "mental_health": EvolutionaryMedicalAgent("mental", "Mental Health and Psychology"), "emergency_assessor": EvolutionaryMedicalAgent("emergency", "Emergency Assessment and Urgent Care") } def process_medical_query(self, user_query: str) -> Dict: """Process medical query through evolutionary agent system""" timestamp = datetime.now().isoformat() # Determine which agents should handle this query relevant_agents = self._select_relevant_agents(user_query) # Search for medical information search_results = self.search_tool.search_medical_info(user_query, "symptoms") # Build conversation context context = "\n".join(self.conversation_history[-3:]) if self.conversation_history else "" # Get responses from relevant agents agent_responses = {} for agent_name in relevant_agents: agent = self.agents[agent_name] response, confidence = agent.process_query(user_query, context, search_results) agent_responses[agent_name] = { 'response': response, 'confidence': confidence, 'specialization': agent.specialization } # Generate main LLM response main_response, main_confidence = self.llm.generate_response( f"{user_query}\n\nRelevant Information: {search_results}", self.conversation_history ) # Combine responses intelligently final_response = self._combine_responses(main_response, agent_responses) # Update conversation history self.conversation_history.extend([ f"User: {user_query}", f"Assistant: {final_response}" ]) # Extract symptoms for analysis symptoms = self._extract_symptoms(user_query) severity_score = self._assess_severity(user_query, symptoms) # Store conversation data conversation_entry = ConversationEntry( timestamp=timestamp, user_input=user_query, assistant_response=final_response, symptoms=symptoms, severity_score=severity_score, confidence_score=main_confidence, search_queries_used=[user_query] ) self.conversation_data.append(conversation_entry) return { 'response': final_response, 'confidence': main_confidence, 'severity_score': severity_score, 'symptoms_detected': symptoms, 'agents_consulted': relevant_agents, 'agent_responses': agent_responses, 'search_performed': True } def _select_relevant_agents(self, query: str) -> List[str]: """Select most relevant agents for the query""" query_lower = query.lower() relevant_agents = ["general_practitioner"] # Always include GP # Mental health keywords mental_health_keywords = ["stress", "anxiety", "depression", "sleep", "mood", "worry", "panic", "sad"] if any(keyword in query_lower for keyword in mental_health_keywords): relevant_agents.append("mental_health") # Emergency keywords emergency_keywords = ["severe", "intense", "emergency", "urgent", "chest pain", "difficulty breathing", "blood"] if any(keyword in query_lower for keyword in emergency_keywords): relevant_agents.append("emergency_assessor") # Wellness keywords wellness_keywords = ["prevention", "healthy", "nutrition", "exercise", "lifestyle", "diet"] if any(keyword in query_lower for keyword in wellness_keywords): relevant_agents.append("wellness_advisor") # Always include symptom analyzer for health queries if any(keyword in query_lower for keyword in ["pain", "ache", "hurt", "symptom", "feel"]): relevant_agents.append("symptom_analyzer") return list(set(relevant_agents)) def _combine_responses(self, main_response: str, agent_responses: Dict) -> str: """Intelligently combine responses from multiple agents""" if not agent_responses: return main_response combined = main_response + "\n\n**Specialist Insights:**\n" for agent_name, data in agent_responses.items(): if data['confidence'] > 0.6: # Only include confident responses combined += f"\n⢠**{data['specialization']}**: {data['response'][:200]}...\n" return combined def _extract_symptoms(self, query: str) -> List[str]: """Extract symptoms from user query""" common_symptoms = [ 'fever', 'headache', 'nausea', 'pain', 'cough', 'fatigue', 'dizziness', 'rash', 'swelling', 'shortness of breath', 'chest pain', 'abdominal pain' ] query_lower = query.lower() detected_symptoms = [symptom for symptom in common_symptoms if symptom in query_lower] return detected_symptoms def _assess_severity(self, query: str, symptoms: List[str]) -> float: """Assess severity of reported symptoms (0-10 scale)""" severity_score = 0.0 query_lower = query.lower() # High severity indicators high_severity = ["severe", "intense", "unbearable", "emergency", "chest pain", "difficulty breathing"] medium_severity = ["moderate", "persistent", "recurring", "worse", "concerning"] if any(indicator in query_lower for indicator in high_severity): severity_score += 7.0 elif any(indicator in query_lower for indicator in medium_severity): severity_score += 4.0 else: severity_score += 2.0 # Add points for multiple symptoms severity_score += min(len(symptoms) * 0.5, 2.0) return min(severity_score, 10.0) def update_agent_performance(self, query_index: int, feedback_score: int, was_helpful: bool): """Update agent performance based on user feedback""" if query_index < len(self.conversation_data): entry = self.conversation_data[query_index] entry.user_feedback = feedback_score entry.was_helpful = was_helpful # Update all agents that were involved in this query for agent in self.agents.values(): agent.update_from_feedback(entry.user_input, entry.assistant_response, feedback_score, was_helpful) def get_system_metrics(self) -> Dict: """Get comprehensive system performance metrics""" total_conversations = len(self.conversation_data) if total_conversations == 0: return {"status": "No conversations yet"} avg_confidence = np.mean([entry.confidence_score for entry in self.conversation_data]) avg_severity = np.mean([entry.severity_score for entry in self.conversation_data]) feedback_entries = [entry for entry in self.conversation_data if entry.user_feedback is not None] avg_feedback = np.mean([entry.user_feedback for entry in feedback_entries]) if feedback_entries else 0 return { "total_conversations": total_conversations, "average_confidence": avg_confidence, "average_severity": avg_severity, "average_user_feedback": avg_feedback, "agent_performance": {name: agent.get_expertise_summary() for name, agent in self.agents.items()} } # Initialize session state if 'medical_system' not in st.session_state: st.session_state.medical_system = MedicalConsultationSystem() if 'chat_messages' not in st.session_state: st.session_state.chat_messages = [] medical_system = st.session_state.medical_system # Main interface st.markdown("""
Advanced AI-powered medical guidance with evolutionary learning agents
This AI system provides general health information and is NOT a substitute for professional medical advice, diagnosis, or treatment. Always consult with qualified healthcare professionals for medical concerns. In case of emergency, contact emergency services immediately.
Queries: {expertise['total_queries']}
Success Rate: {expertise['success_rate']:.1f}%
Satisfaction: {expertise['user_satisfaction']:.1f}/5
Learning Rate: {expertise['learning_rate']:.3f}
Total Chats: {metrics['total_conversations']}
Avg Confidence: {metrics['average_confidence']:.2f}
Avg Severity: {metrics['average_severity']:.1f}/10
User Rating: {metrics['average_user_feedback']:.1f}/5
MedAssist v1.0 | AI-Powered Medical Preconsultation System
š¤ Evolutionary Learning Agents ⢠š Real-time Medical Search ⢠š¬ Intelligent Chat Interface
ā ļø This system is for informational purposes only and is not a substitute for professional medical advice