Spaces:
Runtime error
Runtime error
| # app_interface.py - Version alternative avec gr.Interface pour garantir l'API REST | |
| # Cette version utilise gr.Interface qui expose automatiquement l'API REST dans Gradio 5.x | |
| import os | |
| os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' | |
| import gradio as gr | |
| import tensorflow as tf | |
| from tensorflow.keras.models import Model | |
| from tensorflow.keras.layers import GlobalAveragePooling2D, Dense | |
| from tensorflow.keras.applications import MobileNetV2 | |
| from ultralytics import YOLO | |
| from PIL import Image | |
| import numpy as np | |
| from sklearn.cluster import KMeans | |
| import json | |
| print("=" * 60) | |
| print("🚀 DÉMARRAGE LABASNI CLOTH DETECTION (Interface Version)") | |
| print("=" * 60) | |
| # ============================================ | |
| # CHARGEMENT DES MODÈLES | |
| # ============================================ | |
| print("\n🔄 Chargement du modèle YOLO...") | |
| try: | |
| yolo_model = YOLO("best.pt") | |
| print("✅ YOLO chargé avec succès") | |
| except Exception as e: | |
| print(f"❌ Erreur YOLO: {e}") | |
| raise | |
| print("\n🔄 Chargement du modèle Style/Season...") | |
| try: | |
| base_model = MobileNetV2( | |
| input_shape=(224, 224, 3), | |
| include_top=False, | |
| weights=None | |
| ) | |
| x = base_model.output | |
| x = GlobalAveragePooling2D()(x) | |
| style_output = Dense(4, activation='softmax', name='style_output')(x) | |
| season_output = Dense(4, activation='softmax', name='season_output')(x) | |
| style_model = Model( | |
| inputs=base_model.input, | |
| outputs=[style_output, season_output] | |
| ) | |
| style_model.load_weights( | |
| "style_season_model.h5", | |
| by_name=True, | |
| skip_mismatch=True | |
| ) | |
| print("✅ Style/Season model chargé avec succès") | |
| except Exception as e: | |
| print(f"❌ Erreur Style/Season: {e}") | |
| raise | |
| print("\n" + "=" * 60) | |
| print("✅ TOUS LES MODÈLES CHARGÉS") | |
| print("=" * 60 + "\n") | |
| # ============================================ | |
| # FONCTIONS UTILITAIRES | |
| # ============================================ | |
| def get_dominant_color(crop): | |
| """Extrait la couleur dominante via K-Means""" | |
| try: | |
| img_array = np.array(crop).reshape(-1, 3) | |
| img_array = img_array[np.any(img_array != [0, 0, 0], axis=1)] | |
| if len(img_array) == 0: | |
| return "#808080" | |
| kmeans = KMeans(n_clusters=3, random_state=0, n_init=10) | |
| kmeans.fit(img_array) | |
| dominant = kmeans.cluster_centers_[0] | |
| return '#{:02x}{:02x}{:02x}'.format( | |
| int(dominant[0]), | |
| int(dominant[1]), | |
| int(dominant[2]) | |
| ).upper() | |
| except: | |
| return "#808080" | |
| # ============================================ | |
| # FONCTION PRINCIPALE DE DÉTECTION | |
| # ============================================ | |
| def detect_cloth(image): | |
| """Détecte type, couleur, style et saison d'un vêtement""" | |
| print("\n" + "="*60) | |
| print("🔍 NOUVELLE DÉTECTION") | |
| print("="*60) | |
| try: | |
| # Validation | |
| if image is None: | |
| error_result = {"error": "Aucune image fournie"} | |
| print(f"❌ {error_result['error']}") | |
| return error_result | |
| # Conversion PIL | |
| if not isinstance(image, Image.Image): | |
| image = Image.fromarray(image) | |
| img = image.convert('RGB') | |
| w, h = img.size | |
| print(f"📸 Image: {w}x{h} pixels") | |
| # YOLO Detection | |
| print("🤖 Détection YOLO...") | |
| results = yolo_model(img, verbose=False)[0] | |
| boxes = results.boxes | |
| if not boxes or len(boxes) == 0: | |
| error_result = {"error": "Aucun vêtement détecté"} | |
| print(f"❌ {error_result['error']}") | |
| return error_result | |
| best_idx = boxes.conf.argmax() | |
| confidence = float(boxes.conf[best_idx]) | |
| print(f"✅ Confiance: {confidence:.2%}") | |
| # Extraction | |
| x1, y1, x2, y2 = map(int, boxes.xyxy[best_idx]) | |
| x1, y1 = max(0, x1), max(0, y1) | |
| x2, y2 = min(w, x2), min(h, y2) | |
| if x2 <= x1 or y2 <= y1: | |
| error_result = {"error": "Boîte de détection invalide"} | |
| print(f"❌ {error_result['error']}") | |
| return error_result | |
| cropped = img.crop((x1, y1, x2, y2)) | |
| # Couleur | |
| print("🎨 Extraction couleur...") | |
| hex_color = get_dominant_color(cropped) | |
| print(f"✅ Couleur: {hex_color}") | |
| # Style & Saison | |
| print("👔 Classification...") | |
| resized = cropped.resize((224, 224)) | |
| arr = np.array(resized) / 255.0 | |
| arr = np.expand_dims(arr, axis=0) | |
| style_pred, season_pred = style_model.predict(arr, verbose=0) | |
| styles = ["casual", "formal", "sport"] | |
| seasons = ["summer", "winter", "fall", "spring"] | |
| style = styles[np.argmax(style_pred)] | |
| season = seasons[np.argmax(season_pred)] | |
| style_conf = float(np.max(style_pred)) | |
| season_conf = float(np.max(season_pred)) | |
| print(f"✅ Style: {style} ({style_conf:.2%})") | |
| print(f"✅ Saison: {season} ({season_conf:.2%})") | |
| # Type | |
| type_vetement = results.names[int(boxes.cls[best_idx])] | |
| print(f"✅ Type: {type_vetement}") | |
| # Résultat | |
| result = { | |
| "success": True, | |
| "detection": { | |
| "type": type_vetement, | |
| "color": hex_color, | |
| "style": style, | |
| "season": season | |
| }, | |
| "confidence": { | |
| "detection": f"{confidence:.2%}", | |
| "style": f"{style_conf:.2%}", | |
| "season": f"{season_conf:.2%}" | |
| } | |
| } | |
| print("="*60) | |
| print("✅ DÉTECTION RÉUSSIE") | |
| print("="*60) | |
| print(json.dumps(result, indent=2)) | |
| return result | |
| except Exception as e: | |
| error_result = {"error": f"Erreur: {str(e)}"} | |
| print(f"❌ {error_result['error']}") | |
| import traceback | |
| traceback.print_exc() | |
| return error_result | |
| # ============================================ | |
| # INTERFACE GRADIO 5.x - AVEC API GARANTIE | |
| # ============================================ | |
| # ✅ SOLUTION : Utiliser gr.Interface qui expose automatiquement l'API REST | |
| # gr.Interface garantit que l'API est accessible via /api/predict dans Gradio 5.x | |
| demo = gr.Interface( | |
| fn=detect_cloth, | |
| inputs=gr.Image( | |
| type="pil", | |
| label="📸 Photo du vêtement" | |
| ), | |
| outputs=gr.JSON( | |
| label="📊 Résultat de la détection" | |
| ), | |
| title="🧥 Labasni - Détection de Vêtements", | |
| description=""" | |
| ## 👔 Labasni - Détection Automatique de Vêtements | |
| Cette API utilise l'intelligence artificielle pour analyser vos photos de vêtements et détecter : | |
| - 👕 **Type** : Haut, pantalon, robe, chaussures, etc. | |
| - 🎨 **Couleur dominante** : Code hexadécimal de la couleur principale | |
| - 👔 **Style** : Casual, Formel, Sport | |
| - 🌤️ **Saison** : Été, Hiver, Automne, Printemps | |
| ## 🚀 Comment utiliser | |
| 1. **Via l'interface** : Uploadez une image ci-dessous | |
| 2. **Via l'API** : Utilisez l'endpoint `/api/predict` | |
| ## 📡 Exemple d'appel API | |
| ```bash | |
| curl -X POST "https://syleto-labasni-detection.hf.space/api/predict" \\ | |
| -H "Content-Type: application/json" \\ | |
| -d '{"data": ["<BASE64_IMAGE>"]}' | |
| ``` | |
| ## ⚙️ Modèles utilisés | |
| - **YOLO** (best.pt) : Détection des vêtements | |
| - **MobileNetV2** : Classification style/saison | |
| - **K-Means** : Extraction couleur dominante | |
| --- | |
| **Développé par** : Aziz Ben Ammar & Équipe Labasni | |
| **Version** : 1.0.0 | |
| **Contact** : [Hugging Face Space](https://huggingface.co/spaces/Syleto/labasni-detection) | |
| """, | |
| theme=gr.themes.Soft(), | |
| api_name="predict" # ✅ Expose l'endpoint /api/predict | |
| ) | |
| # ============================================ | |
| # LANCEMENT | |
| # ============================================ | |
| if __name__ == "__main__": | |
| print("\n" + "="*60) | |
| print("🌐 LANCEMENT DE L'INTERFACE GRADIO") | |
| print("="*60 + "\n") | |
| # ✅ gr.Interface expose automatiquement l'API REST dans Gradio 5.x | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| show_error=True, | |
| share=False | |
| ) | |