import os
import sys
import requests
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import io
import base64
import pickle
# Configuration de l'API
# prod docker
API_BASE_URL = os.getenv("MULTISEG_API_BASE_URL", "http://127.0.0.1:8080/api")
# test local
# API_BASE_URL = os.getenv("MULTISEG_API_BASE_URL", "http://127.0.0.1:8000") # ← Port 8000 au lieu de 8080
# Import des fonctions utils pour l'affichage local
sys.path.append('/app')
# APRÈS (pour test local)
sys.path.append('.')
from utils.utils import colorize_mask
# Configuration de la page
st.set_page_config(
page_title="Multi-Class Segmentation",
page_icon="🚗",
layout="wide"
)
# CSS personnalisé
st.markdown("""
""", unsafe_allow_html=True)
# En-tête principal
st.markdown("""
🚗 Segmentation Multi-Classes
Système de segmentation sémantique pour véhicules autonomes
""", unsafe_allow_html=True)
# Initialisation des états
if "prediction_result" not in st.session_state:
st.session_state.prediction_result = None
if "selected_image" not in st.session_state:
st.session_state.selected_image = None
if "uploaded_file" not in st.session_state:
st.session_state.uploaded_file = None
def reset_state():
"""Reset des états de session"""
st.session_state.prediction_result = None
st.session_state.selected_image = None
st.session_state.uploaded_file = None
def get_model_info():
"""Récupère les informations du modèle"""
try:
response = requests.get(f"{API_BASE_URL}/models")
if response.status_code == 200:
return response.json()
else:
st.error(f"Erreur lors de la récupération des infos modèle: {response.status_code}")
return None
except Exception as e:
st.error(f"Erreur de connexion à l'API: {e}")
return None
def get_sample_images():
"""Récupère la liste des images d'exemple"""
try:
response = requests.get(f"{API_BASE_URL}/sample-images")
if response.status_code == 200:
return response.json()
else:
st.error(f"Erreur lors de la récupération des images: {response.status_code}")
return None
except Exception as e:
st.error(f"Erreur de connexion à l'API: {e}")
return None
def predict_sample_image(filename):
"""Lance une prédiction sur une image d'exemple"""
try:
# CORRECTION: Envoyer en JSON au lieu de form data
data = {"filename": filename}
response = requests.post(
f"{API_BASE_URL}/predict-sample",
json=data, # ← Changé de 'data=' à 'json='
headers={"Content-Type": "application/json"} # ← Ajout du header explicite
)
if response.status_code == 200:
return response.json()
else:
st.error(f"Erreur API: {response.status_code} - {response.text}")
return None
except Exception as e:
st.error(f"Erreur lors de la prédiction: {e}")
return None
def predict_uploaded_image(uploaded_file):
"""Lance une prédiction sur une image uploadée"""
try:
files = {"file": (uploaded_file.name, uploaded_file.getvalue(), uploaded_file.type)}
response = requests.post(f"{API_BASE_URL}/predict-upload", files=files)
if response.status_code == 200:
return response.json()
else:
st.error(f"Erreur API: {response.status_code} - {response.text}")
return None
except Exception as e:
st.error(f"Erreur lors de la prédiction: {e}")
return None
def display_segmentation_plots(fig):
"""Affiche chaque subplot séparément dans des colonnes"""
if fig is None:
st.warning("Aucune figure de segmentation disponible")
return
axes = fig.get_axes()
num_plots = len(axes)
st.markdown("### 🎨 Résultat de la Segmentation")
# Créer les colonnes selon le nombre de subplots
if num_plots <= 4:
cols = st.columns(num_plots)
else:
cols = st.columns(4) # Maximum 4 colonnes
for i, ax in enumerate(axes):
col_idx = i % len(cols)
with cols[col_idx]:
# Récupérer le titre existant
title = ax.get_title()
# st.markdown(f"**{title}:**")
# Créer une figure individuelle avec ce subplot
individual_fig, individual_ax = plt.subplots(figsize=(6, 6))
# Copier toutes les images de l'axe original
for image in ax.get_images():
individual_ax.imshow(
image.get_array(),
cmap=image.get_cmap() if image.get_cmap() else None,
alpha=image.get_alpha() if image.get_alpha() else None,
vmin=image.get_clim()[0] if image.get_clim() else None,
vmax=image.get_clim()[1] if image.get_clim() else None
)
# Copier les propriétés de l'axe
individual_ax.set_title(title)
individual_ax.axis('off')
# Ajuster la mise en page
individual_fig.tight_layout()
# Afficher dans Streamlit
st.pyplot(individual_fig)
# Libérer la mémoire
plt.close(individual_fig)
# Fermer la figure originale pour libérer la mémoire
plt.close(fig)
def display_prediction_stats_with_chart(stats, model_info):
"""Affiche les statistiques avec un graphique en barres"""
st.markdown("### 📊 Statistiques de Segmentation")
if not stats:
st.warning("Aucune statistique disponible")
return
# Ratio 1:2 pour donner plus de place au graphique
col1, col2 = st.columns([1, 2])
# Colonne 1: Cartes de statistiques compactes avec carrés colorés
with col1:
st.markdown("**Détails par classe:**")
# Récupérer les couleurs des classes pour les carrés
class_colors_dict = {}
if model_info and 'class_colors' in model_info and 'class_names' in model_info:
model_class_names = model_info['class_names']
model_class_colors = model_info['class_colors']
for class_name in stats.keys():
try:
idx = model_class_names.index(class_name)
color = model_class_colors[idx]
# Convertir en hex pour CSS
color_hex = f"#{color[0]:02x}{color[1]:02x}{color[2]:02x}"
class_colors_dict[class_name] = color_hex
except (ValueError, IndexError):
# Couleur par défaut si pas trouvée
class_colors_dict[class_name] = "#808080"
for class_name, data in stats.items():
# Récupérer la couleur pour cette classe
color_hex = class_colors_dict.get(class_name, "#808080")
# ✨ NOUVEAU: Carré coloré + nom de classe
st.markdown(f"""