diff --git a/app/Http/Controllers/Api/Mini/AfiaController.php b/app/Http/Controllers/Api/Mini/AfiaController.php new file mode 100644 index 0000000..51ad2f1 --- /dev/null +++ b/app/Http/Controllers/Api/Mini/AfiaController.php @@ -0,0 +1,82 @@ +validate([ + 'message' => ['required', 'string', 'max:2000'], + 'history' => ['nullable', 'array', 'max:20'], + 'history.*.role' => ['nullable', 'string'], + 'history.*.text' => ['nullable', 'string'], + ]); + + if (! $afia->enabled()) { + return response()->json(['message' => 'Afia is not available right now.'], 503); + } + + try { + $reply = $afia->chat(trim($validated['message']), $validated['history'] ?? [], $this->context()); + } catch (\Throwable $e) { + report($e); + + return response()->json(['message' => 'Afia could not respond right now. Please try again.'], 502); + } + + return response()->json(['reply' => $reply]); + } + + /** @return array */ + private function context(): array + { + $account = ladill_account(); + $types = QrTypeCatalog::paymentTypes(); + $codes = $account->qrCodes()->whereIn('type', $types); + + $ctx = [ + 'signed_in' => 'yes', + 'qr_codes_total' => (clone $codes)->count(), + 'qr_codes_active' => (clone $codes)->where('is_active', true)->count(), + 'scans_total' => (int) (clone $codes)->sum('scans_total'), + 'top_code_type' => (clone $codes) + ->selectRaw('type, count(*) as total') + ->groupBy('type') + ->orderByDesc('total') + ->value('type') ?: 'none yet', + ]; + + if ($account->public_id) { + try { + $ctx['wallet_balance_ghs'] = number_format(app(BillingClient::class)->balanceMinor((string) $account->public_id) / 100, 2); + } catch (\Throwable) { + } + } + + $recent = $account->qrCodes() + ->whereIn('type', $types) + ->latest('updated_at') + ->limit(3) + ->get(['type', 'label', 'short_code', 'scans_total']); + + if ($recent->isNotEmpty()) { + $ctx['recent_codes'] = $recent->map(fn (QrCode $code): string => sprintf( + '%s (%s, %d scans)', + $code->label ?: $code->short_code, + QrTypeCatalog::label($code->type), + $code->scans_total, + ))->implode('; '); + } + + return $ctx; + } +} diff --git a/routes/api.php b/routes/api.php index 5bc2f47..e9a2b1d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -3,6 +3,7 @@ use App\Http\Controllers\Api\AuthController; use App\Http\Controllers\Api\MeController; use App\Http\Controllers\Api\Mini\AccountController as MiniAccountController; +use App\Http\Controllers\Api\Mini\AfiaController as MiniAfiaController; use App\Http\Controllers\Api\Mini\OverviewController as MiniOverviewController; use App\Http\Controllers\Api\Mini\PaymentQrController as MiniPaymentQrController; use App\Http\Controllers\Api\Mini\PaymentsController as MiniPaymentsController; @@ -30,6 +31,7 @@ Route::prefix('v1')->group(function () { // Ladill Mini — payments product. Route::get('/mini/overview', MiniOverviewController::class)->name('api.mini.overview'); + Route::post('/mini/afia/chat', [MiniAfiaController::class, 'chat'])->middleware('throttle:30,1')->name('api.mini.afia.chat'); Route::get('/mini/payment-qrs', [MiniPaymentQrController::class, 'index'])->name('api.mini.payment-qrs.index'); Route::post('/mini/payment-qrs', [MiniPaymentQrController::class, 'store'])->name('api.mini.payment-qrs.store'); Route::get('/mini/payment-qrs/{paymentQr}', [MiniPaymentQrController::class, 'show'])->whereNumber('paymentQr')->name('api.mini.payment-qrs.show');