Spaces:
Running
Running
Update src/modules/map_dashboard.py
Browse files- src/modules/map_dashboard.py +28 -42
src/modules/map_dashboard.py
CHANGED
|
@@ -41,16 +41,13 @@ COLOR_YELLOW_LINE = "#FFD700" # Lignes de distance
|
|
| 41 |
# --- 1. FONCTIONS DE GÉOCODAGE (AVEC CACHE) ---
|
| 42 |
@st.cache_data(show_spinner=False, ttl=3600)
|
| 43 |
def geocode_addresses(df_clients):
|
| 44 |
-
"""Géocodage via
|
| 45 |
|
| 46 |
if 'Adresse' not in df_clients.columns or 'ID_Client' not in df_clients.columns:
|
| 47 |
return pd.DataFrame()
|
| 48 |
|
| 49 |
-
# METTEZ VOTRE TOKEN
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
# Bounding Box du Sénégal : [lon_min, lat_min, lon_max, lat_max]
|
| 53 |
-
SENEGAL_BBOX = [-17.535, 12.307, -11.355, 16.691]
|
| 54 |
|
| 55 |
geocoded_data = []
|
| 56 |
|
|
@@ -59,46 +56,31 @@ def geocode_addresses(df_clients):
|
|
| 59 |
client_id = row['ID_Client']
|
| 60 |
|
| 61 |
try:
|
| 62 |
-
# Encoder l'adresse pour l'URL
|
| 63 |
import urllib.parse
|
| 64 |
-
|
| 65 |
|
| 66 |
-
#
|
| 67 |
-
url =
|
| 68 |
params = {
|
| 69 |
-
'
|
|
|
|
|
|
|
|
|
|
| 70 |
'limit': 1,
|
| 71 |
-
'language': 'fr'
|
| 72 |
-
'country': 'sn', # Limiter au Sénégal uniquement
|
| 73 |
-
'bbox': ','.join(map(str, SENEGAL_BBOX)), # Bounding box Sénégal
|
| 74 |
-
'proximity': '-17.4467,14.6928' # Prioriser autour de Dakar
|
| 75 |
}
|
| 76 |
|
| 77 |
-
import requests
|
| 78 |
response = requests.get(url, params=params, timeout=10)
|
| 79 |
|
| 80 |
if response.status_code == 200:
|
| 81 |
data = response.json()
|
| 82 |
|
| 83 |
-
if data
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
lon
|
| 87 |
-
|
| 88 |
-
relevance = feature.get('relevance', 0)
|
| 89 |
-
|
| 90 |
-
# Vérifier la pertinence du résultat
|
| 91 |
-
if relevance < 0.5:
|
| 92 |
-
st.warning(f"⚠️ {client_id}: Résultat peu fiable ({relevance:.2f}) - '{place_name}'")
|
| 93 |
-
|
| 94 |
-
# Vérifier que c'est bien au Sénégal
|
| 95 |
-
context = feature.get('context', [])
|
| 96 |
-
is_senegal = any('Senegal' in str(ctx) or 'Sénégal' in str(ctx) for ctx in context)
|
| 97 |
|
| 98 |
-
if not is_senegal and 'Senegal' not in place_name and 'Sénégal' not in place_name:
|
| 99 |
-
st.error(f"❌ {client_id}: Résultat hors Sénégal - '{place_name}' (IGNORÉ)")
|
| 100 |
-
continu
|
| 101 |
-
|
| 102 |
geocoded_data.append({
|
| 103 |
"ID": client_id,
|
| 104 |
"Nom": row.get('Nom_Complet', 'Client Inconnu'),
|
|
@@ -108,17 +90,20 @@ def geocode_addresses(df_clients):
|
|
| 108 |
"Revenus": row.get('Revenus_Mensuels', 0)
|
| 109 |
})
|
| 110 |
|
| 111 |
-
st.success(f"✅ {client_id}: {
|
| 112 |
else:
|
| 113 |
st.error(f"❌ {client_id}: Adresse introuvable - '{address}'")
|
| 114 |
-
|
| 115 |
elif response.status_code == 401:
|
| 116 |
-
st.error(f"❌ Token
|
| 117 |
-
break
|
|
|
|
|
|
|
|
|
|
| 118 |
else:
|
| 119 |
-
st.error(f"❌ {client_id}: Erreur
|
| 120 |
-
|
| 121 |
-
time.sleep(
|
| 122 |
|
| 123 |
except Exception as e:
|
| 124 |
st.error(f"❌ {client_id}: Erreur - {str(e)}")
|
|
@@ -325,4 +310,5 @@ def show_map_dashboard(client, sheet_name):
|
|
| 325 |
"""
|
| 326 |
|
| 327 |
# Afficher la carte
|
| 328 |
-
st.components.v1.html(mapbox_html, height=600)
|
|
|
|
|
|
| 41 |
# --- 1. FONCTIONS DE GÉOCODAGE (AVEC CACHE) ---
|
| 42 |
@st.cache_data(show_spinner=False, ttl=3600)
|
| 43 |
def geocode_addresses(df_clients):
|
| 44 |
+
"""Géocodage via LocationIQ - Gratuit et précis"""
|
| 45 |
|
| 46 |
if 'Adresse' not in df_clients.columns or 'ID_Client' not in df_clients.columns:
|
| 47 |
return pd.DataFrame()
|
| 48 |
|
| 49 |
+
# METTEZ VOTRE TOKEN LOCATIONIQ ICI
|
| 50 |
+
LOCATIONIQ_TOKEN = "pk.e1561a89e1ed2bc2ddeb3ee53fd88fb8"
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
geocoded_data = []
|
| 53 |
|
|
|
|
| 56 |
client_id = row['ID_Client']
|
| 57 |
|
| 58 |
try:
|
|
|
|
| 59 |
import urllib.parse
|
| 60 |
+
import requests
|
| 61 |
|
| 62 |
+
# URL LocationIQ Geocoding
|
| 63 |
+
url = "https://us1.locationiq.com/v1/search.php"
|
| 64 |
params = {
|
| 65 |
+
'key': LOCATIONIQ_TOKEN,
|
| 66 |
+
'q': address,
|
| 67 |
+
'format': 'json',
|
| 68 |
+
'countrycodes': 'sn', # Limiter au Sénégal
|
| 69 |
'limit': 1,
|
| 70 |
+
'accept-language': 'fr'
|
|
|
|
|
|
|
|
|
|
| 71 |
}
|
| 72 |
|
|
|
|
| 73 |
response = requests.get(url, params=params, timeout=10)
|
| 74 |
|
| 75 |
if response.status_code == 200:
|
| 76 |
data = response.json()
|
| 77 |
|
| 78 |
+
if data and len(data) > 0:
|
| 79 |
+
result = data[0]
|
| 80 |
+
lat = float(result['lat'])
|
| 81 |
+
lon = float(result['lon'])
|
| 82 |
+
display_name = result['display_name']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
geocoded_data.append({
|
| 85 |
"ID": client_id,
|
| 86 |
"Nom": row.get('Nom_Complet', 'Client Inconnu'),
|
|
|
|
| 90 |
"Revenus": row.get('Revenus_Mensuels', 0)
|
| 91 |
})
|
| 92 |
|
| 93 |
+
st.success(f"✅ {client_id}: {display_name}")
|
| 94 |
else:
|
| 95 |
st.error(f"❌ {client_id}: Adresse introuvable - '{address}'")
|
| 96 |
+
|
| 97 |
elif response.status_code == 401:
|
| 98 |
+
st.error(f"❌ Token LocationIQ invalide")
|
| 99 |
+
break
|
| 100 |
+
elif response.status_code == 429:
|
| 101 |
+
st.error(f"⚠️ Limite de requêtes atteinte (5000/jour)")
|
| 102 |
+
break
|
| 103 |
else:
|
| 104 |
+
st.error(f"❌ {client_id}: Erreur {response.status_code}")
|
| 105 |
+
|
| 106 |
+
time.sleep(1.2) # Rate limit: max 2 req/sec (on joue safe avec 1.2s)
|
| 107 |
|
| 108 |
except Exception as e:
|
| 109 |
st.error(f"❌ {client_id}: Erreur - {str(e)}")
|
|
|
|
| 310 |
"""
|
| 311 |
|
| 312 |
# Afficher la carte
|
| 313 |
+
st.components.v1.html(mapbox_html, height=600)
|
| 314 |
+
|