Skip to content

Commit

Permalink
[TASK] Move ItemProvider class
Browse files Browse the repository at this point in the history
[TASK] Add dropdown styling
[TASK] Filter out non-images for image recognition
[TASK] Fix linting
  • Loading branch information
Sascha Löffler committed Jul 4, 2024
1 parent 17b9781 commit e518bdf
Show file tree
Hide file tree
Showing 15 changed files with 96 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

declare(strict_types=1);

namespace Pagemachine\AItools\ContextMenu;
namespace Pagemachine\AItools\ContextMenu\ItemProviders;

use TYPO3\CMS\Backend\ContextMenu\ItemProviders\AbstractProvider;
use TYPO3\CMS\Core\Resource\AbstractFile;
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
Expand Down Expand Up @@ -95,40 +96,13 @@ protected function getAdditionalAttributes(string $itemName): array
if ($itemName === 'generateAIMetadata') {
$attributes += [
'data-identifier' => htmlspecialchars($this->identifier),
'data-type' => $this->record instanceof File ? 'file' : 'folder',
'data-filecontext-identifier' => htmlspecialchars($this->identifier),
'data-filecontext-type' => $this->record instanceof File ? 'file' : 'folder',
];
}
return $attributes;
}

/**
* This method adds custom item to list of items generated by item providers with higher priority value (PageProvider)
* You could also modify existing items here.
* The new item is added after the 'info' item.
*
* @param array $items
* @return array
*/
public function addItems(array $items): array
{
$this->initDisabledItems();
// renders an item based on the configuration from $this->itemsConfiguration
$localItems = $this->prepareItems($this->itemsConfiguration);

if (isset($items['info'])) {
//finds a position of the item after which 'hello' item should be added
$position = array_search('info', array_keys($items), true);

//slices array into two parts
$beginning = array_slice($items, 0, $position + 1, true);
$end = array_slice($items, $position, null, true);

// adds custom item in the correct position
$items = $beginning + $localItems + $end;
} else {
$items = $items + $localItems;
}
//passes array of items to the next item provider
return $items;
return $attributes;
}

/**
Expand All @@ -147,7 +121,7 @@ protected function canRender(string $itemName, string $type): bool
$canRender = false;
switch ($itemName) {
case 'generateAIMetadata':
$canRender = $this->canEditMetadata();
$canRender = $this->canEditMetadataOfFile() || $this->canEditMetadataOfFolder();
break;
}
return $canRender;
Expand All @@ -160,12 +134,37 @@ protected function isFile(): bool
{
return $this->record instanceof File;
}
protected function isFolder(): bool
{
return $this->record instanceof Folder;
}
protected function isImage(): bool
{
return $this->isFile() && $this->record->getType() == AbstractFile::FILETYPE_IMAGE;
}

/**
* @return bool
*/
protected function canEditMetadata(): bool
protected function canEditMetadataOfFile(): bool
{
return true;
return $this->isImage()
&& $this->record->isIndexed()
&& $this->record->checkActionPermission('editMeta')
&& $this->record->getMetaData()->offsetExists('uid')
&& $this->backendUser->check('tables_modify', 'sys_file_metadata')
&& $this->backendUser->checkLanguageAccess(0);
}

protected function canEditMetadataOfFolder(): bool
{
return $this->isFolder()
&& $this->backendUser->check('tables_modify', 'sys_file_metadata')
&& $this->backendUser->checkLanguageAccess(0);
}

protected function getIdentifier(): string
{
if ($this->record == null) {
return '';
}
return $this->record->getCombinedIdentifier();
}
}
8 changes: 3 additions & 5 deletions Classes/Controller/Backend/ImageCreationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Pagemachine\AItools\Controller\Backend;

use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use OpenAI\Client;
use Pagemachine\AItools\Domain\Model\Aiimage;
use Pagemachine\AItools\Service\SettingsService;
Expand All @@ -14,15 +13,14 @@
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\StorageRepository;
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Http\ForwardResponse;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;

