File size: 9,300 Bytes
083c3f2
4877f61
0330b43
4877f61
 
0330b43
4877f61
0330b43
19df6ba
0330b43
 
19df6ba
0330b43
 
 
 
 
a8313d9
a4eb225
19df6ba
0330b43
 
 
 
 
 
 
 
 
4877f61
 
19df6ba
4877f61
a4eb225
19df6ba
a4eb225
 
 
 
4877f61
 
 
19df6ba
4877f61
a4eb225
19df6ba
a4eb225
 
 
 
4877f61
 
 
 
 
4ac9342
4877f61
 
 
 
 
8dddc4d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4877f61
 
19df6ba
 
 
 
4877f61
 
0330b43
4877f61
19df6ba
 
8535e1d
 
41e226b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8535e1d
4877f61
 
 
 
 
4e31076
19df6ba
4877f61
19df6ba
 
4e31076
 
 
 
a4eb225
4e31076
 
19df6ba
 
 
 
 
 
 
 
 
 
 
 
 
7d4d5f3
4e31076
 
 
 
19df6ba
4e31076
 
 
 
 
 
 
 
 
 
 
 
 
 
19df6ba
 
 
 
4e31076
4877f61
 
c5d1822
d8dbe79
19df6ba
1d0174b
6c64113
 
 
19df6ba
6c64113
1d0174b
bb2c8a0
6c64113
1d0174b
087b55e
bf72f4e
1d0174b
 
 
 
 
 
 
 
6c64113
1d0174b
6c64113
 
 
 
 
1d0174b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
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 ---
@st.cache_data(ttl=600)
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 ---
@st.cache_resource(ttl=3600)
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")