MedAssist-AI / api_server.py
Youssef1F's picture
Update api_server.py
c2a2c54 verified
Raw History Blame Contribute Delete
4.58 kB
import os
import torch
import torch.nn as nn
from torchvision import models, transforms
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from PIL import Image
import io
import base64
import requests
app = FastAPI()
# تفعيل الـ CORS للربط مع Lovable
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# --- إعداد الموديل المحلي (DenseNet121) ---
device = torch.device("cpu")
def load_medical_model():
model = models.densenet121(weights=None)
num_ftrs = model.classifier.in_features
model.classifier = nn.Sequential(
nn.Dropout(0.2),
nn.Linear(num_ftrs, 14)
)
if os.path.exists('best_densenet121.pth'):
try:
checkpoint = torch.load('best_densenet121.pth', map_location=device)
model.load_state_dict(checkpoint)
model.eval()
print("✅ Medical Model Loaded!")
return model
except Exception as e:
print(f"❌ Error loading .pth: {e}")
return None
return None
medical_model = load_medical_model()
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
class_names = [
"Atelectasis", "Cardiomegaly", "Effusion", "Infiltration", "Mass",
"Nodule", "Pneumonia", "Pneumothorax", "Consolidation", "Edema",
"Emphysema", "Fibrosis", "Pleural_Thickening", "Hernia"
]
# --- دالة الاتصال المباشر بجوجل (الحل القاطع للـ 404) ---
def ask_gemini_direct(prompt, api_key):
# استخدام v1beta لأنها النسخة المستقرة حالياً لموديل Flash
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={api_key}"
payload = {"contents": [{"parts": [{"text": prompt}]}]}
headers = {'Content-Type': 'application/json'}
try:
response = requests.post(url, json=payload, headers=headers, timeout=15)
if response.status_code == 200:
return response.json()['candidates'][0]['content']['parts'][0]['text']
else:
return f"Error: {response.status_code} - {response.text}"
except Exception as e:
return f"Request Failed: {str(e)}"
# --- Endpoints ---
@app.get("/")
def home():
return {"status": "Healytics Backend is Ready", "model": medical_model is not None}
@app.post("/chat")
async def chat_endpoint(request: Request):
try:
data = await request.json()
api_key = os.getenv("GEMINI_API_KEY")
if not api_key:
return {"response": "❌ خطأ: لم يتم العثور على GEMINI_API_KEY في الـ Secrets."}
# استقبال الرسالة من Lovable
user_message = ""
if "messages" in data and len(data["messages"]) > 0:
user_message = data["messages"][-1].get("content", "")
elif "message" in data:
user_message = data["message"]
image_data = data.get("image")
# 1. تحليل الأشعة
if image_data and medical_model:
header, encoded = image_data.split(",", 1) if "," in image_data else (None, image_data)
image = Image.open(io.BytesIO(base64.b64decode(encoded))).convert('RGB')
input_tensor = transform(image).unsqueeze(0).to(device)
with torch.no_grad():
outputs = medical_model(input_tensor)
probs = torch.sigmoid(outputs)
preds = (probs > 0.5).nonzero(as_tuple=True)[1]
detected = [class_names[i] for i in preds]
res_text = ", ".join(detected) if detected else "سليم"
prompt = f"المريض رفع أشعة والذكاء الاصطناعي اكتشف: {res_text}. اشرح ده بالعربي بأسلوب طبي مطمئن."
ai_res = ask_gemini_direct(prompt, api_key)
return {"response": ai_res, "analysis": detected}
# 2. دردشة نصية
if user_message:
ai_res = ask_gemini_direct(f"أنت مساعد طبي في نظام Healytics. رد بالعربي: {user_message}", api_key)
return {"response": ai_res}
return {"response": "أهلاً بك، أنا أسمعك جيداً."}
except Exception as e:
return {"response": f"❌ حدث خطأ: {str(e)}"}