168 lines
6.6 KiB
PHP
168 lines
6.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\Artwork;
|
|
use App\Models\ArtworkAiAssist;
|
|
use App\Models\Category;
|
|
use App\Models\ContentType;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
it('generates and stores artwork ai suggestions from the artisan command', function (): void {
|
|
config()->set('vision.enabled', true);
|
|
config()->set('vision.gateway.base_url', 'https://vision.local');
|
|
config()->set('vision.lm_studio.base_url', 'https://lmstudio.local');
|
|
config()->set('vision.lm_studio.model', 'google/gemma-3-4b');
|
|
config()->set('cdn.files_url', 'https://files.local');
|
|
|
|
$photography = ContentType::query()->create([
|
|
'name' => 'Photography',
|
|
'slug' => 'photography',
|
|
]);
|
|
|
|
Category::query()->create([
|
|
'content_type_id' => $photography->id,
|
|
'name' => 'Flowers',
|
|
'slug' => 'flowers',
|
|
'is_active' => true,
|
|
]);
|
|
|
|
$user = User::factory()->create();
|
|
$artwork = Artwork::factory()->create([
|
|
'user_id' => $user->id,
|
|
'hash' => 'cmdaa112233',
|
|
'file_name' => 'rose-closeup.jpg',
|
|
'title' => 'Rose Study',
|
|
]);
|
|
|
|
Http::fake([
|
|
'https://vision.local/analyze/all' => Http::response([
|
|
'clip' => [
|
|
['tag' => 'rose', 'confidence' => 0.96],
|
|
['tag' => 'flower', 'confidence' => 0.91],
|
|
],
|
|
'yolo' => [
|
|
['label' => 'flower', 'confidence' => 0.79],
|
|
],
|
|
'blip' => 'a close up photograph of a rose bud with soft natural background',
|
|
], 200),
|
|
'https://lmstudio.local/v1/chat/completions' => Http::response([
|
|
'choices' => [
|
|
[
|
|
'message' => [
|
|
'content' => json_encode([
|
|
'rose macro',
|
|
'flower close-up',
|
|
'soft petals',
|
|
'natural light',
|
|
'botanical photography',
|
|
'pink tones',
|
|
'shallow depth',
|
|
'floral detail',
|
|
'macro photography',
|
|
'garden bloom',
|
|
], JSON_THROW_ON_ERROR),
|
|
],
|
|
],
|
|
],
|
|
], 200),
|
|
]);
|
|
|
|
$this->artisan('artworks:ai-suggest', ['artwork_id' => $artwork->id])
|
|
->expectsOutputToContain('provider: lm_studio')
|
|
->expectsOutputToContain('tags: rose-macro, flower-close-up')
|
|
->expectsOutputToContain('content type: photography | category: flowers')
|
|
->assertSuccessful();
|
|
|
|
$assist = ArtworkAiAssist::query()->where('artwork_id', $artwork->id)->first();
|
|
|
|
expect($assist)->not->toBeNull();
|
|
expect($assist?->status)->toBe(ArtworkAiAssist::STATUS_READY);
|
|
expect($assist?->tag_suggestions_json)->not->toBeEmpty();
|
|
expect(collect($assist?->tag_suggestions_json ?? [])->contains(fn (array $row): bool => ($row['tag'] ?? null) === 'rose-macro'))->toBeTrue();
|
|
expect($assist?->raw_response_json['tag_generation']['raw_content'] ?? null)->toBe('["rose macro","flower close-up","soft petals","natural light","botanical photography","pink tones","shallow depth","floral detail","macro photography","garden bloom"]');
|
|
expect($assist?->raw_response_json['tag_generation']['image_url'] ?? null)->toBe('https://files.local/artworks/md/cm/da/cmdaa112233.webp');
|
|
});
|
|
|
|
it('supports overriding the provider to together from the artisan command', function (): void {
|
|
config()->set('vision.enabled', true);
|
|
config()->set('vision.gateway.base_url', 'https://vision.local');
|
|
config()->set('vision.together.base_url', 'https://api.together.xyz');
|
|
config()->set('vision.together.endpoint', '/v1/chat/completions');
|
|
config()->set('vision.together.model', 'meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo');
|
|
config()->set('vision.together.api_key', 'together-test-key');
|
|
config()->set('cdn.files_url', 'https://files.local');
|
|
|
|
$photography = ContentType::query()->create([
|
|
'name' => 'Photography',
|
|
'slug' => 'photography',
|
|
]);
|
|
|
|
Category::query()->create([
|
|
'content_type_id' => $photography->id,
|
|
'name' => 'Flowers',
|
|
'slug' => 'flowers',
|
|
'is_active' => true,
|
|
]);
|
|
|
|
$user = User::factory()->create();
|
|
$artwork = Artwork::factory()->create([
|
|
'user_id' => $user->id,
|
|
'hash' => 'tgaa11223344',
|
|
'file_name' => 'rose-closeup.jpg',
|
|
'title' => 'Together Rose Study',
|
|
]);
|
|
|
|
Http::fake([
|
|
'https://vision.local/analyze/all' => Http::response([
|
|
'clip' => [
|
|
['tag' => 'rose', 'confidence' => 0.96],
|
|
['tag' => 'flower', 'confidence' => 0.91],
|
|
],
|
|
'yolo' => [
|
|
['label' => 'flower', 'confidence' => 0.79],
|
|
],
|
|
'blip' => 'a close up photograph of a rose bud with soft natural background',
|
|
], 200),
|
|
'https://api.together.xyz/v1/chat/completions' => Http::response([
|
|
'choices' => [
|
|
[
|
|
'message' => [
|
|
'content' => json_encode([
|
|
'rose macro',
|
|
'flower close-up',
|
|
'soft petals',
|
|
'natural light',
|
|
'botanical photography',
|
|
'pink tones',
|
|
'shallow depth',
|
|
'floral detail',
|
|
'macro photography',
|
|
'garden bloom',
|
|
], JSON_THROW_ON_ERROR),
|
|
],
|
|
],
|
|
],
|
|
], 200),
|
|
]);
|
|
|
|
$this->artisan('artworks:ai-suggest', [
|
|
'artwork_id' => $artwork->id,
|
|
'--provider' => 'together',
|
|
])
|
|
->expectsOutputToContain('provider: together')
|
|
->expectsOutputToContain('tags: rose-macro, flower-close-up')
|
|
->assertSuccessful();
|
|
|
|
$assist = ArtworkAiAssist::query()->where('artwork_id', $artwork->id)->first();
|
|
|
|
expect($assist)->not->toBeNull();
|
|
expect($assist?->raw_response_json['tag_generation']['provider'] ?? null)->toBe('together');
|
|
expect($assist?->raw_response_json['tag_generation']['endpoint'] ?? null)->toBe('https://api.together.xyz/v1/chat/completions');
|
|
|
|
Http::assertSent(function (\Illuminate\Http\Client\Request $request): bool {
|
|
return $request->url() === 'https://api.together.xyz/v1/chat/completions'
|
|
&& $request->hasHeader('Authorization', 'Bearer together-test-key');
|
|
});
|
|
}); |