import streamlit as st import pandas as pd import pydeck as pdk # <-- Cette ligne doit être présente from geopy.geocoders import Nominatim from geopy.exc import GeocoderTimedOut import time # Ajoutez ceci juste après vos imports, avant les constantes st.markdown(""" """, unsafe_allow_html=True) # --- CONSTANTES GOTHAM & CONFIG --- HQ_LOCATION = [48.913418, 2.396667] # 1 Rue Marcelin Berthelot, Aubervilliers COLOR_BLUE_GOTHAM = "#25C1F7" # Bleu clair COLOR_BLUE_FILL = "#83D6F7" # Remplissage bleu COLOR_GREEN_ZONE = "#54BD4B" # Vert Cluster COLOR_YELLOW_LINE = "#FFD700" # Lignes de distance # --- 1. FONCTIONS DE GÉOCODAGE (AVEC CACHE) --- @st.cache_data(show_spinner=False) def geocode_addresses(df_clients): """Récupère les coordonnées lat/lon pour les adresses clients.""" if 'Adresse' not in df_clients.columns or 'ID_Client' not in df_clients.columns: return pd.DataFrame() geolocator = Nominatim(user_agent="vortex_flux_app") geocoded_data = [] for index, row in df_clients.iterrows(): address = row['Adresse'] client_id = row['ID_Client'] try: search_query = str(address) time.sleep(1.5) location = geolocator.geocode(search_query, timeout=10) if location: geocoded_data.append({ "ID": client_id, "Nom": row.get('Nom_Complet', 'Client Inconnu'), "Adresse": address, "lat": location.latitude, "lon": location.longitude, "Revenus": row.get('Revenus_Mensuels', 0) }) except: pass return pd.DataFrame(geocoded_data) # --- 2. FONCTION PRINCIPALE D'AFFICHAGE --- def show_map_dashboard(client, sheet_name): st.markdown("## VUE TACTIQUE : GÉOLOCALISATION") # 1. Récupération des données depuis Google Sheets try: sh = client.open(sheet_name) ws = sh.worksheet("Clients_KYC") data = ws.get_all_records() df_raw = pd.DataFrame(data) except Exception as e: st.error(f"Erreur de lecture des données : {e}") return if df_raw.empty: st.info("Aucune donnée client à afficher sur la carte.") return # 2. Géocodage (mis en cache) with st.spinner("Triangulation des positions satellites..."): df_map = geocode_addresses(df_raw) if df_map.empty: st.warning("Impossible de géolocaliser les adresses fournies.") return # --- LAYOUT : NAVIGATEUR (GAUCHE) / CARTE (DROITE) --- col_nav, col_map = st.columns([1, 3]) with col_nav: st.markdown("### CIBLES") # Filtres Tactiques st.markdown("#### FILTRES VISUELS") show_dist = st.checkbox("GeoDistance (Lignes HQ)", value=True) show_labels = st.checkbox("LabelZoom (Noms)", value=False) show_cluster = st.checkbox("ClusterZones (Densité)", value=False) show_pop = st.checkbox("PopDensity (ANSD Data)", value=False) st.divider() # Liste des clients (Cartes cliquables simulées par des expanders) st.markdown("#### LISTE CLIENTS") for idx, row in df_map.iterrows(): with st.expander(f"📍 {row['ID']} - {row['Nom']}"): st.caption(f"Ad: {row['Adresse']}") st.caption(f"Rev: {row['Revenus']} XOF") with col_map: # Préparer les données des clients clients_markers = [] for _, row in df_map.iterrows(): clients_markers.append({ 'lon': row['lon'], 'lat': row['lat'], 'id': row['ID'], 'adresse': row['Adresse'] }) # Créer le HTML avec Mapbox GL mapbox_html = f"""
""" # Afficher la carte st.components.v1.html(mapbox_html, height=600)