|
|
import gradio as gr |
|
|
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig |
|
|
import torch |
|
|
import re |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
model_name = "augtoma/qCammel-13" |
|
|
print("Loading tokenizer and model...") |
|
|
|
|
|
try: |
|
|
tokenizer = AutoTokenizer.from_pretrained(model_name) |
|
|
if tokenizer.pad_token is None: |
|
|
tokenizer.pad_token = tokenizer.eos_token |
|
|
|
|
|
model = AutoModelForCausalLM.from_pretrained( |
|
|
model_name, |
|
|
device_map="auto", |
|
|
torch_dtype=torch.float16, |
|
|
trust_remote_code=True, |
|
|
low_cpu_mem_usage=True |
|
|
) |
|
|
model.eval() |
|
|
print("β
Model loaded successfully!") |
|
|
except Exception as e: |
|
|
print(f"β Error loading model: {e}") |
|
|
raise |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MEDICAL_DISCLAIMER = """ |
|
|
β οΈ **IMPORTANT MEDICAL DISCLAIMER:** |
|
|
- This is an AI simulation for educational purposes only |
|
|
- For medical emergencies, call emergency services immediately (911/999/local emergency number) |
|
|
- Always consult a licensed healthcare provider for diagnosis and treatment |
|
|
- Do not use this for serious, worsening, or life-threatening symptoms |
|
|
- This AI cannot diagnose conditions or prescribe medications |
|
|
""" |
|
|
|
|
|
EMERGENCY_KEYWORDS = [ |
|
|
"chest pain", "can't breathe", "breathing difficulty", "suicide", |
|
|
"heart attack", "stroke", "severe bleeding", "unconscious", |
|
|
"overdose", "severe pain", "emergency" |
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def extract_name(text): |
|
|
"""Extract name from user input""" |
|
|
text = text.lower() |
|
|
|
|
|
for phrase in ["yes", "i am", "i'm", "my name is", "name is", "it's", "its"]: |
|
|
text = text.replace(phrase, "") |
|
|
|
|
|
|
|
|
text = re.sub(r'[^\w\s]', '', text).strip() |
|
|
return text.title() if text and len(text) > 1 else "Patient" |
|
|
|
|
|
|
|
|
def extract_age(text): |
|
|
"""Extract age from user input""" |
|
|
|
|
|
numbers = re.findall(r'\b(\d{1,3})\b', text) |
|
|
for num in numbers: |
|
|
age = int(num) |
|
|
if 1 <= age <= 120: |
|
|
return age |
|
|
return None |
|
|
|
|
|
|
|
|
def check_emergency(text): |
|
|
"""Check if message contains emergency keywords""" |
|
|
text_lower = text.lower() |
|
|
return any(keyword in text_lower for keyword in EMERGENCY_KEYWORDS) |
|
|
|
|
|
|
|
|
def create_initial_session(): |
|
|
"""Create a fresh session dictionary""" |
|
|
return { |
|
|
"name": None, |
|
|
"age": None, |
|
|
"gender": None, |
|
|
"symptoms": None, |
|
|
"duration": None, |
|
|
"medication": None, |
|
|
"stage": "intro" |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_diet_suggestion(name, symptoms): |
|
|
"""Get personalized diet suggestions based on symptoms""" |
|
|
symptoms_lower = symptoms.lower() |
|
|
|
|
|
if "fever" in symptoms_lower: |
|
|
return f"""π **Diet Plan for {name} (Fever)** |
|
|
|
|
|
**Meals:** |
|
|
- π₯£ **Breakfast:** Oatmeal or boiled egg with banana/apple |
|
|
- π² **Lunch:** Rice with lentil soup or boiled vegetables |
|
|
- π **Dinner:** Light soup or grilled chicken with plain rice |
|
|
|
|
|
**Hydration:** |
|
|
- π§ Drink 8β10 glasses of water daily |
|
|
- Coconut water or clear soups |
|
|
- Herbal teas (chamomile, ginger) |
|
|
|
|
|
**Avoid:** |
|
|
- π« Fried, oily, or spicy foods |
|
|
- Heavy meals |
|
|
- Caffeinated drinks |
|
|
|
|
|
**Tips:** Eat small portions frequently to help your body recover.""" |
|
|
|
|
|
elif any(word in symptoms_lower for word in ["stomach", "vomit", "nausea", "diarrhea"]): |
|
|
return f"""π₯ **Diet Plan for {name} (Stomach Issues)** |
|
|
|
|
|
**BRAT Diet:** |
|
|
- π Bananas |
|
|
- π Rice (plain white rice) |
|
|
- π Applesauce |
|
|
- π Toast (dry or with minimal butter) |
|
|
|
|
|
**Hydration:** |
|
|
- π§ Sip water frequently |
|
|
- Oral rehydration solution (ORS) |
|
|
- Clear broths |
|
|
|
|
|
**Avoid:** |
|
|
- π« Dairy products |
|
|
- Fried or spicy foods |
|
|
- Caffeine and alcohol |
|
|
- Raw vegetables |
|
|
|
|
|
**Tips:** Start with small amounts and gradually increase as you feel better.""" |
|
|
|
|
|
elif any(word in symptoms_lower for word in ["cold", "flu", "cough", "sore throat"]): |
|
|
return f"""π **Diet Plan for {name} (Cold/Flu)** |
|
|
|
|
|
**Immunity Boosters:** |
|
|
- π Citrus fruits (oranges, lemons) |
|
|
- π― Honey with warm water |
|
|
- π§ Garlic (natural antibiotic) |
|
|
- π§
Onions |
|
|
|
|
|
**Meals:** |
|
|
- π² Chicken soup (helps clear congestion) |
|
|
- β Ginger or green tea |
|
|
- π₯£ Warm porridge or oatmeal |
|
|
|
|
|
**Hydration:** |
|
|
- π§ Plenty of warm fluids |
|
|
- Herbal teas |
|
|
|
|
|
**Avoid:** |
|
|
- π« Sugary drinks |
|
|
- Chilled beverages |
|
|
- Dairy (may increase mucus) |
|
|
|
|
|
**Tips:** Stay warm and get plenty of rest.""" |
|
|
|
|
|
elif any(word in symptoms_lower for word in ["headache", "migraine"]): |
|
|
return f"""π§ **Diet Plan for {name} (Headache)** |
|
|
|
|
|
**Helpful Foods:** |
|
|
- π§ Stay well-hydrated (dehydration causes headaches) |
|
|
- π₯ Magnesium-rich: bananas, nuts, spinach |
|
|
- π Omega-3: fish, walnuts |
|
|
- π§ Small amounts of salt if low blood pressure |
|
|
|
|
|
**Avoid:** |
|
|
- π« Processed foods |
|
|
- Artificial sweeteners |
|
|
- Aged cheeses |
|
|
- Alcohol |
|
|
- Excessive caffeine |
|
|
|
|
|
**Tips:** Eat regular meals; skipping meals can trigger headaches.""" |
|
|
|
|
|
else: |
|
|
return f"""π₯ **General Healthy Diet Plan for {name}** |
|
|
|
|
|
**Balanced Meals:** |
|
|
- π Fresh fruits and vegetables |
|
|
- π Lean proteins (chicken, fish, legumes) |
|
|
- π Whole grains (brown rice, oats) |
|
|
- π₯ Nuts and seeds |
|
|
|
|
|
**Hydration:** |
|
|
- π§ 8β10 glasses of water daily |
|
|
|
|
|
**Avoid:** |
|
|
- π« Processed and fried foods |
|
|
- Excessive sugar and salt |
|
|
- Junk food |
|
|
|
|
|
**Tips:** Eat at regular intervals and maintain portion control.""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_ai_response(session, user_message): |
|
|
"""Generate AI consultation response using the model""" |
|
|
try: |
|
|
|
|
|
prompt = f"""You are Dr. Aiden β a warm, caring, and professional doctor. |
|
|
You are consulting a {session['age']}-year-old {session['gender']} named {session['name']}. |
|
|
|
|
|
Patient details: |
|
|
- Symptoms: {session['symptoms']} |
|
|
- Duration: {session['duration']} |
|
|
- Current medications: {session['medication']} |
|
|
|
|
|
Now the patient says: "{user_message}" |
|
|
|
|
|
Respond as a real doctor would β empathetic, clear, and personalized. |
|
|
Include: |
|
|
1. Acknowledge their condition |
|
|
2. Possible causes |
|
|
3. Simple home remedies or OTC medicines (if safe) |
|
|
4. Diet, rest, and hydration tips |
|
|
5. When to visit a real doctor |
|
|
6. End with a reassuring tone""" |
|
|
|
|
|
|
|
|
inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=2048).to(model.device) |
|
|
|
|
|
gen_cfg = GenerationConfig( |
|
|
temperature=0.7, |
|
|
top_p=0.9, |
|
|
max_new_tokens=350, |
|
|
repetition_penalty=1.1, |
|
|
pad_token_id=tokenizer.pad_token_id, |
|
|
eos_token_id=tokenizer.eos_token_id |
|
|
) |
|
|
|
|
|
with torch.no_grad(): |
|
|
output = model.generate(**inputs, generation_config=gen_cfg) |
|
|
|
|
|
|
|
|
output_text = tokenizer.decode(output[0], skip_special_tokens=True) |
|
|
|
|
|
|
|
|
|
|
|
if "reassuring tone" in output_text: |
|
|
parts = output_text.split("reassuring tone") |
|
|
if len(parts) > 1: |
|
|
output_text = parts[-1].strip() |
|
|
|
|
|
|
|
|
if user_message in output_text: |
|
|
parts = output_text.split(user_message) |
|
|
if len(parts) > 1: |
|
|
output_text = parts[-1].strip() |
|
|
|
|
|
|
|
|
output_text = output_text.strip() |
|
|
|
|
|
|
|
|
if len(output_text) < 20: |
|
|
output_text = f"Hello {session['name']}, I understand you have {session['symptoms']} for {session['duration']}. This could be due to several reasons. I recommend staying hydrated, getting plenty of rest, and monitoring your temperature. If your fever persists beyond 5 days or gets worse, please visit a doctor in person for proper examination." |
|
|
|
|
|
|
|
|
if not output_text.endswith((".", "!", "?")): |
|
|
output_text += "." |
|
|
|
|
|
|
|
|
output_text += "\n\nβοΈ *Note: This advice is AI-generated and not a substitute for professional medical care.*" |
|
|
|
|
|
return output_text |
|
|
|
|
|
except Exception as e: |
|
|
print(f"Error in generate_ai_response: {e}") |
|
|
return f"I understand you're experiencing {session['symptoms']}, {session['name']}. Since this has been going on for {session['duration']}, I recommend consulting with a healthcare provider for a proper examination and diagnosis.\n\nβοΈ *Note: This advice is AI-generated and not a substitute for professional medical care.*" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def doctor_response(user_message, session): |
|
|
"""Generate doctor's response based on conversation stage""" |
|
|
if not user_message or not user_message.strip(): |
|
|
return "Please type your message.", session |
|
|
|
|
|
user_message_clean = user_message.strip() |
|
|
user_message_lower = user_message_clean.lower() |
|
|
|
|
|
|
|
|
if check_emergency(user_message_clean): |
|
|
emergency_response = """π¨ **EMERGENCY ALERT** π¨ |
|
|
|
|
|
Your message suggests a potentially serious medical emergency. |
|
|
|
|
|
**PLEASE TAKE IMMEDIATE ACTION:** |
|
|
- Call emergency services NOW (911 in US, 999 in UK, or your local emergency number) |
|
|
- Go to the nearest emergency room |
|
|
- Do not delay seeking immediate medical attention |
|
|
|
|
|
This AI chatbot cannot handle emergencies. Your safety is the priority.""" |
|
|
return emergency_response, session |
|
|
|
|
|
|
|
|
try: |
|
|
if session["stage"] == "intro": |
|
|
session["stage"] = "ask_name" |
|
|
return "π¨ββοΈ Hello! I'm Dr. Aiden, your AI medical assistant.\n\n" + MEDICAL_DISCLAIMER + "\n\nMay I know your name, please?", session |
|
|
|
|
|
elif session["stage"] == "ask_name": |
|
|
session["name"] = extract_name(user_message_clean) |
|
|
session["stage"] = "ask_age" |
|
|
return f"Nice to meet you, {session['name']}! How old are you?", session |
|
|
|
|
|
elif session["stage"] == "ask_age": |
|
|
age = extract_age(user_message_clean) |
|
|
if age: |
|
|
session["age"] = age |
|
|
session["stage"] = "ask_gender" |
|
|
return f"Got it, {session['name']}. Are you male or female?", session |
|
|
else: |
|
|
return "Please tell me your age in numbers (e.g., 25, 30, 45).", session |
|
|
|
|
|
elif session["stage"] == "ask_gender": |
|
|
if "male" in user_message_lower and "female" not in user_message_lower: |
|
|
session["gender"] = "male" |
|
|
elif "female" in user_message_lower: |
|
|
session["gender"] = "female" |
|
|
else: |
|
|
return "Could you please specify whether you are male or female?", session |
|
|
|
|
|
session["stage"] = "ask_symptoms" |
|
|
return f"Thanks, {session['name']}! So you're a {session['age']}-year-old {session['gender']}.\n\nWhat symptoms are you experiencing? Please describe them in detail.", session |
|
|
|
|
|
elif session["stage"] == "ask_symptoms": |
|
|
if len(user_message_clean) < 5: |
|
|
return "Please describe your symptoms in more detail so I can help you better.", session |
|
|
session["symptoms"] = user_message_clean |
|
|
session["stage"] = "ask_duration" |
|
|
return "Since when have you been feeling this way? (e.g., 2 days, 1 week, etc.)", session |
|
|
|
|
|
elif session["stage"] == "ask_duration": |
|
|
session["duration"] = user_message_clean |
|
|
session["stage"] = "ask_medicine" |
|
|
return "Are you currently taking any medications or treatments? If not, just say 'no'.", session |
|
|
|
|
|
elif session["stage"] == "ask_medicine": |
|
|
session["medication"] = user_message_clean |
|
|
session["stage"] = "consult" |
|
|
|
|
|
summary = f"""Thank you for providing all the information, {session['name']}. |
|
|
|
|
|
π **Summary:** |
|
|
- **Name:** {session['name']} |
|
|
- **Age:** {session['age']} years old |
|
|
- **Gender:** {session['gender']} |
|
|
- **Symptoms:** {session['symptoms']} |
|
|
- **Duration:** {session['duration']} |
|
|
- **Current medication:** {session['medication']} |
|
|
|
|
|
Let me assess your condition...\n\n""" |
|
|
|
|
|
|
|
|
initial_consultation = generate_ai_response(session, "Please assess my condition and give me advice") |
|
|
return summary + initial_consultation, session |
|
|
|
|
|
elif session["stage"] == "consult": |
|
|
|
|
|
if any(word in user_message_lower for word in ["diet", "food", "meal", "eat", "nutrition", "drink"]): |
|
|
diet_plan = get_diet_suggestion(session["name"], session["symptoms"]) |
|
|
return diet_plan + "\n\nβοΈ *Note: This is general advice. Consult a healthcare provider for personalized dietary recommendations, especially if you have allergies or other conditions.*", session |
|
|
|
|
|
|
|
|
return generate_ai_response(session, user_message_clean), session |
|
|
|
|
|
else: |
|
|
|
|
|
session["stage"] = "intro" |
|
|
return "Let's start over. Say 'Hi Doctor' to begin your consultation.", session |
|
|
|
|
|
except Exception as e: |
|
|
print(f"Error in doctor_response: {e}") |
|
|
return "I apologize, but I encountered an error. Please try again or start a new consultation.", session |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft()) as demo: |
|
|
gr.HTML(""" |
|
|
<div style="text-align:center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color:white; padding:25px; border-radius:15px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);"> |
|
|
<h1 style="margin:0; font-size: 2.5em;">π₯ Dr. Aiden - AI Medical Assistant</h1> |
|
|
<p style="margin:10px 0 0 0; font-size: 1.1em;">Compassionate AI-powered health consultation</p> |
|
|
<p style="margin:5px 0 0 0; font-size: 0.9em; opacity: 0.9;">β οΈ For emergencies, call 911 immediately</p> |
|
|
</div> |
|
|
""") |
|
|
|
|
|
|
|
|
session_state = gr.State(create_initial_session) |
|
|
|
|
|
chatbot = gr.Chatbot( |
|
|
label="π¨ββοΈ Chat with Dr. Aiden", |
|
|
height=500, |
|
|
type='messages', |
|
|
avatar_images=( |
|
|
"https://cdn-icons-png.flaticon.com/512/706/706830.png", |
|
|
"https://cdn-icons-png.flaticon.com/512/3774/3774299.png" |
|
|
) |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
user_input = gr.Textbox( |
|
|
placeholder="Type your message here (say 'Hi Doctor' to start)...", |
|
|
label="Your Message", |
|
|
lines=2, |
|
|
scale=4 |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
send_btn = gr.Button("π¬ Send", variant="primary", scale=1) |
|
|
clear_btn = gr.Button("π New Consultation", variant="secondary", scale=1) |
|
|
|
|
|
gr.HTML(""" |
|
|
<div style="margin-top: 20px; padding: 15px; background-color: #fff3cd; border-left: 4px solid #ffc107; border-radius: 5px;"> |
|
|
<strong>β οΈ Important Reminders:</strong> |
|
|
<ul style="margin: 10px 0; padding-left: 20px;"> |
|
|
<li>This is an AI simulation for educational purposes only</li> |
|
|
<li>Always consult a real doctor for medical diagnosis and treatment</li> |
|
|
<li>For emergencies, call 911 or your local emergency services immediately</li> |
|
|
<li>Do not use this for serious or life-threatening conditions</li> |
|
|
</ul> |
|
|
</div> |
|
|
""") |
|
|
|
|
|
def respond(message, history, session): |
|
|
"""Handle user message and update chat""" |
|
|
if history is None: |
|
|
history = [] |
|
|
|
|
|
if not message or not message.strip(): |
|
|
return "", history, session |
|
|
|
|
|
response, updated_session = doctor_response(message, session) |
|
|
|
|
|
history.append({"role": "user", "content": message}) |
|
|
history.append({"role": "assistant", "content": response}) |
|
|
|
|
|
return "", history, updated_session |
|
|
|
|
|
def reset(): |
|
|
"""Reset conversation and session""" |
|
|
return [], create_initial_session() |
|
|
|
|
|
|
|
|
send_btn.click( |
|
|
respond, |
|
|
[user_input, chatbot, session_state], |
|
|
[user_input, chatbot, session_state] |
|
|
) |
|
|
|
|
|
user_input.submit( |
|
|
respond, |
|
|
[user_input, chatbot, session_state], |
|
|
[user_input, chatbot, session_state] |
|
|
) |
|
|
|
|
|
clear_btn.click( |
|
|
reset, |
|
|
None, |
|
|
[chatbot, session_state], |
|
|
queue=False |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
print("π₯ Launching Dr. Aiden Medical Assistant...") |
|
|
print("β οΈ Remember: This is for educational purposes only!") |
|
|
demo.queue() |
|
|
demo.launch(share=True) |