From 2667f3d11cc7dbc60ec55e9be8647c7909ad9414 Mon Sep 17 00:00:00 2001 From: Richard Dern Date: Tue, 14 May 2024 08:32:53 +0200 Subject: [PATCH] Added command allowing to describe images with AI --- .../Commands/Bundle/DescribeAttachments.php | 87 +++++++++++++++++++ app/Services/Ollama.php | 24 +++++ app/Services/Translator.php | 22 +++++ docker-compose.yml | 11 +++ 4 files changed, 144 insertions(+) create mode 100644 app/Console/Commands/Bundle/DescribeAttachments.php create mode 100644 app/Services/Ollama.php create mode 100644 app/Services/Translator.php diff --git a/app/Console/Commands/Bundle/DescribeAttachments.php b/app/Console/Commands/Bundle/DescribeAttachments.php new file mode 100644 index 0000000..56813e0 --- /dev/null +++ b/app/Console/Commands/Bundle/DescribeAttachments.php @@ -0,0 +1,87 @@ +signature = 'bundle:describe-attachments + { --r|recursive : Also upgrade sub-bundles } + { --source-disk= : Use specified content disk - Defaults to ' . env('CONTENT_DISK') . ' } + { path? : Path to a specific bundle to upgrade - Default to / } + '; + + parent::__construct(); + } + + /** + * Execute the console command. + */ + public function handle() + { + $this->selectDisk() + ->selectBundles() + ->perform(); + } + + private function perform() + { + progress('Updating bundles...', $this->bundles, function (Bundle $bundle, $progress) { + $this->handleBundle($bundle, $progress); + }); + } + + private function handleBundle(Bundle $bundle, $progress) + { + $attachmentsManager = $bundle->attachments(AttachmentsManager::Images); + + foreach ($attachmentsManager->manager()->get('files') ?? [] as $ref => $data) { + if (!empty($data['alt'])) { + continue; + } + + $altSelected = false; + $fullPath = $attachmentsManager->getAttachmentFullPath($ref); + $content = $this->sourceDisk->get($fullPath); + $content = Image::read($content)->toJpeg(); + $base64 = base64_encode($content); + + while (!$altSelected) { + $sentence = Ollama::describeImage([$base64]); + $translated = Translator::translate($sentence); + $alt = textarea(sprintf('Image description for %s', $fullPath), '', $translated); + + if (confirm('Use this text as the `alt` attribute for image?', true, 'Yes', 'No', false, null, $alt)) { + $attachmentsManager->manager()->set(sprintf('files.%s.alt', $ref), $alt); + $attachmentsManager->manager()->save(); + + $altSelected = true; + } + } + } + } +} diff --git a/app/Services/Ollama.php b/app/Services/Ollama.php new file mode 100644 index 0000000..c376139 --- /dev/null +++ b/app/Services/Ollama.php @@ -0,0 +1,24 @@ +timeout(240)->post(sprintf('%s/api/generate', env('OLLAMA_HOST')), [ + 'model' => 'llava', + 'prompt' => 'Describe this image in a sentence or two', + 'stream' => false, + 'images' => $base64JpegImages, + ])->json(); + + return $result['response']; + } +} diff --git a/app/Services/Translator.php b/app/Services/Translator.php new file mode 100644 index 0000000..ba9a89e --- /dev/null +++ b/app/Services/Translator.php @@ -0,0 +1,22 @@ +post(sprintf('%s/translate', env('TRANSLATOR_URL')), [ + 'q' => $sentence, + 'source' => $sourceLang, + 'target' => $targetLang, + ])->json(); + + return $response['translatedText']; + } +} diff --git a/docker-compose.yml b/docker-compose.yml index da540b6..1b9185b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -38,6 +38,7 @@ services: - selenium - nu-validator - base_laravel.test + - libretranslate pgsql: image: 'postgres:15' ports: @@ -88,6 +89,16 @@ services: - sail nu-validator: image: ghcr.io/validator/validator:latest + extra_hosts: + - 'host.docker.internal:host-gateway' + networks: + - sail + libretranslate: + image: libretranslate/libretranslate + extra_hosts: + - 'host.docker.internal:host-gateway' + environment: + - DBUS_SESSION_BUS_ADDRESS=/dev/null networks: - sail networks: