Spaces:
Runtime error
Runtime error
| import streamlit as st | |
| import pandas as pd | |
| import boto3 | |
| import os | |
| from datetime import datetime | |
| from dotenv import load_dotenv | |
| import plotly.express as px | |
| # --- CHARGEMENT DES SECRETS --- | |
| load_dotenv() | |
| # S3 / Hugging Face secrets | |
| AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID") | |
| AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY") | |
| AWS_DEFAULT_REGION = os.getenv("AWS_DEFAULT_REGION", "eu-west-3") | |
| S3_BUCKET_NAME = os.getenv("S3_BUCKET_NAME") | |
| HF_API_TOKEN = os.getenv("HF_API_TOKEN") | |
| # --- INITIALISATION CLIENT S3 --- | |
| s3 = None | |
| if AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY and S3_BUCKET_NAME: | |
| s3 = boto3.client( | |
| "s3", | |
| aws_access_key_id=AWS_ACCESS_KEY_ID, | |
| aws_secret_access_key=AWS_SECRET_ACCESS_KEY, | |
| region_name=AWS_DEFAULT_REGION | |
| ) | |
| # --- CACHE POUR LES DONNÉES --- | |
| def load_csv_from_s3(_s3_client, bucket_name, key): | |
| local_path = f"/tmp/{key.split('/')[-1]}" | |
| try: | |
| _s3_client.download_file(bucket_name, key, local_path) | |
| return pd.read_csv(local_path) | |
| except Exception as e: | |
| st.error(f"Erreur lors du téléchargement depuis S3 : {e}") | |
| return pd.DataFrame() | |
| # --- CACHE POUR LES IMAGES --- | |
| def load_image_from_s3(_s3_client, bucket_name, key): | |
| local_path = f"/tmp/{key.split('/')[-1]}" | |
| try: | |
| _s3_client.download_file(bucket_name, key, local_path) | |
| return local_path | |
| except Exception as e: | |
| st.warning(f"Impossible de charger l'image depuis S3 : {e}") | |
| return None | |
| # --- CONFIG PAGE --- | |
| st.set_page_config(page_title="Dashboard Fraude", page_icon="🚨", layout="wide") | |
| # --- SIDEBAR NAVIGATION --- | |
| pages = ["Accueil", "Dataset principal", "Suivi des fraudes"] | |
| selected_page = st.sidebar.radio("Navigation", pages) | |
| # --- PAGE 1 : ACCUEIL / ARCHITECTURE --- | |
| if selected_page == "Accueil": | |
| st.title("🚨 Dashboard de suivi du projet de détection de fraude") | |
| st.markdown( | |
| """ | |
| <div style='font-size:18px; line-height:1.6;'> | |
| <b>Bienvenue sur le dashboard de suivi du projet de détection automatisée des fraudes bancaires</b>.<br><br> | |
| Ce dashboard a pour objectif de présenter le contexte et les chiffres relatifs aux fraudes, ainsi que | |
| la démarche de détection automatisée mise en place.<br><br> | |
| 📊 En janvier 2025, le <b>Sous-Gouverneur de la Banque de France</b> a présenté les chiffres officiels | |
| de la fraude sur le premier semestre 2024. | |
| 👉 Consultez le rapport complet <a href='https://www.banque-france.fr/fr/interventions-gouverneur/presentation-des-statistiques-de-fraude-au-1er-semestre-2024-par-losmp#:~:text=Dans%20ce%20contexte%20de%20progression,fraude%20au%20premier%20semestre%202023' target='_blank' style='color:#1E90FF; text-decoration:none;'>ici</a>.<br><br> | |
| <b>Chiffres clés :</b> | |
| <ul> | |
| <li>Montant total fraudé : <b>584,6 millions d'euros</b> sur le premier semestre</li> | |
| <li>Part des paiements et retraits par carte : <b>43%</b> des montants totaux fraudés (en légère progression par rapport à 2023 : 41,5%)</li> | |
| <li>Tendance générale : légère baisse de <b>1%</b> par rapport à l’année précédente</li> | |
| </ul> | |
| L'enjeu est crucial pour les institutions financières afin de protéger leurs clients | |
| et de minimiser les pertes financières liées à ces activités frauduleuses.<br><br> | |
| Ce projet vise à développer un système de détection automatisée des paiements frauduleux | |
| afin de proposer des solutions complémentaires aux systèmes existants et ce tableau de bord vous permettra de suivre la démarche initiée | |
| et de visualiser les paiements frauduleux au fil du temps. | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| st.markdown("### Architecture du projet") | |
| architecture_img = None | |
| if s3: | |
| architecture_img = load_image_from_s3(s3, S3_BUCKET_NAME, "images/architecture.png") | |
| if architecture_img: | |
| st.image(architecture_img, use_container_width=False) | |
| else: | |
| st.info("Placez `architecture.png` en local ou sur S3 pour affichage.") | |
| st.markdown("---") | |
| st.markdown( | |
| """ | |
| <div style="font-size:18px; line-height:1.6;"> | |
| <b>Les principes clés de l'architecture mise en place :</b> | |
| <ul> | |
| <li><b>Entraînement initial du modèle</b> sur le dataset fourni par Jedha, permettant de disposer d'un modèle de base fiable.</li> | |
| <li><b>Stockage et gestion des modèles</b> avec MLflow et AWS S3, garantissant la traçabilité et la persistance des artefacts.</li> | |
| <li><b>Déploiement du modèle via FastAPI</b>, offrant des prédictions en temps réel pour les transactions entrantes.</li> | |
| <li><b>Conteneurisation avec Docker</b>, permettant d'isoler l'environnement, garantir la reproductibilité et faciliter le déploiement du modèle sur différents environnements (local, cloud, Hugging Face Spaces, etc.).</li> | |
| <li><b>Orchestration avec Airflow</b>, exécutant les tâches de prédiction 5 fois par minute pour assurer une détection quasi instantanée.</li> | |
| <li><b>Stockage des prédictions et des requêtes API</b> dans une base de données PostgreSQL, permettant un audit et une analyse historique.</li> | |
| <li><b>Notification quotidienne par email</b> des fraudes détectées la veille, fournissant aux équipes métier un résumé et les transactions concernées.</li> | |
| <li><b>Stockage hebdomadaire des données de prédiction</b> dans un bucket S3, assurant la sauvegarde et la disponibilité des données pour des analyses futures.</li> | |
| </ul> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| # --- PAGE 2 : DATASET PRINCIPAL --- | |
| elif selected_page == "Dataset principal": | |
| st.header("Exploration du dataset principal") | |
| # Chargement du dataset | |
| try: | |
| df = load_csv_from_s3(s3, S3_BUCKET_NAME, "data/fraudTest.csv") | |
| st.subheader("Aperçu des données") | |
| st.dataframe(df.head(5)) | |
| except Exception as e: | |
| st.error(f"Erreur lors du chargement du dataset : {e}") | |
| st.markdown("---") | |
| # Répartition des paiements frauduleux | |
| try: | |
| fraud_counts = df["is_fraud"].value_counts() | |
| fraud_percent = df["is_fraud"].value_counts(normalize=True) * 100 | |
| df_plot = pd.DataFrame({ | |
| "Fraude": fraud_counts.index.astype(str), | |
| "Nombre": fraud_counts.values, | |
| "Pourcentage": fraud_percent.values | |
| }) | |
| color_map = {'0': 'royalblue', '1': 'crimson'} | |
| fig = px.pie( | |
| df_plot, names='Fraude', values='Nombre', color='Fraude', color_discrete_map=color_map | |
| ) | |
| fig.update_traces(textinfo='label+percent+value', pull=[0.05]*len(df_plot)) | |
| st.plotly_chart(fig, use_container_width=True) | |
| st.subheader(f"👉 Taux de fraude : **{df['is_fraud'].mean()*100:.2f}%**") | |
| except Exception as e: | |
| st.error(f"Erreur lors de la visualisation de la répartition des fraudes : {e}") | |
| st.markdown("---") | |
| # Image des performances du modèle | |
| st.subheader("Voici les performances du modèle de prédiction utilisé") | |
| try: | |
| perf_img = load_image_from_s3(s3, S3_BUCKET_NAME, "images/aucpr.png") | |
| if perf_img: | |
| st.image(perf_img, use_container_width=False) | |
| except Exception as e: | |
| st.error(f"Erreur lors du chargement de l'image des performances : {e}") | |
| st.markdown("---") | |
| # Image des features principales | |
| st.subheader("Regardons également les principales features prises en compte par le modèle prédictif") | |
| try: | |
| features_img = load_image_from_s3(s3, S3_BUCKET_NAME, "images/features.png") | |
| if features_img: | |
| st.image(features_img, use_container_width=False) | |
| except Exception as e: | |
| st.error(f"Erreur lors du chargement de l'image des features : {e}") | |
| # --- PAGE 3 : REPORTING S3 --- | |
| elif selected_page == "Suivi des fraudes": | |
| st.header("Reporting des fraudes détectées") | |
| s3_key = "backups/all_payments.csv" | |
| if s3: | |
| try: | |
| df_s3 = load_csv_from_s3(s3, S3_BUCKET_NAME, s3_key) | |
| if not df_s3.empty: | |
| # Filtrer les fraudes | |
| df_fraudes = df_s3[df_s3["predicted_fraud"] == 1] | |
| if not df_fraudes.empty: | |
| st.subheader("Visualisation") | |
| st.dataframe(df_fraudes) | |
| total_fraudes = df_fraudes.shape[0] | |
| montant_total = df_fraudes["amt"].sum() | |
| st.markdown( | |
| f"<h3>Grâce au modèle, un total de <span style='color:red;'>{total_fraudes}</span> fraudes a été détecté à ce jour pour un montant de <span style='color:red;'>{montant_total:,.2f} €</span></h3>", | |
| unsafe_allow_html=True | |
| ) | |
| else: | |
| st.info("Aucune fraude détectée dans le dataset.") | |
| else: | |
| st.warning("Le fichier S3 est vide.") | |
| except Exception as e: | |
| st.error(f"Impossible de charger le fichier S3 : {e}") | |
| else: | |
| st.error("Connexion S3 non configurée") | |