Architecture
How the hour is written.
Data arrives as OSM topology via OSMnx and NetworkX, and as a 60-day multivariate stream: speed, flow, congestion, weather, density. Preprocessing is unromantic and non-negotiable — missing values, outlier interpolation, time sync, min-max, graph index mapping.
The LSTM consumes the temporal window. Its hidden state is the city’s short-term memory. The GAT consumes the same moment as a graph: each road asking its neighbors how much of their present should become its future. Fusion is the hybrid forecast. That tensor is not a chart. It is an edge-weight field.
From speed to policy
Dynamic weights enter the PPO environment. The agent proposes a path. Reward is the negative of experienced time, with penalties for re-entering a predicted jam. The clip in PPO is the adult in the room: updates stay proximal so a noisy afternoon cannot unteach a month.
Why hybrid error can be higher
A univariate LSTM can hug a single series until the residual is tiny and the route is still stupid. GAT spends capacity on neighbors. That shows up as MAE you can quote against us, and as detours you can actually drive. We print both numbers. The Ember CTA is the routing one.
Systems, not slides
PyTorch for the nets. Ultralytics for detection. Stable-Baselines3 for PPO. Folium for the scientific map. Three.js on this site for the public graph — a cousin of the adjacency matrix, not a replacement. Flask remains the lab server. Next.js 16 is the instrument face.
Nothing in this stack is a secret sauce. The sauce is the closed loop and the refusal to ship a predictor that cannot move a vehicle.
Constraints we keep
Five-minute bins, because finer is vanity without sensors. A real capital graph beats a synthetic grid. Optional YOLO, because not every host should download weights to say hello. Ember only on actions, because a technology page that shouts has already lost the argument.
What each public page uses
Predict and Map consume demo edge speeds + OSM geometry + place search (Nominatim / Overpass catalog). Influence builds a local attention-style matrix from those speeds near a place. Detect calls YOLOv8 when weights are present. Network is a Three.js teaching graph. Keeping the stack named this way stops “AI traffic” from becoming a single vague button.