Spaces:
Build error
Build error
Download app.py from fgireyige/dhuthjyddg: direct link, hf CLI and curl.
- Browser
- Download file 13.4 kB
-
https://huggingface.co/spaces/fgireyige/dhuthjyddg/resolve/main/app.py
- Command line
-
hf download hf://spaces/fgireyige/dhuthjyddg/app.py
-
curl -L -o app.py https://huggingface.co/spaces/fgireyige/dhuthjyddg/resolve/main/app.py
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 | |
| 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) |