licorne2lc commited on
Commit
0ffaa2d
·
1 Parent(s): ddc29b3

Déploiement initial du dashboard Getaround Streamlit

Browse files
.gitattributes CHANGED
@@ -33,3 +33,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.xlsx filter=lfs diff=lfs merge=lfs -text
37
+ *.csv filter=lfs diff=lfs merge=lfs -text
38
+ *.png filter=lfs diff=lfs merge=lfs -text
39
+ *.ipynb filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+
4
+ # Installer les dépendances système
5
+ RUN apt-get update && apt-get install -y \
6
+ build-essential \
7
+ libgl1-mesa-glx \
8
+ libglib2.0-0 \
9
+ curl \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ # Mettre à jour pip + installer setuptools et wheel
13
+ RUN pip install --upgrade pip setuptools wheel
14
+
15
+ # Créer un dossier de travail
16
+ WORKDIR /app
17
+
18
+ # Copier les fichiers nécessaires
19
+ COPY requirements.txt ./
20
+ COPY app.py ./
21
+ COPY get_around_delay_analysis.xlsx ./
22
+ COPY get_around_pricing_project.csv ./
23
+ COPY logo.png ./
24
+
25
+ # Installer les dépendances Python (avec wheels)
26
+ RUN pip install --no-cache-dir -r requirements.txt
27
+
28
+ # Exposer le port
29
+ EXPOSE 7860
30
+
31
+ # Lancer Streamlit
32
+ CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
33
+
README.md CHANGED
@@ -1,11 +1,46 @@
1
  ---
2
- title: Get Around Streamlit
3
- emoji: 🏢
4
  colorFrom: pink
5
  colorTo: indigo
6
  sdk: docker
7
  pinned: false
8
- short_description: 'dashboard '
9
  ---
10
 
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Getaround Streamlit Dashboard
3
+ emoji: 🚗
4
  colorFrom: pink
5
  colorTo: indigo
6
  sdk: docker
7
  pinned: false
8
+ app_port: 8501
9
  ---
10
 
