Spaces:
Build error
Build error
| #!/usr/bin/env python | |
| # coding: utf-8 | |
| from langchain_community.document_loaders import PyPDFDirectoryLoader | |
| from langchain.text_splitter import RecursiveCharacterTextSplitter | |
| from langchain_community.embeddings import HuggingFaceEmbeddings | |
| from langchain.vectorstores import FAISS, Chroma | |
| from langchain_community.llms import LlamaCpp | |
| from langchain.chains import RetrievalQA, LLMChain | |
| from langchain.prompts import ChatPromptTemplate | |
| from langchain.schema.runnable import RunnablePassthrough | |
| from langchain.schema.output_parser import StrOutputParser | |
| from transformers import AutoTokenizer, AutoModel | |
| from sklearn.metrics.pairwise import cosine_similarity | |
| import google.generativeai as genai | |
| import matplotlib.pyplot as plt | |
| import os | |
| from typing import Dict, List, Tuple | |
| import json | |
| import numpy as np | |
| import seaborn as sns | |
| from llama_cpp import Llama | |
| import os | |
| GEMINI_API_KEY = os.getenv('GEMINI') | |
| HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGING') | |
| os.environ["HUGGINGFACEHUB_API_TOKEN"] = HUGGINGFACEHUB_API_TOKEN | |
| # Initialize the Sentence Transformer model for intent classification | |
| tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2") | |
| model = AutoModel.from_pretrained("sentence-transformers/all-MiniLM-L6-v2") | |
| # Define intents with keywords | |
| intents = { | |
| "stomach": { | |
| "keywords": [ | |
| "pain", "cramps", "nausea", "indigestion", "diarrhea", "bloating", "acid reflux", "constipation", | |
| "ulcers", "food poisoning", "heartburn", "vomiting", "gassiness", "stomach flu", "gastritis", | |
| "stomach ache", "IBS", "peptic ulcers", "acidity", "flatulence", "abdominal pain", "acid reflux disease", | |
| "GERD", "feeling full quickly", "poor appetite", "belching", "sharp abdominal pain", "dull stomach ache", | |
| "epigastric pain", "dyspepsia", "gurgling stomach sounds" | |
| ], | |
| "embedding_vector": None | |
| }, | |
| "skin": { | |
| "keywords": [ | |
| "rash", "itch", "eczema", "dry skin", "acne", "redness", "hives", "fungal infection", "psoriasis", | |
| "dermatitis", "sunburn", "skin peeling", "discoloration", "swelling", "pimples", "spots", "cysts", | |
| "skin tags", "lesions", "ulcers", "allergic reaction", "rosacea", "warts", "athlete's foot", "moles", | |
| "boils", "flaky skin", "stretch marks", "pigmentation", "vitiligo", "skin irritation", "flaky scalp", | |
| "blisters", "cracked skin", "sensitivity", "prickly heat", "bruising", "scars" | |
| ], | |
| "embedding_vector": None | |
| }, | |
| "bp": { | |
| "keywords": [ | |
| "hypertension", "blood pressure", "dizziness", "headache", "fatigue", "high blood pressure", | |
| "low blood pressure", "hypotension", "chest pain", "palpitations", "fainting", "shortness of breath", | |
| "blurred vision", "confusion", "nosebleeds", "lightheadedness", "pounding heartbeat", | |
| "irregular heartbeat", "heart strain", "stroke risk", "renal issues", "diastolic pressure", | |
| "systolic pressure", "blood flow issues", "heart failure", "hypertension crisis", "high pulse rate", | |
| "low pulse rate", "cardiovascular disease", "pressure behind eyes" | |
| ], | |
| "embedding_vector": None | |
| }, | |
| "diabetes": { | |
| "keywords": [ | |
| "insulin", "sugar", "glucose", "thirst", "frequent urination", "weight loss", "blurred vision", | |
| "fatigue", "tingling", "numbness", "slow healing wounds", "dry mouth", "diabetic neuropathy", "hunger", | |
| "high blood sugar", "low blood sugar", "polyuria", "polydipsia", "glycemic index", "hyperglycemia", | |
| "hypoglycemia", "ketoacidosis", "foot ulcers", "nerve pain", "eye problems", "retinopathy", "nephropathy", | |
| "glucose intolerance", "sugar cravings", "sweating", "shakiness", "dizzy spells", "carb counting", | |
| "A1C levels", "prediabetes", "metabolic syndrome" | |
| ], | |
| "embedding_vector": None | |
| } | |
| } | |
| # Precompute intent embeddings | |
| for intent, data in intents.items(): | |
| tokens = tokenizer(' '.join(data['keywords']), return_tensors="pt", padding=True, truncation=True) | |
| data['embedding_vector'] = model(**tokens).pooler_output.detach().numpy() | |
| # Text preprocessing | |
| def preprocess_text(text: str) -> str: | |
| text = text.lower() | |
| text = ''.join(char for char in text if char.isalnum() or char.isspace()) | |
| replacements = {'bp': 'blood pressure', 'ut': 'urinary tract', 'hr': 'heart rate'} | |
| for abbr, full_form in replacements.items(): | |
| text = text.replace(abbr, full_form) | |
| return text | |
| # Intent classification | |
| def classify_medical_intent(symptoms: str) -> str: | |
| preprocessed_symptoms = preprocess_text(symptoms) | |
| tokens = tokenizer(preprocessed_symptoms, return_tensors="pt", padding=True, truncation=True) | |
| symptoms_embedding = model(**tokens).pooler_output.detach().numpy() | |
| similarities = [ | |
| cosine_similarity(symptoms_embedding, intent_data['embedding_vector'])[0][0] | |
| for intent_data in intents.values() | |
| ] | |
| keyword_scores = [ | |
| sum(keyword in preprocessed_symptoms for keyword in intent_data['keywords']) | |
| for intent_data in intents.values() | |
| ] | |
| ensemble_scores = [ | |
| 0.7 * similarity + 0.3 * keyword_match | |
| for similarity, keyword_match in zip(similarities, keyword_scores) | |
| ] | |
| best_intent_index = np.argmax(ensemble_scores) | |
| return list(intents.keys())[best_intent_index] | |
| def plot_enhanced_fishbone(disease: str, causes: Dict[str, List[str]]) -> plt.Figure: | |
| """ | |
| Create an enhanced fishbone diagram with detailed sub-branches | |
| """ | |
| # Setup | |
| sns.set_theme(style="whitegrid") | |
| fig, ax = plt.subplots(figsize=(20, 12), facecolor='#f0f2f6') | |
| # Main spine parameters | |
| spine_length = 14 | |
| spine_start = 2 | |
| spine_end = spine_start + spine_length | |
| # Draw main spine with arrow | |
| ax.arrow(spine_start, 0, spine_length, 0, | |
| head_width=0.4, head_length=0.6, | |
| fc='black', ec='black', lw=2) | |
| # Calculate positions | |
| num_causes = len(causes) | |
| spacing = spine_length / (num_causes + 1) | |
| branch_length = 3.5 | |
| angle = 45 | |
| # Calculate branch geometry | |
| dx = branch_length * np.cos(np.deg2rad(angle)) | |
| dy = branch_length * np.sin(np.deg2rad(angle)) | |
| # Use a colormap for different categories | |
| colors = plt.cm.Pastel1(np.linspace(0, 1, num_causes)) | |
| # Draw branches and sub-branches | |
| for i, (cause, subcauses) in enumerate(causes.items()): | |
| x_pos = spine_start + (i + 1) * spacing | |
| # Alternate between top and bottom | |
| if i % 2 == 0: | |
| y_end = dy | |
| sub_y_offset = 0.5 | |
| va = 'bottom' | |
| else: | |
| y_end = -dy | |
| sub_y_offset = -0.5 | |
| va = 'top' | |
| # Draw main branch | |
| color = colors[i] | |
| ax.plot([x_pos, x_pos + dx], [0, y_end], | |
| color=color, lw=2, zorder=2) | |
| # Add main cause text | |
| ax.text(x_pos + dx, y_end + sub_y_offset, | |
| cause.upper(), | |
| ha='center', | |
| va=va, | |
| fontsize=10, | |
| fontweight='bold', | |
| bbox=dict(facecolor='white', | |
| edgecolor=color, | |
| boxstyle='round,pad=0.5', | |
| alpha=0.9)) | |
| # Add sub-branches | |
| for j, subcause in enumerate(subcauses): | |
| # Calculate sub-branch positions | |
| sub_ratio = (j + 1) / (len(subcauses) + 1) | |
| sub_x = x_pos + dx * sub_ratio | |
| sub_y = y_end * sub_ratio | |
| # Draw sub-branch | |
| ax.plot([sub_x, sub_x + dx/2], | |
| [sub_y, sub_y], | |
| color=color, lw=1, zorder=2) | |
| # Add sub-cause text | |
| ax.text(sub_x + dx/2 + 0.1, | |
| sub_y, | |
| subcause, | |
| ha='left', | |
| va='center', | |
| fontsize=8, | |
| bbox=dict(facecolor='white', | |
| edgecolor=color, | |
| alpha=0.7, | |
| boxstyle='round,pad=0.3')) | |
| # Add decorative elements | |
| ax.plot(x_pos, 0, 'o', color=color, markersize=6, zorder=3) | |
| # Add problem statement | |
| ax.text(spine_end + 0.7, 0, | |
| disease.upper(), | |
| ha='left', | |
| va='center', | |
| fontsize=12, | |
| fontweight='bold', | |
| bbox=dict(facecolor='lightgray', | |
| edgecolor='gray', | |
| boxstyle='round,pad=0.5')) | |
| # Styling | |
| plt.title('Enhanced Root Cause Analysis (Ishikawa Diagram)', | |
| pad=20, | |
| fontsize=14, | |
| fontweight='bold') | |
| # Set limits and remove axes | |
| margin = 2 | |
| ax.set_xlim(0, spine_end + 4) | |
| ax.set_ylim(-branch_length - margin, branch_length + margin) | |
| ax.axis('off') | |
| plt.tight_layout() | |
| return fig | |
| def generate_interview_questions(initial_symptoms: str, category: str, gemini_model) -> List[str]: | |
| """Generate 5 specific interview questions using Gemini API based on initial symptoms and category.""" | |
| prompt = f"""Given a patient with {category}-related symptoms: '{initial_symptoms}', | |
| generate exactly 5 specific medical interview questions to understand their condition better. | |
| Focus on gathering important diagnostic information for {category} conditions. | |
| Return ONLY a JSON array of 5 questions in this exact format: | |
| [ | |
| "Question 1 text here", | |
| "Question 2 text here", | |
| "Question 3 text here", | |
| "Question 4 text here", | |
| "Question 5 text here" | |
| ]""" | |
| try: | |
| response = gemini_model.generate_content(prompt) | |
| response_text = response.text.strip() | |
| # Handle potential formatting issues | |
| if not response_text.startswith('['): | |
| # Try to extract JSON array if it's buried in additional text | |
| import re | |
| json_match = re.search(r'\[(.*?)\]', response_text, re.DOTALL) | |
| if json_match: | |
| response_text = json_match.group(0) | |
| else: | |
| # Fallback: Convert response to list format | |
| questions = [q.strip() for q in response_text.split('\n') if q.strip()] | |
| return questions[:5] | |
| questions = json.loads(response_text) | |
| # Ensure exactly 5 questions | |
| if len(questions) < 5: | |
| questions.extend([ | |
| "How long have you been experiencing these symptoms?", | |
| "Have you noticed any patterns or triggers?", | |
| "Are there any other symptoms you've experienced?", | |
| "Have you made any recent lifestyle changes?", | |
| "Have you tried any treatments or medications?" | |
| ][:5 - len(questions)]) | |
| return questions[:5] | |
| except json.JSONDecodeError: | |
| # Fallback questions based on category | |
| fallback_questions = { | |
| "bp": [ | |
| "How often do you check your blood pressure?", | |
| "Do you experience headaches or dizziness?", | |
| "What is your typical salt intake?", | |
| "Do you have a family history of hypertension?", | |
| "What is your current exercise routine?" | |
| ], | |
| "diabetes": [ | |
| "When did you last check your blood sugar?", | |
| "Have you noticed increased thirst or urination?", | |
| "What is your typical daily diet?", | |
| "Do you have a family history of diabetes?", | |
| "How often do you exercise?" | |
| ], | |
| "skin": [ | |
| "How long have you had this skin condition?", | |
| "Is there any itching or pain?", | |
| "Have you used any new products recently?", | |
| "Does the condition worsen at any particular time?", | |
| "Have you noticed any triggers?" | |
| ], | |
| "stomach": [ | |
| "When did your stomach problems begin?", | |
| "How would you describe the pain or discomfort?", | |
| "Are symptoms related to eating specific foods?", | |
| "Have you noticed any changes in appetite?", | |
| "Do you experience nausea or vomiting?" | |
| ] | |
| } | |
| return fallback_questions.get(category.lower(), [ | |
| "How long have you been experiencing these symptoms?", | |
| "Have you noticed any patterns or triggers?", | |
| "Are there any other symptoms you've experienced?", | |
| "Have you made any recent lifestyle changes?", | |
| "Have you tried any treatments or medications?" | |
| ]) | |
| # In[20]: | |
| def conduct_interview(questions: List[str], category: str, llm) -> Dict: | |
| """Conduct the interview using provided questions and gather responses.""" | |
| interview_data = { | |
| 'intent': category, | |
| 'initial_symptoms': questions[0], | |
| 'detailed_responses': {} | |
| } | |
| print("\nStarting detailed medical interview...\n") | |
| for i, question in enumerate(questions, 1): | |
| print(f"Question {i}: {question}") | |
| user_response = input("Your answer: ").strip() | |
| # Modified prompt to be more explicit about the required response format | |
| prompt = f"""As a medical professional, respond to this patient statement with empathy: '{user_response}' | |
| Requirements: | |
| - Respond directly to the patient | |
| - Show understanding of their situation | |
| - Keep response to 2-3 sentences | |
| - Do not include any instructions or labels | |
| - Start response with 'I' or 'Thank you' or similar direct phrases | |
| For example, if patient says they have a headache, respond like: | |
| "I understand you're experiencing head pain. Let's work together to identify the cause and find appropriate relief." | |
| Now provide your response:""" | |
| # Get response and handle empty cases | |
| chatbot_response = get_llm_response(llm, prompt) | |
| clean_response = clean_llm_response(chatbot_response) | |
| # If we got an empty response after cleaning, use a fallback response | |
| if not clean_response: | |
| clean_response = generate_fallback_response(user_response) | |
| print(f"\nAssistant: {clean_response}\n") | |
| interview_data['detailed_responses'][f"Q{i}"] = user_response | |
| return interview_data | |
| def clean_llm_response(response: str) -> str: | |
| """Clean and validate the LLM response.""" | |
| if not response: | |
| return "" | |
| # List of words that indicate instruction text rather than actual response | |
| instruction_indicators = [ | |
| "instructions:", "example:", "note:", "response should", "requirements:", | |
| "remember to", "make sure to", "the response", "your response", | |
| "if they", "if patient", "keep it", "be brief", "respond with" | |
| ] | |
| # Get all non-empty lines | |
| lines = [line.strip() for line in response.strip().split('\n') if line.strip()] | |
| for line in lines: | |
| # Skip if line is too short | |
| if len(line) < 10: | |
| continue | |
| # Skip if line starts with common prefixes | |
| if any(line.lower().startswith(prefix) for prefix in [ | |
| "assistant:", "ai:", "chatbot:", "response:", "answer:", | |
| "example:", "note:", "question:" | |
| ]): | |
| continue | |
| # Skip if line contains instruction indicators | |
| if any(indicator in line.lower() for indicator in instruction_indicators): | |
| continue | |
| # Skip if line looks like a template or placeholder | |
| if '[' in line or ']' in line or '{' in line or '}' in line: | |
| continue | |
| # Line passes all checks - likely a valid response | |
| return line | |
| return "" | |
| def generate_fallback_response(user_response: str) -> str: | |
| """Generate a fallback response when the LLM response is empty or invalid.""" | |
| # Convert user response to lowercase once | |
| response_lower = user_response.lower() | |
| # Check for symptoms first (more specific) | |
| symptoms = ['pain', 'ache', 'hurt', 'dizzy', 'nausea', 'sick', 'fever', | |
| 'cough', 'tired', 'exhausted', 'headache', 'sore'] | |
| if any(symptom in response_lower for symptom in symptoms): | |
| return "I hear that you're not feeling well, and I want you to know that your symptoms are being taken seriously. We'll work together to understand what's happening and find the right approach to help you feel better." | |
| # Check for negative responses | |
| if not user_response or response_lower in ['no', 'none', 'n/a', 'nope', 'nothing']: | |
| return "Thank you for letting me know. Please don't hesitate to mention if you experience any new symptoms or concerns. Your health is our priority." | |
| # Check for medication or treatment related responses | |
| if any(word in response_lower for word in ['medicine', 'medication', 'pill', 'drug', 'treatment']): | |
| return "Thank you for sharing these details about your medication history. This information is very helpful for understanding your situation and planning appropriate care." | |
| # Default response | |
| return "I appreciate you sharing this information with me. It helps us better understand your situation so we can provide the most appropriate care for your needs." | |
| def generate_comprehensive_analysis(interview_data: Dict, category: str, gemini_model, llm) -> Dict: | |
| """Generate comprehensive medical analysis using both Gemini and Llama.""" | |
| analysis_prompt = f"""Medical Analysis Request: | |
| Patient Concern: {interview_data['intent'].capitalize()} Related Health Issue | |
| Initial Symptoms: {interview_data['initial_symptoms']} | |
| Detailed Interview Responses: | |
| {chr(10).join([f"{k}: {v}" for k, v in interview_data['detailed_responses'].items()])} | |
| Provide a detailed medical analysis in exactly this format using markdown: | |
| **Possible Medical Diagnoses** | |
| • First possible diagnosis with brief explanation | |
| • Second possible diagnosis with brief explanation | |
| • Third possible diagnosis with brief explanation | |
| **Recommended Medical Tests** | |
| • First recommended test with brief explanation | |
| • Second recommended test with brief explanation | |
| • Third recommended test with brief explanation | |
| **Lifestyle and Dietary Recommendations** | |
| • First lifestyle recommendation with brief explanation | |
| • Second lifestyle recommendation with brief explanation | |
| • Third lifestyle recommendation with brief explanation | |
| **Signs Requiring Immediate Attention** | |
| • First warning sign with brief explanation | |
| • Second warning sign with brief explanation | |
| • Third warning sign with brief explanation | |
| **Treatment Approaches** | |
| • First treatment approach with brief explanation | |
| • Second treatment approach with brief explanation | |
| • Third treatment approach with brief explanation""" | |
| try: | |
| # Get analysis from Gemini | |
| analysis_response = gemini_model.generate_content(analysis_prompt) | |
| response_text = analysis_response.text.strip() | |
| # Parse the response into structured format | |
| medical_analysis = parse_formatted_response(response_text) | |
| # If parsing failed or returned empty, use fallback | |
| if not medical_analysis: | |
| medical_analysis = get_fallback_analysis(category) | |
| except Exception as e: | |
| print(f"Error generating medical analysis: {str(e)}") | |
| medical_analysis = get_fallback_analysis(category) | |
| # Generate root cause analysis | |
| root_cause_prompt = f"""Based on the patient's {category} condition and responses: | |
| {chr(10).join([f"{k}: {v}" for k, v in interview_data['detailed_responses'].items()])} | |
| Provide a root cause analysis in exactly this format: | |
| **Dietary Factors** | |
| • First dietary factor with explanation | |
| • Second dietary factor with explanation | |
| **Stress Factors** | |
| • First stress factor with explanation | |
| • Second stress factor with explanation | |
| **Lifestyle Factors** | |
| • First lifestyle factor with explanation | |
| • Second lifestyle factor with explanation""" | |
| try: | |
| root_cause_response = gemini_model.generate_content(root_cause_prompt) | |
| root_cause_text = root_cause_response.text.strip() | |
| root_cause_data = parse_formatted_response(root_cause_text) | |
| if not root_cause_data: | |
| root_cause_data = get_root_cause_template(category) | |
| except Exception as e: | |
| print(f"Error generating root cause analysis: {str(e)}") | |
| root_cause_data = get_root_cause_template(category) | |
| # Generate root cause analysis based on category | |
| root_cause_template = { | |
| "stomach": { | |
| "diet": [], "stress": [], "medication": [], "infection": [], | |
| "lifestyle": [], "hydration": [], "allergies": [] | |
| }, | |
| "skin": { | |
| "allergy": [], "hygiene": [], "environment": [], "genetics": [], | |
| "nutrition": [], "stress": [], "cosmetic_use": [] | |
| }, | |
| "bp": { | |
| "diet": [], "lifestyle": [], "stress": [], "physical_activity": [], | |
| "salt_intake": [], "sleep_disorders": [] | |
| }, | |
| "diabetes": { | |
| "diet": [], "exercise": [], "genetics": [], "insulin_resistance": [], | |
| "obesity": [], "stress": [], "medication": [] | |
| } | |
| } | |
| root_cause_prompt1 = f"""Based on the patient's {category} condition and responses: | |
| {json.dumps(interview_data['detailed_responses'], indent=2)} | |
| Return EXACTLY this JSON structure for {category} with 2-3 specific items per category: | |
| {json.dumps(get_root_cause_template(category), indent=2)}""" | |
| try: | |
| root_cause_response = gemini_model.generate_content(root_cause_prompt1) | |
| response_text = root_cause_response.text.strip() | |
| if not response_text.startswith('{'): | |
| import re | |
| json_match = re.search(r'\{.*\}', response_text, re.DOTALL) | |
| if json_match: | |
| response_text = json_match.group(0) | |
| else: | |
| return {"medical_analysis": medical_analysis, "root_cause_data1": get_root_cause_template(category)} | |
| root_cause_data1 = json.loads(response_text) | |
| except (json.JSONDecodeError, Exception): | |
| root_cause_data1 = get_root_cause_template(category) | |
| # Ensure we return valid dictionaries | |
| result = { | |
| "medical_analysis": medical_analysis or get_fallback_analysis(category), | |
| "root_cause_data": root_cause_data or get_root_cause_template(category), | |
| "root_cause_data1": root_cause_data1 | |
| } | |
| return result | |
| def parse_formatted_response(text: str) -> Dict: | |
| """Parse the formatted text response into a structured dictionary.""" | |
| result = {} | |
| current_section = None | |
| current_items = [] | |
| if not text: | |
| return None | |
| lines = text.split('\n') | |
| for line in lines: | |
| line = line.strip() | |
| if not line: | |
| continue | |
| # Check for section headers (bolded text) | |
| if line.startswith('**') and line.endswith('**'): | |
| # Save previous section if it exists | |
| if current_section and current_items: | |
| key = current_section.lower().replace(' ', '_') | |
| result[key] = current_items | |
| current_items = [] | |
| # Start new section | |
| current_section = line.strip('*').strip() | |
| continue | |
| # Check for bullet points | |
| if line.startswith('•'): | |
| item = line[1:].strip() | |
| if item: # Only add non-empty items | |
| current_items.append(item) | |
| # Don't forget to save the last section | |
| if current_section and current_items: | |
| key = current_section.lower().replace(' ', '_') | |
| result[key] = current_items | |
| # Verify we got some content | |
| return result if result else None | |
| def display_analysis_results(analysis_results: Dict): | |
| """Display the analysis results in a formatted way.""" | |
| if not analysis_results or not analysis_results.get("medical_analysis"): | |
| print("\nError: No analysis results available.") | |
| return | |
| print("\n=== Comprehensive Medical Analysis ===\n") | |
| # Display medical analysis | |
| medical_analysis = analysis_results["medical_analysis"] | |
| for key, value in medical_analysis.items(): | |
| section_title = key.replace('_', ' ').title() | |
| print(f"\n**{section_title}**") | |
| if isinstance(value, list): | |
| for item in value: | |
| print(f"• {item}") | |
| else: | |
| print(f"• {value}") | |
| print("\n=== Root Cause Analysis ===\n") | |
| # Display root cause analysis | |
| root_cause_data = analysis_results["root_cause_data"] | |
| for key, value in root_cause_data.items(): | |
| section_title = key.replace('_', ' ').title() | |
| print(f"\n**{section_title}**") | |
| if isinstance(value, list): | |
| for item in value: | |
| print(f"• {item}") | |
| else: | |
| print(f"• {value}") | |
| def get_fallback_analysis(category: str) -> Dict: | |
| """Provide fallback analysis if Gemini API fails.""" | |
| fallback_analyses = { | |
| "bp": { | |
| "possible_diagnoses": [ | |
| "Essential Hypertension", | |
| "Secondary Hypertension", | |
| "White Coat Hypertension" | |
| ], | |
| "recommended_tests": [ | |
| "24-hour Blood Pressure Monitoring", | |
| "ECG", | |
| "Basic Blood Work" | |
| ], | |
| "lifestyle_recommendations": [ | |
| "Reduce Salt Intake", | |
| "Regular Exercise", | |
| "Stress Management" | |
| ], | |
| "immediate_attention_signs": [ | |
| "Severe Headache", | |
| "Chest Pain", | |
| "Vision Problems" | |
| ], | |
| "treatment_approaches": [ | |
| "Lifestyle Modifications", | |
| "Blood Pressure Medications", | |
| "Regular Monitoring" | |
| ] | |
| }, | |
| "diabetes": { | |
| "possible_diagnoses": [ | |
| "Type 2 Diabetes", | |
| "Prediabetes", | |
| "Insulin Resistance" | |
| ], | |
| "recommended_tests": [ | |
| "HbA1c Test", | |
| "Fasting Blood Sugar", | |
| "Glucose Tolerance Test" | |
| ], | |
| "lifestyle_recommendations": [ | |
| "Balanced Diet", | |
| "Regular Exercise", | |
| "Weight Management" | |
| ], | |
| "immediate_attention_signs": [ | |
| "Very High Blood Sugar", | |
| "Severe Dehydration", | |
| "Confusion or Drowsiness" | |
| ], | |
| "treatment_approaches": [ | |
| "Diet Control", | |
| "Oral Medications", | |
| "Blood Sugar Monitoring" | |
| ] | |
| }, | |
| "skin": { | |
| "possible_diagnoses": [ | |
| "Eczema", | |
| "Psoriasis", | |
| "Acne", | |
| "Skin Allergies", | |
| "Fungal Infections" | |
| ], | |
| "recommended_tests": [ | |
| "Skin Patch Test", | |
| "Biopsy (if required)", | |
| "Allergy Test" | |
| ], | |
| "lifestyle_recommendations": [ | |
| "Use of Gentle Cleansers", | |
| "Hydration and Moisturizing", | |
| "Avoiding Known Allergens" | |
| ], | |
| "immediate_attention_signs": [ | |
| "Severe Rash with Swelling", | |
| "Skin Infection with Fever", | |
| "Rapidly Spreading Lesions" | |
| ], | |
| "treatment_approaches": [ | |
| "Topical Ointments", | |
| "Antihistamines", | |
| "Prescription Medications (e.g., Steroids)" | |
| ] | |
| }, | |
| "stomach": { | |
| "possible_diagnoses": [ | |
| "Gastritis", | |
| "Irritable Bowel Syndrome (IBS)", | |
| "Acid Reflux (GERD)", | |
| "Peptic Ulcer", | |
| "Stomach Infection" | |
| ], | |
| "recommended_tests": [ | |
| "Endoscopy", | |
| "Stool Test", | |
| "Helicobacter Pylori Test" | |
| ], | |
| "lifestyle_recommendations": [ | |
| "Eating Smaller Meals", | |
| "Avoiding Spicy or Acidic Foods", | |
| "Stress Management" | |
| ], | |
| "immediate_attention_signs": [ | |
| "Severe Abdominal Pain", | |
| "Blood in Stool or Vomit", | |
| "Unexplained Weight Loss" | |
| ], | |
| "treatment_approaches": [ | |
| "Antacids or Acid Blockers", | |
| "Probiotics", | |
| "Medication for H. Pylori (if present)" | |
| ] | |
| } | |
| } | |
| return fallback_analyses.get(category.lower(), { | |
| "possible_diagnoses": ["Requires Medical Evaluation"], | |
| "recommended_tests": ["Consult Healthcare Provider"], | |
| "lifestyle_recommendations": ["Follow General Health Guidelines"], | |
| "immediate_attention_signs": ["Severe Symptoms", "Persistent Problems"], | |
| "treatment_approaches": ["Professional Medical Assessment"] | |
| }) | |
| def get_root_cause_template(category: str) -> Dict: | |
| """Return the template for root cause analysis with sample data.""" | |
| templates = { | |
| "stomach": { | |
| "diet": ["Irregular eating patterns", "Spicy food consumption"], | |
| "stress": ["Work-related stress", "Anxiety"], | |
| "medication": ["Recent antibiotics", "NSAIDs"], | |
| "infection": ["Possible H. pylori", "Food-borne infection"], | |
| "lifestyle": ["Late night eating", "Fast food consumption"], | |
| "hydration": ["Inadequate water intake", "Excess caffeine"], | |
| "allergies": ["Food sensitivities", "Lactose intolerance"] | |
| }, | |
| "skin": { | |
| "allergy": ["Contact dermatitis", "Environmental allergens"], | |
| "hygiene": ["Cleansing routine", "Product usage"], | |
| "environment": ["Sun exposure", "Pollution"], | |
| "genetics": ["Family history", "Predisposition"], | |
| "nutrition": ["Vitamin deficiency", "Diet impact"], | |
| "stress": ["Psychological factors", "Hormonal changes"], | |
| "cosmetic_use": ["Reaction to products", "Skin barrier damage"] | |
| }, | |
| "bp": { | |
| "diet": ["Salt intake", "Processed foods"], | |
| "lifestyle": ["Sedentary behavior", "Smoking"], | |
| "stress": ["Work pressure", "Anxiety"], | |
| "physical_activity": ["Exercise routine", "Daily movement"], | |
| "salt_intake": ["Hidden sodium", "Dietary habits"], | |
| "sleep_disorders": ["Sleep apnea", "Insomnia"] | |
| }, | |
| "diabetes": { | |
| "diet": ["Carbohydrate intake", "Sugar consumption"], | |
| "exercise": ["Activity level", "Fitness routine"], | |
| "genetics": ["Family history", "Genetic factors"], | |
| "insulin_resistance": ["Metabolic factors", "Body composition"], | |
| "obesity": ["Weight status", "Fat distribution"], | |
| "stress": ["Hormonal impact", "Lifestyle factors"], | |
| "medication": ["Current medications", "Treatment adherence"] | |
| } | |
| } | |
| return templates.get(category.lower(), { | |
| "general_factors": ["To be evaluated", "Requires assessment"], | |
| "lifestyle": ["To be determined", "Needs analysis"], | |
| "medical": ["Pending evaluation", "Professional assessment needed"] | |
| }) | |
| def get_llm_response(llm, prompt: str, max_tokens: int = 256) -> str: | |
| """Get response from Llama model with proper formatting.""" | |
| try: | |
| response = llm(prompt, max_tokens=max_tokens) | |
| return response['choices'][0]['text'].strip() | |
| except ValueError: | |
| shortened_prompt = prompt[-500:] | |
| response = llm(shortened_prompt, max_tokens=max_tokens) | |
| return response['choices'][0]['text'].strip() | |
| def main(): | |
| # Initialize models | |
| llm = Llama.from_pretrained( | |
| repo_id="tensorblock/Llama3-Aloe-8B-Alpha-GGUF", | |
| filename="Llama3-Aloe-8B-Alpha-Q2_K.gguf", | |
| n_ctx=2048 | |
| ) | |
| genai.configure(api_key=GEMINI_API_KEY) | |
| gemini_model = genai.GenerativeModel('gemini-1.5-flash') | |
| print("\nWelcome to the Enhanced Healthcare Assistant!") | |
| print("Please describe your symptoms:\n") | |
| initial_input = input("You: ").strip() | |
| detected_category = classify_medical_intent(initial_input) # You have this function | |
| # Generate interview questions using Gemini | |
| questions = generate_interview_questions(initial_input, detected_category, gemini_model) | |
| # Conduct interview | |
| interview_data = conduct_interview(questions, detected_category, llm) | |
| # Generate comprehensive analysis | |
| analysis_results = generate_comprehensive_analysis( | |
| interview_data, detected_category, gemini_model, llm | |
| ) | |
| # # Display results | |
| # print("\n=== Comprehensive Medical Analysis ===\n") | |
| # for key, value in analysis_results["medical_analysis"].items(): | |
| # print(f"\n{key.replace('_', ' ').title()}:") | |
| # if isinstance(value, list): | |
| # for item in value: | |
| # print(f"• {item}") | |
| # else: | |
| # print(value) | |
| display_analysis_results(analysis_results) | |
| # Create and display fishbone diagram | |
| plot_enhanced_fishbone( | |
| detected_category.title(), | |
| analysis_results["root_cause_data1"] | |
| ) | |
| plt.show() | |
| if __name__ == "__main__": | |
| main() | |