Spaces:
Sleeping
Sleeping
File size: 12,094 Bytes
9db0bbe 7c23890 9db0bbe 0d54cf5 f6ecc7d 540a516 58605f8 9db0bbe b416941 540a516 58605f8 540a516 d35cbc5 6f5562b e8f8a15 540a516 7c23890 a9bb3c0 7c23890 a9bb3c0 7c23890 9db0bbe d35cbc5 9db0bbe a9bb3c0 540a516 d35cbc5 540a516 d35cbc5 a9bb3c0 d35cbc5 a9bb3c0 d35cbc5 540a516 d35cbc5 540a516 a9bb3c0 540a516 d35cbc5 540a516 d35cbc5 540a516 d35cbc5 540a516 d35cbc5 540a516 d35cbc5 a9bb3c0 9db0bbe 540a516 a9bb3c0 9db0bbe a9bb3c0 9db0bbe a9bb3c0 540a516 a9bb3c0 9db0bbe d35cbc5 9db0bbe 540a516 a9bb3c0 540a516 9db0bbe 5dc20d7 9db0bbe d35cbc5 9db0bbe e8f8a15 9db0bbe a9bb3c0 b6d966a 7c23890 d35cbc5 7c23890 d35cbc5 a9bb3c0 d35cbc5 a9bb3c0 d35cbc5 a9bb3c0 540a516 d35cbc5 540a516 9db0bbe 7c23890 9db0bbe |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# app.py
from flask import Flask, render_template, request, jsonify, Response
import requests
import re
import time
import os
from bs4 import BeautifulSoup
from huggingface_hub import InferenceClient
from typing import Optional, Tuple
app = Flask(__name__)
# Debug versions
print("Hugging Face Hub version:", os.environ.get("HUGGINGFACE_HUB_VERSION", "Not set"))
# Set Hugging Face cache directory explicitly (optional for InferenceClient, but useful for consistency)
os.environ["HF_HOME"] = "/home/user/.cache/huggingface"
print(f"Hugging Face cache directory: {os.environ['HF_HOME']}")
# Use Hugging Face InferenceClient for Qwen/Qwen2-1.5B-Instruct (public model, no token needed)
# You can switch to other public models by changing the model name
model_name = "Qwen/Qwen2-1.5B-Instruct"
client = InferenceClient(model=model_name)
# System prompt for better medical responses
SYSTEM_PROMPT = """
You are MedChat, an educational medical assistant designed to provide detailed, accurate information about medications, side effects, drug interactions, alternative treatments (including natural options), and recent medical studies for any condition, including diabetes, heart disease, and more. Your responses are for educational purposes only, not medical advice—always include the disclaimer: "This is an educational tool, not medical advice. Consult a healthcare professional." For any query, identify the medical condition or drug mentioned, and provide relevant medications, side effects, alternatives, or studies. If no specific drug or condition is mentioned, suggest common medications or treatments for the implied condition (e.g., for diabetes, suggest metformin, insulin). Use simple, clear language, and cite sources like DailyMed, PubMed, or reliable websites (e.g., WebMD, Mayo Clinic) for all information. Respond quickly and concisely, streaming the output character by character.
"""
# DailyMed and PubMed API base URLs with timeout
DAILYMED_BASE_URL = "https://dailymed.nlm.nih.gov/dailymed/services/v2/drugnames"
PUBMED_BASE_URL = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi"
PUBMED_SUMMARY_URL = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi"
# Web scraping sources for additional data
WEBMD_URL = "https://www.webmd.com/search/search_results/default.aspx?query={query}"
MAYO_CLINIC_URL = "https://www.mayoclinic.org/search/search-results?q={query}"
def process_query(query: str) -> Tuple[Optional[str], Optional[str], str, str]:
"""Process user query with InferenceClient and return response, with error handling."""
try:
# Format prompt with system instruction and user query
prompt = f"{SYSTEM_PROMPT}\n\nUser: {query}\nMedChat:"
print(f"Processing query: {query}") # Debug query
# Use InferenceClient to generate response (streamed via API)
response = client.text_generation(
prompt,
max_new_tokens=300, # Increased for detailed responses
temperature=0.7,
top_p=0.9,
return_full_text=False, # Only return generated text after prompt
stream=True # Enable streaming
)
# Collect streamed response
full_response = ""
for chunk in response:
full_response += chunk
response_text = full_response.strip()
# Parse response for condition, drug, intent (expanded for flexibility)
drug = None
condition = None
intent = "general"
if any(d in response_text.lower() for d in ["ibuprofen", "aspirin", "metformin", "tylenol", "metoprolol", "lisinopril", "insulin"]):
drug = re.search(r"Drug:\s*([^\n,]+)", response_text)
drug = drug.group(1).strip() if drug else None
if any(c in query.lower() or c in response_text.lower() for c in ["diabetes", "heart", "headache", "pain"]):
condition = re.search(r"condition:\s*([^\n,]+)", response_text) or re.search(r"for\s+([^\n,]+)", query.lower())
condition = condition.group(1).strip() if condition else None
if "side effects" in response_text.lower():
intent = "side effects"
elif "interaction" in response_text.lower():
intent = "interaction"
elif "alternatives" in response_text.lower() or "natural" in query.lower():
intent = "alternatives"
elif "studies" in response_text.lower() or "research" in query.lower():
intent = "studies"
return drug, condition, intent, response_text
except Exception as e:
print(f"Error processing query: {e}")
return None, None, "error", f"Error processing your request: {str(e)}"
def get_drug_info(drug_name: str) -> str:
"""Fetch drug info from DailyMed and web scrape for additional data."""
try:
# DailyMed API
daily_response = requests.get(f"{DAILYMED_BASE_URL}?drug_name={drug_name}", timeout=5)
daily_data = ""
if daily_response.status_code == 200:
data = daily_response.json()
if data.get("data"):
daily_data = f"Drug: {drug_name.capitalize()} - Found in DailyMed. Details: https://dailymed.nlm.nih.gov/dailymed/"
# Web scraping for additional info (WebMD)
webmd_query = f"{drug_name}+medication"
webmd_response = requests.get(WEBMD_URL.format(query=webmd_query), timeout=5)
if webmd_response.status_code == 200:
soup = BeautifulSoup(webmd_response.text, 'html.parser')
content = soup.find('div', class_='search-results-content')
if content:
webmd_info = content.get_text(strip=True)[:200] + "..." # Limit length
daily_data += f"\nAdditional info from WebMD: {webmd_info} (Source: https://www.webmd.com)"
return daily_data if daily_data else "No drug info found on DailyMed or WebMD."
except Exception as e:
print(f"Error fetching drug info: {e}")
return f"Error fetching drug info: {str(e)}"
def get_condition_info(condition: str) -> str:
"""Provide common medications or treatments for a condition, with web scraping."""
try:
medications = ""
if "diabetes" in condition.lower():
medications = "Common medications for diabetes include metformin, insulin (e.g., insulin glargine), and sulfonylureas (e.g., glipizide). Consult a healthcare professional."
elif "heart" in condition.lower():
medications = "Common heart medications include beta-blockers like metoprolol, ACE inhibitors like lisinopril, and statins like atorvastatin. Consult a healthcare professional."
elif "headache" in condition.lower() or "pain" in condition.lower():
medications = "Common medications for headaches or pain include ibuprofen, acetaminophen (Tylenol), or aspirin. Natural alternatives might include turmeric or ginger. Consult a healthcare professional."
# Web scraping for additional info (Mayo Clinic)
mayo_query = f"{condition}+medications"
mayo_response = requests.get(MAYO_CLINIC_URL.format(query=mayo_query), timeout=5)
if mayo_response.status_code == 200:
soup = BeautifulSoup(mayo_response.text, 'html.parser')
content = soup.find('div', class_='content')
if content:
mayo_info = content.get_text(strip=True)[:200] + "..." # Limit length
medications += f"\nAdditional info from Mayo Clinic: {mayo_info} (Source: https://www.mayoclinic.org)"
return medications if medications else "No condition-specific information found."
except Exception as e:
print(f"Error fetching condition info: {e}")
return f"Error fetching condition info: {str(e)}"
def get_recent_studies(query: str) -> str:
try:
params = {
"db": "pubmed",
"term": query,
"retmax": 3,
"datetype": "pdat",
"mindate": "2020",
"maxdate": "2025",
"retmode": "json"
}
response = requests.get(PUBMED_BASE_URL, params=params, timeout=5)
if response.status_code == 200:
data = response.json()
id_list = data["esearchresult"]["idlist"]
if not id_list:
return "No recent studies found on PubMed."
summary_params = {
"db": "pubmed",
"id": ",".join(id_list),
"retmode": "json"
}
summary_response = requests.get(PUBMED_SUMMARY_URL, params=summary_params, timeout=5)
if summary_response.status_code == 200:
summaries = summary_response.json()["result"]
result = "Recent studies from PubMed:\n"
for uid in id_list:
study = summaries[uid]
title = study.get("title", "No title")
result += f"- {title} (PMID: {uid}, https://pubmed.ncbi.nlm.nih.gov/{uid}/)\n"
return result
return "Found studies, but couldn’t retrieve details."
return "No recent studies found."
except Exception as e:
print(f"Error fetching studies: {e}")
return f"Error fetching studies: {str(e)}"
@app.route("/")
def index():
return render_template("index.html")
@app.route("/chat", methods=["POST"])
def chat():
print(f"Received request method: {request.method}") # Debug request method
user_message = request.json.get("message", "").lower()
if not user_message:
return jsonify({"response": "Please enter a message."})
drug, condition, intent, full_response = process_query(user_message)
def event_stream():
try:
if intent == "error":
response = full_response # Return the error message
else:
response = "This is an educational tool, not medical advice. Consult a healthcare professional.\n\n"
if drug:
response += get_drug_info(drug)
if "alternatives" in intent or "natural" in user_message:
response += f"\nNatural alternatives might include dietary changes or herbal options (consult a professional)."
elif condition:
response += get_condition_info(condition)
if "alternatives" in intent or "natural" in user_message:
response += f"\nNatural alternatives might include dietary changes or herbal options (consult a professional)."
else:
response += "Please specify a drug, condition, or question for more details (e.g., 'medications for diabetes' or 'side effects of metformin')."
if (drug or condition) and "studies" not in intent and ("studies" in user_message or "research" in user_message):
response += "\n\n" + get_recent_studies(drug or condition)
# Web scrape for additional context if no specific data found
if not (drug or condition) and "medications" in user_message:
web_response = get_condition_info(user_message.replace("medications", "").strip() or "general health")
if web_response and "Error" not in web_response:
response += f"\n\nAdditional info: {web_response}"
# Stream the response character by character
for char in response:
yield f"data: {char}\n\n"
time.sleep(0.005) # Very fast streaming for better performance
yield "data: [END]\n\n"
except Exception as e:
print(f"Error in event stream: {e}")
response = f"Error: Cannot connect to server. Details: {str(e)}"
for char in response:
yield f"data: {char}\n\n"
yield "data: [END]\n\n"
return Response(event_stream(), mimetype="text/event-stream")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860, debug=True) |