Kuzan2077/DeepLearningNgadena
0
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()