tyriaa commited on
Commit
59d0b04
·
1 Parent(s): dc87f2b

initial commit

Browse files
.DS_Store ADDED
Binary file (6.15 kB). View file
 
Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use a lightweight Python image
2
+ FROM python:3.9-slim
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /app
6
+
7
+ # Copy the project files into the container
8
+ COPY . /app
9
+
10
+ # Install system dependencies for required Python packages
11
+ RUN apt-get update && apt-get install -y \
12
+ libgl1 \
13
+ libglib2.0-0 \
14
+ && rm -rf /var/lib/apt/lists/*
15
+
16
+ # Install Python dependencies
17
+ RUN pip install --no-cache-dir -r requirements.txt
18
+
19
+ # Expose the port used by Flask
20
+ EXPOSE 7860
21
+
22
+ # Command to start the application
23
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, jsonify, request, render_template, Markup
2
+ import requests
3
+ import json
4
+
5
+ TOMTOM_API_KEY = "PVt4NaZSKKtziZi9DaqNAUzN4flNJnSo"
6
+
7
+ app = Flask(__name__)
8
+
9
+ @app.route('/')
10
+ def index():
11
+ """Serve the main UI with the traffic report."""
12
+ try:
13
+ # Lire le contenu de traffic_report.html
14
+ with open("traffic_report.html", "r", encoding="utf-8") as report_file:
15
+ traffic_report_content = report_file.read()
16
+ except FileNotFoundError:
17
+ # Gérer le cas où le fichier n'existe pas
18
+ traffic_report_content = "<p>Aucun rapport de trafic disponible pour le moment.</p>"
19
+
20
+ # Rendre le contenu HTML sécuritaire pour l'injection dans la page
21
+ traffic_report = Markup(traffic_report_content)
22
+
23
+ return render_template('index.html', traffic_report=traffic_report)
24
+
25
+ @app.route('/api/incidents', methods=['GET'])
26
+ def get_incidents():
27
+ """
28
+ Récupère les incidents depuis l'API TomTom Traffic.
29
+ """
30
+ try:
31
+ # Définir les coordonnées pour Paris et une zone de bounding box
32
+ bounding_box = "1.79804455,48.52917947,2.88843762,49.24075760" # Paris: sud-ouest, nord-est
33
+ url = f"https://api.tomtom.com/traffic/services/5/incidentDetails?bbox={bounding_box}&fields=%7Bincidents%7Btype%2Cgeometry%7Btype%2Ccoordinates%7D%2Cproperties%7BiconCategory%7D%7D%7D&language=en-GB&categoryFilter=0%2C1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C14&timeValidityFilter=present&key={TOMTOM_API_KEY}"
34
+
35
+ # Appel API
36
+ response = requests.get(url)
37
+ response.raise_for_status() # Vérifie les erreurs HTTP
38
+
39
+ data = response.json() # Convertit la réponse en JSON
40
+ incidents = data.get("incidents", []) # Récupère les incidents
41
+
42
+ # Ajouter un affichage pour voir les incidents
43
+ print(f"Incidents récupérés ({len(incidents)} incidents) : {json.dumps(incidents, indent=2)}")
44
+
45
+ return jsonify({"status": "success", "data": incidents}), 200
46
+
47
+ except requests.exceptions.RequestException as e:
48
+ print(f"Erreur lors de la récupération des incidents: {e}")
49
+ return jsonify({"status": "error", "message": str(e)}), 500
50
+
51
+ if __name__ == "__main__":
52
+ app.run(debug=True)
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ Flask==2.2.5
2
+ flask-socketio==5.3.4
3
+ numpy==1.23.5
4
+ torch==1.13.1
5
+ ultralytics==8.0.40
6
+ pillow==9.3.0
7
+ requests==2.28.1
static/icons/.DS_Store ADDED
Binary file (6.15 kB). View file
 
static/icons/1.svg ADDED
static/icons/10.svg ADDED
static/icons/11.svg ADDED
static/icons/14.svg ADDED
static/icons/2.svg ADDED
static/icons/3.svg ADDED
static/icons/4.svg ADDED
static/icons/5.svg ADDED
static/icons/6.svg ADDED
static/icons/7.svg ADDED
static/icons/8.svg ADDED
static/icons/9.svg ADDED
templates/.DS_Store ADDED
Binary file (8.2 kB). View file
 
templates/index.html ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Carte des Incidents</title>
7
+ <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
8
+ <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
9
+ <style>
10
+ #map {
11
+ width: 95%;
12
+ height: 1000px;
13
+ margin: 0 auto;
14
+ }
15
+ #traffic-report {
16
+ margin: 20px;
17
+ padding: 15px;
18
+ border: 1px solid #ddd;
19
+ background-color: #f9f9f9;
20
+ }
21
+ </style>
22
+ </head>
23
+ <body>
24
+ <h1>Carte des Incidents à Paris</h1>
25
+ <div id="map"></div>
26
+ <script>
27
+ // Initialiser la carte
28
+ const map = L.map('map').setView([48.8566, 2.3522], 12);
29
+
30
+ // Ajouter une couche de tuiles
31
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
32
+ attribution: '© Contributeurs OpenStreetMap'
33
+ }).addTo(map);
34
+
35
+ // Récupérer les incidents depuis l'API
36
+ fetch('/api/incidents')
37
+ .then(response => response.json())
38
+ .then(data => {
39
+ if (data.status === "success") {
40
+ const incidents = data.data;
41
+
42
+ // Parcourir chaque incident
43
+ incidents.forEach(incident => {
44
+ const coordinates = incident.geometry.coordinates;
45
+ const type = incident.geometry.type;
46
+
47
+ if (type === "LineString") {
48
+ // Ajouter une polyligne pour les types LineString
49
+ const latlngs = coordinates.map(coord => [coord[1], coord[0]]);
50
+ L.polyline(latlngs, { color: 'red' }).addTo(map);
51
+ } else if (type === "Point") {
52
+ // Ajouter un marqueur pour les types Point
53
+ const [lon, lat] = coordinates;
54
+ const iconCategory = incident.properties.iconCategory;
55
+
56
+ // Définir une icône personnalisée pour chaque catégorie d'incident
57
+ const customIcon = L.icon({
58
+ iconUrl: `/static/icons/${iconCategory}.svg`, // Ajuster le chemin selon votre configuration
59
+ iconSize: [72, 72], // Ajuster la taille des icônes
60
+ });
61
+
62
+ // Définir les descriptions des catégories
63
+ const categoryDescriptions = {
64
+ 1: "Accident",
65
+ 2: "Brouillard",
66
+ 3: "Conditions dangereuses",
67
+ 4: "Pluie",
68
+ 5: "Verglas",
69
+ 6: "Embouteillage",
70
+ 7: "Voie fermée",
71
+ 8: "Route fermée",
72
+ 9: "Travaux routiers",
73
+ 10: "Vent",
74
+ 11: "Inondation",
75
+ 14: "Véhicule en panne"
76
+ };
77
+
78
+ // Utiliser la description de la catégorie dans la popup
79
+ const description = categoryDescriptions[iconCategory] || "Incident inconnu";
80
+
81
+ // Créer un marqueur avec une icône personnalisée et une popup
82
+ L.marker([lat, lon], { icon: customIcon })
83
+ .addTo(map)
84
+ .bindPopup(`<b>Incident</b><br>${description}`)
85
+ .on('click', function () {
86
+ this.openPopup(); // Ouvrir la popup au clic
87
+ });
88
+ }
89
+ });
90
+ } else {
91
+ console.error("Impossible de charger les incidents :", data.message);
92
+ }
93
+ })
94
+ .catch(error => console.error("Erreur lors du chargement des incidents :", error));
95
+ </script>
96
+
97
+ <!-- Section pour afficher le rapport de trafic -->
98
+ <div id="traffic-report">
99
+ {{ traffic_report|safe }}
100
+ </div>
101
+ </body>
102
+ </html>
traffic_report.html ADDED
@@ -0,0 +1,526 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <!DOCTYPE html>
3
+ <html lang="fr">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Rapport des Perturbations</title>
8
+ <style>
9
+ body {
10
+ font-family: Arial, sans-serif;
11
+ margin: 0;
12
+ padding: 0;
13
+ background-color: #f4f4f9;
14
+ }
15
+ h1 {
16
+ text-align: center;
17
+ padding: 20px 0;
18
+ background-color: #007BFF;
19
+ color: white;
20
+ margin: 0;
21
+ }
22
+ h2 {
23
+ color: #007BFF;
24
+ text-align: left;
25
+ margin: 20px 40px;
26
+ }
27
+ table {
28
+ width: 90%;
29
+ margin: 20px auto;
30
+ border-collapse: collapse;
31
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
32
+ }
33
+ th, td {
34
+ padding: 12px;
35
+ text-align: left;
36
+ border: 1px solid #ddd;
37
+ }
38
+ th {
39
+ background-color: #007BFF;
40
+ color: white;
41
+ }
42
+ /* Suppression de l'alternance des couleurs */
43
+ /* tr:nth-child(even) {
44
+ background-color: #f9f9f9;
45
+ } */
46
+ tr:hover {
47
+ background-color: #f1f1f1;
48
+ }
49
+ .summary {
50
+ margin: 20px 40px;
51
+ padding: 20px;
52
+ background-color: #FFF9C4;
53
+ border: 1px solid #FFEB3B;
54
+ border-radius: 5px;
55
+ }
56
+ .severity-perturbee {
57
+ background-color: #F9A972; /* Orange */
58
+ color: black;
59
+ }
60
+ .severity-bloquante {
61
+ background-color: #EC2828; /* Rouge */
62
+ color: white;
63
+ }
64
+ .category-bold {
65
+ font-weight: bold;
66
+ }
67
+ </style>
68
+ </head>
69
+ <body>
70
+ <h1>Rapport des Perturbations</h1>
71
+
72
+ <!-- Section Récapitulatif -->
73
+ <div class="summary">
74
+ <h2>Récapitulatif des Lignes Impactées (Perturbée / Bloquante)</h2>
75
+ <table>
76
+ <thead>
77
+ <tr>
78
+ <th>Catégorie</th>
79
+ <th>Ligne</th>
80
+ <th>Cause</th>
81
+ <th>Gravité</th>
82
+ </tr>
83
+ </thead>
84
+ <tbody>
85
+
86
+ <tr class="severity-bloquante">
87
+ <td class="category-bold">Métro</td>
88
+ <td>Métro 14</td>
89
+ <td>travaux</td>
90
+ <td>bloquante</td>
91
+ </tr>
92
+
93
+ <tr class="severity-bloquante">
94
+ <td class="category-bold">Métro</td>
95
+ <td>Métro 9</td>
96
+ <td>perturbation</td>
97
+ <td>bloquante</td>
98
+ </tr>
99
+
100
+ <tr class="severity-perturbee">
101
+ <td class="category-bold">Bus</td>
102
+ <td>Argenteuil - boucles de seine bus 34</td>
103
+ <td>perturbation</td>
104
+ <td>perturbée</td>
105
+ </tr>
106
+
107
+ <tr class="severity-perturbee">
108
+ <td class="category-bold">Bus</td>
109
+ <td>Argenteuil - boucles de seine bus m</td>
110
+ <td>information</td>
111
+ <td>perturbée</td>
112
+ </tr>
113
+
114
+ <tr class="severity-perturbee">
115
+ <td class="category-bold">Bus</td>
116
+ <td>Argenteuil - boucles de seine bus 12</td>
117
+ <td>information</td>
118
+ <td>perturbée</td>
119
+ </tr>
120
+
121
+ <tr class="severity-perturbee">
122
+ <td class="category-bold">Bus</td>
123
+ <td>Argenteuil - boucles de seine bus e</td>
124
+ <td>information</td>
125
+ <td>perturbée</td>
126
+ </tr>
127
+
128
+ <tr class="severity-perturbee">
129
+ <td class="category-bold">Bus</td>
130
+ <td>Argenteuil - boucles de seine bus d</td>
131
+ <td>perturbation</td>
132
+ <td>perturbée</td>
133
+ </tr>
134
+
135
+ <tr class="severity-perturbee">
136
+ <td class="category-bold">Bus</td>
137
+ <td>Argenteuil - boucles de seine bus 56</td>
138
+ <td>perturbation</td>
139
+ <td>perturbée</td>
140
+ </tr>
141
+
142
+ <tr class="severity-perturbee">
143
+ <td class="category-bold">Bus</td>
144
+ <td>Argenteuil - boucles de seine bus 1</td>
145
+ <td>perturbation</td>
146
+ <td>perturbée</td>
147
+ </tr>
148
+
149
+ <tr class="severity-perturbee">
150
+ <td class="category-bold">Bus</td>
151
+ <td>Argenteuil - boucles de seine bus 7</td>
152
+ <td>perturbation</td>
153
+ <td>perturbée</td>
154
+ </tr>
155
+
156
+ <tr class="severity-perturbee">
157
+ <td class="category-bold">Bus</td>
158
+ <td>Argenteuil - boucles de seine bus 9</td>
159
+ <td>perturbation</td>
160
+ <td>perturbée</td>
161
+ </tr>
162
+
163
+ <tr class="severity-perturbee">
164
+ <td class="category-bold">Bus</td>
165
+ <td>Argenteuil - boucles de seine bus 503</td>
166
+ <td>perturbation</td>
167
+ <td>perturbée</td>
168
+ </tr>
169
+
170
+ <tr class="severity-perturbee">
171
+ <td class="category-bold">Transilien</td>
172
+ <td>Transilien train transilien p</td>
173
+ <td>travaux</td>
174
+ <td>perturbée</td>
175
+ </tr>
176
+
177
+ <tr class="severity-perturbee">
178
+ <td class="category-bold">Transilien</td>
179
+ <td>Transilien train transilien r</td>
180
+ <td>travaux</td>
181
+ <td>perturbée</td>
182
+ </tr>
183
+
184
+ <tr class="severity-bloquante">
185
+ <td class="category-bold">Tram</td>
186
+ <td>Toutes les lignes</td>
187
+ <td>travaux</td>
188
+ <td>bloquante</td>
189
+ </tr>
190
+
191
+ <tr class="severity-bloquante">
192
+ <td class="category-bold">Tram</td>
193
+ <td>Tramway t1</td>
194
+ <td>travaux</td>
195
+ <td>bloquante</td>
196
+ </tr>
197
+
198
+ <tr class="severity-perturbee">
199
+ <td class="category-bold">Tram</td>
200
+ <td>Transilien tramway t4</td>
201
+ <td>perturbation</td>
202
+ <td>perturbée</td>
203
+ </tr>
204
+
205
+ <tr class="severity-perturbee">
206
+ <td class="category-bold">Tram</td>
207
+ <td>Transilien tramway t12</td>
208
+ <td>perturbation</td>
209
+ <td>perturbée</td>
210
+ </tr>
211
+
212
+ </tbody>
213
+ </table>
214
+ </div>
215
+ <h2>Métro</h2>
216
+ <table>
217
+ <thead>
218
+ <tr>
219
+ <th>Ligne</th>
220
+ <th>Cause</th>
221
+ <th>Gravité</th>
222
+ <th>Message</th>
223
+ </tr>
224
+ </thead>
225
+ <tbody>
226
+
227
+ <tr>
228
+ <td>Métro 14</td>
229
+ <td>travaux</td>
230
+ <td>bloquante</td>
231
+ <td><p>En raison de travaux, l'arrêt Villejuif - Gustave Roussy n'est pas desservi.</p></td>
232
+ </tr>
233
+
234
+ <tr>
235
+ <td>RATP Métro 9</td>
236
+ <td>perturbation</td>
237
+ <td>bloquante</td>
238
+ <td>Métro 9 : Bagage oublié dans un train - Trafic interrompu</td>
239
+ </tr>
240
+
241
+ <tr>
242
+ <td>RATP Métro 9</td>
243
+ <td>perturbation</td>
244
+ <td>bloquante</td>
245
+ <td>Métro 9 : Bagage oublié dans un train - Trafic interrompu</td>
246
+ </tr>
247
+
248
+ <tr>
249
+ <td>Métro 14</td>
250
+ <td>information</td>
251
+ <td>information</td>
252
+ <td>Métro 14 : Tarif majoré pour les trajets à destination ou au départ de la station Aéroport d'Orly</td>
253
+ </tr>
254
+
255
+ <tr>
256
+ <td>RATP Métro 14</td>
257
+ <td>information</td>
258
+ <td>information</td>
259
+ <td>Métro 14 : Information - Autre</td>
260
+ </tr>
261
+
262
+ </tbody>
263
+ </table>
264
+ <h2>RER</h2>
265
+ <table>
266
+ <thead>
267
+ <tr>
268
+ <th>Ligne</th>
269
+ <th>Cause</th>
270
+ <th>Gravité</th>
271
+ <th>Message</th>
272
+ </tr>
273
+ </thead>
274
+ <tbody>
275
+
276
+ </tbody>
277
+ </table>
278
+ <h2>Bus</h2>
279
+ <table>
280
+ <thead>
281
+ <tr>
282
+ <th>Ligne</th>
283
+ <th>Cause</th>
284
+ <th>Gravité</th>
285
+ <th>Message</th>
286
+ </tr>
287
+ </thead>
288
+ <tbody>
289
+
290
+ <tr>
291
+ <td>Argenteuil - Boucles de Seine Bus 34</td>
292
+ <td>perturbation</td>
293
+ <td>perturbée</td>
294
+ <td><p>⚠️Déviation - Ligne 34 - Du 20 Novembre 2023 au 05 Janvier 2025</p><p>&nbsp;</p><p>En raison de travaux sur la commune de Bezons, la ligne 34 est déviée en direction de Marché des Coteaux.</p><p>&nbsp;</p><p><strong>❌L’arrêt JS Bach ne sera pas desservi en direction de Marché des Coteaux.</strong></p><p><strong>✅L’arrêt de report se fera au N°23/27 rue Rouget de Lisle.</strong></p><p>&nbsp;</p><p>Veuillez nous excuser de la gêne occasionnée</p></td>
295
+ </tr>
296
+
297
+ <tr>
298
+ <td>Argenteuil - Boucles de Seine Bus M</td>
299
+ <td>information</td>
300
+ <td>perturbée</td>
301
+ <td><p><span>⚠️🚍</span><span style="color:rgb(29,155,240);"><span>#InfoTrafic</span></span><span> - Lignes E, M et 12 -À partir du mercredi 04 Septembre 2024 : Tous les mercredis de 5h00 à 16h00</span><br>&nbsp;</p><p><span>Changement de Terminus Arrivée/ Départ :</span></p><p><span><strong>❌Arrêt Gare de Chatou parvis Nord non desservi</strong></span></p><p><span><strong>✅Report arrêt Gare de Chatou parvis Sud</strong></span></p><p><br>&nbsp;</p><p><span>Veuillez nous excuser de la gêne occasionnée.</span></p></td>
302
+ </tr>
303
+
304
+ <tr>
305
+ <td>Argenteuil - Boucles de Seine Bus 12</td>
306
+ <td>information</td>
307
+ <td>perturbée</td>
308
+ <td><p><span>⚠️🚍</span><span style="color:rgb(29,155,240);"><span>#InfoTrafic</span></span><span> - Lignes E, M et 12 -À partir du mercredi 04 Septembre 2024 : Tous les mercredis de 5h00 à 16h00</span><br>&nbsp;</p><p><span>Changement de Terminus Arrivée/ Départ :</span></p><p><span><strong>❌Arrêt Gare de Chatou parvis Nord non desservi</strong></span></p><p><span><strong>✅Report arrêt Gare de Chatou parvis Sud</strong></span></p><p><br>&nbsp;</p><p><span>Veuillez nous excuser de la gêne occasionnée.</span></p></td>
309
+ </tr>
310
+
311
+ <tr>
312
+ <td>Argenteuil - Boucles de Seine Bus E</td>
313
+ <td>information</td>
314
+ <td>perturbée</td>
315
+ <td><p><span>⚠️🚍</span><span style="color:rgb(29,155,240);"><span>#InfoTrafic</span></span><span> - Lignes E, M et 12 -À partir du mercredi 04 Septembre 2024 : Tous les mercredis de 5h00 à 16h00</span><br>&nbsp;</p><p><span>Changement de Terminus Arrivée/ Départ :</span></p><p><span><strong>❌Arrêt Gare de Chatou parvis Nord non desservi</strong></span></p><p><span><strong>✅Report arrêt Gare de Chatou parvis Sud</strong></span></p><p><br>&nbsp;</p><p><span>Veuillez nous excuser de la gêne occasionnée.</span></p></td>
316
+ </tr>
317
+
318
+ <tr>
319
+ <td>Argenteuil - Boucles de Seine Bus 12</td>
320
+ <td>perturbation</td>
321
+ <td>perturbée</td>
322
+ <td>⚠🚍 Ligne D, 12, 56, E - du jeudi 4 avril au mardi 31 décembre 2024</td>
323
+ </tr>
324
+
325
+ <tr>
326
+ <td>Argenteuil - Boucles de Seine Bus E</td>
327
+ <td>perturbation</td>
328
+ <td>perturbée</td>
329
+ <td>⚠🚍 Ligne D, 12, 56, E - du jeudi 4 avril au mardi 31 décembre 2024</td>
330
+ </tr>
331
+
332
+ <tr>
333
+ <td>Argenteuil - Boucles de Seine Bus D</td>
334
+ <td>perturbation</td>
335
+ <td>perturbée</td>
336
+ <td>⚠🚍 Ligne D, 12, 56, E - du jeudi 4 avril au mardi 31 décembre 2024</td>
337
+ </tr>
338
+
339
+ <tr>
340
+ <td>Argenteuil - Boucles de Seine Bus 56</td>
341
+ <td>perturbation</td>
342
+ <td>perturbée</td>
343
+ <td>⚠🚍 Ligne D, 12, 56, E - du jeudi 4 avril au mardi 31 décembre 2024</td>
344
+ </tr>
345
+
346
+ <tr>
347
+ <td>Argenteuil - Boucles de Seine Bus 1</td>
348
+ <td>perturbation</td>
349
+ <td>perturbée</td>
350
+ <td>⚠🚍 Ligne 1 - du mardi 26 novembre au lundi 2 décembre 2024</td>
351
+ </tr>
352
+
353
+ <tr>
354
+ <td>Argenteuil - Boucles de Seine Bus 7</td>
355
+ <td>perturbation</td>
356
+ <td>perturbée</td>
357
+ <td>⚠🚍#InfoTrafic Ligne 7 - Vendredi 29 novembre 2024</td>
358
+ </tr>
359
+
360
+ <tr>
361
+ <td>Argenteuil - Boucles de Seine Bus 9</td>
362
+ <td>perturbation</td>
363
+ <td>perturbée</td>
364
+ <td><p><strong>⚠🚍#InfoTrafic - Ligne 9 - Vendredi 29 novembre 2024</strong></p><p>&nbsp;</p><p>En raison de contraintes d'exploitation, les départs suivants sont supprimés :</p><p>&nbsp;</p><p>❌Départs de Gare de Sartrouville : 07h06, 07h36, 08h42, 09h12, 17h00, 17h12, 18h36, 18h48</p><p>❌Départs de Gare d'Argenteuil : 06h48, 07h54, 08h24, 09h30, 17h48, 18h00</p><p>&nbsp;</p><p>Veuillez nous excuser pour la gêne occasionnée.</p></td>
365
+ </tr>
366
+
367
+ <tr>
368
+ <td>Argenteuil - Boucles de Seine Bus 503</td>
369
+ <td>perturbation</td>
370
+ <td>perturbée</td>
371
+ <td>⚠🚍 Ligne 503 - du jeudi 28 novembre au vendredi 20 décembre 2024</td>
372
+ </tr>
373
+
374
+ <tr>
375
+ <td>Argenteuil - Boucles de Seine Bus 9</td>
376
+ <td>perturbation</td>
377
+ <td>perturbée</td>
378
+ <td>⚠️🚍#InfoTrafic - Ligne 9 - Vendredi 29 novembre 2024</td>
379
+ </tr>
380
+
381
+ <tr>
382
+ <td>Argenteuil - Boucles de Seine Bus 34</td>
383
+ <td>perturbation</td>
384
+ <td>perturbée</td>
385
+ <td>⚠️🚍#InfoTrafic - Ligne 34 - Vendredi 29 novembre 2024</td>
386
+ </tr>
387
+
388
+ <tr>
389
+ <td>Argenteuil - Boucles de Seine Bus 9</td>
390
+ <td>perturbation</td>
391
+ <td>perturbée</td>
392
+ <td>⚠🚍Ligne 9 - vendredi 29 novembre 2024</td>
393
+ </tr>
394
+
395
+ </tbody>
396
+ </table>
397
+ <h2>Transilien</h2>
398
+ <table>
399
+ <thead>
400
+ <tr>
401
+ <th>Ligne</th>
402
+ <th>Cause</th>
403
+ <th>Gravité</th>
404
+ <th>Message</th>
405
+ </tr>
406
+ </thead>
407
+ <tbody>
408
+
409
+ <tr>
410
+ <td>Transilien Train Transilien P</td>
411
+ <td>travaux</td>
412
+ <td>perturbée</td>
413
+ <td><p>P&#233;riode : toute la journ&#233;e<br><br>Dates : du lundi 28 octobre au vendredi 29 novembre, sauf les week-ends, 1er et 11 novembre<br><br>Les horaires de trains sont avanc&#233;s ou retard&#233;s diff&#233;remment chaque jour entre&#160;<br>- Paris Est et Meaux ;&#160;<br>- Paris Est et Ch&#226;teau-Thierry ;&#160;<br>- Paris Est et La Fert&#233; Milon.&#160;<br><br>Les horaires du calculateur d'itin&#233;raire tiennent compte des travaux.&#160;<br>Nous vous conseillons de les consulter chaque jour.&#160;<br><br>Motif : travaux (limitation de la vitesse des trains).</p></td>
414
+ </tr>
415
+
416
+ <tr>
417
+ <td>Transilien Train Transilien P</td>
418
+ <td>travaux</td>
419
+ <td>perturbée</td>
420
+ <td><p>P&#233;riode : toute la journ&#233;e<br><br>Dates : du lundi 28 octobre au vendredi 29 novembre, sauf les week-ends, 1er et 11 novembre<br><br>Les horaires de trains sont avanc&#233;s ou retard&#233;s diff&#233;remment chaque jour entre&#160;<br>- Paris Est et Meaux ;&#160;<br>- Paris Est et Ch&#226;teau-Thierry ;&#160;<br>- Paris Est et La Fert&#233; Milon.&#160;<br><br>Les horaires du calculateur d'itin&#233;raire tiennent compte des travaux.&#160;<br>Nous vous conseillons de les consulter chaque jour.&#160;<br><br>Motif : travaux (limitation de la vitesse des trains).</p></td>
421
+ </tr>
422
+
423
+ <tr>
424
+ <td>Transilien Train Transilien P</td>
425
+ <td>travaux</td>
426
+ <td>perturbée</td>
427
+ <td><p>P&#233;riode : toute la journ&#233;e<br><br>Dates : du lundi 28 octobre au vendredi 29 novembre, sauf les week-ends, 1er et 11 novembre<br><br>Les horaires de trains sont avanc&#233;s ou retard&#233;s diff&#233;remment chaque jour entre&#160;<br>- Paris Est et Meaux ;&#160;<br>- Paris Est et Ch&#226;teau-Thierry ;&#160;<br>- Paris Est et La Fert&#233; Milon.&#160;<br><br>Les horaires du calculateur d'itin&#233;raire tiennent compte des travaux.&#160;<br>Nous vous conseillons de les consulter chaque jour.&#160;<br><br>Motif : travaux (limitation de la vitesse des trains).</p></td>
428
+ </tr>
429
+
430
+ <tr>
431
+ <td>Transilien Train Transilien P</td>
432
+ <td>travaux</td>
433
+ <td>perturbée</td>
434
+ <td><p>P&#233;riode : toute la journ&#233;e<br><br>Dates : du lundi 28 octobre au vendredi 29 novembre, sauf les week-ends, 1er et 11 novembre<br><br>Les horaires de trains sont avanc&#233;s ou retard&#233;s diff&#233;remment chaque jour entre&#160;<br>- Paris Est et Meaux ;&#160;<br>- Paris Est et Ch&#226;teau-Thierry ;&#160;<br>- Paris Est et La Fert&#233; Milon.&#160;<br><br>Les horaires du calculateur d'itin&#233;raire tiennent compte des travaux.&#160;<br>Nous vous conseillons de les consulter chaque jour.&#160;<br><br>Motif : travaux (limitation de la vitesse des trains).</p></td>
435
+ </tr>
436
+
437
+ <tr>
438
+ <td>Transilien Train Transilien P</td>
439
+ <td>travaux</td>
440
+ <td>perturbée</td>
441
+ <td><p>P&#233;riode : toute la journ&#233;e<br><br>Dates : du lundi 28 octobre au vendredi 29 novembre, sauf les week-ends, 1er et 11 novembre<br><br>Les horaires de trains sont avanc&#233;s ou retard&#233;s diff&#233;remment chaque jour entre&#160;<br>- Paris Est et Meaux ;&#160;<br>- Paris Est et Ch&#226;teau-Thierry ;&#160;<br>- Paris Est et La Fert&#233; Milon.&#160;<br><br>Les horaires du calculateur d'itin&#233;raire tiennent compte des travaux.&#160;<br>Nous vous conseillons de les consulter chaque jour.&#160;<br><br>Motif : travaux (limitation de la vitesse des trains).</p></td>
442
+ </tr>
443
+
444
+ <tr>
445
+ <td>Transilien Train Transilien P</td>
446
+ <td>travaux</td>
447
+ <td>perturbée</td>
448
+ <td><p>P&#233;riode : toute la journ&#233;e<br><br>Dates : du lundi 28 octobre au vendredi 29 novembre, sauf les week-ends, 1er et 11 novembre<br><br>Les horaires de trains sont avanc&#233;s ou retard&#233;s diff&#233;remment chaque jour entre&#160;<br>- Paris Est et Meaux ;&#160;<br>- Paris Est et Ch&#226;teau-Thierry ;&#160;<br>- Paris Est et La Fert&#233; Milon.&#160;<br><br>Les horaires du calculateur d'itin&#233;raire tiennent compte des travaux.&#160;<br>Nous vous conseillons de les consulter chaque jour.&#160;<br><br>Motif : travaux (limitation de la vitesse des trains).</p></td>
449
+ </tr>
450
+
451
+ <tr>
452
+ <td>Transilien Train Transilien R</td>
453
+ <td>travaux</td>
454
+ <td>perturbée</td>
455
+ <td><p>P&#233;riode : &#224; partir de 21h30<br><br><br>Dates : en semaine du lundi 25 novembre au vendredi 13 d&#233;cembre 2024<br><br><br>Le trafic est interrompu entre Melun et Montereau via H&#233;ricy dans les deux sens.<br><br><br><b>De Melun vers Montereau via H&#233;ricy, dernier train &#224; circuler :</b><br><br>- KOHO d&#233;part Melun 20h48, arriv&#233;e Montereau 21h25.<br><br><br><b>De Montereau vers Melun via H&#233;ricy, dernier train &#224; circuler :</b><br><br>- ZOHA d&#233;part Montereau 20h29, arriv&#233;e &#224; Melun &#224; 21h06.<br><br><br>Les horaires du calculateur d'itin&#233;raire tiennent compte des travaux.<br><br><br>Motif : travaux de maintenance.<br></p></td>
456
+ </tr>
457
+
458
+ <tr>
459
+ <td>Transilien Train Transilien R</td>
460
+ <td>travaux</td>
461
+ <td>perturbée</td>
462
+ <td><p>P&#233;riode : &#224; partir de 21h30<br><br><br>Dates : en semaine du lundi 25 novembre au vendredi 13 d&#233;cembre 2024<br><br><br>Le trafic est interrompu entre Melun et Montereau via H&#233;ricy dans les deux sens.<br><br><br><b>De Melun vers Montereau via H&#233;ricy, dernier train &#224; circuler :</b><br><br>- KOHO d&#233;part Melun 20h48, arriv&#233;e Montereau 21h25.<br><br><br><b>De Montereau vers Melun via H&#233;ricy, dernier train &#224; circuler :</b><br><br>- ZOHA d&#233;part Montereau 20h29, arriv&#233;e &#224; Melun &#224; 21h06.<br><br><br>Les horaires du calculateur d'itin&#233;raire tiennent compte des travaux.<br><br><br>Motif : travaux de maintenance.<br></p></td>
463
+ </tr>
464
+
465
+ <tr>
466
+ <td>Transilien Train Transilien V</td>
467
+ <td>information</td>
468
+ <td>information</td>
469
+ <td><p><span>À partir du 15/12, le tronçon du RER C Versailles–Chantiers &lt;&gt; Massy – Palaiseau via la vallée de la Bièvre devient la ligne V.</span></p><p><span>Sauf aléa ou travaux, la fréquence de la ligne V sera de 15 minutes aux heures de pointe et de 30 minutes aux heures creuses (1h en toute fin de soirée et le dimanche matin), et ce, dans les deux sens de circulation. Le dernier départ de Versailles–Chantiers vers Massy – Palaiseau s’effectuera à 23h15.</span><br><br><span>Pour plus d'informations sur la ligne V, n'hésitez pas à consulter cette </span><a href="https://www.iledefrance-mobilites.fr/actualites/ligne-v-massy-palaiseau-versailles-chantiers"><span><strong>page</strong></span></a><span>.</span></p></td>
470
+ </tr>
471
+
472
+ </tbody>
473
+ </table>
474
+ <h2>Tram</h2>
475
+ <table>
476
+ <thead>
477
+ <tr>
478
+ <th>Ligne</th>
479
+ <th>Cause</th>
480
+ <th>Gravité</th>
481
+ <th>Message</th>
482
+ </tr>
483
+ </thead>
484
+ <tbody>
485
+
486
+ <tr>
487
+ <td>Toutes les lignes</td>
488
+ <td>travaux</td>
489
+ <td>bloquante</td>
490
+ <td>Tramway T1 : Travaux - Arrêt non desservi</td>
491
+ </tr>
492
+
493
+ <tr>
494
+ <td>RATP Tramway T1</td>
495
+ <td>travaux</td>
496
+ <td>bloquante</td>
497
+ <td>Tramway T1 : Travaux - Trafic interrompu</td>
498
+ </tr>
499
+
500
+ <tr>
501
+ <td>Transilien Tramway T4</td>
502
+ <td>perturbation</td>
503
+ <td>perturbée</td>
504
+ <td><p>Le trafic est ralenti sur l'ensemble de la ligne. <br></p><p>Le temps d'attente en station peut &#234;tre allong&#233;.</p><p>Pour plus d'informations sur cette perturbation, consultez le <a>fil Twitter de la ligne T4</a>. <br></p><p><br></p><p>Motif : difficult&#233;s li&#233;es &#224; un manque de personnel.</p></td>
505
+ </tr>
506
+
507
+ <tr>
508
+ <td>Transilien Tramway T12</td>
509
+ <td>perturbation</td>
510
+ <td>perturbée</td>
511
+ <td><p>Le trafic est ralenti sur l'ensemble de la ligne. <br><br>Motif : panne d'un tram- train.</p></td>
512
+ </tr>
513
+
514
+ <tr>
515
+ <td>Keolis Ouest Val-de-Marne Tramway T9</td>
516
+ <td>information</td>
517
+ <td>information</td>
518
+ <td>Tram T9 - Fréquence adaptée</td>
519
+ </tr>
520
+
521
+ </tbody>
522
+ </table>
523
+
524
+ </body>
525
+ </html>
526
+
traficFranceBleuParis.py ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from collections import defaultdict
3
+ from tabulate import tabulate
4
+ import requests
5
+ import re
6
+ import hashlib
7
+
8
+ def normalize_line_name(line_name):
9
+ """
10
+ Normalise les noms de lignes pour éviter les doublons causés par des préfixes ou variations.
11
+ Exemples :
12
+ - "RATP Métro 14" devient "Métro 14"
13
+ - "SNCF RER A" devient "RER A"
14
+ """
15
+ line_name = line_name.lower() # Convertir en minuscule pour uniformiser
16
+ line_name = re.sub(r"\b(ratp|sncf)\b", "", line_name) # Supprimer les préfixes "RATP" ou "SNCF"
17
+ line_name = re.sub(r"\s+", " ", line_name).strip() # Supprimer les espaces multiples et les espaces de début/fin
18
+ return line_name.capitalize() # Capitaliser la première lettre pour cohérence
19
+
20
+ # Configurer l'API
21
+ headers = {
22
+ 'accept': 'application/json',
23
+ 'apiKey': '3WsgOWybmrTiEwa3q8ZsvovvwPkrctnX' # Remplacez par votre clé API
24
+ }
25
+
26
+ base_url_api = 'https://prim.iledefrance-mobilites.fr/marketplace/v2/navitia/line_reports/physical_modes/physical_mode%3A'
27
+
28
+ categories = {
29
+ "Métro": "Metro",
30
+ "RER": "RapidTransit",
31
+ "Bus": "Bus",
32
+ "Transilien": "LocalTrain",
33
+ "Tram": "Tramway" # Nouvelle catégorie
34
+ }
35
+
36
+ # Fonction pour récupérer les perturbations par catégorie
37
+ def fetch_disruptions(category_key, category_value):
38
+ url_api = f"{base_url_api}{category_value}/line_reports?"
39
+ try:
40
+ response_api = requests.get(url_api, headers=headers)
41
+ response_api.raise_for_status() # Vérifie les erreurs HTTP
42
+ data = response_api.json() # Convertit la réponse en JSON
43
+ print(f"Données récupérées avec succès pour {category_key}.")
44
+ return data.get("disruptions", [])
45
+ except requests.exceptions.RequestException as e:
46
+ print(f"Erreur lors de la récupération des données pour {category_key}: {e}")
47
+ return []
48
+
49
+ def extract_lines_from_message(messages):
50
+ """
51
+ Extraire les lignes mentionnées dans les messages d'une perturbation.
52
+ """
53
+ lines = []
54
+ for msg in messages:
55
+ text = msg.get("text", "")
56
+ # Rechercher des noms de lignes tels que "Métro 1", "RER A", "Bus 72", etc.
57
+ matches = re.findall(r"(Métro \d+|RER [A-Z]|Bus \d+|Transilien \w+|Tram \d+)", text)
58
+ lines.extend(matches)
59
+ return lines or ["Toutes les lignes"]
60
+
61
+ # Extraire les perturbations actives pour chaque catégorie
62
+ all_disruptions = {}
63
+ for category, api_value in categories.items():
64
+ disruptions = fetch_disruptions(category, api_value)
65
+ active_disruptions = [
66
+ {
67
+ "id": disruption.get("id"),
68
+ "cause": disruption.get("cause"),
69
+ "severity": disruption.get("severity", {}).get("name", "N/A"),
70
+ "effect": disruption.get("effect"),
71
+ "message": disruption.get("messages")[0].get("text") if disruption.get("messages") else "No message",
72
+ # Compléter les lignes impactées avec celles extraites des messages si nécessaire
73
+ "impacted_lines": [
74
+ obj.get("pt_object", {}).get("name", "Unknown Line")
75
+ for obj in disruption.get("impacted_objects", [])
76
+ if obj.get("pt_object", {}).get("embedded_type") == "line"
77
+ ] or extract_lines_from_message(disruption.get("messages", [])),
78
+ }
79
+ for disruption in disruptions
80
+ if disruption.get("status") == "active"
81
+ and all(excluded not in (disruption.get("cause", "").lower() + " " +
82
+ " ".join([msg.get("text", "").lower() for msg in disruption.get("messages", [])]))
83
+ for excluded in ["ascenseur", "transdev"])
84
+ ]
85
+ all_disruptions[category] = active_disruptions
86
+
87
+ # Générer le fichier HTML avec un récapitulatif filtré
88
+ html_output_path = "/Users/clementfrerebeau/Downloads/traffic_report.html"
89
+ with open(html_output_path, "w", encoding="utf-8") as html_file:
90
+ # Collecter les lignes ayant des problèmes sans doublons et filtrer par gravité pour le récapitulatif
91
+ seen_lines = set()
92
+ summary_data = []
93
+
94
+ # Gravités à inclure uniquement pour le récapitulatif
95
+ allowed_severities = {"perturbée", "bloquante"}
96
+
97
+ for category, disruptions in all_disruptions.items():
98
+ for disruption in disruptions:
99
+ # Filtrer par gravité uniquement pour le récapitulatif
100
+ severity = disruption.get("severity", "").lower()
101
+ if severity not in allowed_severities:
102
+ continue # Ignorer dans le récapitulatif si la gravité ne correspond pas
103
+
104
+ for line in disruption["impacted_lines"]:
105
+ # Normaliser le nom de la ligne avant de vérifier les doublons
106
+ normalized_line = normalize_line_name(line)
107
+ if normalized_line not in seen_lines:
108
+ summary_data.append({
109
+ "category": category,
110
+ "line": normalized_line, # Utiliser la version normalisée
111
+ "cause": disruption["cause"],
112
+ "severity": disruption["severity"]
113
+ })
114
+ seen_lines.add(normalized_line) # Ajouter la version normalisée à l'ensemble
115
+
116
+ # Générer le fichier HTML
117
+ html_file.write(f"""
118
+ <!DOCTYPE html>
119
+ <html lang="fr">
120
+ <head>
121
+ <meta charset="UTF-8">
122
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
123
+ <title>Rapport des Perturbations</title>
124
+ <style>
125
+ body {{
126
+ font-family: Arial, sans-serif;
127
+ margin: 0;
128
+ padding: 0;
129
+ background-color: #f4f4f9;
130
+ }}
131
+ h1 {{
132
+ text-align: center;
133
+ padding: 20px 0;
134
+ background-color: #007BFF;
135
+ color: white;
136
+ margin: 0;
137
+ }}
138
+ h2 {{
139
+ color: #007BFF;
140
+ text-align: left;
141
+ margin: 20px 40px;
142
+ }}
143
+ table {{
144
+ width: 90%;
145
+ margin: 20px auto;
146
+ border-collapse: collapse;
147
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
148
+ }}
149
+ th, td {{
150
+ padding: 12px;
151
+ text-align: left;
152
+ border: 1px solid #ddd;
153
+ }}
154
+ th {{
155
+ background-color: #007BFF;
156
+ color: white;
157
+ }}
158
+ /* Suppression de l'alternance des couleurs */
159
+ /* tr:nth-child(even) {{
160
+ background-color: #f9f9f9;
161
+ }} */
162
+ tr:hover {{
163
+ background-color: #f1f1f1;
164
+ }}
165
+ .summary {{
166
+ margin: 20px 40px;
167
+ padding: 20px;
168
+ background-color: #FFF9C4;
169
+ border: 1px solid #FFEB3B;
170
+ border-radius: 5px;
171
+ }}
172
+ .severity-perturbee {{
173
+ background-color: #F9A972; /* Orange */
174
+ color: black;
175
+ }}
176
+ .severity-bloquante {{
177
+ background-color: #EC2828; /* Rouge */
178
+ color: white;
179
+ }}
180
+ .category-bold {{
181
+ font-weight: bold;
182
+ }}
183
+ </style>
184
+ </head>
185
+ <body>
186
+ <h1>Rapport des Perturbations</h1>
187
+
188
+ <!-- Section Récapitulatif -->
189
+ <div class="summary">
190
+ <h2>Récapitulatif des Lignes Impactées (Perturbée / Bloquante)</h2>
191
+ <table>
192
+ <thead>
193
+ <tr>
194
+ <th>Catégorie</th>
195
+ <th>Ligne</th>
196
+ <th>Cause</th>
197
+ <th>Gravité</th>
198
+ </tr>
199
+ </thead>
200
+ <tbody>
201
+ """)
202
+
203
+ # Ajouter les lignes impactées uniques au récapitulatif avec des couleurs selon la gravité
204
+ for item in summary_data:
205
+ severity_class = "severity-perturbee" if item["severity"].lower() == "perturbée" else "severity-bloquante"
206
+ html_file.write(f"""
207
+ <tr class="{severity_class}">
208
+ <td class="category-bold">{item["category"]}</td>
209
+ <td>{item["line"]}</td>
210
+ <td>{item["cause"]}</td>
211
+ <td>{item["severity"]}</td>
212
+ </tr>
213
+ """)
214
+
215
+ # Fermer la section récapitulative
216
+ html_file.write("""
217
+ </tbody>
218
+ </table>
219
+ </div>
220
+ """)
221
+
222
+ # Reste de la génération des détails des perturbations
223
+ for category, disruptions in all_disruptions.items():
224
+ html_file.write(f"<h2>{category}</h2>")
225
+ html_file.write("""
226
+ <table>
227
+ <thead>
228
+ <tr>
229
+ <th>Ligne</th>
230
+ <th>Cause</th>
231
+ <th>Gravité</th>
232
+ <th>Message</th>
233
+ </tr>
234
+ </thead>
235
+ <tbody>
236
+ """)
237
+ for disruption in disruptions:
238
+ for line in disruption["impacted_lines"]:
239
+ html_file.write(f"""
240
+ <tr>
241
+ <td>{line}</td>
242
+ <td>{disruption["cause"]}</td>
243
+ <td>{disruption["severity"]}</td>
244
+ <td>{disruption["message"]}</td>
245
+ </tr>
246
+ """)
247
+ html_file.write("""
248
+ </tbody>
249
+ </table>
250
+ """)
251
+
252
+ # Fermer les balises HTML
253
+ html_file.write("""
254
+ </body>
255
+ </html>
256
+ """)
257
+
258
+ print(f"HTML report generated at {html_output_path}")