Skip to content

Commit

Permalink
Merge branch '12.4-video-stabilityai' into '12.4'
Browse files Browse the repository at this point in the history
Image to video - Stability AI

See merge request typo3-commons/mkcontentai!41
  • Loading branch information
hannesbochmann committed May 22, 2024
2 parents 6941c06 + fb1fd5a commit 74b6cab
Show file tree
Hide file tree
Showing 26 changed files with 678 additions and 152 deletions.
19 changes: 17 additions & 2 deletions Classes/ContextMenu/ContentAiItemProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ class ContentAiItemProvider extends AbstractProvider
'iconIdentifier' => 'actions-rocket',
'callbackAction' => 'altTexts',
],
'filePrepareImageToVideo' => [
'type' => 'item',
'label' => 'LLL:EXT:mkcontentai/Resources/Private/Language/locallang_contentai.xlf:labelContextMenuImageToVideo',
'iconIdentifier' => 'actions-rocket',
'callbackAction' => 'prepareImageToVideo',
],
];

public function setContext(string $table, string $identifier, string $context = ''): void
Expand Down Expand Up @@ -127,7 +133,7 @@ public function canRender(string $itemName, string $type): bool
$canRender = false;

if (
(('fileUpscale' === $itemName || 'fileExtend' === $itemName) && true === $this->checkAllowedOperationsByClient($itemName, $imageAiEngine))
(('fileUpscale' === $itemName || 'fileExtend' === $itemName || 'filePrepareImageToVideo' === $itemName) && true === $this->checkAllowedOperationsByClient($itemName, $imageAiEngine))
|| 'fileAlt' === $itemName
) {
return $this->isImage();
Expand Down Expand Up @@ -209,6 +215,7 @@ private function updateParametersForItemName(array &$parameters, string $itemNam
'fileExtend' => 'cropAndExtend',
'fileAlt' => 'altText',
'folderAltTexts' => 'altTexts',
'filePrepareImageToVideo' => 'prepareImageToVideo',
];

if (11 === $version) {
Expand All @@ -218,6 +225,10 @@ private function updateParametersForItemName(array &$parameters, string $itemNam
if (('fileAlt' === $itemName || 'folderAltTexts' === $itemName) && 11 === $version) {
$parameters['tx_mkcontentai_system_mkcontentaicontentai']['controller'] = 'AiText';
}

if (('filePrepareImageToVideo' === $itemName) && 11 === $version) {
$parameters['tx_mkcontentai_system_mkcontentaicontentai']['controller'] = 'AiVideo';
}
}

/**
Expand Down Expand Up @@ -273,6 +284,10 @@ private function getPathInfo(string $itemName, int $version): string
12 => '/module/mkcontentai/AiText/altTexts',
11 => '/module/system/MkcontentaiContentai',
],
'filePrepareImageToVideo' => [
12 => '/module/mkcontentai/AiVideo/prepareImageToVideo',
11 => '/module/system/MkcontentaiContentai',
],
];

return $pathInfoMapping[$itemName][$version] ?? '';
Expand All @@ -287,7 +302,7 @@ private function checkAllowedOperationsByClient(string $itemName, int $imageAiEn
$openAiClient = GeneralUtility::makeInstance(OpenAiClient::class);

foreach ([$stabilityAiClient, $openAiClient] as $aiClient) {
if (get_class($aiClient) === AiImageController::GENERATOR_ENGINE[$imageAiEngine] && in_array(strtolower(str_replace('file', '', $itemName)), $aiClient->getAllowedOperations())) {
if (get_class($aiClient) === AiImageController::GENERATOR_ENGINE[$imageAiEngine] && in_array(lcfirst(str_replace('file', '', $itemName)), $aiClient->getAllowedOperations())) {
return true;
}
}
Expand Down
71 changes: 23 additions & 48 deletions Classes/Controller/AiImageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,37 +57,7 @@ class AiImageController extends BaseController

public function initializeAction(): void
{
$client = $this->initializeClient();
if (isset($client['error'])) {
$this->addFlashMessage(
$client['error'],
'',
AbstractMessage::ERROR
);

return;
}
if (isset($client['client'])) {
$this->client = $client['client'];
}

$arguments['actionName'] = $this->request->getControllerActionName();
if (!in_array($arguments['actionName'], $this->client->getAllowedOperations())) {
$translatedMessage = LocalizationUtility::translate('labelNotAllowed', 'mkcontentai', $arguments) ?? '';
$this->addFlashMessage($translatedMessage.' '.get_class($this->client), '', AbstractMessage::ERROR);
$this->redirect('filelist');
}

$infoMessage = LocalizationUtility::translate('labelEngineInitialized', 'mkcontentai') ?? '';
if (isset($client['clientClass'])) {
$infoMessage .= ' '.$client['clientClass'];
}
$this->addFlashMessage(
$infoMessage,
'',
AbstractMessage::INFO
);
parent::initializeAction();
$this->initializeAndAuthorizeAction();
}

/**
Expand All @@ -108,20 +78,6 @@ public function filelistAction()
return $this->handleResponse();
}

protected function handleResponse(): ResponseInterface
{
if (null === $this->moduleTemplateFactory) {
$translatedMessage = LocalizationUtility::translate('labelErrorModuleTemplateFactory', 'mkcontentai') ?? '';

throw new \Exception($translatedMessage, 1623345720);
}

$moduleTemplate = $this->moduleTemplateFactory->create($this->request);
$moduleTemplate->setContent($this->view->render());

return $this->htmlResponse($moduleTemplate->renderContent());
}

/**
* @return ResponseInterface
*/
Expand Down Expand Up @@ -190,7 +146,7 @@ public function upscaleAction(File $file)
}

$fileService = GeneralUtility::makeInstance(FileService::class, $this->client->getFolderName());
$fileService->saveImageFromUrl($upscaledImage->getUrl(), 'upscaled image', $file->getOriginalResource()->getNameWithoutExtension().'_upscaled');
$fileService->saveFileFromUrl($upscaledImage->getUrl(), 'upscaled image', $file->getOriginalResource()->getNameWithoutExtension().'_upscaled');
$translatedMessage = LocalizationUtility::translate('mlang_label_upscaled_image_saved', 'mkcontentai') ?? '';

$this->addFlashMessage($translatedMessage, '', AbstractMessage::INFO);
Expand All @@ -213,7 +169,7 @@ public function extendAction(string $direction, ?File $file = null, string $base
$fileService = GeneralUtility::makeInstance(FileService::class, $this->client->getFolderName());
$filePath = $fileService->saveTempBase64Image($base64);
}
if ($file) {
if ($file && '' === $filePath) {
$filePath = $file->getOriginalResource()->getForLocalProcessing(false);
}
if ('' == $filePath) {
Expand Down Expand Up @@ -246,7 +202,12 @@ public function cropAndExtendAction(File $file, ?string $promptText = ''): Respo

$this->view->assignMultiple(
[
'options' => $this->client->getAvailableResolutions($this->request->getControllerActionName()),
'file' => $file,
'actionName' => 'extend',
'operationName' => 'extend',
'controllerName' => $this->request->getControllerName(),
'withExtend' => true,
'promptText' => $promptText,
'clientApi' => substr(get_class($this->client), 28),
]
Expand All @@ -259,11 +220,25 @@ public function saveFileAction(string $imageUrl, string $description = ''): Resp
{
$fileService = GeneralUtility::makeInstance(FileService::class, $this->client->getFolderName());
try {
$fileService->saveImageFromUrl($imageUrl, $description);
$fileService->saveFileFromUrl($imageUrl, $description);
} catch (\Exception $e) {
$this->addFlashMessage($e->getMessage(), '', AbstractMessage::ERROR);
}

return $this->redirect('filelist');
}

protected function handleResponse(): ResponseInterface
{
if (null === $this->moduleTemplateFactory) {
$translatedMessage = LocalizationUtility::translate('labelErrorModuleTemplateFactory', 'mkcontentai') ?? '';

throw new \Exception($translatedMessage, 1623345720);
}

$moduleTemplate = $this->moduleTemplateFactory->create($this->request);
$moduleTemplate->setContent($this->view->render());

return $this->htmlResponse($moduleTemplate->renderContent());
}
}
125 changes: 125 additions & 0 deletions Classes/Controller/AiVideoController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

declare(strict_types=1);

/*
* Copyright notice
*
* (c) DMK E-BUSINESS GmbH <dev@dmk-ebusiness.de>
* All rights reserved
*
* This file is part of TYPO3 CMS-based extension "mkcontentai" by DMK E-BUSINESS GmbH.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*/

namespace DMK\MkContentAi\Controller;

use DMK\MkContentAi\Service\FileService;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Messaging\AbstractMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\File;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;

/**
* This file is part of the "MK Content AI" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* (c) 2023
*/

/**
* AiVideoController.
*/
class AiVideoController extends BaseController
{
private FileService $fileService;

public function __construct(FileService $fileService)
{
$this->fileService = $fileService;
}

public function initializeAction(): void
{
$this->initializeAndAuthorizeAction();
}

/**
* @return ResponseInterface
*/
public function imageToVideoAction(File $file, string $base64)
{
$this->initializeAction();

try {
$filePath = $this->fileService->saveTempBase64Image($base64);
$generatedVideo = $this->client->imageToVideo($filePath);
} catch (\Exception $e) {
$this->addFlashMessage($e->getMessage(), '', AbstractMessage::ERROR);

return $this->redirect('filelist', 'AiImage');
}
$translatedMessage = LocalizationUtility::translate('mlang_label_image_to_video_generated', 'mkcontentai') ?? '';

$this->view->assignMultiple(
[
'croppedImage' => $base64,
'sourceFile' => $file,
'generatedVideo' => $generatedVideo,
'clientApi' => substr(get_class($this->client), 28),
]
);
$this->addFlashMessage($translatedMessage, '', AbstractMessage::INFO);

return $this->handleResponse();
}

public function prepareImageToVideoAction(File $file): ResponseInterface
{
$this->view->assignMultiple(
[
'options' => $this->client->getAvailableResolutions($this->request->getControllerActionName()),
'file' => $file,
'clientApi' => substr(get_class($this->client), 28),
'actionName' => 'imageToVideo',
'operationName' => $this->request->getControllerActionName(),
'controllerName' => $this->request->getControllerName(),
'withExtend' => false,
]
);

return $this->handleResponse();
}

public function saveFileAction(File $sourceFile, string $videoUrl): ResponseInterface
{
$fileService = GeneralUtility::makeInstance(FileService::class, $this->client->getFolderName());
try {
$fileService->saveFileFromUrl($videoUrl, $sourceFile->getOriginalResource()->getNameWithoutExtension().' - generated video', $sourceFile->getOriginalResource()->getNameWithoutExtension().'_generated_video', '.mp4');
} catch (\Exception $e) {
$this->addFlashMessage($e->getMessage(), '', AbstractMessage::ERROR);
}

return $this->redirect('filelist', 'AiImage');
}

protected function handleResponse(): ResponseInterface
{
if (null === $this->moduleTemplateFactory) {
$translatedMessage = LocalizationUtility::translate('labelErrorModuleTemplateFactory', 'mkcontentai') ?? '';

throw new \Exception($translatedMessage, 1623345720);
}

$moduleTemplate = $this->moduleTemplateFactory->create($this->request);
$moduleTemplate->setContent($this->view->render());

return $this->htmlResponse($moduleTemplate->renderContent());
}
}
14 changes: 10 additions & 4 deletions Classes/Controller/AjaxController.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,15 @@ public function __construct()
*/
public function blobImage(ServerRequestInterface $request): ResponseInterface
{
if (!isset($request->getParsedBody()['imageUrl'])) {
/** @var array<mixed> $parsedBody */
$parsedBody = $request->getParsedBody();
$imageUrl = $parsedBody['imageUrl'] ?? null;

if (!$imageUrl) {
$translatedMessage = LocalizationUtility::translate('labelErrorMissingImageUrl', 'mkcontentai') ?? '';

throw new \Exception($translatedMessage);
}
$imageUrl = $request->getParsedBody()['imageUrl'];

$imageData = GeneralUtility::getUrl($imageUrl);
if (!is_string($imageData)) {
Expand Down Expand Up @@ -170,7 +173,11 @@ public function promptResultAjaxAction(ServerRequestInterface $request)
}
$client = $clientResponse['client'];

if (empty($request->getParsedBody()['promptText'])) {
/** @var array<mixed> $parsedBody */
$parsedBody = $request->getParsedBody();
$text = $parsedBody['promptText'] ?? null;

if (empty($text)) {
$translatedMessage = LocalizationUtility::translate('labelErrorPromptText', 'mkcontentai') ?? '';

return new JsonResponse(
Expand All @@ -179,7 +186,6 @@ public function promptResultAjaxAction(ServerRequestInterface $request)
],
500);
}
$text = $request->getParsedBody()['promptText'];

try {
$images = $client->image($text);
Expand Down
Loading

0 comments on commit 74b6cab

Please sign in to comment.