Julia Wright commited on
Commit
f30b9a3
Β·
1 Parent(s): 7cf7eb9

clean HF deploy (no large files)

Browse files
.gitattributes CHANGED
@@ -15,7 +15,6 @@
15
  *.npz filter=lfs diff=lfs merge=lfs -text
16
  *.onnx filter=lfs diff=lfs merge=lfs -text
17
  *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
  *.pb filter=lfs diff=lfs merge=lfs -text
20
  *.pickle filter=lfs diff=lfs merge=lfs -text
21
  *.pkl filter=lfs diff=lfs merge=lfs -text
@@ -30,6 +29,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
30
  *.tgz filter=lfs diff=lfs merge=lfs -text
31
  *.wasm filter=lfs diff=lfs merge=lfs -text
32
  *.xz 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
 
 
 
 
15
  *.npz filter=lfs diff=lfs merge=lfs -text
16
  *.onnx filter=lfs diff=lfs merge=lfs -text
17
  *.ot filter=lfs diff=lfs merge=lfs -text
 
18
  *.pb filter=lfs diff=lfs merge=lfs -text
19
  *.pickle filter=lfs diff=lfs merge=lfs -text
20
  *.pkl filter=lfs diff=lfs merge=lfs -text
 
29
  *.tgz filter=lfs diff=lfs merge=lfs -text
30
  *.wasm filter=lfs diff=lfs merge=lfs -text
31
  *.xz filter=lfs diff=lfs merge=lfs -text
 
32
  *.zst filter=lfs diff=lfs merge=lfs -text
33
  *tfevents* filter=lfs diff=lfs merge=lfs -text
34
+ *.jar filter=lfs diff=lfs merge=lfs -text
35
+ data/gtfs_stm.zip !text !filter !merge !diff
36
+ data/quebec-260603.osm.pbf !text !filter !merge !diff
.gitignore ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Large GIS / OTP files
2
+ *.pbf
3
+ *.osm.pbf
4
+ *.jar
5
+ graph.obj
6
+ data/quebec-260603.osm.pbf
7
+
8
+ # Logs
9
+ *.log
10
+
11
+ # System files
12
+ .DS_Store
13
+
14
+ # Python cache
15
+ __pycache__/
16
+ *.pyc
17
+
18
+ # Data folders (optional safety)
19
+ data/
20
+ *.pbf
21
+ *.jar
22
+ *.zip
23
+ data/
24
+ *.log
25
+ .DS_Store
26
+ data/
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
- title: ExperimentingV2
3
- emoji: 🏒
4
- colorFrom: red
5
- colorTo: blue
6
  sdk: gradio
7
  sdk_version: 6.16.0
8
  python_version: '3.13'
 
1
  ---
2
+ title: UrbanAccessV1
3
+ emoji: 🌍
4
+ colorFrom: blue
5
+ colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 6.16.0
8
  python_version: '3.13'
