42Cummer commited on
Commit
4b24c92
·
verified ·
1 Parent(s): ff79c1b

Upload app.py

Browse files
Files changed (1) hide show
  1. src/app.py +27 -17
src/app.py CHANGED
@@ -107,12 +107,11 @@ async def get_route_view(route_id: str):
107
  placeholders = ','.join(['?'] * len(trip_ids))
108
 
109
  # We use CAST(? AS VARCHAR) to force DuckDB to match strings to strings
110
- # Use COALESCE(departure_time, arrival_time) to match prediction logic
111
  query = f"""
112
  SELECT
113
  CAST(st.trip_id AS VARCHAR),
114
  CAST(st.stop_id AS VARCHAR),
115
- COALESCE(st.departure_time, st.arrival_time) as scheduled_time,
116
  t.trip_headsign
117
  FROM stop_times st
118
  JOIN trips t ON CAST(st.trip_id AS VARCHAR) = CAST(t.trip_id AS VARCHAR)
@@ -140,9 +139,12 @@ async def get_route_view(route_id: str):
140
  if pred_time and stop_id:
141
  sched_hms = schedule_map.get((str(bus['trip_id']), str(stop_id)))
142
  if sched_hms:
143
- # Math: (Reality Unix - Plan Unix) / 60
144
- plan_ts = service_day_ts + hms_to_seconds(sched_hms)
145
- raw_delay_mins = round((pred_time - plan_ts) / 60)
 
 
 
146
 
147
  enriched.append({
148
  "number": bus['id'],
@@ -183,7 +185,7 @@ async def get_vehicle_view(vehicle_id: str):
183
  query = """
184
  SELECT
185
  t.trip_headsign,
186
- COALESCE(st.departure_time, st.arrival_time) as scheduled_time
187
  FROM trips t
188
  JOIN stop_times st ON CAST(t.trip_id AS VARCHAR) = CAST(st.trip_id AS VARCHAR)
189
  WHERE CAST(t.trip_id AS VARCHAR) = ?
@@ -196,13 +198,14 @@ async def get_vehicle_view(vehicle_id: str):
196
  destination = row[0]
197
  scheduled_hms = row[1]
198
 
199
- # Math: Reality (Unix Time) - Plan (Service Day + Scheduled Seconds)
200
- # Note: predicted_time uses departure.time if available, else arrival.time
201
- # So we use COALESCE(departure_time, arrival_time) to match
202
  if predicted_time:
203
  service_day_ts = get_service_day_start_ts()
204
- plan_ts = service_day_ts + hms_to_seconds(scheduled_hms)
205
- delay_mins = round((predicted_time - plan_ts) / 60)
 
 
 
206
  else:
207
  # If no next_stop_id, try to get destination from trip_id only
208
  query = """
@@ -246,7 +249,8 @@ async def get_stop_view(stop_code: str):
246
  # Build vehicles map for quick lookup
247
  vehicles = {str(v['trip_id']): v for v in vehicles_list}
248
 
249
- now = datetime.now().timestamp()
 
250
  two_hours_out = now + 7200
251
  arrivals = []
252
 
@@ -259,9 +263,8 @@ async def get_stop_view(stop_code: str):
259
  if now <= pred_time <= two_hours_out:
260
 
261
  # 4. Handshake with DB for destination and schedule
262
- # Use COALESCE(departure_time, arrival_time) to match prediction logic
263
  query = """
264
- SELECT t.trip_headsign, COALESCE(st.departure_time, st.arrival_time) as scheduled_time, r.route_short_name
265
  FROM trips t
266
  JOIN stop_times st ON CAST(t.trip_id AS VARCHAR) = CAST(st.trip_id AS VARCHAR)
267
  JOIN routes r ON t.route_id = r.route_id
@@ -274,13 +277,19 @@ async def get_stop_view(stop_code: str):
274
  # Find the actual bus for fullness (if it's on the road)
275
  bus = vehicles.get(trip_id)
276
 
277
- plan_ts = get_service_day_start_ts() + hms_to_seconds(row[1])
 
 
 
 
 
 
278
 
279
  arrivals.append({
280
  "route": row[2],
281
  "destination": row[0],
282
  "eta_mins": round((pred_time - now) / 60),
283
- "delay_mins": round((pred_time - plan_ts) / 60),
284
  "fullness": translate_occupancy(bus['occupancy']) if bus else "Unknown",
285
  "vehicle_id": bus['id'] if bus else "In Transit"
286
  })
@@ -293,9 +302,10 @@ async def get_all_alerts():
293
  """
294
  Returns every active service alert for the entire TTC network.
295
  """
 
296
  data = await ttc_cache.get_data()
