ahmedda/Arabic-Sign-Language-API
0
1from fastapi import FastAPI, UploadFile, File, Form, HTTPException
2import tensorflow as tf
3from PIL import Image
4import io, base64, numpy as np
5import pandas as pd
6import re
7
8app = FastAPI(title="Sign ↔ Text API")
9
10# دالة تنظيف وتوحيد النص العربي
11def normalize_arabic(text):
12 text = str(text).strip()
13 text = re.sub("[إأآ]", "ا", text)
14 text = re.sub("ة", "ه", text)
15 return text
16
17# 1. تحميل ملف الإكسل وعمل القاموس
18word_to_id = {}
19try:
20 file_name = "KARSL-100_Labels (1).xlsx"
21 df = pd.read_excel(file_name)
22 df.columns = [str(col).strip() for col in df.columns]
23
24 if 'Sign-Arabic' in df.columns and 'SignID' in df.columns:
25 for index, row in df.iterrows():
26 if pd.notna(row['Sign-Arabic']):
27 key = normalize_arabic(row['Sign-Arabic'])
28 word_to_id[key] = row['SignID']
29 print(f"✅ تم تحميل {len(word_to_id)} كلمة بنجاح")
30except Exception as e:
31 print(f"❌ خطأ في الإكسل: {e}")
32
33# 2. تحميل الموديلات
34try:
35 sign_to_text_model = tf.keras.models.load_model("best_model.h5", compile=False)
36 text_to_sign_model = tf.keras.models.load_model("word_to_sign_model.h5", compile=False)
37 print("✅ تم تحميل الموديلات بنجاح")
38except Exception as e:
39 print(f"❌ خطأ في الموديلات: {e}")
40
41@app.post("/text-to-sign")
42async def text_to_sign(text: str = Form(...)):
43 try:
44 clean_text = normalize_arabic(text)
45 label_id = word_to_id.get(clean_text)
46
47 if label_id is None:
48 raise ValueError(f"الكلمة '{text}' مش موجودة في الإكسل.")
49
50 # --- الحل الجذري لمشكلة الـ Shape (100) ---
51 # بنعمل مصفوفة فيها 100 صفر
52 one_hot_input = np.zeros((1, 100), dtype=np.float32)
53
54 # بننور الرقم بتاع الكلمة (مثلاً 72) بنخلي قيمته 1
55 # ملحوظة: لو الـ IDs في الإكسل بتبدأ من 1، بنطرح 1 عشان الـ index بيبدأ من 0
56 idx = int(label_id) - 1 if int(label_id) > 0 else 0
57
58 if idx < 100:
59 one_hot_input[0, idx] = 1.0
60 else:
61 raise ValueError(f"الـ ID رقم {label_id} أكبر من حجم الموديل (100)")
62
63 # التوقع (دلوقتي الـ Shape بقا 100 ومظبوط)
64 prediction = text_to_sign_model.predict(one_hot_input)
65 # ---------------------------------------
66
67 if isinstance(prediction, np.ndarray):
68 img_data = prediction[0]
69 if img_data.max() <= 1.0: img_data = (img_data * 255).astype("uint8")
70 else: img_data = img_data.astype("uint8")
71
72 if len(img_data.shape) == 3 and img_data.shape[-1] == 1:
73 img_data = img_data.reshape(img_data.shape[0], img_data.shape[1])
74 img = Image.fromarray(img_data)
75 else:
76 img = prediction
77
78 buf = io.BytesIO()
79 img.save(buf, format="PNG")
80 encoded = base64.b64encode(buf.getvalue()).decode("utf-8")
81
82 return {
83 "status": "success",
84 "word": clean_text,
85 "sign_id": int(label_id),
86 "image_base64": encoded
87 }
88
89 except Exception as e:
90 raise HTTPException(status_code=500, detail=f"خطأ في الموديل: {str(e)}")
91
92if __name__ == "__main__":
93 import uvicorn
94 uvicorn.run(app, host="0.0.0.0", port=8000)