dhuthjyddg / app.py
fgireyige's picture
Update app.py
a5c9f7c verified
Raw History Blame Contribute Delete
13.4 kB
from flask import Flask, request, render_template_string
from PIL import Image, ImageEnhance
from facenet_pytorch import MTCNN
from transformers import AutoImageProcessor, AutoModelForImageClassification
import torch
from torch.nn.functional import softmax
import numpy as np
import cv2
import warnings
import base64
import io
import os
warnings.filterwarnings('ignore')
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"🔧 جهاز التشغيل: {device}")
print("⏳ جاري تحميل النماذج...")
# كشف الوجه
mtcnn = MTCNN(keep_all=True, device=device, min_face_size=40, thresholds=[0.6, 0.7, 0.7])
print("✅ MTCNN")
# نموذج ViT للجنس والعمر
try:
vit_processor = AutoImageProcessor.from_pretrained("abhilash88/age-gender-prediction")
vit_model = AutoModelForImageClassification.from_pretrained("abhilash88/age-gender-prediction").to(device)
vit_model.eval()
print("✅ ViT Age-Gender (94.3%)")
except Exception as e:
vit_model = None
print(f"⚠️ ViT: {e}")
# نموذج MetaCLIP-2
try:
clip_processor = AutoImageProcessor.from_pretrained("prithivMLmods/MetaCLIP-2-Gender-Identifier")
clip_model = AutoModelForImageClassification.from_pretrained("prithivMLmods/MetaCLIP-2-Gender-Identifier").to(device)
clip_model.eval()
print("✅ MetaCLIP-2 (97.25%)")
except Exception as e:
clip_model = None
print(f"⚠️ MetaCLIP-2: {e}")
# نموذج SigLIP2 لفحص المحتوى
try:
nsfw_processor = AutoImageProcessor.from_pretrained("prithivMLmods/siglip2-mini-explicit-content")
nsfw_model = AutoModelForImageClassification.from_pretrained("prithivMLmods/siglip2-mini-explicit-content").to(device)
nsfw_model.eval()
print("✅ SigLIP2 NSFW (F1: 0.94)")
except Exception as e:
nsfw_model = None
print(f"⚠️ SigLIP2: {e}")
print("✅ جميع النماذج جاهزة\n")
def enhance_image(img):
try:
for cls, factor in [(ImageEnhance.Contrast, 1.2), (ImageEnhance.Sharpness, 1.3), (ImageEnhance.Brightness, 1.05)]:
img = cls(img).enhance(factor)
return img
except:
return img
def img_to_base64(img):
buf = io.BytesIO()
img.save(buf, format="JPEG", quality=85)
return base64.b64encode(buf.getvalue()).decode()
HTML_TEMPLATE = '''
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🔍 نظام تحليل الصور المتطور</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma;
background: linear-gradient(135deg, #0f2027 0%, #203a43 50%, #2c5364 100%);
min-height: 100vh; padding: 20px; color: white;
}
.container { max-width: 1200px; margin: 0 auto; }
.header { text-align: center; margin-bottom: 25px; }
.header h1 {
font-size: 2.5em; margin-bottom: 8px;
background: linear-gradient(135deg, #f093fb, #f5576c, #4facfe);
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.upload-box {
background: rgba(255,255,255,0.08); backdrop-filter: blur(15px);
border-radius: 18px; padding: 30px; text-align: center;
margin-bottom: 25px; border: 1px solid rgba(255,255,255,0.15);
}
.upload-box input[type="file"] { display: none; }
.file-label {
display: inline-block; padding: 14px 35px;
background: linear-gradient(135deg, #f093fb, #f5576c);
color: white; border-radius: 40px; cursor: pointer;
font-size: 1.1em; transition: all 0.3s;
}
.file-label:hover { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(240,147,251,0.4); }
.btn-analyze {
padding: 16px 50px; background: linear-gradient(135deg, #4facfe, #00f2fe);
color: white; border: none; border-radius: 40px; cursor: pointer;
font-size: 1.2em; font-weight: bold; margin: 15px 0; transition: all 0.3s;
}
.btn-analyze:hover { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(79,172,254,0.4); }
.file-name { display: block; margin: 12px 0; color: rgba(255,255,255,0.7); }
.preview-img {
max-width: 350px; border-radius: 15px;
box-shadow: 0 15px 35px rgba(0,0,0,0.5); border: 2px solid rgba(255,255,255,0.2);
}
.results-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 18px; margin-top: 25px;
}
.card {
background: rgba(255,255,255,0.06); backdrop-filter: blur(12px);
border-radius: 16px; padding: 20px; border: 1px solid rgba(255,255,255,0.12);
}
.card-title {
font-size: 1.2em; font-weight: bold; margin-bottom: 15px;
padding-bottom: 10px; border-bottom: 1px solid rgba(255,255,255,0.15);
}
.result-row {
display: flex; justify-content: space-between; align-items: center;
padding: 10px; background: rgba(255,255,255,0.04);
border-radius: 8px; margin: 8px 0;
}
.badge {
display: inline-block; padding: 6px 16px; border-radius: 20px;
font-weight: bold; font-size: 0.9em;
}
.badge-male { background: #2196F3; color: white; }
.badge-female { background: #E91E63; color: white; }
.badge-safe { background: #4CAF50; color: white; }
.badge-danger { background: #f44336; color: white; }
.badge-warn { background: #FF9800; color: white; }
.confidence-bar {
width: 100%; height: 6px; background: rgba(255,255,255,0.15);
border-radius: 3px; margin: 6px 0; overflow: hidden;
}
.confidence-fill {
height: 100%; border-radius: 3px;
background: linear-gradient(90deg, #4CAF50, #8BC34A);
transition: width 0.5s;
}
.msg { padding: 12px; border-radius: 12px; text-align: center; margin: 15px 0; }
.error { background: rgba(244,67,54,0.2); border: 1px solid rgba(244,67,54,0.4); }
.warning { background: rgba(255,152,0,0.2); border: 1px solid rgba(255,152,0,0.4); }
.model-tag {
font-size: 0.7em; background: rgba(255,255,255,0.15);
padding: 3px 10px; border-radius: 12px; margin-right: 8px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔍 نظام تحليل الصور المتطور</h1>
<p>ViT (94.3%) + MetaCLIP-2 (97.25%) + SigLIP2 (F1: 0.94)</p>
</div>
<div class="upload-box">
<form method="POST" enctype="multipart/form-data">
<input type="file" name="image" id="fileInput" accept="image/*" required
onchange="document.getElementById('fileName').textContent=this.files[0]?'📎 '+this.files[0].name:'لم يتم اختيار ملف'">
<label for="fileInput" class="file-label">📁 اختر صورة للتحليل</label>
<span class="file-name" id="fileName">لم يتم اختيار ملف</span><br>
<button type="submit" class="btn-analyze">🚀 تحليل الصورة</button>
</form>
</div>
{% if error_msg %}<div class="msg error">❌ {{ error_msg }}</div>{% endif %}
{% if warning_msg %}<div class="msg warning">⚠️ {{ warning_msg }}</div>{% endif %}
{% if uploaded_image %}
<div style="text-align: center; margin: 20px 0;">
<h3>📷 الصورة</h3>
<img src="data:image/jpeg;base64,{{ uploaded_image }}" class="preview-img" alt="preview">
</div>
{% endif %}
{% if results %}
<div class="results-grid">
{% if results.vit %}
<div class="card">
<div class="card-title">🧠 ViT Transformer <span class="model-tag">دقة 94.3%</span></div>
<div class="result-row">
<span>👤 الجنس:</span>
<span class="badge {{ 'badge-male' if 'ذكر' in results.vit.gender else 'badge-female' }}">{{ results.vit.gender }}</span>
</div>
<div class="result-row">
<span>📊 الثقة:</span>
<span>{{ results.vit.confidence }}%</span>
</div>
<div class="confidence-bar">
<div class="confidence-fill" style="width: {{ results.vit.confidence|replace('%','')|float }}%"></div>
</div>
</div>
{% endif %}
{% if results.clip %}
<div class="card">
<div class="card-title">⚡ MetaCLIP-2 <span class="model-tag">دقة 97.25%</span></div>
<div class="result-row">
<span>👤 الجنس:</span>
<span class="badge {{ 'badge-male' if 'ذكر' in results.clip.gender else 'badge-female' }}">{{ results.clip.gender }}</span>
</div>
<div class="result-row">
<span>📊 الثقة:</span>
<span>{{ results.clip.confidence }}%</span>
</div>
<div class="confidence-bar">
<div class="confidence-fill" style="width: {{ results.clip.confidence|replace('%','')|float }}%"></div>
</div>
</div>
{% endif %}
{% if results.nsfw %}
<div class="card">
<div class="card-title">🛡 فحص المحتوى <span class="model-tag">F1: 0.94</span></div>
<div class="result-row">
<span>SigLIP2:</span>
<span class="badge {{ 'badge-safe' if 'آمن' in results.nsfw.status else 'badge-danger' if 'غير' in results.nsfw.status else 'badge-warn' }}">{{ results.nsfw.status }}</span>
</div>
<div class="result-row">
<span>📊 التفاصيل:</span>
<span style="font-size: 0.85em;">{{ results.nsfw.detail }}</span>
</div>
</div>
{% endif %}
</div>
{% endif %}
</div>
</body>
</html>
'''
def process_image(img):
"""تنفيذ جميع التحليلات"""
results = {"faces": 0, "vit": None, "clip": None, "nsfw": None}
# تحسين الصورة
img_enhanced = enhance_image(img)
# 1. فحص NSFW
if nsfw_model:
try:
inputs = nsfw_processor(images=img_enhanced, return_tensors="pt").to(device)
with torch.no_grad():
outputs = nsfw_model(**inputs)
probs = softmax(outputs.logits, dim=1).squeeze()
safe_prob = probs[4].item() if probs.shape[0] > 4 else probs[0].item()
explicit_prob = 1 - safe_prob
if explicit_prob > 0.7:
status = "⚠️ غير آمن"
elif explicit_prob > 0.3:
status = "⚠️ مشبوه"
else:
status = "✅ آمن"
results["nsfw"] = {
"status": status,
"detail": f"نسبة الأمان: {safe_prob*100:.1f}%"
}
except Exception as e:
print(f"خطأ NSFW: {e}")
# 2. كشف الوجوه
boxes, _ = mtcnn.detect(img_enhanced)
if boxes is not None and len(boxes) > 0:
results["faces"] = len(boxes)
# 3. تحليل ViT
if vit_model:
try:
inputs = vit_processor(images=img_enhanced, return_tensors="pt").to(device)
with torch.no_grad():
outputs = vit_model(**inputs)
probs = softmax(outputs.logits, dim=1).squeeze()
female_prob = probs[0].item()
male_prob = probs[1].item() if probs.shape[0] > 1 else 1 - female_prob
if male_prob > female_prob:
gender = "👨 ذكر (Male)"
conf = male_prob * 100
else:
gender = "👩 أنثى (Female)"
conf = female_prob * 100
results["vit"] = {"gender": gender, "confidence": f"{conf:.1f}"}
except Exception as e:
print(f"خطأ ViT: {e}")
# 4. تحليل MetaCLIP-2
if clip_model:
try:
inputs = clip_processor(images=img_enhanced, return_tensors="pt").to(device)
with torch.no_grad():
outputs = clip_model(**inputs)
probs = softmax(outputs.logits, dim=1).squeeze()
female_prob = probs[0].item()
male_prob = probs[1].item() if probs.shape[0] > 1 else 1 - female_prob
if male_prob > female_prob:
gender = "👨 ذكر (Male)"
conf = male_prob * 100
else:
gender = "👩 أنثى (Female)"
conf = female_prob * 100
results["clip"] = {"gender": gender, "confidence": f"{conf:.1f}"}
except Exception as e:
print(f"خطأ MetaCLIP-2: {e}")
return results
@app.route("/", methods=["GET", "POST"])
def index():
context = {}
if request.method == "POST":
file = request.files.get("image")
if not file or file.filename == "":
context["error_msg"] = "❌ الرجاء اختيار ملف صورة"
return render_template_string(HTML_TEMPLATE, **context)
try:
img = Image.open(file).convert("RGB")
context["uploaded_image"] = img_to_base64(img)
context["results"] = process_image(img)
except Exception as e:
context["error_msg"] = f"❌ خطأ: {str(e)}"
return render_template_string(HTML_TEMPLATE, **context)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860, debug=True, threaded=True)