import gradio as gr import cv2 import numpy as np import insightface import faiss import sqlite3 import uuid import json from datetime import datetime # ========== 1. تحميل نموذج ArcFace (IResNet100) ========== print("Loading ArcFace model...") model = insightface.app.FaceAnalysis(name='buffalo_l') model.prepare(ctx_id=0) # 0 للـ CPU print("Model ready.") def get_embedding(image): """استخراج embedding (512-dim) من الصورة""" faces = model.get(cv2.cvtColor(image, cv2.COLOR_RGB2BGR)) if len(faces) == 0: return None return faces[0].embedding # ========== 2. تهيئة FAISS (مؤشر متجهات) ========== dim = 512 index = faiss.IndexFlatL2(dim) # يمكن تبديلها بـ IndexFlatIP للـ cosine id_map = [] # يربط فهرس FAISS مع identity_id # ========== 3. قاعدة بيانات SQLite ========== conn = sqlite3.connect('faces.db', check_same_thread=False) c = conn.cursor() c.execute(''' CREATE TABLE IF NOT EXISTS identities ( identity_id TEXT PRIMARY KEY, name TEXT NOT NULL, embedding_id INTEGER, created_at TIMESTAMP, metadata TEXT ) ''') conn.commit() def add_identity(identity_id, name, embedding, metadata=None): """إضافة شخص جديد إلى النظام""" # إضافة إلى FAISS embedding_np = np.array([embedding]).astype('float32') idx = index.ntotal index.add(embedding_np) id_map.append(identity_id) # إضافة إلى SQLite c.execute(''' INSERT OR REPLACE INTO identities (identity_id, name, embedding_id, created_at, metadata) VALUES (?, ?, ?, ?, ?) ''', (identity_id, name, idx, datetime.now(), metadata)) conn.commit() return idx def search_identity(embedding, k=5): """البحث عن أقرب k شخص""" if embedding is None: return [] embedding_np = np.array([embedding]).astype('float32') distances, indices = index.search(embedding_np, k) results = [] for dist, idx in zip(distances[0], indices[0]): if idx == -1: continue identity_id = id_map[idx] c.execute('SELECT name, metadata FROM identities WHERE identity_id=?', (identity_id,)) row = c.fetchone() if row: name, metadata = row confidence = max(0, 1 - dist / 2) # تحويل المسافة إلى ثقة results.append({ 'identity_id': identity_id, 'name': name, 'confidence': confidence, 'metadata': metadata }) return results def list_all_identities(): c.execute('SELECT identity_id, name, created_at FROM identities') rows = c.fetchall() if not rows: return "📭 لا توجد هويات مسجلة." out = "## 📋 قائمة الهويات:\n" for row in rows: out += f"- **{row[1]}** (ID: {row[0]}) – تم التسجيل: {row[2]}\n" return out def delete_identity(identity_id): """حذف شخص (سيتم إعادة بناء الفهرس لاحقاً – مبسط)""" # للتبسيط، نقوم بحذف من SQLite فقط # الإعادة الكاملة للفهرس تتطلب إعادة بناء FAISS، يمكن تنفيذها لاحقاً c.execute('DELETE FROM identities WHERE identity_id=?', (identity_id,)) conn.commit() return f"✅ تم حذف {identity_id} (ملاحظة: الفهرس لم يُحدث تلقائياً)" # ========== 4. وظائف Gradio ========== def enroll(image, identity_id, name, metadata_str): """تسجيل وجه جديد""" if image is None: return "⚠️ يرجى تحميل صورة." emb = get_embedding(image) if emb is None: return "❌ لم يتم اكتشاف وجه في الصورة." metadata = None if metadata_str.strip(): try: metadata = json.loads(metadata_str) except: return "⚠️ البيانات الإضافية ليست JSON صحيح." add_identity(identity_id, name, emb, json.dumps(metadata) if metadata else None) return f"✅ تم تسجيل {name} (ID: {identity_id}) بنجاح." def search(image, threshold): """البحث عن وجه""" if image is None: return "⚠️ يرجى تحميل صورة." emb = get_embedding(image) if emb is None: return "❌ لم يتم اكتشاف وجه في الصورة." results = search_identity(emb) if not results: return "⚠️ لم يتم العثور على تطابق." out = f"## 🔍 نتائج البحث (أعلى {len(results)}):\n" for res in results: out += f"- **{res['name']}** (ID: {res['identity_id']}) – ثقة: {res['confidence']:.2%}\n" return out def filter_by_metadata(key, value): """مثال على فلترة حسب metadata (يمكن إضافتها إلى الواجهة)""" c.execute("SELECT identity_id, name FROM identities WHERE metadata LIKE ?", (f'%"{key}": "{value}"%',)) rows = c.fetchall() if not rows: return "⚠️ لا توجد نتائج." out = "## 🔎 نتائج الفلترة:\n" for row in rows: out += f"- {row[1]} (ID: {row[0]})\n" return out # ========== 5. بناء واجهة Gradio ========== with gr.Blocks(title="Malath - Face Recognition System") as demo: gr.Markdown("# 🧠 Malath – نظام التعرف على الوجه\n### ArcFace + FAISS + SQLite") with gr.Tabs(): with gr.TabItem("📝 تسجيل"): with gr.Row(): enroll_img = gr.Image(type="numpy", label="صورة الوجه") with gr.Column(): enroll_id = gr.Textbox(label="رقم الهويه") enroll_name = gr.Textbox(label="الاسم") enroll_meta = gr.Textbox(label="بيانات إضافية (JSON)", placeholder='{"القسم": "IT"}') enroll_btn = gr.Button("تسجيل", variant="primary") enroll_out = gr.Textbox(label="النتيجة") enroll_btn.click(enroll, [enroll_img, enroll_id, enroll_name, enroll_meta], enroll_out) with gr.TabItem("🔍 بحث"): search_img = gr.Image(type="numpy", label="صورة الوجه") search_thresh = gr.Slider(minimum=0, maximum=1, value=0.7, label="عتبة الثقة") search_btn = gr.Button("بحث", variant="primary") search_out = gr.Textbox(label="النتيجة") search_btn.click(search, [search_img, search_thresh], search_out) with gr.TabItem("📋 قائمة"): list_btn = gr.Button("عرض الكل") list_out = gr.Markdown() list_btn.click(list_all_identities, outputs=list_out) # تبويب إضافي للفلترة (مثال) with gr.TabItem("🔎 فلترة"): filter_key = gr.Textbox(label="المفتاح (مثال: القسم)") filter_val = gr.Textbox(label="القيمة (مثال: IT)") filter_btn = gr.Button("فلترة") filter_out = gr.Markdown() filter_btn.click(filter_by_metadata, [filter_key, filter_val], filter_out) demo.launch(server_name="0.0.0.0", server_port=7860)