class ImageCreationController extends ActionController
{
public function __construct(private readonly ?SettingsService $settingsService)
{
}
public function __construct(private readonly ?SettingsService $settingsService) {}

private function getOpenAIClient(): Client
{
Expand Down Expand Up @@ -86,7 +84,7 @@ public function variateAction(Aiimage $aiimage): ResponseInterface
if ($file['tmp_name']) {
$filePath = $file['tmp_name'];
$fileName = $file['name'];
$fileName = str_replace('.png', '', (string) $fileName);
$fileName = str_replace('.png', '', (string)$fileName);

$imageVariationUrlArray = $this->variationImage($filePath, $imagesnumber, $resolution);

Expand Down
8 changes: 5 additions & 3 deletions Classes/Controller/Backend/ImageRecognizeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
use TYPO3\CMS\Core\Resource\AbstractFile;
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Core\Resource\FolderInterface;
Expand Down Expand Up @@ -99,13 +100,14 @@ private function getFileObjectFromRequestTarget(ServerRequestInterface $request)
if ($target) {
$fileObject = $this->resourceFactory->retrieveFileOrFolderObject($target);
if ($fileObject instanceof FileInterface) {
if ($fileObject->getType() !== AbstractFile::FILETYPE_IMAGE) {
return null;
}
return [$fileObject];
}
if ($fileObject instanceof FolderInterface) {
$files = $fileObject->getFiles();
$files = array_filter($files, function ($file) {
return $file->getType() === AbstractFile::FILETYPE_IMAGE;
});
$files = array_filter($files, fn($file) => $file->getType() === AbstractFile::FILETYPE_IMAGE);
return $files;
}
}
Expand Down
3 changes: 1 addition & 2 deletions Classes/Controller/Backend/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ public function __construct(
private readonly PromptRepository $promptRepository,
private readonly PersistenceManagerInterface $persistenceManager,
private readonly ModuleTemplateFactory $moduleTemplateFactory
) {
}
) {}

/**
* Check if the current user has the permission to manage prompts
Expand Down
5 changes: 1 addition & 4 deletions Classes/Domain/Repository/PromptRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,4 @@

use TYPO3\CMS\Extbase\Persistence\Repository;

class PromptRepository extends Repository
{

}
class PromptRepository extends Repository {}
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ public function sendFileToApi(FileInterface $fileObject, string $textPrompt = ''
$text = $response->getBody()->getContents();

// cleanup text from "The image depicts" introduction text.
$text = preg_replace(self::$cleanUpRegex, '', (string) $text);
$text = trim($text);
$text = preg_replace(self::$cleanUpRegex, '', (string)$text);
$text = trim((string) $text);
$text[0] = strtoupper($text[0]);
return $text;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public function sendFileToApi(FileInterface $fileObject, string $textPrompt = ''

if ($response->getStatusCode() === 200) {
$responseBody = $response->getBody()->getContents();
$responseArray = json_decode((string) $responseBody, true);
$responseArray = json_decode((string)$responseBody, true);
return $responseArray['choices'][0]['message']['content'] ?? '';
}

Expand Down
2 changes: 1 addition & 1 deletion Classes/Service/Translation/CustomTranslationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public function sendTranslationRequestToApi(string $text, string $sourceLang = '

$url = $this->settingsService->getSetting('custom_translation_api_uri');

$url .= '?source_lang=' . urlencode((string) $sourceLang) . '&target_lang=' . urlencode((string) $targetLang);
$url .= '?source_lang=' . urlencode((string)$sourceLang) . '&target_lang=' . urlencode((string)$targetLang);

// Prepare the form data
$formData = http_build_query([
Expand Down
2 changes: 1 addition & 1 deletion Classes/Service/Translation/DeepLTranslationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public function sendTranslationRequestToApi(string $text, string $sourceLang = '
]);

if ($response->getStatusCode() === 200) {
$responseBody = json_decode((string) $response->getBody()->getContents(), true);
$responseBody = json_decode((string)$response->getBody()->getContents(), true);
return $responseBody['translations'][0]['text']; // Extracting the translated text
}

Expand Down
1 change: 1 addition & 0 deletions Configuration/Backend/AjaxRoutes.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use Pagemachine\AItools\Controller\Backend\ImageRecognizeController;

/**
* Definitions for routes provided by EXT:backend
* Contains all "regular" routes for entry points
Expand Down
1 change: 1 addition & 0 deletions Configuration/Backend/Modules.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use Pagemachine\AItools\Controller\Backend\SettingsController;

return [
'aitools' => [
'position' => ['after' => 'web'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,33 @@
.w5 {
width: 49%;
}
.info-block {
padding: 10px;
margin: 10px;
border: 1px solid #ccc;
border-left: 5px solid orange;
border-radius: 5px;
font-size: 1.25rem;
}
</style>

<f:if condition="{fileObjects -> f:count()} > 1">
<div class="row">
<div class="col-xs-12">
<f:render section="form-group-select" arguments="{label: 'Global AI Prompt', class: 'globalTextPrompt', name: 'globalTextPrompt', options: allTextPrompts, value: textPrompt.prompt, optionLabelField: 'description', optionValueField: 'prompt'}" />
<f:then>
<div class="row">
<div class="col-xs-12">
<f:render section="form-group-select" arguments="{label: 'Global AI Prompt', class: 'globalTextPrompt', name: 'globalTextPrompt', options: allTextPrompts, value: textPrompt.prompt, optionLabelField: 'description', optionValueField: 'prompt'}" />

<label for="skipExistingDescriptions">Skip existing descriptions <input type="checkbox" id="skipExistingDescriptions" name="skipExistingDescriptions" class="skipExistingDescriptions" value="1" checked /></label><br />
<button onclick="callAjaxMetaGenerateActionForAll(this, false)" class="btn btn-primary">Generate Meta-Data for all Images</button>
<button onclick="callAjaxMetaGenerateActionForAll(this, true)" class="btn btn-primary">Generate, Save + Translate Meta-Data for all Images</button>
<progress value="0" max="{fileObjects -> f:count()}" id="progressBar" class="progressBar"></progress>
<label for="skipExistingDescriptions">Skip existing descriptions <input type="checkbox" id="skipExistingDescriptions" name="skipExistingDescriptions" class="skipExistingDescriptions" value="1" checked /></label><br />
<button onclick="callAjaxMetaGenerateActionForAll(this, false)" class="btn btn-primary">Generate Meta-Data for all Images</button>
<button onclick="callAjaxMetaGenerateActionForAll(this, true)" class="btn btn-primary">Generate, Save + Translate Meta-Data for all Images</button>
<progress value="0" max="{fileObjects -> f:count()}" id="progressBar" class="progressBar"></progress>
</div>
</div>
</div>
<div class="help-block">&nbsp;</div>
<div class="help-block">&nbsp;</div>
</f:then>
<f:else>
<div class="info-block">No image.</div>
</f:else>
</f:if>

<f:for as="fileObject" each="{fileObjects}">
Expand Down Expand Up @@ -143,7 +156,7 @@ <h1>Generate File Metadata "{fileObject.name}"</h1>
<div class="formengine-field-item t3js-formengine-field-item"><div class="form-control-wrap" style="max-width: 636px">
<div class="form-wizards-wrap">
<div class="form-wizards-element">
<f:form.select options="{options}" optionLabelField="{optionLabelField}" optionValueField="{optionValueField}" class="form-control form-select-sm t3-js-jumpMenuBox {class}" value="{value}" />
<f:form.select options="{options}" optionLabelField="{optionLabelField}" optionValueField="{optionValueField}" class="form-control form-select t3-js-jumpMenuBox {class}" value="{value}" />
</div>
</div>
</div></div>
Expand Down
10 changes: 5 additions & 5 deletions Resources/Private/Templates/Backend/Settings/Settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ <h3>Open AI</h3>

<h3>DeepL</h3>
<label for="deepl_endpoint">DeepL Endpoint:</label>
<f:form.select name="deepl_endpoint" id="deepl_endpoint" value="{deepl_endpoint}" class="form-control">
<f:form.select name="deepl_endpoint" id="deepl_endpoint" value="{deepl_endpoint}" class="form-control form-select">
<f:form.select.option value="free">Free</f:form.select.option>
<f:form.select.option value="pro">Pro</f:form.select.option>
</f:form.select>
<label for="deepl_auth_key">DeepL Auth Key:</label>
<f:form.textfield name="deepl_auth_key" id="deepl_auth_key" value="{deepl_auth_key}" class="form-control" type="password" />
<label for="deepl_formality">Formality:</label>
<f:form.select name="deepl_formality" id="deepl_formality" value="{deepl_formality}" class="form-control">
<f:form.select name="deepl_formality" id="deepl_formality" value="{deepl_formality}" class="form-control form-select">
<f:form.select.option value="">Default</f:form.select.option>
<f:form.select.option value="prefer_more">More</f:form.select.option>
<f:form.select.option value="prefer_less">Less</f:form.select.option>
Expand Down Expand Up @@ -97,15 +97,15 @@ <h3>Custom</h3>
<div class="form-group">
<h3>Image Recognition</h3>
<label for="image_recognition_service">Image Recognition Service:</label>
<f:form.select name="image_recognition_service" id="image_recognition_service" value="{image_recognition_service}" class="form-control">
<f:form.select name="image_recognition_service" id="image_recognition_service" value="{image_recognition_service}" class="form-control form-select">
<f:form.select.option value="">Select Service</f:form.select.option>
<f:form.select.option value="custom">Custom</f:form.select.option>
<f:form.select.option value="openai">Open AI</f:form.select.option>
</f:form.select>

<h3>Translation</h3>
<label for="translation_service">Translation Service:</label>
<f:form.select name="translation_service" id="translation_service" value="{translation_service}" class="form-control">
<f:form.select name="translation_service" id="translation_service" value="{translation_service}" class="form-control form-select">
<f:form.select.option value="">Select Service</f:form.select.option>
<f:form.select.option value="custom">Custom</f:form.select.option>
<f:form.select.option value="deepl">DeepL</f:form.select.option>
Expand All @@ -121,7 +121,7 @@ <h3>Translation</h3>
<div class="form-group">
<h3>Default Prompt</h3>
<label for="defaultPrompt">Default Prompt:</label>
<f:form.select name="defaultPrompt" id="defaultPrompt" value="{defaultPrompt}" class="form-control" options="{prompts}" optionValueField="uid" optionLabelField="descriptionPrompt">
<f:form.select name="defaultPrompt" id="defaultPrompt" value="{defaultPrompt}" class="form-control form-select" options="{prompts}" optionValueField="uid" optionLabelField="descriptionPrompt">
<f:if condition="!{defaultPrompt}">
<f:form.select.option value="">Select Prompt</f:form.select.option>
</f:if>
Expand Down
26 changes: 13 additions & 13 deletions Tests/Unit/Service/CustomImageRecognitionServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Pagemachine\AItools\Tests\Unit\Service;

use PHPUnit\Framework\Attributes\DataProvider;
use Pagemachine\AItools\Service\ImageRecognition\CustomImageRecognitionService;
use PHPUnit\Framework\Attributes\DataProvider;
use TYPO3\TestingFramework\Core\Unit\UnitTestCase;

class CustomImageRecognitionServiceTest extends UnitTestCase
Expand All @@ -19,24 +19,24 @@ public function testCleanUpRegex(string $input, string $expected)
$regex = $property->getValue();

$result = preg_replace($regex, '', $input);
$this->assertEquals($expected, trim((string) $result));
self::assertEquals($expected, trim((string)$result));
}

public static function regexProvider(): array
{
return [
["Certainly! The main subject of the image is a cat.", "a cat."],
["This image prominently shows a beautiful landscape.", "a beautiful landscape."],
["The image showcases a modern building.", "a modern building."],
["Certainly! This image predominantly features a sunset.", "a sunset."],
["The main subject of the image displays a group of people.", "a group of people."],
["Certainly! The main subject of the image is a cat!@#.", "a cat!@#."],
["This image prominently shows a beautiful landscape, with mountains.", "a beautiful landscape, with mountains."],
['Certainly! The main subject of the image is a cat.', 'a cat.'],
['This image prominently shows a beautiful landscape.', 'a beautiful landscape.'],
['The image showcases a modern building.', 'a modern building.'],
['Certainly! This image predominantly features a sunset.', 'a sunset.'],
['The main subject of the image displays a group of people.', 'a group of people.'],
['Certainly! The main subject of the image is a cat!@#.', 'a cat!@#.'],
['This image prominently shows a beautiful landscape, with mountains.', 'a beautiful landscape, with mountains.'],
["The image showcases a modern building; it's very tall.", "a modern building; it's very tall."],
["Certainly! This image predominantly features a sunset... amazing!", "a sunset... amazing!"],
["The main subject of the image displays a group of people - friends.", "a group of people - friends."],
["The image predominantly showcases a dog.", "a dog."],
["A dinosaur in the park.", "A dinosaur in the park."],
['Certainly! This image predominantly features a sunset... amazing!', 'a sunset... amazing!'],
['The main subject of the image displays a group of people - friends.', 'a group of people - friends.'],
['The image predominantly showcases a dog.', 'a dog.'],
['A dinosaur in the park.', 'A dinosaur in the park.'],
];
}
}
2 changes: 1 addition & 1 deletion ext_localconf.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

declare(strict_types=1);
use Pagemachine\AItools\ContextMenu\AiToolItemProvider;
use Pagemachine\AItools\ContextMenu\ItemProviders\AiToolItemProvider;

use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
Expand Down

0 comments on commit e518bdf

Please sign in to comment.