feat: add LLM prediction providers with structured output support
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -30,22 +30,25 @@ class NationalFuelPredictionService
|
||||
* signals: array
|
||||
* }
|
||||
*/
|
||||
public function predict(FuelType $fuelType, ?float $lat = null, ?float $lng = null): array
|
||||
public function predict(?float $lat = null, ?float $lng = null): array
|
||||
{
|
||||
$currentAvg = $this->getCurrentNationalAverage($fuelType);
|
||||
$fuelType = FuelType::E10;
|
||||
$hasCoordinates = $lat !== null && $lng !== null;
|
||||
|
||||
$currentAvg = $this->getCurrentAverage($fuelType, $lat, $lng);
|
||||
$trend = $this->computeTrendSignal($fuelType);
|
||||
$dayOfWeek = $this->computeDayOfWeekSignal($fuelType);
|
||||
$brandBehaviour = $this->computeBrandBehaviourSignal($fuelType);
|
||||
$stickiness = $this->computeStickinessSignal($fuelType);
|
||||
|
||||
$nationalMomentum = $this->disabledSignal('National momentum disabled for national predictions');
|
||||
$regionalMomentum = $lat !== null && $lng !== null
|
||||
$regionalMomentum = $hasCoordinates
|
||||
? $this->computeRegionalMomentumSignal($fuelType, $lat, $lng)
|
||||
: $this->disabledSignal('No coordinates provided for regional momentum analysis');
|
||||
|
||||
$signals = compact('trend', 'dayOfWeek', 'brandBehaviour', 'nationalMomentum', 'regionalMomentum', 'stickiness');
|
||||
|
||||
[$direction, $confidenceScore] = $this->aggregateSignals($signals);
|
||||
[$direction, $confidenceScore] = $this->aggregateSignals($signals, $hasCoordinates);
|
||||
|
||||
$slope = $trend['slope'] ?? 0.0;
|
||||
$predictedChangePence = round($slope * self::PREDICTION_HORIZON_DAYS, 1);
|
||||
@@ -72,7 +75,7 @@ class NationalFuelPredictionService
|
||||
'action' => $action,
|
||||
'reasoning' => $this->buildReasoning($direction, $slope, $trend, $brandBehaviour),
|
||||
'prediction_horizon_days' => self::PREDICTION_HORIZON_DAYS,
|
||||
'region_key' => 'national',
|
||||
'region_key' => $hasCoordinates ? 'regional' : 'national',
|
||||
'methodology' => 'multi_signal_live_fallback',
|
||||
'signals' => [
|
||||
'trend' => $trend,
|
||||
@@ -85,8 +88,20 @@ class NationalFuelPredictionService
|
||||
];
|
||||
}
|
||||
|
||||
private function getCurrentNationalAverage(FuelType $fuelType): float
|
||||
private function getCurrentAverage(FuelType $fuelType, ?float $lat, ?float $lng): float
|
||||
{
|
||||
if ($lat !== null && $lng !== null) {
|
||||
$avg = DB::table('station_prices_current')
|
||||
->join('stations', 'station_prices_current.station_id', '=', 'stations.node_id')
|
||||
->where('station_prices_current.fuel_type', $fuelType->value)
|
||||
->whereRaw('(6371 * acos(LEAST(1.0, cos(radians(?)) * cos(radians(lat)) * cos(radians(lng) - radians(?)) + sin(radians(?)) * sin(radians(lat))))) <= 50', [$lat, $lng, $lat])
|
||||
->avg('station_prices_current.price_pence');
|
||||
|
||||
if ($avg !== null) {
|
||||
return round((float) $avg / 100, 1);
|
||||
}
|
||||
}
|
||||
|
||||
$avg = StationPriceCurrent::where('fuel_type', $fuelType->value)->avg('price_pence');
|
||||
|
||||
return $avg !== null ? round((float) $avg / 100, 1) : 0.0;
|
||||
@@ -391,14 +406,22 @@ class NationalFuelPredictionService
|
||||
* @param array<string, array{score: float, confidence: float, enabled: bool}> $signals
|
||||
* @return array{0: string, 1: float}
|
||||
*/
|
||||
private function aggregateSignals(array $signals): array
|
||||
private function aggregateSignals(array $signals, bool $hasCoordinates = false): array
|
||||
{
|
||||
$weights = [
|
||||
'trend' => 0.45,
|
||||
'dayOfWeek' => 0.20,
|
||||
'brandBehaviour' => 0.25,
|
||||
'stickiness' => 0.10,
|
||||
];
|
||||
$weights = $hasCoordinates
|
||||
? [
|
||||
'regionalMomentum' => 0.50,
|
||||
'trend' => 0.20,
|
||||
'dayOfWeek' => 0.15,
|
||||
'brandBehaviour' => 0.10,
|
||||
'stickiness' => 0.05,
|
||||
]
|
||||
: [
|
||||
'trend' => 0.45,
|
||||
'dayOfWeek' => 0.20,
|
||||
'brandBehaviour' => 0.25,
|
||||
'stickiness' => 0.10,
|
||||
];
|
||||
|
||||
$weightedSum = 0.0;
|
||||
$totalWeight = 0.0;
|
||||
|
||||
Reference in New Issue
Block a user