CoolFace
Apppublic

Kuzan2077/DeepLearningNgadena

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
app.py642 linesDownload Raw Back to root
1import streamlit as st2import pandas as pd 3import pickle as pk4import matplotlib.pyplot as plt5from sklearn.preprocessing import StandardScaler6import seaborn as sns7import numpy as np8import os 9from dotenv import load_dotenv10load_dotenv()11from groq import Groq12import tensorflow as tf13 14@st.cache_data15def load_data(dataset):16    df = pd.read_csv(dataset)17    return df18 19# Fonction pour effectuer le preprocessing20@st.cache_data21def preprocess_data(df):22    # Créer une copie pour éviter de modifier les données brutes23    df_processed = df.copy()24 25    # Étape 1 : Supprimer les doublons (si nécessaire)26    duplicate_count = df_processed.duplicated().sum()27    if duplicate_count > 0:28        df_processed = df_processed.drop_duplicates()29 30    # Étape 2 : Traiter les outliers (par exemple, les limiter avec IQR)31    numerical_cols = df_processed.select_dtypes(include=['int64', 'float64']).columns.tolist()32    for col in numerical_cols:33        Q1 = df_processed[col].quantile(0.25)34        Q3 = df_processed[col].quantile(0.75)35        IQR = Q3 - Q136        lower_bound = Q1 - 1.5 * IQR37        upper_bound = Q3 + 1.5 * IQR38        # Limiter les valeurs aux bornes39        df_processed[col] = df_processed[col].clip(lower=lower_bound, upper=upper_bound)40 41    # Étape 3 : Encoder les colonnes catégoriques (par exemple, Gender)42    if 'Gender' in df_processed.columns:43        df_processed['Gender'] = df_processed['Gender'].astype(int)44 45    # Étape 4 : Normalisation des features numériques46    scaler = StandardScaler()47    cols_to_scale = ['Age', 'Annual Salary', 'Credit Card Debt', 'Net Worth']48    df_processed[cols_to_scale] = scaler.fit_transform(df_processed[cols_to_scale])49 50    return df_processed, scaler51 52st.sidebar.image('images\R (7).jpeg', width=250)53 54def main():55    # CSS pour le thème noir et or56    st.markdown("""57    <style>58    /* Fond global */59    .stApp {60        background-color: #1A1A1A;61        color: #F5F5F5;62    }63 64    /* Sidebar */65    .css-1d391kg {  /* Classe de la sidebar dans Streamlit */66        background-color: #1A1A1A;67        color: #F5F5F5;68    }69    .css-1d391kg .sidebar-content {70        background-color: #1A1A1A;71    }72    .sidebar .sidebar-content h2 {73        color: #F5F5F5;74        font-size: 24px;75        font-weight: bold;76        background: linear-gradient(90deg, #FFD700, #DAA520);77        -webkit-background-clip: text;78        -webkit-text-fill-color: transparent;79        margin-bottom: 20px;80    }81 82    /* Style des boutons dans la sidebar */83    .sidebar .stButton > button {84        width: 100%;85        padding: 12px 20px;86        margin: 10px 0;87        border-radius: 8px;88        font-size: 16px;89        font-weight: bold;90        background-color: #2A2A2A;91        color: #F5F5F5;92        border: 2px solid transparent;93        border-image: linear-gradient(90deg, #FFD700, #DAA520) 1;94        transition: all 0.3s ease-in-out;95        text-align: left;96    }97    .sidebar .stButton > button:hover {98        background-color: #4A3C1A;99        color: #FFFFFF;100        border-image: linear-gradient(90deg, #FFD700, #DAA520) 1;101        transform: scale(1.02);102    }103    .selected > button {104        background-color: #4A3C1A;105        color: #FFFFFF;106        border-image: linear-gradient(90deg, #FFD700, #DAA520) 1;107    }108 109    /* Style des boutons dans le contenu principal */110    .stButton > button {111        padding: 12px 24px;112        border-radius: 8px;113        font-size: 16px;114        font-weight: bold;115        background-color: #2A2A2A;116        color: #F5F5F5;117        border: 2px solid transparent;118        border-image: linear-gradient(90deg, #FFD700, #DAA520) 1;119        transition: all 0.3s ease-in-out;120        margin: 10px 0;121    }122    .stButton > button:hover {123        background-color: #4A3C1A;124        color: #FFFFFF;125        border-image: linear-gradient(90deg, #FFD700, #DAA520) 1;126        transform: scale(1.02);127    }128 129    /* Style des titres principaux */130    h1, h2, h3 {131        color: #F5F5F5;132        font-weight: bold;133        margin-bottom: 20px;134    }135    h1 {136        background: linear-gradient(90deg, #FFD700, #DAA520);137        -webkit-background-clip: text;138        -webkit-text-fill-color: transparent;139    }140    h2 {141        border-bottom: 2px solid;142        border-image: linear-gradient(90deg, #FFD700, #DAA520) 1;143        padding-bottom: 10px;144    }145    h3 {146        color: #F5F5F5;147    }148 149    /* Style des conteneurs pour un rendu épuré */150    .stMarkdown, .stText, .stDataFrame, .stWarning, .stSuccess, .stInfo {151        background-color: #252525;152        border-radius: 8px;153        padding: 15px;154        margin: 10px 0;155        border: 1px solid #3A3A3A;156    }157 158    /* Style des selectbox pour qu'ils s'intègrent au thème */159    .stSelectbox > div > div {160        background-color: #2A2A2A;161        color: #F5F5F5;162        border-radius: 8px;163        border: 2px solid;164        border-image: linear-gradient(90deg, #FFD700, #DAA520) 1;165        transition: all 0.3s ease-in-out;166    }167    .stSelectbox > div > div:hover {168        background-color: #4A3C1A;169    }170 171    /* Style des sliders */172    .stSlider > div > div > div {173        background: linear-gradient(90deg, #FFD700, #DAA520);174    }175 176    /* Style des éléments de texte */177    p, div, span {178        color: #F5F5F5;179    }180 181    /* Style des tableaux */182    .stDataFrame table {183        background-color: #2A2A2A;184        color: #F5F5F5;185    }186 187    /* Style des messages d'alerte */188    .stSuccess {189        background-color: #2A3C1A;190        color: #F5F5F5;191    }192    .stWarning {193        background-color: #4A3C1A;194        color: #F5F5F5;195    }196    .stInfo {197        background-color: #2A2A3A;198        color: #F5F5F5;199    }200 201    /* Style des onglets */202    .stTabs [role="tab"] {203        background-color: #2A2A2A;204        color: #F5F5F5;205        border: 2px solid transparent;206        border-image: linear-gradient(90deg, #FFD700, #DAA520) 1;207        border-radius: 8px 8px 0 0;208        padding: 10px 20px;209        margin-right: 5px;210        transition: all 0.3s ease-in-out;211    }212    .stTabs [role="tab"]:hover {213        background-color: #4A3C1A;214        color: #FFFFFF;215    }216    .stTabs [role="tab"][aria-selected="true"] {217        background-color: #4A3C1A;218        color: #FFFFFF;219        border-bottom: none;220    }221    .stTabs [data-baseweb="tab-panel"] {222        background-color: #252525;223        border-radius: 0 8px 8px 8px;224        padding: 15px;225        border: 1px solid #3A3A3A;226    }227    </style>228    """, unsafe_allow_html=True)229 230    # Initialiser l'état de la sélection dans session_state231    if 'selected_option' not in st.session_state:232        st.session_state.selected_option = "🏠 Accueil"233    234    # Initialiser l'historique des prédictions235    if 'prediction_history' not in st.session_state:236        st.session_state.prediction_history = []237 238    # Liste des options du menu239    menu_options = ["🏠 Accueil", "🚘 Car Purchase Data", "📶 Autre Dataset ❓", "🦾 Chatbot"]240 241    # Afficher les options dans la sidebar avec des boutons242    st.sidebar.header("Menu")243 244    for option in menu_options:245        container = st.sidebar.container()246        with container:247            button_style = "selected" if st.session_state.selected_option == option else ""248            if st.button(option, key=option, help=f"Aller à {option}"):249                st.session_state.selected_option = option250 251    # Récupérer l'option sélectionnée252    choice = st.session_state.selected_option253 254    # Charger les données une seule fois pour "Car Purchase Data"255    data = load_data('data/Car_Purchasing_Data.csv')256 257    # Appliquer le preprocessing une fois pour "Car Purchase Data"258    data_processed, scaler = preprocess_data(data)259 260    # Charger le modèle ANN et le scaler261    with open('ann_car_purchase_model.pkl', 'rb') as f:262        model = pk.load(f)263    with open('scaler.pkl', 'rb') as f:264        ann_scaler = pk.load(f)265 266    # Logique pour chaque section267    if choice == "🏠 Accueil":268        with st.container():269            st.markdown('<h1 style="text-align: center;">Application Streamlit Vente de Voiture</h1>', unsafe_allow_html=True)270            st.write("Bienvenue sur la page d'accueil ! Prédis le montant d'achat d'une voiture.")271            st.write("Parcourez l'application de fond en comble, vous ne serez pas deçu😉")272    273    elif choice == "🚘 Car Purchase Data":274        with st.container():275            st.subheader('Traitement de Car Purchasing Data')276 277            # Créer les onglets278            tab1, tab2, tab3, tab4 = st.tabs(["📊 Données", "📈 Visualisation", "🔮 Prédiction", "📜 Historique"])279 280            # Onglet 1 : Données281            with tab1:282                st.write("### Données")283                st.info("Les données affichées ci-dessous sont les données par défaut (Car_Purchasing_Data.csv). Vous pouvez charger votre propre dataset CSV pour remplacer ces données.")284                285                # File uploader pour charger un dataset personnalisé286                uploaded_file = st.file_uploader("Chargez un fichier CSV", type=["csv"], key="car_purchase_uploader")287                288                # Colonnes attendues289                expected_columns = ['Customer Name', 'Customer e-mail', 'Country', 'Gender', 'Age', 290                                  'Annual Salary', 'Credit Card Debt', 'Net Worth', 'Car Purchase Amount']291                292                # Vérifier si un dataset personnalisé a été chargé293                if uploaded_file is not None:294                    try:295                        custom_df = pd.read_csv(uploaded_file)296                        # Vérifier les colonnes297                        if list(custom_df.columns) != expected_columns:298                            st.error(f"Erreur : Le dataset chargé ne correspond pas au format attendu. Les colonnes attendues sont : {', '.join(expected_columns)}. Colonnes trouvées : {', '.join(custom_df.columns)}.")299                            st.session_state.custom_df_processed = None300                            st.session_state.custom_scaler = None301                        else:302                            # Appliquer le preprocessing au dataset chargé303                            custom_df_processed, custom_scaler = preprocess_data(custom_df)304                            st.session_state.custom_df_processed = custom_df_processed305                            st.session_state.custom_scaler = custom_scaler306                            st.success("Dataset chargé avec succès !")307                    except Exception as e:308                        st.error(f"Erreur lors du chargement du fichier : {e}")309                        st.session_state.custom_df_processed = None310                        st.session_state.custom_scaler = None311                312                # Déterminer quel dataset utiliser313                if 'custom_df_processed' in st.session_state and st.session_state.custom_df_processed is not None:314                    active_df = st.session_state.custom_df_processed315                    st.write("#### Aperçu du dataset chargé")316                else:317                    active_df = data_processed318                    st.write("#### Aperçu du dataset par défaut")319                320                st.dataframe(active_df.head())321                st.write("#### Statistiques descriptives")322                st.write(active_df.describe())323 324            # Onglet 2 : Visualisation325            with tab2:326                st.write("### Visualisation des données")327                328                # Déterminer quel dataset utiliser329                if 'custom_df_processed' in st.session_state and st.session_state.custom_df_processed is not None:330                    active_df = st.session_state.custom_df_processed331                    st.write("Visualisations basées sur le dataset chargé.")332                else:333                    active_df = data_processed334                    st.write("Visualisations basées sur le dataset par défaut.")335 336                viz_option = st.selectbox(337                    "Choisis un type de visualisation :",338                    ["Matrice de corrélation", "Boxplot", "Scatterplot", "Histogramme", "Pairplot"]339                )340 341                numerical_cols = ['Age', 'Annual Salary', 'Credit Card Debt', 'Net Worth', 'Car Purchase Amount']342 343                if viz_option == "Matrice de corrélation":344                    st.write("#### Matrice de corrélation")345                    plt.figure(figsize=(8, 6))346                    corr = active_df[numerical_cols].corr()347                    sns.heatmap(corr, annot=True, cmap='coolwarm', vmin=-1, vmax=1)348                    plt.title("Matrice de corrélation")349                    st.pyplot(plt)350 351                elif viz_option == "Boxplot":352                    st.write("#### Boxplot")353                    col = st.selectbox("Choisis une variable :", numerical_cols)354                    plt.figure(figsize=(8, 6))355                    sns.boxplot(x=active_df[col])356                    plt.title(f"Boxplot de {col}")357                    st.pyplot(plt)358 359                elif viz_option == "Scatterplot":360                    st.write("#### Scatterplot")361                    x_col = st.selectbox("Choisis la variable X :", numerical_cols, index=1)362                    y_col = st.selectbox("Choisis la variable Y :", numerical_cols, index=4)363                    plt.figure(figsize=(8, 6))364                    sns.scatterplot(x=active_df[x_col], y=active_df[y_col], hue=active_df['Gender'])365                    plt.title(f"{x_col} vs {y_col}")366                    st.pyplot(plt)367 368                elif viz_option == "Histogramme":369                    st.write("#### Histogramme")370                    col = st.selectbox("Choisis une variable :", numerical_cols)371                    plt.figure(figsize=(8, 6))372                    sns.histplot(active_df[col], bins=20, kde=True)373                    plt.title(f"Distribution de {col}")374                    st.pyplot(plt)375 376                elif viz_option == "Pairplot":377                    st.write("#### Pairplot")378                    pairplot = sns.pairplot(active_df[numerical_cols])379                    st.pyplot(plt)380 381            # Onglet 3 : Prédiction382            with tab3:383                st.write("### Prédire le montant d'achat d'une voiture")384                385                # Déterminer quel scaler utiliser386                if 'custom_scaler' in st.session_state and st.session_state.custom_scaler is not None:387                    active_scaler = st.session_state.custom_scaler388                    st.write("Prédictions basées sur le dataset chargé.")389                else:390                    active_scaler = ann_scaler391                    st.write("Prédictions basées sur le dataset par défaut.")392 393                # Sliders pour ajuster les entrées394                st.write("Ajuste les valeurs pour prédire le montant d'achat :")395                age = st.slider("Âge", 20, 70, 40, key="age_slider")396                annual_salary = st.slider("Salaire Annuel ($)", 30000, 100000, 60000, step=1000, key="salary_slider")397                credit_card_debt = st.slider("Dette Carte de Crédit ($)", 0, 20000, 10000, step=500, key="debt_slider")398                net_worth = st.slider("Patrimoine Net ($)", 0, 1000000, 400000, step=10000, key="net_worth_slider")399                gender = st.slider("Genre (0 pour Femme, 1 pour Homme)", 0, 1, 0, key="gender_slider")400 401                # Bouton pour déclencher la prédiction402                if st.button("Faire une prédiction"):403                    # Préparer les données d'entrée404                    input_data = np.array([[gender, age, annual_salary, credit_card_debt, net_worth]])405                    # Normaliser les entrées (sauf Gender)406                    input_features = input_data[:, 1:]  # Exclure Gender407                    input_features_scaled = active_scaler.transform(input_features)408                    # Recomposer l'entrée avec Gender409                    input_scaled = np.hstack([input_data[:, :1], input_features_scaled])410                    411                    # Faire la prédiction avec le modèle ANN412                    prediction = model.predict(input_scaled, verbose=0)[0][0]413 414                    # Afficher la prédiction415                    st.write("#### Résultat de la prédiction :")416                    st.write(f"**Montant estimé : ${prediction:,.2f}**")417 418                    # Sauvegarder la prédiction dans l'historique419                    prediction_entry = {420                        'Âge': age,421                        'Salaire Annuel ($)': annual_salary,422                        'Dette Carte de Crédit ($)': credit_card_debt,423                        'Patrimoine Net ($)': net_worth,424                        'Genre': 'Femme' if gender == 0 else 'Homme',425                        'Prédiction ANN ($)': round(prediction, 2)426                    }427                    st.session_state.prediction_history.append(prediction_entry)428 429            # Onglet 4 : Historique430            with tab4:431                st.write("### Historique des prédictions")432                if st.session_state.prediction_history:433                    history_df = pd.DataFrame(st.session_state.prediction_history)434                    st.dataframe(history_df)435                else:436                    st.info("Aucune prédiction effectuée pour le moment.")437 438    elif choice == "📶 Autre Dataset ❓":439        with st.container():440            st.subheader("Analyse exploratoire d’un autre dataset")441 442            # Ajout du file uploader pour charger un dataset443            uploaded_file = st.file_uploader("Chargez un fichier CSV", type=["csv"], key="autre_dataset_uploader")444            445            # Si un fichier est chargé, on le lit et on le stocke dans st.session_state.df446            if uploaded_file is not None:447                try:448                    df = pd.read_csv(uploaded_file)449                    st.session_state.df = df450                    st.success("Dataset chargé avec succès !")451                except Exception as e:452                    st.error(f"Erreur lors du chargement du fichier : {e}")453                    st.session_state.df = None454 455            # Vérifier si un dataset est chargé dans st.session_state.df456            if "df" in st.session_state and st.session_state.df is not None:457                df = st.session_state.df458 459                # Aperçu du dataset460                st.markdown("<h3 style='color: #F5F5F5;'>Aperçu du dataset 📌</h3>", unsafe_allow_html=True)461                st.dataframe(df.head())462                463                # Forme du dataset464                st.markdown("<h3 style='color: #F5F5F5;'>Forme du dataset</h3>", unsafe_allow_html=True)465                st.write(f"🔹 Le dataset contient **{df.shape[0]} lignes** et **{df.shape[1]} colonnes**.")466                467                # Noms des colonnes et types de données468                st.markdown("<h3 style='color: #F5F5F5;'>Noms des colonnes et types de données</h3>", unsafe_allow_html=True)469                st.write(df.dtypes)470 471                # Informations sur le dataset (équivalent à df.info())472                st.markdown("<h3 style='color: #F5F5F5;'>Informations sur le dataset 📝</h3>", unsafe_allow_html=True)473                474                buffer = io.StringIO()475                df.info(buf=buffer)476                info_str = buffer.getvalue()477                st.markdown(f"<pre style='background-color: #252525; padding: 10px; border-radius: 5px; font-size: 14px; font-family: monospace; color: #F5F5F5;'>{info_str}</pre>", unsafe_allow_html=True)478 479                # Colonnes numériques et catégoriques480                st.markdown("<h3 style='color: #F5F5F5;'>Colonnes numériques et catégoriques</h3>", unsafe_allow_html=True)481                482                numerical_cols = df.select_dtypes(include=['int64', 'float64']).columns.tolist()483                categorical_cols = df.select_dtypes(include=['object', 'category']).columns.tolist()484                485                st.write(f"🔹 **Colonnes numériques ({len(numerical_cols)}):** {', '.join(numerical_cols) if numerical_cols else 'Aucune'}")486                st.write(f"🔹 **Colonnes catégoriques ({len(categorical_cols)}):** {', '.join(categorical_cols) if categorical_cols else 'Aucune'}")487 488                # Valeurs uniques dans les colonnes catégoriques489                st.markdown("<h3 style='color: #F5F5F5;'>Valeurs uniques dans les colonnes catégoriques</h3>", unsafe_allow_html=True)490                491                if categorical_cols:492                    for col in categorical_cols:493                        unique_count = df[col].nunique()494                        st.write(f"**{col}:** {unique_count} valeurs uniques")495                else:496                    st.info("Aucune colonne catégorique détectée ℹ️.")497                498                # Comptage des valeurs dans les colonnes catégoriques499                st.markdown("<h3 style='color: #F5F5F5;'>Répartition des valeurs dans les colonnes catégoriques</h3>", unsafe_allow_html=True)500                501                if categorical_cols:502                    for col in categorical_cols:503                        st.write(f"🔹 **Répartition des valeurs de {col}:**")504                        st.write(df[col].value_counts().head(10))505                else:506                    st.info("Aucune colonne catégorique détectée ℹ️.")507 508                # Statistiques sommaires509                st.markdown("<h3 style='color: #F5F5F5;'>Statistiques sommaires pour les colonnes numériques</h3>", unsafe_allow_html=True)510                511                st.write("🔹 **Aperçu statistique de base du dataset :**")512                st.write(df.describe())513 514                st.markdown("<h3 style='color: #F5F5F5;'>Statistiques sommaires pour les colonnes catégoriques</h3>", unsafe_allow_html=True)515                516                if categorical_cols:517                    st.write(df[categorical_cols].describe(include='object'))518                else:519                    st.info("Aucune colonne catégorique détectée ℹ️.")520                521                # Vérification des valeurs manquantes522                st.markdown("<h3 style='color: #F5F5F5;'>Valeurs manquantes dans le dataset ⚠️</h3>", unsafe_allow_html=True)523                missing_values = df.isnull().sum()524                525                if missing_values.sum() == 0:526                    st.success("Aucune valeur manquante trouvée !")527                else:528                    st.warning(f"Des valeurs manquantes ont été trouvées dans le dataset.")529                    st.write("🔹 **Colonnes avec des valeurs manquantes :**")530                    st.write(missing_values[missing_values > 0])531 532                # Vérification des doublons533                st.markdown("<h3 style='color: #F5F5F5;'>Doublons dans le dataset</h3>", unsafe_allow_html=True)534                duplicate_count = df.duplicated().sum()535                536                if duplicate_count == 0:537                    st.success("Aucun doublon trouvé !")538                else:539                    st.warning(f"{duplicate_count} lignes dupliquées trouvées dans le dataset.")540                    st.write("🔹 **Exemples de lignes dupliquées :**")541                    st.dataframe(df[df.duplicated()].head())542 543                # Détection des outliers544                st.markdown("<h3 style='color: #F5F5F5;'>Détection des outliers</h3>", unsafe_allow_html=True)545                546                if numerical_cols:547                    outlier_info = {}548                    549                    for col in numerical_cols:550                        Q1 = df[col].quantile(0.25)551                        Q3 = df[col].quantile(0.75)552                        IQR = Q3 - Q1553                        lower_bound = Q1 - 1.5 * IQR554                        upper_bound = Q3 + 1.5 * IQR555                        outliers = ((df[col] < lower_bound) | (df[col] > upper_bound)).sum()556                        557                        if outliers > 0:558                            outlier_info[col] = outliers559                560                    if outlier_info:561                        st.warning("Outliers détectés :")562                        for col, count in outlier_info.items():563                            st.write(f"🔹 **{col}:** {count} outliers")564                    else:565                        st.success("Aucun outlier significatif détecté !")566                else:567                    st.info("Aucune colonne numérique détectée ℹ️.")568 569                # Bouton pour activer/désactiver les visualisations570                if st.button('Afficher les visualisations'):571                    st.session_state.show_visualizations_autre_dataset = not st.session_state.show_visualizations_autre_dataset572 573                # Afficher les visualisations si elles sont activées574                if st.session_state.show_visualizations_autre_dataset:575                    st.subheader("Visualisation des données")576                    viz_option = st.selectbox(577                        "Choisissez un type de visualisation :",578                        ["Matrice de corrélation", "Boxplot", "Scatterplot", "Histogramme", "Pairplot"]579                    )580 581                    numerical_cols = df.select_dtypes(include=['int64', 'float64']).columns.tolist()582 583                    if numerical_cols:584                        if viz_option == "Matrice de corrélation":585                            st.write("### Matrice de corrélation")586                            plt.figure(figsize=(8, 6))587                            corr = df[numerical_cols].corr()588                            sns.heatmap(corr, annot=True, cmap='coolwarm', vmin=-1, vmax=1)589                            plt.title("Matrice de corrélation")590                            st.pyplot(plt)591 592                        elif viz_option == "Boxplot":593                            st.write("### Boxplot")594                            col = st.selectbox("Choisissez une variable :", numerical_cols)595                            plt.figure(figsize=(8, 6))596                            sns.boxplot(x=df[col])597                            plt.title(f"Boxplot de {col}")598                            st.pyplot(plt)599 600                        elif viz_option == "Scatterplot":601                            st.write("### Scatterplot")602                            x_col = st.selectbox("Choisissez la variable X :", numerical_cols, index=0 if numerical_cols else None)603                            y_col = st.selectbox("Choisissez la variable Y :", numerical_cols, index=1 if len(numerical_cols) > 1 else 0)604                            if x_col and y_col and x_col != y_col:605                                plt.figure(figsize=(8, 6))606                                sns.scatterplot(x=df[x_col], y=df[y_col], hue=df.get('Gender', None))607                                plt.title(f"{x_col} vs {y_col}")608                                st.pyplot(plt)609 610                        elif viz_option == "Histogramme":611                            st.write("### Histogramme")612                            col = st.selectbox("Choisissez une variable :", numerical_cols)613                            plt.figure(figsize=(8, 6))614                            sns.histplot(df[col], bins=20, kde=True)615                            plt.title(f"Distribution de {col}")616                            st.pyplot(plt)617 618                        elif viz_option == "Pairplot":619                            st.write("### Pairplot")620                            pairplot = sns.pairplot(df[numerical_cols])621                            st.pyplot(plt)622                    else:623                        st.warning("Aucune colonne numérique détectée pour les visualisations.")624 625            else:626                st.warning("Aucun dataset trouvé ! Veuillez charger un dataset en premier ⚠️.")627 628    elif choice == "🦾 Chatbot":629        with st.container():630            st.header("Kuzan & Grok AI")631            st.subheader("Tu as des questions qui te perturbent l'esprit ? Discute avec Grok et Kuzan, ces deux potes ont la réponse à tout 😉")632            st.write("Commence à parler avec nous, même si cela n'a rien à voir avec le machine learning bien sûr 😁")633            message = st.text_input("Entrez votre message ici")634            client = Groq(api_key=os.environ.get("GROQ_API_KEY"))635            if message:636                chat_completion = client.chat.completions.create(637                    messages=[{"role": "user", "content": message}],638                    model="meta-llama/llama-4-scout-17b-16e-instruct")639                st.write(chat_completion.choices[0].message.content)640 641if __name__=='__main__':642    main()