app.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ from huggingface_hub import InferenceClient
4
+
5
+ client = InferenceClient(token=os.environ.get("HF_TOKEN"))
6
+
7
+ STATION_INFO = {
8
+ 'Berri-UQAM': 'Elevator available. Accessible entrance on Berri St. Tactile strips present.',
9
+ 'McGill': 'Elevator under maintenance. Ramp available on McGill College Ave.',
10
+ 'Stop Sherbrooke / St-Denis': 'Standard bus stop. No shelter. Curb cut present.',
11
+ 'Stop McGill College / Sherbrooke': 'Bus stop with shelter. Level boarding platform.',
12
+ }
13
+
14
+ INCIDENTS = 'Icy sidewalk near Berri St (Jan 2025). Construction blocking curb cut on Ste-Catherine (ongoing).'
15
+
16
+ SAMPLE_PATHS = """
17
+ Path 1:
18
+ - Walk 5 min (near Berri St)
19
+ - Metro Green line: board at Berri-UQAM, exit at McGill
20
+ - Walk 3 min (near McGill College Ave)
21
+
22
+ Path 2:
23
+ - Walk 8 min (near Sherbrooke / St-Denis)
24
+ - Bus line 24: board at Stop Sherbrooke / St-Denis, exit at Stop McGill College / Sherbrooke
25
+ - Walk 2 min (near McGill College Ave)
26
+ """
27
+
28
+ SYSTEM_PROMPT = (
29
+ "You are an accessibility routing assistant for Montreal transit.\n\n"
30
+ "Your task:\n"
31
+ "1. Rank the routes from most to least accessible for the user's disability type.\n"
32
+ "2. For each route, briefly note accessibility concerns or advantages.\n"
33
+ "3. Give a confidence level (Low/Medium/High) for your top recommendation.\n"
34
+ "4. Consider the date and season when assessing walking conditions.\n"
35
+ "5. Do not invent information not provided. If data is missing, say so.\n"
36
+ "6. Be concise and practical."
37
+ )
38
+
39
+ def build_prompt(origin, destination, disability_type, date):
40
+ station_context = "\n".join([f"- {k}: {v}" for k, v in STATION_INFO.items()])
41
+ return (
42
+ f"User profile:\n"
43
+ f"- Origin: {origin}\n"
44
+ f"- Destination: {destination}\n"
45
+ f"- Disability type: {disability_type}\n"
46
+ f"- Date: {date}\n\n"
47
+ f"Station accessibility info:\n{station_context}\n\n"
48
+ f"Sidewalk/crosswalk incidents:\n{INCIDENTS}\n\n"
49
+ f"Available paths:\n{SAMPLE_PATHS}\n\n"
50
+ "Please rank these paths and recommend the best one for this user."
51
+ )
52
+
53
+ def get_recommendation(origin, destination, disability_type, date):
54
+ response = client.chat_completion(
55
+ model="Qwen/Qwen2.5-72B-Instruct",
56
+ messages=[
57
+ {"role": "system", "content": SYSTEM_PROMPT},
58
+ {"role": "user", "content": build_prompt(origin, destination, disability_type, date)},
59
+ ],
60
+ max_tokens=1024,
61
+ )
62
+ return response.choices[0].message.content
63
+
64
+ demo = gr.Interface(
65
+ fn=get_recommendation,
66
+ inputs=[
67
+ gr.Textbox(label="Origin", value="Plateau-Mont-Royal, Montreal"),
68
+ gr.Textbox(label="Destination", value="McGill University, Montreal"),
69
+ gr.Dropdown(
70
+ choices=["wheelchair user", "visual impairment", "limited mobility", "hearing impairment"],
71
+ label="Disability type",
72
+ value="wheelchair user"
73
+ ),
74
+ gr.Textbox(label="Date", value="2025-01-15"),
75
+ ],
76
+ outputs=gr.Markdown(label="Route Recommendation"),
77
+ title="Accessibility Route Advisor",
78
+ )
79
+
80
+ demo.launch()
collation_points_grid_centre-ville.csv ADDED
The diff for this file is too large to render. See raw diff
 
