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.