11
+ # 🚗 Dashboard Getaround
12
+
13
+ Bienvenue sur le tableau de bord interactif **Getaround** !
14
+
15
+ Ce dashboard Streamlit vous permet de :
16
+
17
+ ### 📊 Analyses exploratoires (EDA)
18
+ - Explorer les **retards de location** et leur gravité.
19
+ - Visualiser l’impact des retards sur la **réservation suivante**.
20
+ - Analyser la **répartition des check-ins** et des états de location.
21
+ - Étudier la **distribution des prix** selon :
22
+ - le type de voiture 🚙
23
+ - le carburant ⛽
24
+ - la présence de Getaround Connect 🔗
25
+ - la puissance moteur ⚙️
26
+
27
+ ### 🔮 Prédiction du prix
28
+ - Un formulaire intelligent permet d’estimer le prix journalier d’une voiture à partir de ses caractéristiques.
29
+ - L’estimation est faite via une API déployée dans un [Space Hugging Face dédié](https://huggingface.co/spaces/licorne2lc/get_around_api).
30
+
31
+ ### 📎 Liens utiles
32
+ - 🔌 API utilisée pour les prédictions : [Voir la documentation Swagger](https://licorne2lc-get-around-api.hf.space/docs)
33
+ - 🧠 Notebook d’analyse : inclus dans la version locale
34
+
35
+ ---
36
+
37
+ **Technologies** :
38
+ - Streamlit
39
+ - Plotly
40
+ - Seaborn & Matplotlib
41
+ - API REST (FastAPI)
42
+ - Docker
43
+
44
+ ---
45
+
46
+ **Auteur** : [licorne2lc](https://huggingface.co/licorne2lc) • Projet encadré par Jedha Bootcamp
app.py ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import streamlit as st
3
+ import pandas as pd
4
+ import matplotlib.pyplot as plt
5
+ import seaborn as sns
6
+ import requests
7
+ import plotly.express as px
8
+ from streamlit_option_menu import option_menu
9
+ from PIL import Image
10
+
11
+ # ========== CONFIGURATION ==========
12
+ st.set_page_config(page_title="Getaround Dashboard", layout="wide")
13
+ st.markdown("<h1 style='text-align: center;'>🚗 Getaround Dashboard</h1>", unsafe_allow_html=True)
14
+
15
+ # ========== LOGO ==========
16
+ try:
17
+ logo = Image.open("logo.png")
18
+ st.sidebar.image(logo, width=200)
19
+ except Exception:
20
+ st.sidebar.warning("Logo non chargé")
21
+
22
+ # ========== MENU ==========
23
+ with st.sidebar:
24
+ selected = option_menu(
25
+ "Menu principal",
26
+ ["🏁 EDA delay", "📈 EDA pricing", "🔮 API prediction"],
27
+ icons=["hourglass-split", "bar-chart-line", "cpu"],
28
+ menu_icon="cast",
29
+ default_index=0,
30
+ )
31
+ st.markdown("---")
32
+ st.markdown("📄 [Espace API HuggingFace](https://huggingface.co/spaces/licorne2lc/get_around_api)")
33
+ st.markdown("🛠️ [Docs API /predict](https://licorne2lc-get-around-api.hf.space/docs)")
34
+
35
+ # ========== 1. EDA DELAY ==========
36
+ if selected == "🏁 EDA delay":
37
+ st.title("📊 Analyse des retards de Getaround")
38
+ try:
39
+ dataset = pd.read_excel("get_around_delay_analysis.xlsx")
40
+
41
+ dataset["delay_status"] = dataset["delay_at_checkout_in_minutes"].apply(
42
+ lambda x: "En avance" if x < 0 else "À l’heure" if x == 0 else "En retard"
43
+ )
44
+
45
+ def catégoriser_retard(x):
46
+ if x <= 0:
47
+ return "Pas de retard"
48
+ elif x <= 30:
49
+ return "< 30 min"
50
+ elif x <= 60:
51
+ return "30-60 min"
52
+ elif x <= 120:
53
+ return "1h-2h"
54
+ elif x <= 240:
55
+ return "2h-4h"
56
+ else:
57
+ return "> 4h"
58
+
59
+ retard_order = ["Pas de retard", "< 30 min", "30-60 min", "1h-2h", "2h-4h", "> 4h"]
60
+ dataset["retard_cat"] = dataset["delay_at_checkout_in_minutes"].apply(catégoriser_retard)
61
+ dataset["retard_cat"] = pd.Categorical(dataset["retard_cat"], categories=retard_order, ordered=True)
62
+
63
+ fig_checkin = px.pie(dataset, names="checkin_type", title="Répartition des types de check-in",
64
+ hole=0.4, color_discrete_sequence=px.colors.qualitative.Pastel, width=1000, height=400)
65
+ st.plotly_chart(fig_checkin)
66
+
67
+ fig_state = px.pie(dataset, names="state", title="Répartition des états de location",
68
+ hole=0.4, color_discrete_sequence=px.colors.qualitative.Set3, width=1000, height=400)
69
+ st.plotly_chart(fig_state)
70
+
71
+ fig_delay_status = px.pie(dataset, names="delay_status", title="Retards : avance / à l’heure / en retard",
72
+ hole=0.4, color_discrete_sequence=px.colors.qualitative.Vivid, width=1000, height=400)
73
+ st.plotly_chart(fig_delay_status)
74
+
75
+ filtered = dataset[(dataset["delay_at_checkout_in_minutes"] > 0) & (dataset["delay_at_checkout_in_minutes"] <= 1440)]
76
+ fig_delay_hist = px.histogram(filtered, x="delay_at_checkout_in_minutes", nbins=50,
77
+ title="Distribution des retards (0 à 1440 minutes)", width=1000, height=400)
78
+ st.plotly_chart(fig_delay_hist)
79
+
80
+ fig_retard_cat = px.bar(dataset["retard_cat"].value_counts().reindex(retard_order),
81
+ title="Gravité des retards", labels={"value": "Nombre", "index": "Catégorie"},
82
+ width=1000, height=400)
83
+ st.plotly_chart(fig_retard_cat)
84
+
85
+ dataset_for_join_B = dataset[["rental_id", "delay_at_checkout_in_minutes"]].rename(
86
+ columns={"rental_id": "rental_id_join", "delay_at_checkout_in_minutes": "delay_at_checkout_in_minutes_join"}
87
+ )
88
+ dataset_join = pd.merge(dataset, dataset_for_join_B,
89
+ left_on="previous_ended_rental_id", right_on="rental_id_join")
90
+ dataset_join["real_delay"] = dataset_join["time_delta_with_previous_rental_in_minutes"] - dataset_join["delay_at_checkout_in_minutes_join"]
91
+ dataset_join_clean = dataset_join.dropna(subset=["delay_at_checkout_in_minutes_join"])
92
+ dataset_join_clean["annulation_due_au_retard"] = dataset_join_clean.apply(
93
+ lambda row: "Oui" if row["state"] == "canceled" and row["real_delay"] < 0 else
94
+ "Annulée (autre raison)" if row["state"] == "canceled" else "Non", axis=1
95
+ )
96
+ fig_annul = px.pie(dataset_join_clean, names="annulation_due_au_retard",
97
+ title="Répartition des annulations dues au retard du locataire précédent",
98
+ hole=0.4, color_discrete_sequence=px.colors.qualitative.Bold, width=1000, height=400)
99
+ st.plotly_chart(fig_annul)
100
+
101
+ except FileNotFoundError:
102
+ st.error("❌ Fichier Excel non trouvé : get_around_delay_analysis.xlsx")
103
+
104
+ # ========== 2. EDA PRICING ==========
105
+ elif selected == "📈 EDA pricing":
106
+ st.title("💰 Analyse des prix de location Getaround")
107
+ try:
108
+ df_price = pd.read_csv("get_around_pricing_project.csv")
109
+
110
+ st.subheader("Distribution du prix journalier")
111
+ fig, ax = plt.subplots(figsize=(10, 4))
112
+ sns.histplot(df_price["rental_price_per_day"], bins=50, kde=True, ax=ax)
113
+ st.pyplot(fig)
114
+
115
+ st.subheader("Prix par type de carburant")
116
+ fig, ax = plt.subplots(figsize=(10, 4))
117
+ sns.boxplot(x="fuel", y="rental_price_per_day", data=df_price, ax=ax)
118
+ st.pyplot(fig)
119
+
120
+ st.subheader("Prix par type de voiture")
121
+ fig, ax = plt.subplots(figsize=(10, 4))
122
+ sns.boxplot(x="car_type", y="rental_price_per_day", data=df_price, ax=ax)
123
+ st.pyplot(fig)
124
+
125
+ st.subheader("Prix selon la présence de Getaround Connect")
126
+ fig, ax = plt.subplots(figsize=(10, 4))
127
+ sns.boxplot(x="has_getaround_connect", y="rental_price_per_day", data=df_price, ax=ax)
128
+ st.pyplot(fig)
129
+
130
+ st.subheader("Corrélation entre puissance moteur et prix journalier")
131
+ fig, ax = plt.subplots(figsize=(10, 4))
132
+ sns.scatterplot(x="engine_power", y="rental_price_per_day", data=df_price, hue="car_type", ax=ax)
133
+ st.pyplot(fig)
134
+ except FileNotFoundError:
135
+ st.error("❌ Fichier CSV non trouvé : get_around_pricing_project.csv")
136
+
137
+ # ========== 3. API PREDICTION ==========
138
+ elif selected == "🔮 API prediction":
139
+ st.title("🔮 Prédiction du prix de location")
140
+ st.markdown("Remplis les informations suivantes pour obtenir une estimation du prix")
141
+
142
+ with st.form("prediction_form"):
143
+ model_key = st.selectbox("Modèle de voiture", ["Peugeot", "Audi", "BMW"])
144
+ mileage = st.number_input("Kilométrage", value=50000)
145
+ engine_power = st.number_input("Puissance moteur", value=100)
146
+ fuel = st.selectbox("Type de carburant", ["diesel", "petrol", "electric", "hybrid"])
147
+ paint_color = st.selectbox("Couleur", ["black", "white", "grey", "blue", "red"])
148
+ car_type = st.selectbox("Type de voiture", ["sedan", "convertible", "suv", "coupe"])
149
+ private_parking_available = st.checkbox("Parking privé disponible", value=True)
150
+ has_gps = st.checkbox("GPS", value=True)
151
+ has_air_conditioning = st.checkbox("Climatisation", value=True)
152
+ automatic_car = st.checkbox("Boîte automatique", value=True)
153
+ has_getaround_connect = st.checkbox("Getaround Connect", value=True)
154
+ has_speed_regulator = st.checkbox("Régulateur de vitesse", value=True)
155
+ winter_tires = st.checkbox("Pneus hiver", value=True)
156
+ submitted = st.form_submit_button("📤 Envoyer")
157
+
158
+ if submitted:
159
+ data = {
160
+ "model_key": model_key,
161
+ "mileage": mileage,
162
+ "engine_power": engine_power,
163
+ "fuel": fuel,
164
+ "paint_color": paint_color,
165
+ "car_type": car_type,
166
+ "private_parking_available": private_parking_available,
167
+ "has_gps": has_gps,
168
+ "has_air_conditioning": has_air_conditioning,
169
+ "automatic_car": automatic_car,
170
+ "has_getaround_connect": has_getaround_connect,
171
+ "has_speed_regulator": has_speed_regulator,
172
+ "winter_tires": winter_tires,
173
+ }
174
+ api_url = "https://licorne2lc-get-around-api.hf.space/predict"
175
+ try:
176
+ response = requests.post(api_url, json=data)
177
+ if response.status_code == 200:
178
+ price = round(response.json()["prediction"], 2)
179
+ st.success(f"💰 Prix de location estimé : {price} € / jour")
180
+ else:
181
+ st.error(f"❌ Erreur {response.status_code} : {response.text}")
182
+ except Exception as e:
183
+ st.error(f"❌ Erreur lors de la requête : {e}")
get_around_delay_analysis.xlsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a5c17402d38c9245f64a5139de72f671fcd518217afc2bcbc427b48f3c069263
3
+ size 889529
get_around_pricing_project.csv ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cbc7e7e3e05837c21690ef49a1741c962ab79b1909df3c9bae883ead84f58c8f
3
+ size 408763
getaround_EDA.ipynb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8cb343ce7c1f0f2e5737fdbf797330d89359d9a9b80dea94060d79ae0456ffd8
3
+ size 2517879
logo.png ADDED

Git LFS Details

  • SHA256: fa74d308c28416bb05a65966a88a9ae68368ef55922e4bc6a991a8c3e26aefd7
  • Pointer size: 130 Bytes
  • Size of remote file: 22.5 kB
requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ bokeh==3.6.0
2
+ numpy==1.26.0
3
+ plotly==5.24.1
4
+ streamlit-lottie==0.0.5
5
+
6
+ streamlit==1.37.1
7
+ pandas==2.2.1
8
+ matplotlib==3.7.3
9
+ seaborn==0.13.2
10
+ requests==2.32.3
11
+ streamlit-option-menu==0.4.0
12
+ Pillow==10.3.0
13
+ pyarrow==16.1.0
14
+ openpyxl==3.1.2