montreal_routes.json ADDED
@@ -0,0 +1,912 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "route_id": 0,
4
+ "duration_sec": 4.648,
5
+ "transfers": 0,
6
+ "legs": [
7
+ {
8
+ "mode": "WALK",
9
+ "from": "Origin",
10
+ "to": "Destination",
11
+ "start_time": 1780574400000,
12
+ "end_time": 1780579048000,
13
+ "duration_sec": 4.648,
14
+ "distance_m": 5564.94,
15
+ "route": "",
16
+ "geometry_sampled_50m": [
17
+ [
18
+ 45.53082,
19
+ -73.61352
20
+ ],
21
+ [
22
+ 45.53036,
23
+ -73.6125
24
+ ],
25
+ [
26
+ 45.52952,
27
+ -73.61065
28
+ ],
29
+ [
30
+ 45.52927,
31
+ -73.61067
32
+ ],
33
+ [
34
+ 45.52882,
35
+ -73.61108
36
+ ],
37
+ [
38
+ 45.52851,
39
+ -73.61125
40
+ ],
41
+ [
42
+ 45.52824,
43
+ -73.6115
44
+ ],
45
+ [
46
+ 45.52809,
47
+ -73.61163
48
+ ],
49
+ [
50
+ 45.52759,
51
+ -73.61209
52
+ ],
53
+ [
54
+ 45.52733,
55
+ -73.61232
56
+ ],
57
+ [
58
+ 45.52698,
59
+ -73.61264
60
+ ],
61
+ [
62
+ 45.52675,
63
+ -73.61249
64
+ ],
65
+ [
66
+ 45.52572,
67
+ -73.61038
68
+ ],
69
+ [
70
+ 45.52549,
71
+ -73.61054
72
+ ],
73
+ [
74
+ 45.52533,
75
+ -73.61048
76
+ ],
77
+ [
78
+ 45.52513,
79
+ -73.61043
80
+ ],
81
+ [
82
+ 45.52492,
83
+ -73.61044
84
+ ],
85
+ [
86
+ 45.52458,
87
+ -73.60968
88
+ ],
89
+ [
90
+ 45.52384,
91
+ -73.60804
92
+ ],
93
+ [
94
+ 45.52353,
95
+ -73.60733
96
+ ],
97
+ [
98
+ 45.52305,
99
+ -73.60625
100
+ ],
101
+ [
102
+ 45.52296,
103
+ -73.60604
104
+ ],
105
+ [
106
+ 45.52208,
107
+ -73.60405
108
+ ],
109
+ [
110
+ 45.52158,
111
+ -73.60293
112
+ ],
113
+ [
114
+ 45.52144,
115
+ -73.60279
116
+ ],
117
+ [
118
+ 45.51992,
119
+ -73.59938
120
+ ],
121
+ [
122
+ 45.5195,
123
+ -73.59844
124
+ ],
125
+ [
126
+ 45.51931,
127
+ -73.59794
128
+ ],
129
+ [
130
+ 45.51911,
131
+ -73.5975
132
+ ],
133
+ [
134
+ 45.51892,
135
+ -73.59708
136
+ ],
137
+ [
138
+ 45.5188,
139
+ -73.5968
140
+ ],
141
+ [
142
+ 45.51863,
143
+ -73.5967
144
+ ],
145
+ [
146
+ 45.51844,
147
+ -73.59626
148
+ ],
149
+ [
150
+ 45.51831,
151
+ -73.59598
152
+ ],
153
+ [
154
+ 45.51806,
155
+ -73.59539
156
+ ],
157
+ [
158
+ 45.5177,
159
+ -73.59554
160
+ ],
161
+ [
162
+ 45.51685,
163
+ -73.59364
164
+ ],
165
+ [
166
+ 45.51624,
167
+ -73.59223
168
+ ],
169
+ [
170
+ 45.51613,
171
+ -73.59202
172
+ ],
173
+ [
174
+ 45.51602,
175
+ -73.59181
176
+ ],
177
+ [
178
+ 45.51607,
179
+ -73.59159
180
+ ],
181
+ [
182
+ 45.51606,
183
+ -73.59118
184
+ ],
185
+ [
186
+ 45.51582,
187
+ -73.59059
188
+ ],
189
+ [
190
+ 45.51569,
191
+ -73.59032
192
+ ],
193
+ [
194
+ 45.51522,
195
+ -73.59067
196
+ ],
197
+ [
198
+ 45.51504,
199
+ -73.5907
200
+ ],
201
+ [
202
+ 45.51484,
203
+ -73.59067
204
+ ],
205
+ [
206
+ 45.51465,
207
+ -73.59053
208
+ ],
209
+ [
210
+ 45.51442,
211
+ -73.59023
212
+ ],
213
+ [
214
+ 45.51396,
215
+ -73.58954
216
+ ],
217
+ [
218
+ 45.51378,
219
+ -73.58926
220
+ ],
221
+ [
222
+ 45.51359,
223
+ -73.58908
224
+ ],
225
+ [
226
+ 45.51341,
227
+ -73.58903
228
+ ],
229
+ [
230
+ 45.51321,
231
+ -73.58909
232
+ ],
233
+ [
234
+ 45.51305,
235
+ -73.58927
236
+ ],
237
+ [
238
+ 45.51295,
239
+ -73.58951
240
+ ],
241
+ [
242
+ 45.51287,
243
+ -73.58964
244
+ ],
245
+ [
246
+ 45.51273,
247
+ -73.58944
248
+ ],
249
+ [
250
+ 45.51269,
251
+ -73.58906
252
+ ],
253
+ [
254
+ 45.51253,
255
+ -73.58885
256
+ ],
257
+ [
258
+ 45.51246,
259
+ -73.58843
260
+ ],
261
+ [
262
+ 45.51231,
263
+ -73.5882
264
+ ],
265
+ [
266
+ 45.51205,
267
+ -73.58817
268
+ ],
269
+ [
270
+ 45.51187,
271
+ -73.58817
272
+ ],
273
+ [
274
+ 45.51169,
275
+ -73.588
276
+ ],
277
+ [
278
+ 45.51145,
279
+ -73.58776
280
+ ],
281
+ [
282
+ 45.51124,
283
+ -73.58753
284
+ ],
285
+ [
286
+ 45.51102,
287
+ -73.5874
288
+ ],
289
+ [
290
+ 45.51084,
291
+ -73.58723
292
+ ],
293
+ [
294
+ 45.51072,
295
+ -73.58702
296
+ ],
297
+ [
298
+ 45.51041,
299
+ -73.5867
300
+ ],
301
+ [
302
+ 45.51026,
303
+ -73.5865
304
+ ],
305
+ [
306
+ 45.51013,
307
+ -73.58628
308
+ ],
309
+ [
310
+ 45.50999,
311
+ -73.58608
312
+ ],
313
+ [
314
+ 45.50972,
315
+ -73.58581
316
+ ],
317
+ [
318
+ 45.50957,
319
+ -73.58563
320
+ ],
321
+ [
322
+ 45.50932,
323
+ -73.58533
324
+ ],
325
+ [
326
+ 45.50913,
327
+ -73.58515
328
+ ],
329
+ [
330
+ 45.50887,
331
+ -73.58494
332
+ ],
333
+ [
334
+ 45.50869,
335
+ -73.58482
336
+ ],
337
+ [
338
+ 45.50846,
339
+ -73.58476
340
+ ],
341
+ [
342
+ 45.50827,
343
+ -73.58474
344
+ ],
345
+ [
346
+ 45.50807,
347
+ -73.5847
348
+ ],
349
+ [
350
+ 45.5076,
351
+ -73.58444
352
+ ],
353
+ [
354
+ 45.50736,
355
+ -73.5844
356
+ ],
357
+ [
358
+ 45.50715,
359
+ -73.58442
360
+ ],
361
+ [
362
+ 45.5069,
363
+ -73.58447
364
+ ],
365
+ [
366
+ 45.50652,
367
+ -73.58455
368
+ ],
369
+ [
370
+ 45.5061,
371
+ -73.58462
372
+ ],
373
+ [
374
+ 45.50595,
375
+ -73.58443
376
+ ],
377
+ [
378
+ 45.50578,
379
+ -73.58434
380
+ ],
381
+ [
382
+ 45.50559,
383
+ -73.58427
384
+ ],
385
+ [
386
+ 45.50538,
387
+ -73.58429
388
+ ],
389
+ [
390
+ 45.50517,
391
+ -73.58439
392
+ ],
393
+ [
394
+ 45.50499,
395
+ -73.58452
396
+ ],
397
+ [
398
+ 45.50482,
399
+ -73.58455
400
+ ],
401
+ [
402
+ 45.50462,
403
+ -73.58441
404
+ ],
405
+ [
406
+ 45.50439,
407
+ -73.58411
408
+ ],
409
+ [
410
+ 45.50446,
411
+ -73.58386
412
+ ],
413
+ [
414
+ 45.50438,
415
+ -73.58366
416
+ ],
417
+ [
418
+ 45.50418,
419
+ -73.58371
420
+ ],
421
+ [
422
+ 45.50398,
423
+ -73.58377
424
+ ],
425
+ [
426
+ 45.50381,
427
+ -73.58369
428
+ ],
429
+ [
430
+ 45.50365,
431
+ -73.58381
432
+ ],
433
+ [
434
+ 45.50356,
435
+ -73.58364
436
+ ],
437
+ [
438
+ 45.5034,
439
+ -73.58355
440
+ ],
441
+ [
442
+ 45.50306,
443
+ -73.58371
444
+ ],
445
+ [
446
+ 45.50284,
447
+ -73.58381
448
+ ],
449
+ [
450
+ 45.50263,
451
+ -73.58388
452
+ ],
453
+ [
454
+ 45.50248,
455
+ -73.58377
456
+ ],
457
+ [
458
+ 45.50209,
459
+ -73.58393
460
+ ],
461
+ [
462
+ 45.50186,
463
+ -73.58411
464
+ ],
465
+ [
466
+ 45.50169,
467
+ -73.58424
468
+ ],
469
+ [
470
+ 45.50147,
471
+ -73.58442
472
+ ],
473
+ [
474
+ 45.5012,
475
+ -73.58463
476
+ ],
477
+ [
478
+ 45.50109,
479
+ -73.58441
480
+ ],
481
+ [
482
+ 45.50098,
483
+ -73.58419
484
+ ],
485
+ [
486
+ 45.50078,
487
+ -73.58379
488
+ ],
489
+ [
490
+ 45.50058,
491
+ -73.58335
492
+ ],
493
+ [
494
+ 45.50047,
495
+ -73.58313
496
+ ],
497
+ [
498
+ 45.50037,
499
+ -73.58291
500
+ ],
501
+ [
502
+ 45.50025,
503
+ -73.58266
504
+ ],
505
+ [
506
+ 45.49997,
507
+ -73.58204
508
+ ],
509
+ [
510
+ 45.49976,
511
+ -73.58158
512
+ ],
513
+ [
514
+ 45.49965,
515
+ -73.58134
516
+ ],
517
+ [
518
+ 45.49949,
519
+ -73.58099
520
+ ],
521
+ [
522
+ 45.49938,
523
+ -73.58075
524
+ ],
525
+ [
526
+ 45.49917,
527
+ -73.58031
528
+ ],
529
+ [
530
+ 45.49886,
531
+ -73.57979
532
+ ],
533
+ [
534
+ 45.49871,
535
+ -73.57982
536
+ ],
537
+ [
538
+ 45.49854,
539
+ -73.57998
540
+ ],
541
+ [
542
+ 45.49833,
543
+ -73.58019
544
+ ],
545
+ [
546
+ 45.49822,
547
+ -73.57996
548
+ ],
549
+ [
550
+ 45.49805,
551
+ -73.57963
552
+ ],
553
+ [
554
+ 45.49774,
555
+ -73.57981
556
+ ],
557
+ [
558
+ 45.49755,
559
+ -73.57991
560
+ ]
561
+ ]
562
+ }
563
+ ]
564
+ },
565
+ {
566
+ "route_id": 1,
567
+ "duration_sec": 2.548,
568
+ "transfers": 1,
569
+ "legs": [
570
+ {
571
+ "mode": "WALK",
572
+ "from": "Origin",
573
+ "to": "Clark / Saint-Zotique",
574
+ "start_time": 1780574709000,
575
+ "end_time": 1780574784000,
576
+ "duration_sec": 0.075,
577
+ "distance_m": 74.55,
578
+ "route": "",
579
+ "geometry_sampled_50m": [
580
+ [
581
+ 45.53082,
582
+ -73.61352
583
+ ],
584
+ [
585
+ 45.53106,
586
+ -73.61324
587
+ ],
588
+ [
589
+ 45.5313,
590
+ -73.61301
591
+ ]
592
+ ]
593
+ },
594
+ {
595
+ "mode": "BUS",
596
+ "from": "Clark / Saint-Zotique",
597
+ "to": "Saint-Urbain / Sherbrooke",
598
+ "start_time": 1780574784000,
599
+ "end_time": 1780576091000,
600
+ "duration_sec": 1.307,
601
+ "distance_m": 4025.92,
602
+ "route": "Saint-Laurent",
603
+ "geometry_sampled_50m": null
604
+ },
605
+ {
606
+ "mode": "WALK",
607
+ "from": "Saint-Urbain / Sherbrooke",
608
+ "to": "Sherbrooke / Saint-Urbain",
609
+ "start_time": 1780576091000,
610
+ "end_time": 1780576125000,
611
+ "duration_sec": 0.034,
612
+ "distance_m": 29.45,
613
+ "route": "",
614
+ "geometry_sampled_50m": [
615
+ [
616
+ 45.51115,
617
+ -73.57027
618
+ ],
619
+ [
620
+ 45.51123,
621
+ -73.57014
622
+ ]
623
+ ]
624
+ },
625
+ {
626
+ "mode": "BUS",
627
+ "from": "Sherbrooke / Saint-Urbain",
628
+ "to": "Sherbrooke / Redpath",
629
+ "start_time": 1780576440000,
630
+ "end_time": 1780577125000,
631
+ "duration_sec": 0.685,
632
+ "distance_m": 1681.77,
633
+ "route": "Sherbrooke",
634
+ "geometry_sampled_50m": null
635
+ },
636
+ {
637
+ "mode": "WALK",
638
+ "from": "Sherbrooke / Redpath",
639
+ "to": "Destination",
640
+ "start_time": 1780577125000,
641
+ "end_time": 1780577257000,
642
+ "duration_sec": 0.132,
643
+ "distance_m": 145.33,
644
+ "route": "",
645
+ "geometry_sampled_50m": [
646
+ [
647
+ 45.49813,
648
+ -73.58039
649
+ ],
650
+ [
651
+ 45.498,
652
+ -73.58033
653
+ ],
654
+ [
655
+ 45.49786,
656
+ -73.5803
657
+ ],
658
+ [
659
+ 45.4976,
660
+ -73.58055
661
+ ],
662
+ [
663
+ 45.49739,
664
+ -73.58011
665
+ ],
666
+ [
667
+ 45.49755,
668
+ -73.57991
669
+ ]
670
+ ]
671
+ }
672
+ ]
673
+ },
674
+ {
675
+ "route_id": 2,
676
+ "duration_sec": 2.918,
677
+ "transfers": 0,
678
+ "legs": [
679
+ {
680
+ "mode": "WALK",
681
+ "from": "Origin",
682
+ "to": "Station Beaubien",
683
+ "start_time": 1780574519000,
684
+ "end_time": 1780575660000,
685
+ "duration_sec": 1.141,
686
+ "distance_m": 1052.92,
687
+ "route": "",
688
+ "geometry_sampled_50m": [
689
+ [
690
+ 45.53082,
691
+ -73.61352
692
+ ],
693
+ [
694
+ 45.53106,
695
+ -73.61324
696
+ ],
697
+ [
698
+ 45.5313,
699
+ -73.61301
700
+ ],
701
+ [
702
+ 45.53144,
703
+ -73.61289
704
+ ],
705
+ [
706
+ 45.53166,
707
+ -73.61267
708
+ ],
709
+ [
710
+ 45.53189,
711
+ -73.61245
712
+ ],
713
+ [
714
+ 45.53203,
715
+ -73.6123
716
+ ],
717
+ [
718
+ 45.53192,
719
+ -73.61205
720
+ ],
721
+ [
722
+ 45.53241,
723
+ -73.61152
724
+ ],
725
+ [
726
+ 45.53296,
727
+ -73.61102
728
+ ],
729
+ [
730
+ 45.53346,
731
+ -73.61053
732
+ ],
733
+ [
734
+ 45.53395,
735
+ -73.61009
736
+ ],
737
+ [
738
+ 45.53402,
739
+ -73.60991
740
+ ],
741
+ [
742
+ 45.53436,
743
+ -73.6096
744
+ ],
745
+ [
746
+ 45.53472,
747
+ -73.60926
748
+ ],
749
+ [
750
+ 45.53488,
751
+ -73.60911
752
+ ],
753
+ [
754
+ 45.53515,
755
+ -73.60886
756
+ ],
757
+ [
758
+ 45.53547,
759
+ -73.60857
760
+ ],
761
+ [
762
+ 45.53563,
763
+ -73.60842
764
+ ],
765
+ [
766
+ 45.53599,
767
+ -73.60809
768
+ ],
769
+ [
770
+ 45.53625,
771
+ -73.60785
772
+ ],
773
+ [
774
+ 45.53627,
775
+ -73.60767
776
+ ],
777
+ [
778
+ 45.53597,
779
+ -73.60702
780
+ ],
781
+ [
782
+ 45.53553,
783
+ -73.60605
784
+ ],
785
+ [
786
+ 45.5353,
787
+ -73.60554
788
+ ],
789
+ [
790
+ 45.53517,
791
+ -73.60525
792
+ ]
793
+ ]
794
+ },
795
+ {
796
+ "mode": "SUBWAY",
797
+ "from": "Station Beaubien",
798
+ "to": "Station Lucien-L'Allier",
799
+ "start_time": 1780575660000,
800
+ "end_time": 1780576500000,
801
+ "duration_sec": 0.84,
802
+ "distance_m": 6800.91,
803
+ "route": "Line 2 - Orange",
804
+ "geometry_sampled_50m": null
805
+ },
806
+ {
807
+ "mode": "WALK",
808
+ "from": "Station Lucien-L'Allier",
809
+ "to": "Destination",
810
+ "start_time": 1780576500000,
811
+ "end_time": 1780577437000,
812
+ "duration_sec": 0.937,
813
+ "distance_m": 883.72,
814
+ "route": "",
815
+ "geometry_sampled_50m": [
816
+ [
817
+ 45.49476,
818
+ -73.57111
819
+ ],
820
+ [
821
+ 45.4948,
822
+ -73.57133
823
+ ],
824
+ [
825
+ 45.49505,
826
+ -73.57186
827
+ ],
828
+ [
829
+ 45.49515,
830
+ -73.57206
831
+ ],
832
+ [
833
+ 45.49531,
834
+ -73.57241
835
+ ],
836
+ [
837
+ 45.49561,
838
+ -73.57302
839
+ ],
840
+ [
841
+ 45.4953,
842
+ -73.57336
843
+ ],
844
+ [
845
+ 45.49512,
846
+ -73.57353
847
+ ],
848
+ [
849
+ 45.49523,
850
+ -73.57375
851
+ ],
852
+ [
853
+ 45.49594,
854
+ -73.57522
855
+ ],
856
+ [
857
+ 45.49622,
858
+ -73.57582
859
+ ],
860
+ [
861
+ 45.49643,
862
+ -73.57626
863
+ ],
864
+ [
865
+ 45.49655,
866
+ -73.57648
867
+ ],
868
+ [
869
+ 45.49673,
870
+ -73.57687
871
+ ],
872
+ [
873
+ 45.49683,
874
+ -73.57709
875
+ ],
876
+ [
877
+ 45.49697,
878
+ -73.57737
879
+ ],
880
+ [
881
+ 45.49719,
882
+ -73.57784
883
+ ],
884
+ [
885
+ 45.4973,
886
+ -73.57805
887
+ ],
888
+ [
889
+ 45.49741,
890
+ -73.57826
891
+ ],
892
+ [
893
+ 45.49782,
894
+ -73.57909
895
+ ],
896
+ [
897
+ 45.49801,
898
+ -73.5795
899
+ ],
900
+ [
901
+ 45.49774,
902
+ -73.57981
903
+ ],
904
+ [
905
+ 45.49755,
906
+ -73.57991
907
+ ]
908
+ ]
909
+ }
910
+ ]
911
+ }
912
+ ]
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn[standard]
3
+ gradio
4
+ huggingface_hub
5
+ pydantic
6
+ pandas
routing.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+ import polyline
4
+ import math
5
+
6
+ OTP_BASE_URL = "http://localhost:8080/otp/routers/default/plan"
7
+
8
+ def haversine(lat1, lon1, lat2, lon2):
9
+ R = 6371000 # meters
10
+ phi1, phi2 = math.radians(lat1), math.radians(lat2)
11
+ dphi = math.radians(lat2 - lat1)
12
+ dlambda = math.radians(lon2 - lon1)
13
+
14
+ a = math.sin(dphi/2)**2 + math.cos(phi1)*math.cos(phi2)*math.sin(dlambda/2)**2
15
+ return 2 * R * math.asin(math.sqrt(a))
16
+
17
+ def sample_along_line(coords, step=50):
18
+ if len(coords) < 2:
19
+ return coords
20
+
21
+ sampled = [coords[0]]
22
+ acc_dist = 0
23
+
24
+ for i in range(1, len(coords)):
25
+ lat1, lon1 = coords[i - 1]
26
+ lat2, lon2 = coords[i]
27
+
28
+ seg_dist = haversine(lat1, lon1, lat2, lon2)
29
+ acc_dist += seg_dist
30
+
31
+ if acc_dist >= step:
32
+ sampled.append((lat2, lon2))
33
+ acc_dist = 0
34
+
35
+ return sampled
36
+
37
+ def get_routes(from_lat, from_lon, to_lat, to_lon,
38
+ modes="WALK,TRANSIT",
39
+ num_itineraries=3):
40
+
41
+ params = {
42
+ "fromPlace": f"{from_lat},{from_lon}",
43
+ "toPlace": f"{to_lat},{to_lon}",
44
+ "mode": modes,
45
+ "numItineraries": num_itineraries,
46
+ "maxWalkDistance": 1500,
47
+ "arriveBy": "false",
48
+ "date": "2026-06-04",
49
+ "time": "08:00am"
50
+ }
51
+
52
+ response = requests.get(OTP_BASE_URL, params=params)
53
+ response.raise_for_status()
54
+ data = response.json()
55
+
56
+ itineraries = data.get("plan", {}).get("itineraries", [])
57
+
58
+ routes_output = []
59
+
60
+ for idx, itin in enumerate(itineraries):
61
+ route = {
62
+ "route_id": idx,
63
+ "duration_sec": itin.get("duration", 0) / 1000,
64
+ "transfers": itin.get("transfers", 0),
65
+ "legs": []
66
+ }
67
+
68
+ for leg in itin.get("legs", []):
69
+
70
+ leg_data = {
71
+ "mode": leg.get("mode"),
72
+ "from": leg.get("from", {}).get("name"),
73
+ "to": leg.get("to", {}).get("name"),
74
+ "start_time": leg.get("startTime"),
75
+ "end_time": leg.get("endTime"),
76
+ "duration_sec": leg.get("duration", 0) / 1000,
77
+ "distance_m": leg.get("distance", 0),
78
+ "route": leg.get("route"),
79
+ "geometry_sampled_50m": None
80
+ }
81
+
82
+ # ONLY for walking legs
83
+ if leg.get("mode") == "WALK":
84
+ geom = leg.get("legGeometry", {}).get("points")
85
+
86
+ if geom:
87
+ coords = polyline.decode(geom) # [(lat, lon), ...]
88
+ sampled = sample_along_line(coords, step=20)
89
+ leg_data["geometry_sampled_50m"] = sampled
90
+
91
+ route["legs"].append(leg_data)
92
+
93
+ routes_output.append(route)
94
+
95
+ return routes_output
96
+
97
+
98
+ def save_routes_to_json(routes, filename="otp_routes.json"):
99
+ with open(filename, "w", encoding="utf-8") as f:
100
+ json.dump(routes, f, indent=2, ensure_ascii=False)
101
+ print(f"Saved {len(routes)} routes to {filename}")
102
+
103
+
104
+
105
+ """exmample in montreal"""
106
+ if __name__ == "__main__":
107
+ routes = get_routes(
108
+ from_lat=45.53080483132569, from_lon=-73.61353945157414, # mila
109
+ to_lat=45.49758656380192, to_lon=-73.5799738767698 # accio cup
110
+ )
111
+
112
+ save_routes_to_json(routes, "montreal_routes.json")
scripts/run_otp.sh ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ echo "πŸš€ Starting OTP server"
5
+
6
+ # go to project root (adjust if needed)
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ cd "$SCRIPT_DIR/.."
9
+
10
+ DATA_DIR="data"
11
+
12
+ echo "πŸ“‚ Checking data folder..."
13
+ ls -lh "$DATA_DIR"
14
+
15
+ echo "β˜• Java version:"
16
+ java -version
17
+
18
+ echo "πŸ”Ž Finding OTP jar..."
19
+
20
+ OTP_JAR=$(find . -maxdepth 3 -name "otp-2.5.0-shaded.jar" | head -n 1)
21
+
22
+ if [ -z "$OTP_JAR" ]; then
23
+ echo "❌ OTP jar not found"
24
+ exit 1
25
+ fi
26
+
27
+ echo "βœ… Using: $OTP_JAR"
28
+
29
+ echo "🧹 Cleaning old graph (optional)"
30
+ rm -rf "$DATA_DIR/graph" || true
31
+
32
+ echo "βš™οΈ Building + starting OTP server..."
33
+
34
+ java -Xmx6G -jar "$OTP_JAR" \
35
+ --build "$DATA_DIR" \
36
+ --serve \
37
+ --port 8080
38
+
39
+ echo "βœ… OTP running at http://localhost:8080"