feat: ai analyze

This commit is contained in:
2026-05-18 15:42:56 +02:00
parent 8c612452f2
commit fe78c000f0
7 changed files with 350 additions and 4 deletions
+91
View File
@@ -0,0 +1,91 @@
<?php
use App\Ai\Agents\MealImageAnalyzer;
use App\Enums\IngredientUnit;
use App\Enums\MealPostType;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Laravel\Sanctum\Sanctum;
uses(RefreshDatabase::class);
function fakeMealAnalysisImage(): UploadedFile
{
$path = tempnam(sys_get_temp_dir(), 'meal-analysis-');
file_put_contents($path, base64_decode(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAFgwJ/lmHqWQAAAABJRU5ErkJggg=='
));
return new UploadedFile($path, 'meal.png', 'image/png', null, true);
}
it('analyzes a meal image into a draft', function () {
Sanctum::actingAs(User::factory()->create());
MealImageAnalyzer::fake([
[
'title' => ' Bowl saumon avocat ',
'caption' => 'Un bowl avec du saumon, du riz et de lavocat.',
'type' => MealPostType::LUNCH->value,
'calories' => 612,
'proteins' => 39.4,
'carbs' => 58.2,
'fats' => 25.1,
'ingredients' => [
[
'position' => 12,
'ingredient' => ' Riz ',
'quantity' => 150,
'unit' => IngredientUnit::GRAM->value,
],
[
'position' => 13,
'ingredient' => 'Saumon',
'quantity' => 120,
'unit' => IngredientUnit::GRAM->value,
],
],
],
]);
$response = $this
->withHeader('Accept', 'application/json')
->post('/api/meal-posts/analyze-image', [
'image' => fakeMealAnalysisImage(),
]);
$response
->assertOk()
->assertJsonPath('data.title', 'Bowl saumon avocat')
->assertJsonPath('data.type', MealPostType::LUNCH->value)
->assertJsonPath('data.calories', 612)
->assertJsonPath('data.proteins', 39.4)
->assertJsonPath('data.ingredients.0.position', 1)
->assertJsonPath('data.ingredients.0.ingredient', 'Riz')
->assertJsonPath('data.ingredients.1.ingredient', 'Saumon');
MealImageAnalyzer::assertPrompted(
fn ($prompt): bool => str_contains($prompt->prompt, "Analyse l'image")
&& $prompt->attachments->count() === 1
);
});
it('requires authentication to analyze a meal image', function () {
$this
->withHeader('Accept', 'application/json')
->post('/api/meal-posts/analyze-image', [
'image' => fakeMealAnalysisImage(),
])
->assertUnauthorized();
});
it('validates the analyzed image', function () {
Sanctum::actingAs(User::factory()->create());
$this
->postJson('/api/meal-posts/analyze-image')
->assertUnprocessable()
->assertJsonValidationErrors(['image']);
});