297
  return {
298
- "timestamp": datetime.now().timestamp(),
299
  "count": len(data["alerts"]),
300
  "alerts": data["alerts"]
301
  }
 
107
  placeholders = ','.join(['?'] * len(trip_ids))
108
 
109
  # We use CAST(? AS VARCHAR) to force DuckDB to match strings to strings
 
110
  query = f"""
111
  SELECT
112
  CAST(st.trip_id AS VARCHAR),
113
  CAST(st.stop_id AS VARCHAR),
114
+ st.arrival_time as scheduled_time,
115
  t.trip_headsign
116
  FROM stop_times st
117
  JOIN trips t ON CAST(st.trip_id AS VARCHAR) = CAST(t.trip_id AS VARCHAR)
 
139
  if pred_time and stop_id:
140
  sched_hms = schedule_map.get((str(bus['trip_id']), str(stop_id)))
141
  if sched_hms:
142
+ # DELAY = SCHEDULED - PREDICTED (negative = late, positive = early)
143
+ # Handle GTFS times >= 24 hours (next day)
144
+ h, m, s = map(int, sched_hms.split(':'))
145
+ extra_days = h // 24
146
+ plan_ts = service_day_ts + (extra_days * 86400) + hms_to_seconds(sched_hms)
147
+ raw_delay_mins = round((plan_ts - pred_time) / 60)
148
 
149
  enriched.append({
150
  "number": bus['id'],
 
185
  query = """
186
  SELECT
187
  t.trip_headsign,
188
+ st.arrival_time as scheduled_time
189
  FROM trips t
190
  JOIN stop_times st ON CAST(t.trip_id AS VARCHAR) = CAST(st.trip_id AS VARCHAR)
191
  WHERE CAST(t.trip_id AS VARCHAR) = ?
 
198
  destination = row[0]
199
  scheduled_hms = row[1]
200
 
201
+ # DELAY = SCHEDULED - PREDICTED (negative = late, positive = early)
 
 
202
  if predicted_time:
203
  service_day_ts = get_service_day_start_ts()
204
+ # Handle GTFS times >= 24 hours (next day)
205
+ h, m, s = map(int, scheduled_hms.split(':'))
206
+ extra_days = h // 24
207
+ plan_ts = service_day_ts + (extra_days * 86400) + hms_to_seconds(scheduled_hms)
208
+ delay_mins = round((plan_ts - predicted_time) / 60)
209
  else:
210
  # If no next_stop_id, try to get destination from trip_id only
211
  query = """
 
249
  # Build vehicles map for quick lookup
250
  vehicles = {str(v['trip_id']): v for v in vehicles_list}
251
 
252
+ from datetime import timezone
253
+ now = datetime.now(timezone.utc).timestamp()
254
  two_hours_out = now + 7200
255
  arrivals = []
256
 
 
263
  if now <= pred_time <= two_hours_out:
264
 
265
  # 4. Handshake with DB for destination and schedule
 
266
  query = """
267
+ SELECT t.trip_headsign, st.arrival_time as scheduled_time, r.route_short_name
268
  FROM trips t
269
  JOIN stop_times st ON CAST(t.trip_id AS VARCHAR) = CAST(st.trip_id AS VARCHAR)
270
  JOIN routes r ON t.route_id = r.route_id
 
277
  # Find the actual bus for fullness (if it's on the road)
278
  bus = vehicles.get(trip_id)
279
 
280
+ # DELAY = SCHEDULED - PREDICTED (negative = late, positive = early)
281
+ service_day_ts = get_service_day_start_ts()
282
+ scheduled_hms = row[1]
283
+ # Handle GTFS times >= 24 hours (next day)
284
+ h, m, s = map(int, scheduled_hms.split(':'))
285
+ extra_days = h // 24
286
+ plan_ts = service_day_ts + (extra_days * 86400) + hms_to_seconds(scheduled_hms)
287
 
288
  arrivals.append({
289
  "route": row[2],
290
  "destination": row[0],
291
  "eta_mins": round((pred_time - now) / 60),
292
+ "delay_mins": round((plan_ts - pred_time) / 60),
293
  "fullness": translate_occupancy(bus['occupancy']) if bus else "Unknown",
294
  "vehicle_id": bus['id'] if bus else "In Transit"
295
  })
 
302
  """
303
  Returns every active service alert for the entire TTC network.
304
  """
305
+ from datetime import timezone
306
  data = await ttc_cache.get_data()
307
  return {
308
+ "timestamp": datetime.now(timezone.utc).timestamp(),
309
  "count": len(data["alerts"]),
310
  "alerts": data["alerts"]
311
  }