Now that our Python script generates predictions, weโll save the forecasted values into a database table and display them alongside historical data in Laravel.
๐งฉ Step 1: Create a forecast_results table
php artisan make:model ForecastResult -m
In database/migrations/xxxx_create_forecast_results_table.php
:
public function up(): void
{
Schema::create('forecast_results', function (Blueprint $table) {
$table->id();
$table->date('forecast_date');
$table->decimal('yhat', 10, 2); // predicted value
$table->decimal('yhat_lower', 10, 2); // lower bound
$table->decimal('yhat_upper', 10, 2); // upper bound
$table->timestamps();
});
}
Run the migration:
php artisan migrate
๐ Step 2: Modify Python script to save forecast CSV
Update the end of forecast_sales.py
:
forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail(30).to_csv('forecast_results.csv', index=False)
This will save the latest 30-day forecast to
forecast_results.csv
.
๐ Step 3: Create Laravel import logic
php artisan make:command ImportForecastResults
In app/Console/Commands/ImportForecastResults.php
:
use Illuminate\Console\Command;
use App\Models\ForecastResult;
use Illuminate\Support\Facades\Storage;
class ImportForecastResults extends Command
{
protected $signature = 'forecast:import';
protected $description = 'Import forecasted results from CSV into DB';
public function handle()
{
$file = base_path('app/AI/forecast_results.csv');
if (!file_exists($file)) {
$this->error('CSV file not found.');
return;
}
$data = array_map('str_getcsv', file($file));
$header = array_shift($data);
ForecastResult::truncate();
foreach ($data as $row) {
ForecastResult::create([
'forecast_date' => $row[0],
'yhat' => $row[1],
'yhat_lower' => $row[2],
'yhat_upper' => $row[3],
]);
}
$this->info('Forecast results imported successfully.');
}
}
๐ Step 4: Display forecast in Blade chart
In SalesController.php
:
use App\Models\ForecastResult;
public function index()
{
// Existing sales data
$sales = ...;
// Forecast data
$forecast = ForecastResult::orderBy('forecast_date')->get();
$forecastDates = $forecast->pluck('forecast_date')->map(fn($d) => date('d M', strtotime($d)));
$yhat = $forecast->pluck('yhat');
return view('sales.index', compact('labels', 'totals', 'forecastDates', 'yhat'));
}
In resources/views/sales/index.blade.php
, add another dataset:
{
label: 'Forecast (RM)',
data: @json($yhat),
borderColor: 'rgba(255, 99, 132, 1)',
borderDash: [5, 5],
tension: 0.3
}
โ Up next (Day 7): weโll highlight trends and anomalies in the forecast, and annotate the chart with GPT-generated insights.