feat: add LLM prediction providers with structured output support
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ovidiu U
2026-04-07 14:42:44 +01:00
parent e9612666e3
commit 6a80c11f38
18 changed files with 1101 additions and 484 deletions

View File

@@ -152,18 +152,17 @@ GET /api/stats/searches?period=month
### GET `/api/prediction`
National (or regional) fuel price direction forecast for the next 7 days, based on live price data signals.
National or regional E10 fuel price direction forecast for the next 7 days, based on live price data signals. Always analyses E10 — the most widely available fuel and the one with the most price history.
| Parameter | Type | Description |
|---|---|---|
| `fuel_type` | string | **Required.** Same aliases as `/api/stations` |
| `lat` | float | Optional. Enables regional momentum signal |
| `lng` | float | Optional. Enables regional momentum signal |
| `lat` | float | Optional. Decimal latitude. Enables regional prediction (50km radius). |
| `lng` | float | Optional. Decimal longitude. Required if `lat` is provided. |
**Example request:**
```
GET /api/prediction?fuel_type=diesel
GET /api/prediction?fuel_type=petrol&lat=51.5074&lng=-0.1278
GET /api/prediction
GET /api/prediction?lat=51.5074&lng=-0.1278
```
**Response:**
@@ -235,6 +234,13 @@ GET /api/prediction?fuel_type=petrol&lat=51.5074&lng=-0.1278
}
```
**`region_key` values:**
| Value | Meaning |
|---|---|
| `"national"` | No coordinates provided. `current_avg` and signals use national data. `regional_momentum` is disabled. |
| `"regional"` | Coordinates provided. `current_avg` uses stations within 50km. `regional_momentum` is the primary signal (50% weight). Falls back to national average if no stations found in radius. |
**Key fields:**
| Field | Values | Meaning |
@@ -243,7 +249,21 @@ GET /api/prediction?fuel_type=petrol&lat=51.5074&lng=-0.1278
| `action` | `"fill_now"`, `"wait"`, `"no_signal"` | Consumer-facing recommendation |
| `confidence_label` | `"high"` (≥70), `"medium"` (≥40), `"low"` (<40) | Signal strength |
| `predicted_change_pence` | float | Expected p/litre change over 7 days |
| `current_avg` | float | Current national average in pence (e.g. `143.9` = 143.9p) |
| `current_avg` | float | Average price in pence (e.g. `143.9` = 143.9p). Regional if lat/lng given, else national. |
**Signal weights:**
| Scope | Signal | Weight |
|---|---|---|
| National | trend | 45% |
| National | brand_behaviour | 25% |
| National | day_of_week | 20% |
| National | price_stickiness | 10% |
| Regional | regional_momentum | 50% |
| Regional | trend | 20% |
| Regional | day_of_week | 15% |
| Regional | brand_behaviour | 10% |
| Regional | price_stickiness | 5% |
**Signal structure** (each signal in `signals`):
@@ -254,12 +274,9 @@ GET /api/prediction?fuel_type=petrol&lat=51.5074&lng=-0.1278
| `direction` | `"up"` / `"down"` / `"stable"` | Signal direction |
| `detail` | string | Human-readable explanation |
| `data_points` | int | Number of price records used |
| `enabled` | bool | False if signal was skipped (missing data/coords) |
| `enabled` | bool | False if signal was skipped (missing data or coordinates) |
**Error — unknown fuel type:**
```json
{ "errors": { "fuel_type": ["Unknown fuel type. Use: diesel, petrol, e10, e5, hvo, b10."] } }
```
**LLM-backed prediction** — separately, the nightly `oil:predict` command generates an oil price direction from Brent crude data and stores it in `price_predictions`. This feeds into `AlertScoringService` (Signal 4) but is not exposed directly through this endpoint. See [LLM Prediction Providers](llm-prediction-providers.md).
---