Day 8 – Ask GPT: “What Changed Yesterday?” Using Natural Language#LaravelGPTAudit #AIAssistant #NaturalLanguageAudit #GPTFunctionCalling #LaravelLogs


Today we’ll make your Laravel audit dashboard interactive — by letting admins ask questions in plain English, such as:

  • “What changed yesterday?”
  • “Who deleted records this week?”
  • “Show me updates by finance department”

GPT will parse the question, run the correct query, and reply with a readable answer.


🧠 Step 1: Enable GPT Function Calling

Update your helper or create a new one: AuditQueryAssistant.php

namespace App\Helpers;

use OpenAI\Laravel\Facades\OpenAI;
use Illuminate\Support\Carbon;
use Spatie\Activitylog\Models\Activity;

class AuditQueryAssistant
{
    public static function ask(string $userInput): string
    {
        $functions = [
            [
                'name' => 'query_audit_logs',
                'description' => 'Query Laravel audit logs based on user filters',
                'parameters' => [
                    'type' => 'object',
                    'properties' => [
                        'action' => ['type' => 'string', 'description' => 'The action type (created, updated, deleted)'],
                        'user' => ['type' => 'string', 'description' => 'User name (optional)'],
                        'date' => ['type' => 'string', 'description' => 'Date filter like "yesterday" or "last 7 days"'],
                    ],
                    'required' => ['action', 'date'],
                ],
            ]
        ];

        $response = OpenAI::chat()->create([
            'model' => 'gpt-4o',
            'messages' => [
                ['role' => 'user', 'content' => $userInput],
            ],
            'functions' => $functions,
            'function_call' => 'auto',
        ]);

        $fnCall = $response->choices[0]->message->function_call ?? null;

        if (!$fnCall) return 'Could not understand the query.';

        $args = json_decode($fnCall->arguments, true);

        return self::runQuery($args);
    }

    private static function runQuery(array $args): string
    {
        $query = Activity::with('causer');

        if (!empty($args['action'])) {
            $query->where('description', 'like', '%' . $args['action'] . '%');
        }

        if (!empty($args['user'])) {
            $query->whereHas('causer', function ($q) use ($args) {
                $q->where('name', 'like', '%' . $args['user'] . '%');
            });
        }

        if (!empty($args['date'])) {
            if (str_contains($args['date'], 'yesterday')) {
                $query->whereDate('created_at', Carbon::yesterday());
            } elseif (str_contains($args['date'], 'last 7')) {
                $query->where('created_at', '>=', now()->subDays(7));
            }
        }

        $logs = $query->limit(30)->get();

        if ($logs->isEmpty()) {
            return 'No matching logs found.';
        }

        return AuditSummaryHelper::translateToPlainEnglish($logs);
    }
}

📡 Step 2: Add chat form and controller method

In web.php:

Route::post('/audit-logs/ask', [\App\Http\Controllers\AuditLogController::class, 'ask'])->name('audit.logs.ask');

In AuditLogController.php:

public function ask(Request $request)
{
    $question = $request->input('question');
    $response = \App\Helpers\AuditQueryAssistant::ask($question);

    return back()->with('audit_query_response', $response);
}

💬 Step 3: Add chat input in index.blade.php

<form method="POST" action="{{ route('audit.logs.ask') }}" class="mb-4">
    @csrf
    <input name="question" class="border px-2 py-1 w-96" placeholder="Ask e.g. What changed yesterday?" value="{{ old('question') }}">
    <button class="bg-blue-600 text-white px-3 py-1 rounded">Ask GPT</button>
</form>

@if(session('audit_query_response'))
    <div class="bg-blue-100 text-blue-900 p-3 rounded mb-4 whitespace-pre-wrap">
        <strong>GPT Response:</strong><br>
        {!! nl2br(e(session('audit_query_response'))) !!}
    </div>
@endif

🔍 Example Usage

Input:
Who deleted items yesterday?

Output:
Jane Lee deleted 2 expired renewals on 10 June at 2:30 PM and 3:01 PM. No other deletions recorded that day.


✅ Tomorrow (Day 9), we’ll build GPT-based smart filters, turning natural queries like “customer updates over RM500 last month” into filtered where() queries.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.