Spaces:
Sleeping
Sleeping
#!/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() | |