feat: save ai usage
This commit is contained in:
@@ -3,38 +3,66 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Ai\Agents\MealImageAnalyzer;
|
||||
use App\Enums\AiUsageType;
|
||||
use App\Enums\IngredientUnit;
|
||||
use App\Enums\MealPostType;
|
||||
use App\Http\Requests\MealImageAnalysisRequest;
|
||||
use App\Services\AiUsageRecorder;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Ai\Responses\Data\Usage;
|
||||
use Throwable;
|
||||
|
||||
class MealImageAnalysisController extends Controller
|
||||
{
|
||||
public function store(MealImageAnalysisRequest $request): JsonResponse
|
||||
public function store(MealImageAnalysisRequest $request, AiUsageRecorder $aiUsageRecorder): JsonResponse
|
||||
{
|
||||
$image = $request->file('image');
|
||||
$input = $this->analysisInput($image);
|
||||
|
||||
try {
|
||||
$response = MealImageAnalyzer::make()->prompt(
|
||||
$this->prompt(),
|
||||
[$request->file('image')],
|
||||
[$image],
|
||||
timeout: 90,
|
||||
);
|
||||
} catch (Throwable $exception) {
|
||||
report($exception);
|
||||
|
||||
$aiUsageRecorder->failed(
|
||||
user: $request->user(),
|
||||
type: AiUsageType::MEAL_IMAGE_ANALYSIS,
|
||||
exception: $exception,
|
||||
input: $input,
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('api.meal_image_analysis.failed'),
|
||||
], 502);
|
||||
}
|
||||
|
||||
$draft = $this->normalizeDraft(
|
||||
$response instanceof Arrayable
|
||||
? $response->toArray()
|
||||
: (json_decode($response->text, true) ?: [])
|
||||
);
|
||||
|
||||
$aiUsageRecorder->success(
|
||||
user: $request->user(),
|
||||
type: AiUsageType::MEAL_IMAGE_ANALYSIS,
|
||||
input: $input,
|
||||
output: $draft,
|
||||
provider: $response->meta->provider ?? null,
|
||||
model: $response->meta->model ?? null,
|
||||
promptTokens: $response->usage->promptTokens ?? null,
|
||||
completionTokens: $response->usage->completionTokens ?? null,
|
||||
totalTokens: $this->totalTokens($response->usage ?? null),
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'data' => $this->normalizeDraft(
|
||||
$response instanceof Arrayable
|
||||
? $response->toArray()
|
||||
: (json_decode($response->text, true) ?: [])
|
||||
),
|
||||
'data' => $draft,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -51,6 +79,26 @@ Contraintes:
|
||||
PROMPT;
|
||||
}
|
||||
|
||||
private function analysisInput(UploadedFile $image): array
|
||||
{
|
||||
return [
|
||||
'image' => [
|
||||
'client_original_name' => $image->getClientOriginalName(),
|
||||
'mime_type' => $image->getMimeType(),
|
||||
'size' => $image->getSize(),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function totalTokens(?Usage $usage): ?int
|
||||
{
|
||||
if (! $usage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $usage->promptTokens + $usage->completionTokens;
|
||||
}
|
||||
|
||||
private function normalizeDraft(array $draft): array
|
||||
{
|
||||
$type = MealPostType::tryFrom($this->cleanString($draft['type'] ?? '', 32))
|
||||
|
||||
Reference in New Issue
Block a user