Mariamsayed17/first-aid-api
0
1import os2 3import io4import json5import numpy as np6import joblib7import tensorflow as tf8from PIL import Image9import cv210from fastapi import FastAPI, File, UploadFile, Query11from fastapi.middleware.cors import CORSMiddleware12from pydantic import BaseModel13from database import save_user, save_prediction14 15 16# =========================17# 🔧 FIX KERAS ERROR18 19from keras.layers import InputLayer20 21def custom_input_layer(*args, **kwargs):22 if "batch_shape" in kwargs:23 batch_shape = kwargs.pop("batch_shape")24 kwargs["shape"] = batch_shape[1:]25 26 kwargs.pop("optional", None)27 28 return InputLayer(*args, **kwargs)29 30 31# =========================32# 🚀 APP33# =========================34app = FastAPI(title="Esafny AI Unified")35 36app.add_middleware(37 CORSMiddleware,38 allow_origins=["*"],39 allow_credentials=True,40 allow_methods=["*"],41 allow_headers=["*"],42)43 44 45class User(BaseModel):46 name: str47 email: str48 password: str49 50 51@app.get("/")52def home():53 return {"message": "API is working 🚀"}54 55 56# 🧪 test insert57@app.get("/test-insert")58def test_insert():59 res = save_prediction(1, "test_case")60 61 if res:62 return {"status": "Insert Success ✅"}63 else:64 return {"status": "Insert Failed ❌"}65 66# =========================67# 💬 CHAT MODEL68# =========================69class ChatRequest(BaseModel):70 message: str71 72 73# =========================74# 🧠 IMAGE MODELS75# =========================76import keras77from keras.layers import Dense78 79_old_init = Dense.__init__80 81def new_init(self, *args, **kwargs):82 kwargs.pop("quantization_config", None)83 _old_init(self, *args, **kwargs)84 85Dense.__init__ = new_init86extractor = tf.keras.models.load_model(87 "wound_extractor_model.h5",88 compile=False,89 custom_objects={90 "InputLayer": custom_input_layer91 }92)93ensemble = joblib.load("wound_ensemble_model.pkl")94 95with open("class_indices.json", "r") as f:96 labels = list(json.load(f).keys())97 98 99# =========================100# 🧠 DETECT FROM TEXT101# =========================102def detect_injury(message: str):103 msg = message.lower()104 105 mapping = {106 "headache": ["صداع", "headache"],107 "fever": ["حمى", "fever"],108 "abdominal_pain": ["مغص", "stomach"],109 "diarrhea": ["اسهال", "diarrhea"],110 "vomiting": ["قيء", "vomit"],111 "cough": ["سعال", "cough"],112 "choking": ["اختناق", "choking"],113 "wound": ["جرح", "wound"],114 "bleeding": ["نزيف", "bleeding"],115 "burn": ["حرق", "burn"],116 "bruise": ["كدمة", "bruise"],117 "allergy": ["حساسية", "allergy"],118 "fracture": ["كسر", "fracture"],119 "dizziness": ["دوخة", "dizziness"],120 "cut": ["cut", "جرح"],121 "abrasion": ["abrasion", "سحجات"],122 "laceration": ["laceration", "جرح عميق"],123 "normal skin": ["جلد طبيعي"],124 "poisoning":["poisoning", "تسمم"],125 "diabetic_emergencies":["diabetic_emergencies"," السكري"],126 "seizures":["seizures", "تشنج"]127 }128 129 for k, v in mapping.items():130 if any(i in msg for i in v):131 return k132 133 return "unknown"134 135 136# =========================137# 🧠 SEVERITY138# =========================139def analyze_image_severity(img, injury):140 141 image = np.array(img)142 gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)143 144 if injury in ["cut", "wound", "laceration"]:145 146 edges = cv2.Canny(gray, 50, 150)147 wound_pixels = np.sum(edges > 0)148 149 if wound_pixels > 4000:150 return "شديدة"151 elif wound_pixels > 1500:152 return "متوسطة"153 else:154 return "بسيطة"155 156 elif injury == "burn":157 158 hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)159 160 red_mask = cv2.inRange(161 hsv,162 np.array([0, 50, 50]),163 np.array([20, 255, 255])164 )165 166 burn_area = np.sum(red_mask > 0)167 168 if burn_area > 20000:169 return "شديدة"170 elif burn_area > 8000:171 return "متوسطة"172 else:173 return "بسيطة"174 175 elif injury == "bruise":176 177 dark_pixels = np.sum(gray < 80)178 179 if dark_pixels > 15000:180 return "شديدة"181 elif dark_pixels > 7000:182 return "متوسطة"183 else:184 return "بسيطة"185 186 elif injury in [187 "fracture",188 "seizures",189 "poisoning",190 "choking",191 "diabetic_emergencies"192 ]:193 return "شديدة"194 195 return "بسيطة"196 197# =========================198# 🧠 FIRST AID199# =========================200def get_first_aid(injury, severity):201 data = {"burn": {202 "بسيطة": {203 "explanation": "حرق من الدرجة الأولى يصيب البشرة فقط؛ يظهر كاحمرار وألم بسيط دون فقاعات.",204 "steps": [205 "أبعد المصاب عن مصدر الحرق فوراً.",206 "ضع المنطقة تحت ماء جاري فاتر (15-20 دقيقة) وتجنب الثلج مباشرة.",207 "انزع أي إكسسوارات (خواتم/ساعات) قبل حدوث تورم.",208 "جفف المنطقة بلطف وادهن كريماً مرطباً.",209 "تغطية بسيطة بشاش معقم إذا لزم الأمر."210 ],211 "medicine": ["Panthenol Cream", "Bepanthen Plus", "Aloe Vera Gel", "MEBO (مرطب جروح)"],212 "hospital_trigger": False213 },214 "متوسطة": {215 "explanation": "حرق من الدرجة الثانية؛ يسبب فقاعات سوائل (Blisters) وألماً شديداً جداً وتورم.",216 "steps": [217 "تبريد المنطقة بالماء الفاتر فوراً.",218 "ممنوع ثقب أو فتح الفقاعات نهائياً لتجنب التلوث والعدوى.",219 "تغطية الحرق بشاش معقم غير لاصق (Vaseline Gauze).",220 "رفع الطرف المصاب لتقليل التورم."221 ],222 "medicine": ["MEBO Ointment", "Fucidin Cream (مضاد حيوي)", "Silver Sulfadiazine", "Ibuprofen (مسكن ألم)"],223 "hospital_trigger": True,224 "hospital_note": "في حالة الحروق المتوسطة، اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى لتجنب التلوث."225 },226 "شديدة": {227 "explanation": "حرق من الدرجة الثالثة؛ يتلف الجلد بعمق وقد يبدو متفحماً أو أبيض اللون، وغالباً لا يشعر المصاب بالألم لتلف الأعصاب.",228 "steps": [229 "لا تضع أي سوائل أو كريمات أو مواد منزلية.",230 "غطِّ المنطقة المحروقة بقطعة قماش معقمة وجافة تماماً.",231 "تأكد من علامات التنفس لدى المصاب.",232 "التوجه للطوارئ فوراً أو طلب الإسعاف."233 ],234 "medicine": ["إجراءات المستشفى فقط (IV Fluids, Morphine)"],235 "hospital_trigger": True,236 "hospital_note": "الحالة حرجة جداً! اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى فوراً."237 }238 },"fracture": {239 "بسيطة": {240 "explanation": "كسر مغلق بسيط أو شعري؛ لا يوجد تشوه واضح في شكل العضو.",241 "steps": [242 "تثبيت العضو المصاب بجبيرة مؤقتة (خشب أو كرتون) لمنع الحركة.",243 "وضع كمادات باردة لتقليل الورم.",244 "رفع العضو المصاب قليلاً."245 ],246 "medicine": ["Panadol (Paracetamol)", "Advil (Ibuprofen)", "Catafast (عند الحاجة)"],247 "hospital_trigger": True,248 "hospital_note": "لعمل الأشعة والجبيرة، اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى."249 },250 "شديدة": {251 "explanation": "كسر مضاعف (مفتوح) يبرز منه العظم، أو كسر في العمود الفقري/الجمجمة.",252 "steps": [253 "ممنوع تحريك المصاب نهائياً في حالات كسر الظهر أو الرقبة.",254 "في الكسر المفتوح: غطِّ العظم البارز بشاش معقم ولا تحاول إرجاعه مكانه.",255 "السيطرة على النزيف بالضغط حول منطقة الكسر.",256 "اطلب الإسعاف فوراً."257 ],258 "medicine": ["مسكنات وريدية بالمستشفى"],259 "hospital_trigger": True,260 "hospital_note": "خطر النزيف أو الشلل! اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى فوراً."261 }262 },"bleeding": {263 "بسيطة": {264 "explanation": "نزيف سطحي ناتج عن خدوش بسيطة.",265 "steps": ["غسل الجرح وتطهيره.", "الضغط المباشر لمدة 5 دقائق.", "استخدام لاصق جروح."],266 "medicine": ["Betadine", "Fucidin", "Dettol (مخفف)"],267 "hospital_trigger": False268 },269 "شديدة": {270 "explanation": "نزيف شرياني غزير لا يتوقف بالضغط العادي.",271 "steps": ["ضغط شديد ومستمر بقطعة قماش سميكة ونظيفة.",272 "رفع العضو فوق مستوى القلب.",273 "استخدام رباط ضاغط (Tourniquet) في حالات البتر أو النزيف الذي يهدد الحياة."274 ],275 "medicine": ["Hemo-stop", "Kapron (بإشراف طبي)"],276 "hospital_trigger": True,277 "hospital_note": "خطر هبوط الدورة الدموية! اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى فوراً."278 }279 },"choking": {280 "بسيطة": {281 "explanation": "انسداد جزئي لمجرى الهواء (المصاب يسعل).",282 "steps": ["شجع المصاب على السعال بقوة.", "ابقَ بجانبه وراقبه."],283 "medicine": ["Oplex"],284 "hospital_trigger": False285 },286 "شديدة": {287 "explanation": "انسداد كامل؛ المصاب لا يستطيع التنفس أو الكلام ولون وجهه يتغير للأزرق.",288 "steps": [289 "نفذ مناورة هيمليك (ضغطات قوية على البطن فوق السرة).",290 "إذا فقد المصاب وعيه، ابدأ الإنعاش القلبي الرئوي (CPR).",291 "اطلب الإسعاف فوراً."292 ],293 "medicine": ["أكسجين طوارئ"],294 "hospital_trigger": True,295 "hospital_note": "حالة اختناق! اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى فوراً."296 }297 },"diabetic_emergencies": {298 "متوسطة": {299 "explanation": "هبوط سكري؛ انخفاض حاد في السكر؛ تشوش، عرق بارد، ورعشة.",300 301 "steps": [302 "إعطاء المصاب الواعي نصف كوب عصير أو 3 ملاعق سكر مذابة.",303 "الانتظار 15 دقيقة وإعادة القياس.",304 "إعطاء وجبة خفيفة بعد الإفاقة."305 ],306 "medicine": ["Glucolin Tablets", "Dextrose Gel"],307 "hospital_trigger": False308 },309 "شديدة": {310 "explanation": "غيبوبة_كاملة؛ فقدان وعي تام لمريض السكر .",311 "steps": [312 "ممنوع وضع أي شيء في الفم (خطر الاختناق).",313 "وضع المصاب في وضعية الإفاقة (على جانبه).",314 "طلب الإسعاف فوراً."315 ],316 "medicine": ["GlucaGen HypoKit (حقنة طوارئ)"],317 "hospital_trigger": True,318 "hospital_note": "اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى فوراً."319 }320 }, "abdominal_pain": {321 "بسيطة": {322 "explanation": "مغص ناتج عن غازات أو سوء هضم.",323 "steps": ["شرب سوائل دافئة.", "تدليك البطن.", "الراحة."],324 "medicine": ["Buscopan", "Visceral", "Gast-Reg", "Spasmo-digestin"],325 "hospital_trigger": False326 },327 "شديدة": {328 "explanation": "ألم حاد مفاجئ (اشتباه زائدة دودية أو حصوات).",329 "steps": [330 "ممنوع تناول الطعام أو الشراب.",331 "ممنوع أخذ مسكنات قوية قبل التشخيص.",332 "التوجه للطوارئ فوراً."333 ],334 "medicine": ["لا يؤخذ دواء قبل التشخيص"],335 "hospital_trigger": True,336 "hospital_note": "قد تحتاج لتدخل جراحي! اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى فوراً."337 }338 },"seizures": {339 "شديدة": {340 "explanation": "نوبة تشنجات وفقدان وعي.",341 "steps": [342 "تأمين المكان حول المصاب من الأجسام الحادة.",343 "وضع وسادة تحت الرأس.",344 "ممنوع وضع أي شيء في الفم أو تقييد الحركة.",345 "بعد النوبة، ضعه على جنبه (وضعية الإفاقة)."346 ],347 "medicine": ["Depakine", "Epanutin (للمتابعة)"],348 "hospital_trigger": True,349 "hospital_note": "إذا استمرت النوبة > 5 دقائق، اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى."350 }351 },"allergy": {352 "بسيطة": {353 "explanation": "حكة أو احمرار بسيط.",354 "steps": [355 "غسل المنطقة بماء بارد.", "الابتعاد عن المسبب."356 ],357 "medicine": ["Fenistil Gel", "Zyrtec", "Allerid"],358 "hospital_trigger": False359 },360 "شديدة": {361 "explanation": "صدمة تحسسية؛ تورم اللسان وضيق تنفس حاد.",362 "steps": [363 "استخدام حقنة EpiPen إن وجدت.", "النقل الفوري للمستشفى."364 ],365 "medicine": ["Adrenaline (Epinephrine)", "Telfast"],366 "hospital_trigger": True,367 "hospital_note": "حالة حياة أو موت! اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى فوراً."368 }369 },"poisoning": {370 "شديدة": {371 "explanation": "بلع مواد كيميائية أو جرعات أدوية زائدة.",372 "steps": [373 "تحديد المادة وكميتها.",374 "ممنوع إجبار المصاب على القيء (خاصة مع المنظفات).",375 "الاتصال بمركز السموم فوراً."376 ],377 "medicine": ["Activated Charcoal (فحم نشط)"],378 "hospital_trigger": True,379 "hospital_note": "اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى فوراً."380 }381 },"headache": {382 "بسيطة": {383 "explanation": "صداع توتري أو ناتج عن إجهاد عام.",384 "steps": [385 "الراحة في غرفة مظلمة", "شرب كمية كافية من الماء" 386 ],387 "medicine": ["Panadol ", "Abimol ", "Advil "],388 "hospital_trigger": False,389 },390 "شديدة": {391 "explanation": "صداع حاد ومفاجئ قد يكون مؤشراً لارتفاع شديد في ضغط الدم أو مشاكل وعائية.",392 "steps": [393 "قياس ضغط الدم فوراً", "تجنب الحركة المفاجئة" 394 ],395 "medicine": ["Cataflam ", "Excedrin "],396 "hospital_trigger": True,397 "hospital_note": "خطر! هذا النوع من الصداع يتطلب فحصاً عصبياً فورياً لاستبعاد النزيف أو الجلطة. اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى فوراً."398 }399 },"fever": {400 "بسيطة":{401 "explanation": "ارتفاع طفيف في درجة الحرارة (أقل من 38.5).",402 "steps": [403 "الإكثار من السوائل", "تخفيف الملابس"404 ],405 "medicine": ["Panadol ", "Cetal "],406 "hospital_trigger": False,407 }, 408 "متوسطة":{409 "explanation": "حرارة متوسطة ناتجة عن التهاب محتمل (38.5 - 39.5).",410 "steps": [411 "عمل كمادات ماء فاتر", "الراحة التامة"412 ],413 "medicine": ["Brufen ", "Voltaren Supp "],414 "hospital_trigger": False,415 }, 416 "شديدة": {417 "explanation": "حمى شديدة (فوق 39.5) تهدد وظائف الجسم الحيوية.",418 "steps": [419 "كمادات فورية تحت الإبط وبين الفخذين", "عدم استخدام الماء المثلج"420 ],421 "medicine": ["Perfalgan (حقن وريدية بالمستشفى)"],422 "hospital_trigger": True,423 "hospital_note": "اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى."424 }425 },"bruise": {426 "بسيطة":{427 "explanation": "تجمع دموي سطحي نتيجة اصطدام.",428 "clinical_steps": [429 "كمادات باردة لمدة 15 دقيقة", "رفع العضو المصاب"430 ],431 "prescribed_meds": ["Reparil Gel", "Hirudoid"],432 "hospital_trigger": False,433 },434 "متوسطة": {435 "explanation": "تجمع دموي واسع مع ألم عند اللمس وتورم ملحوظ.",436 "steps": [437 "استخدام كمادات باردة في أول يومين", "ثم كمادات دافئة بعد 48 ساعة"438 ],439 "medicine": ["Alpha-Chymotrypsin ", "Ibuprofen"],440 "hospital_trigger": False,441 },442 "شديدة": {443 "explanation": "كدمة واسعة مع اشتباه نزيف داخليأو كسر.",444 "steps": [445 "تثبيت العضو تماماً", "عمل أشعة X-Ray"446 ],447 "hospital_trigger": True,448 "hospital_note": "اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى."449 }450 },"dizziness": {451 "بسيطة": {452 "explanation": "دوار ناتج عن هبوط طفيف في ضغط الدم أو نقص سكر.",453 "steps": [454 "الاستلقاء مع رفع القدمين", "تناول وجبة خفيفة سكرية"455 ],456 "medicine": ["Effortil (إيفورتيل لرفع الضغط)", "شرب سوائل مملحة"],457 "hospital_trigger": False,458 }, 459 "شديدة": {460 "explanation": "دوار دهليزي حاد أو فقدان توازن يمنع الحركة.",461 "steps": [462 "تثبيت الرأس في وضعية مريحة", "تجنب الإضاءة القوية"463 ],464 "medicine": ["Betaserc ", "Stugeron "],465 "hospital_trigger": True,466 "hospital_note": "قد يشير الدوار الشديد لمشكلة في الأذن الداخلية أو تدفق الدم للمخ. اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى"467 }468 },"vomiting": {469 "بسيطة": {470 "explanation": "اضطراب بسيط في المعدة أو غثيان عارض.",471 "steps": [472 "التوقف عن الأكل لمدة ساعتين", "رشفات صغيرة من الماء"473 ],474 "medicine": ["Motilium (موتيليوم)", "Emetrex (إيميتريكس)"],475 "hospital_trigger": False,476 },477 478 "شديدة": {479 "explanation": "قيء قهري مستمر يمنع الاحتفاظ بأي سوائل داخل الجسم.",480 "steps": [481 "مراقبة علامات الجفاف (جفاف اللسان/قلة التبول)"482 ],483 "medicine": ["Primperan ", "Zofran "],484 "hospital_trigger": True,485 "hospital_note": "تحتاج لتعويض السوائل عن طريق المحاليل الوريدية فوراً. اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى"486 }487 },"diarrhea": {488 "بسيطة": {489 "explanation": "نزلات معوية بسيطة أو سوء هضم.",490 "steps": [491 "شرب محلول الجفاف بعد كل مرة إسهال", "تناول الزبادي والبطاطس المسلوقة"492 ],493 "medicine": ["Smecta ", "ORS (محلول جفاف)"],494 "hospital_trigger": False, 495 },496 "شديدة": {497 "explanation": "إسهال حاد (أكثر من 10 مرات يومياً) أو وجود دم بالبراز.",498 "steps": [499 "جمع عينة للتحليل إذا أمكن", "مراقبة درجة الحرارة"500 ],501 "medicine": ["Antinal ", "Streptoquin "],502 "hospital_trigger": True,503 "hospital_note": "اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى."504 }505 },506 "cut": {507 "بسيطة": {508 "explanation": "جرح قطعي سطحي لا يتجاوز الطبقة الخارجية للجلد والنزيف يتوقف سريعاً.",509 "steps": [510 "غسل الجرح بماء نظيف وصابون", "الضغط المباشر بقطعة شاش معقمة"511 ],512 "medicine": ["Betadine", "Fucidin (مضاد حيوي موضعى)", "لاصق جروح"],513 "hospital_trigger": False,514 },515 "متوسطة": {516 "explanation": "جرح أعمق قليلاً، النزيف يحتاج لضغط مستمر وقد يحتاج لغرز بسيطة.",517 "steps": [518 "تطهير حول الجرح وليس داخله", "استخدام رباط ضاغط خفيف"519 ],520 "medicine": ["Fucicort Cream", "Garamycin Ointment"],521 "hospital_trigger": True,522 "hospital_note": "قد يحتاج الجرح لغرز طبية (Sutures). اضغط على 'مستشفيات' للتقييم الجراحي وللحصول على عنوان أقرب مستشفي."523 },524 "شديدة": {525 "explanation": "جرح قطعي غائر مع نزيف شرياني أو ظهور أنسجة داخلية.",526 "steps": [527 "ضغط شديد جداً فوق النزيف", "رفع العضو فوق مستوى القلب", "عدم إزالة الشاش إذا تشبع بالدم بل أضف فوقه"528 ],529 "medicine": ["حقنة تيتانوس (Tetanus Toxoid) في المستشفى"],530 "hospital_trigger": True,531 "hospital_note": "خطر النزيف الحاد! توجه لأقرب قسم طوارئ فوراً من خلال قائمة المستشفيات للحصول على عنوان أقرب مستشفي"532 }533 },534 "cough": {535 "بسيطة":{536 "explanation": "كحة جافة ناتجة عن حساسية أو تهيج بسيط.",537 "steps": [538 "شرب سوائل دافئة", "ترطيب هواء الغرفة"539 ],540 "medicine": ["Guaifenesin", "Notuss"],541 "hospital_trigger": False,542 },543 "شديدة": {544 "explanation": "كحة حادة مع نهجان، زرقة في الشفاه، أو خروج دم.",545 "steps": [546 "الجلوس بوضع قائم", "محاولة التنفس بهدوء"547 ],548 "medicine": ["Bronchicum", "Selgon "],549 "hospital_trigger": True,550 "hospital_note": "اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى."551 }552 },"laceration": {553 "بسيطة": {554 "explanation": "جرح قطعي سطحي.",555 "steps": ["تطهير بماء وملح", "ضغط لوقف النزيف"556 ],557 "medicine": ["Betadine", "Fucidin"],558 "hospital_trigger": False,559 },560 "متوسطة": {561 "explanation": "تمزق جلدي غير منتظم مع تلوث بالأتربة أو أجسام غريبة.",562 "steps": [563 "غسل مكثف بمحلول ملح (Saline)", "محاولة إيقاف النزيف بقطع معقمة"564 ],565 "medicine": ["Augmentin (مضاد حيوي بالفم)", "Betadine Solution"],566 "hospital_trigger": True,567 "hospital_note": "الجرح المتهتك عرضة للتلوث. اضغط على 'مستشفيات' للتنظيف الجراحي والحصول على عنوان أقرب مستشفي."568 },569 "شديدة": {570 "explanation": "جرح عميق متهتك مع نزيف مستمر.",571 "steps":[572 "ضغط مباشر وقوي", "رفع العضو للأعلى"573 ],574 "medicine": ["Tetanus Shot (Clinic)"],575 "hospital_trigger": True,576 "hospital_note": "اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى."577 }578 },"abrasion": {579 "بسيطة": {580 "explanation": "سحجات جلدية سطحية.",581 "steps":[582 "غسل بمحلول مطهر", "وضع كريم مرطب"583 ],584 "medicine": ["Betadine", "Bepanthen"],585 "hospital_trigger": False,586 },587 "متوسطة": {588 "explanation": "سحجة واسعة تغطي منطقة كبيرة من الجسم (مثل سحجات حوادث الدراجات).",589 "steps": [590 "تنظيف بلطف لإزالة الأتربة", "وضع طبقة رقيقة من ميبو (Mebo)"591 ],592 "medicine": ["Mebo Ointment", "Flamazine Cream"],593 "hospital_trigger": False,594 },595 "شديدة":{596 "explanation": "سحجات واسعة ملوثة بأجسام غريبة.",597 "steps":[598 "تنظيف جراحي هادئ", "مضاد حيوي واسع المدى"599 ],600 "medicine": ["Mebo", "Fucicort"],601 "hospital_trigger": True,602 "hospital_note": "اضغط على 'مستشفيات' من القائمة للحصول على عنوان أقرب مستشفى."603 }604 }, "normal_skin": {605 "بسيطة": {606 "explanation": "الجلد سليم، لا توجد إصابة واضحة.",607 "steps": ["لا يحتاج"],608 "medicine": ["لا يحتاج"]609 }610 }611 }612 return data.get(injury, {}).get(severity, {})613# =========================614# 🧾 RESPONSE615# =========================616def format_response(injury, severity, data):617 if isinstance(data, list):618 data = {619 "explanation": "",620 "steps": [],621 "medicine": data,622 "hospital_trigger": False623 }624 625 if injury in ["normal skin", "normal_skin"]:626 return {627 "injury": "normal_skin",628 "severity": "لا يوجد",629 "explanation": data.get(630 "explanation",631 "الجلد سليم، لا توجد إصابة واضحة."632 ),633 "steps": ["لا يحتاج إلى إسعافات أولية"],634 "medicine": ["لا يحتاج إلى أدوية"],635 "hospital_trigger": False,636 "hospital_note": "لا يحتاج إلى اي شئ سليم معافي"637 }638 639 return {640 "injury": injury,641 "severity": severity,642 "explanation": data.get("explanation", ""),643 "steps": data.get("steps", []),644 "medicine": data.get("medicine", []),645 "hospital_trigger": data.get("hospital_trigger", False),646 "hospital_note": data.get("hospital_note", "")647 }648 649 650# =========================651# 💬 CHAT API652# =========================653@app.post("/chat")654async def chat(data: ChatRequest):655 656 message = data.message657 658 injury = detect_injury(message)659 660 print("injury =", injury)661 662 if injury == "unknown":663 return {664 "bot_response": "❗️ مش قادر أحدد الحالة، ممكن توضحي أكتر؟"665 }666 667 severity = "بسيطة"668 669 result = get_first_aid(injury, severity)670 671 formatted = format_response(672 injury,673 severity,674 result675 )676 677 return {678 "bot_response": formatted679 }680 # =========================681# 🖼 IMAGE API682# =========================683def predict_image(img):684 img = img.resize((224, 224))685 x = np.array(img)686 x = np.expand_dims(x, axis=0)687 x = tf.keras.applications.efficientnet.preprocess_input(x.astype("float32"))688 689 features = extractor.predict(x, verbose=0)690 probs = ensemble.predict_proba(features)[0]691 idx = np.argmax(probs)692 confidence = float(probs[idx])693 injury = labels[idx]694 695 # تحويل المسافة لـ Underscore لتجنب أخطاء القاموس696 if injury == "normal skin":697 injury = "normal_skin"698 699 severity = analyze_image_severity(img, injury)700 data = get_first_aid(injury, severity)701 702 return format_response(injury, severity, data)703 704 705@app.post("/predict")706async def predict(user_id: int = Query(...), file: UploadFile = File(...)):707 try:708 print("========== NEW REQUEST ==========")709 print("user_id =", user_id)710 print("filename =", file.filename)711 712 content = await file.read()713 if not content:714 return {"bot_response": "❌ الملف فارغ"}715 716 # فحص برمجياً هل الملف صورة؟717 try:718 img = Image.open(io.BytesIO(content))719 img.verify()720 except Exception as e:721 print("INVALID IMAGE:", e)722 return {"bot_response": "❌ الملف المرسل ليس صورة صحيحة"}723 724 # إعادة فتح الصورة بعد الـ verify725 img = Image.open(io.BytesIO(content)).convert("RGB")726 727 # تشغيل موديل الذكاء الاصطناعي728 result = predict_image(img)729 print("RESULT =", result)730 731 # استخراج نوع الإصابة لحفظها في قاعدة البيانات732 injury_type = "unknown"733 if result:734 try:735 injury_type = result.split("\n")[0].replace("الحالة: ", "")736 except:737 injury_type = "unknown"738 739 # حفظ في قاعدة البيانات740 save_prediction(user_id, injury_type)741 742 return {743 "type": "image",744 "bot_response": result745 }746 except Exception as e:747 print("ERROR =", str(e))748 return {"bot_response": f"❌ خطأ في السيرفر: {str(e)}"}749 750@app.post("/register")751def register(user: User):752 753 result = save_user(user.name, user.email, user.password)754 755 if isinstance(result, dict) and "error" in result:756 return result757 758 # 👇 دي أهم حاجة759 user_id = result["data"][0]["id"]760 761 return {762 "success": True,763 "user_id": user_id764 }