diff options
17 files changed, 204 insertions, 96 deletions
diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 08cf9679087..9ea92691f2a 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -26,6 +26,7 @@ declare(strict_types=1); namespace OC\TaskProcessing; use OC\AppFramework\Bootstrap\Coordinator; +use OC\Files\SimpleFS\SimpleFile; use OC\TaskProcessing\Db\TaskMapper; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; @@ -33,7 +34,6 @@ use OCP\BackgroundJob\IJobList; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\AppData\IAppDataFactory; use OCP\Files\File; -use OCP\Files\Folder; use OCP\Files\GenericFileException; use OCP\Files\IAppData; use OCP\Files\IRootFolder; @@ -47,7 +47,6 @@ use OCP\SpeechToText\ISpeechToTextProviderWithUserId; use OCP\TaskProcessing\EShapeType; use OCP\TaskProcessing\Events\TaskFailedEvent; use OCP\TaskProcessing\Events\TaskSuccessfulEvent; -use OCP\TaskProcessing\Exception\Exception; use OCP\TaskProcessing\Exception\NotFoundException; use OCP\TaskProcessing\Exception\ProcessingException; use OCP\TaskProcessing\Exception\ValidationException; @@ -71,7 +70,7 @@ class Manager implements IManager { public const LEGACY_PREFIX_TEXTTOIMAGE = 'legacy:TextToImage:'; public const LEGACY_PREFIX_SPEECHTOTEXT = 'legacy:SpeechToText:'; - /** @var |null */ + /** @var list<IProvider>|null */ private ?array $providers = null; /** @var array<string,array{name: string, description: string, inputShape: array<string, ShapeDescriptor>, optionalInputShape: array<string, ShapeDescriptor>, outputShape: array<string, ShapeDescriptor>, optionalOutputShape: array<string, ShapeDescriptor>}>|null */ @@ -281,10 +280,10 @@ class Manager implements IManager { } try { $this->provider->generate($input['input'], $resources); - }catch (\RuntimeException $e) { + } catch (\RuntimeException $e) { throw new ProcessingException($e->getMessage(), 0, $e); } - return ['images' => array_map(fn(File $file) => base64_encode($file->getContent()), $files)]; + return ['images' => array_map(fn (File $file) => base64_encode($file->getContent()), $files)]; } }; $newProviders[$newProvider->getId()] = $newProvider; @@ -358,7 +357,7 @@ class Manager implements IManager { } try { $result = $this->provider->transcribeFile($file); - }catch (\RuntimeException $e) { + } catch (\RuntimeException $e) { throw new ProcessingException($e->getMessage(), 0, $e); } return ['output' => $result]; @@ -443,7 +442,7 @@ class Manager implements IManager { * @return IProvider * @throws \OCP\TaskProcessing\Exception\Exception */ - private function _getPreferredProvider(string $taskType){ + private function _getPreferredProvider(string $taskType) { $providers = $this->getProviders(); foreach ($providers as $provider) { if ($provider->getTaskType() === $taskType) { @@ -454,12 +453,12 @@ class Manager implements IManager { } /** - * @param array<string, ShapeDescriptor> $spec - * @param array<string, mixed> $io + * @param ShapeDescriptor[] $spec + * @param array $io * @return void * @throws ValidationException */ - private function validateInput(array $spec, array $io, bool $optional = false) { + private function validateInput(array $spec, array $io, bool $optional = false): void { foreach ($spec as $key => $descriptor) { $type = $descriptor->getShapeType(); if (!isset($io[$key])) { @@ -471,49 +470,50 @@ class Manager implements IManager { if ($type === EShapeType::Text && !is_string($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('Non-text item provided for Text key: "' . $key . '"'); } - if ($type === EShapeType::ListOfTexts && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_string($item))) > 0)) { + if ($type === EShapeType::ListOfTexts && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-text list item provided for ListOfTexts key: "' . $key . '"'); } if ($type === EShapeType::Number && !is_numeric($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-numeric item provided for Number key: "' . $key . '"'); } - if ($type === EShapeType::ListOfNumbers && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_numeric($item))) > 0)) { + if ($type === EShapeType::ListOfNumbers && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-numeric list item provided for ListOfNumbers key: "' . $key . '"'); } if ($type === EShapeType::Image && !is_numeric($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-image item provided for Image key: "' . $key . '"'); } - if ($type === EShapeType::ListOfImages && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_numeric($item))) > 0)) { + if ($type === EShapeType::ListOfImages && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-image list item provided for ListOfImages key: "' . $key . '"'); } if ($type === EShapeType::Audio && !is_numeric($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio item provided for Audio key: "' . $key . '"'); } - if ($type === EShapeType::ListOfAudio && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_numeric($item))) > 0)) { + if ($type === EShapeType::ListOfAudio && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio list item provided for ListOfAudio key: "' . $key . '"'); } if ($type === EShapeType::Video && !is_numeric($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-video item provided for Video key: "' . $key . '"'); } - if ($type === EShapeType::ListOfVideo && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_numeric($item))) > 0)) { + if ($type === EShapeType::ListOfVideo && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-video list item provided for ListOfTexts key: "' . $key . '"'); } if ($type === EShapeType::File && !is_numeric($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-file item provided for File key: "' . $key . '"'); } - if ($type === EShapeType::ListOfFiles && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_numeric($item))) > 0)) { + if ($type === EShapeType::ListOfFiles && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio list item provided for ListOfFiles key: "' . $key . '"'); } } } /** - * @param array<string, ShapeDescriptor> $spec + * @param ShapeDescriptor[] $spec * @param array $io + * @param bool $optional * @return void * @throws ValidationException */ - private function validateOutput(array $spec, array $io, bool $optional = false) { + private function validateOutput(array $spec, array $io, bool $optional = false): void { foreach ($spec as $key => $descriptor) { $type = $descriptor->getShapeType(); if (!isset($io[$key])) { @@ -525,37 +525,37 @@ class Manager implements IManager { if ($type === EShapeType::Text && !is_string($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('Non-text item provided for Text key: "' . $key . '"'); } - if ($type === EShapeType::ListOfTexts && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_string($item))) > 0)) { + if ($type === EShapeType::ListOfTexts && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-text list item provided for ListOfTexts key: "' . $key . '"'); } if ($type === EShapeType::Number && !is_numeric($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-numeric item provided for Number key: "' . $key . '"'); } - if ($type === EShapeType::ListOfNumbers && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_numeric($item))) > 0)) { + if ($type === EShapeType::ListOfNumbers && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-numeric list item provided for ListOfNumbers key: "' . $key . '"'); } if ($type === EShapeType::Image && !is_string($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-image item provided for Image key: "' . $key . '". Expecting base64 encoded image data.'); } - if ($type === EShapeType::ListOfImages && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_string($item))) > 0)) { + if ($type === EShapeType::ListOfImages && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-image list item provided for ListOfImages key: "' . $key . '". Expecting base64 encoded image data.'); } if ($type === EShapeType::Audio && !is_string($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio item provided for Audio key: "' . $key . '". Expecting base64 encoded audio data.'); } - if ($type === EShapeType::ListOfAudio && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_string($item))) > 0)) { + if ($type === EShapeType::ListOfAudio && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio list item provided for ListOfAudio key: "' . $key . '". Expecting base64 encoded audio data.'); } if ($type === EShapeType::Video && !is_string($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-video item provided for Video key: "' . $key . '". Expecting base64 encoded video data.'); } - if ($type === EShapeType::ListOfVideo && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_string($item))) > 0)) { + if ($type === EShapeType::ListOfVideo && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-video list item provided for ListOfTexts key: "' . $key . '". Expecting base64 encoded video data.'); } if ($type === EShapeType::File && !is_string($io[$key])) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-file item provided for File key: "' . $key . '". Expecting base64 encoded file data.'); } - if ($type === EShapeType::ListOfFiles && (!is_array($io[$key]) || count(array_filter($io[$key], fn($item) => !is_string($item))) > 0)) { + if ($type === EShapeType::ListOfFiles && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio list item provided for ListOfFiles key: "' . $key . '". Expecting base64 encoded image data.'); } } @@ -567,8 +567,8 @@ class Manager implements IManager { * @return array<string, mixed> */ private function removeSuperfluousArrayKeys(array $array, ...$specs): array { - $keys = array_unique(array_reduce($specs, fn($carry, $spec) => $carry + array_keys($spec), [])); - $values = array_map(fn(string $key) => $array[$key], $keys); + $keys = array_unique(array_reduce($specs, fn ($carry, $spec) => $carry + array_keys($spec), [])); + $values = array_map(fn (string $key) => $array[$key], $keys); return array_combine($keys, $values); } @@ -701,7 +701,7 @@ class Manager implements IManager { $task->setStatus(Task::STATUS_FAILED); $task->setErrorMessage($error); $this->logger->warning('A TaskProcessing ' . $task->getTaskType() . ' task with id ' . $id . ' failed with the following message: ' . $error); - } else if ($result !== null) { + } elseif ($result !== null) { $taskTypes = $this->getAvailableTaskTypes(); $outputShape = $taskTypes[$task->getTaskType()]['outputShape']; $optionalOutputShape = $taskTypes[$task->getTaskType()]['optionalOutputShape']; @@ -738,7 +738,7 @@ class Manager implements IManager { } if ($task->getStatus() === Task::STATUS_SUCCESSFUL) { $event = new TaskSuccessfulEvent($task); - }else{ + } else { $event = new TaskFailedEvent($task, $error); } $this->dispatcher->dispatchTyped($event); @@ -773,7 +773,7 @@ class Manager implements IManager { public function getUserTasksByApp(?string $userId, string $appId, ?string $identifier = null): array { try { $taskEntities = $this->taskMapper->findUserTasksByApp($userId, $appId, $identifier); - return array_map(fn($taskEntity) => $taskEntity->toPublicTask(), $taskEntities); + return array_map(fn ($taskEntity) => $taskEntity->toPublicTask(), $taskEntities); } catch (\OCP\DB\Exception $e) { throw new \OCP\TaskProcessing\Exception\Exception('There was a problem finding a task', 0, $e); } catch (\JsonException $e) { @@ -784,52 +784,52 @@ class Manager implements IManager { /** * Takes task input or output data and replaces fileIds with base64 data * - * @param array<string, ShapeDescriptor> ...$specs the specs - * @param array $inputOutput - * @return array<string, mixed> + * @param ShapeDescriptor[] ...$specs the specs + * @param array $input + * @return array * @throws GenericFileException * @throws LockedException * @throws NotPermittedException * @throws ValidationException - */ - public function fillInputOutputFileData(array $inputOutput, ...$specs): array { + */ + public function fillInputFileData(array $input, ...$specs): array { $newInputOutput = []; - $spec = array_reduce($specs, fn($carry, $spec) => $carry + $spec, []); + $spec = array_reduce($specs, fn ($carry, $spec) => $carry + $spec, []); foreach($spec as $key => $descriptor) { $type = $descriptor->getShapeType(); - if (!isset($inputOutput[$key])) { + if (!isset($input[$key])) { continue; } if (!in_array(EShapeType::from($type->value % 10), [EShapeType::Image, EShapeType::Audio, EShapeType::Video, EShapeType::File], true)) { - $newInputOutput[$key] = $inputOutput[$key]; + $newInputOutput[$key] = $input[$key]; continue; } if ($type->value < 10) { - $node = $this->rootFolder->getFirstNodeById((int)$inputOutput[$key]); + $node = $this->rootFolder->getFirstNodeById((int)$input[$key]); if ($node === null) { - $node = $this->rootFolder->getFirstNodeByIdInPath((int)$inputOutput[$key], '/' . $this->rootFolder->getAppDataDirectoryName() . '/'); + $node = $this->rootFolder->getFirstNodeByIdInPath((int)$input[$key], '/' . $this->rootFolder->getAppDataDirectoryName() . '/'); if (!$node instanceof File) { throw new ValidationException('File id given for key "' . $key . '" is not a file'); } - } else if (!$node instanceof File) { + } elseif (!$node instanceof File) { throw new ValidationException('File id given for key "' . $key . '" is not a file'); } // TODO: Validate if userId has access to this file - $newInputOutput[$key] = base64_encode($node->getContent()); + $newInputOutput[$key] = $node; } else { $newInputOutput[$key] = []; - foreach ($inputOutput[$key] as $item) { - $node = $this->rootFolder->getFirstNodeById((int)$inputOutput[$key]); + foreach ($input[$key] as $item) { + $node = $this->rootFolder->getFirstNodeById((int)$input[$key]); if ($node === null) { - $node = $this->rootFolder->getFirstNodeByIdInPath((int)$inputOutput[$key], '/' . $this->rootFolder->getAppDataDirectoryName() . '/'); + $node = $this->rootFolder->getFirstNodeByIdInPath((int)$input[$key], '/' . $this->rootFolder->getAppDataDirectoryName() . '/'); if (!$node instanceof File) { throw new ValidationException('File id given for key "' . $key . '" is not a file'); } - } else if (!$node instanceof File) { + } elseif (!$node instanceof File) { throw new ValidationException('File id given for key "' . $key . '" is not a file'); } // TODO: Validate if userId has access to this file - $newInputOutput[$key][] = base64_encode($node->getContent()); + $newInputOutput[$key][] = $node; } } } @@ -839,40 +839,42 @@ class Manager implements IManager { /** *Takes task input or output and replaces base64 data with file ids * - * @param array<string, mixed> $inputOutput - * @param array<string, ShapeDescriptor> ...$specs the specs that define which keys to keep - * @return array<string, mixed> + * @param array $output + * @param ShapeDescriptor[] ...$specs the specs that define which keys to keep + * @return array * @throws NotPermittedException */ - public function encapsulateInputOutputFileData(array $inputOutput, ...$specs): array { - $newInputOutput = []; + public function encapsulateOutputFileData(array $output, ...$specs): array { + $newOutput = []; try { $folder = $this->appData->getFolder('TaskProcessing'); } catch (\OCP\Files\NotFoundException) { $folder = $this->appData->newFolder('TaskProcessing'); } - $spec = array_reduce($specs, fn($carry, $spec) => $carry + $spec, []); + $spec = array_reduce($specs, fn ($carry, $spec) => $carry + $spec, []); foreach($spec as $key => $descriptor) { $type = $descriptor->getShapeType(); - if (!isset($inputOutput[$key])) { + if (!isset($output[$key])) { continue; } if (!in_array(EShapeType::from($type->value % 10), [EShapeType::Image, EShapeType::Audio, EShapeType::Video, EShapeType::File], true)) { - $newInputOutput[$key] = $inputOutput[$key]; + $newOutput[$key] = $output[$key]; continue; } if ($type->value < 10) { - $file = $folder->newFile((string) rand(0, 10000000), base64_decode($inputOutput[$key])); - $newInputOutput[$key] = $file->getId(); + /** @var SimpleFile $file */ + $file = $folder->newFile((string) rand(0, 10000000), $output[$key]); + $newOutput[$key] = $file->getId(); // polymorphic call to SimpleFile } else { - $newInputOutput = []; - foreach ($inputOutput[$key] as $item) { - $file = $folder->newFile((string) rand(0, 10000000), base64_decode($item)); - $newInputOutput[$key][] = $file->getId(); + $newOutput = []; + foreach ($output[$key] as $item) { + /** @var SimpleFile $file */ + $file = $folder->newFile((string) rand(0, 10000000), $item); + $newOutput[$key][] = $file->getId(); } } } - return $newInputOutput; + return $newOutput; } public function prepareInputData(Task $task): array { @@ -884,7 +886,7 @@ class Manager implements IManager { $this->validateInput($inputShape, $input); $this->validateInput($optionalInputShape, $input, true); $input = $this->removeSuperfluousArrayKeys($input, $inputShape, $optionalInputShape); - $input = $this->fillInputOutputFileData($input, $inputShape, $optionalInputShape); + $input = $this->fillInputFileData($input, $inputShape, $optionalInputShape); return $input; } } diff --git a/lib/public/Files/SimpleFS/ISimpleFile.php b/lib/public/Files/SimpleFS/ISimpleFile.php index cf848d33724..8afc3108836 100644 --- a/lib/public/Files/SimpleFS/ISimpleFile.php +++ b/lib/public/Files/SimpleFS/ISimpleFile.php @@ -121,12 +121,4 @@ interface ISimpleFile { * @since 14.0.0 */ public function write(); - - /** - * Returns the file id - * - * @return int - * @since 30.0.0 - */ - public function getId(): int; } diff --git a/lib/public/TaskProcessing/EShapeType.php b/lib/public/TaskProcessing/EShapeType.php index 514451da068..3da7391daa1 100644 --- a/lib/public/TaskProcessing/EShapeType.php +++ b/lib/public/TaskProcessing/EShapeType.php @@ -25,6 +25,10 @@ declare(strict_types=1); namespace OCP\TaskProcessing; +/** + * The input and output Shape types + * @since 30.0.0 + */ enum EShapeType: int { case Number = 0; case Text = 1; @@ -39,4 +43,3 @@ enum EShapeType: int { case ListOfVideo = 14; case ListOfFiles = 15; } - diff --git a/lib/public/TaskProcessing/Exception/NotFoundException.php b/lib/public/TaskProcessing/Exception/NotFoundException.php index ef3eee9009c..9c8636051ea 100644 --- a/lib/public/TaskProcessing/Exception/NotFoundException.php +++ b/lib/public/TaskProcessing/Exception/NotFoundException.php @@ -2,6 +2,9 @@ namespace OCP\TaskProcessing\Exception; +/** + * @since 30.0.0 + */ class NotFoundException extends Exception { } diff --git a/lib/public/TaskProcessing/Exception/ValidationException.php b/lib/public/TaskProcessing/Exception/ValidationException.php index 82de81226b4..b17da89919d 100644 --- a/lib/public/TaskProcessing/Exception/ValidationException.php +++ b/lib/public/TaskProcessing/Exception/ValidationException.php @@ -2,6 +2,9 @@ namespace OCP\TaskProcessing\Exception; +/** + * @since 30.0.0 + */ class ValidationException extends Exception { } diff --git a/lib/public/TaskProcessing/IManager.php b/lib/public/TaskProcessing/IManager.php index 73e4c85701e..11b969ec379 100644 --- a/lib/public/TaskProcessing/IManager.php +++ b/lib/public/TaskProcessing/IManager.php @@ -52,7 +52,7 @@ interface IManager { public function getProviders(): array; /** - * @return array<string,array{name: string, description: string, inputShape: array<string, ShapeDescriptor>, optionalInputShape: array<string, ShapeDescriptor>, outputShape: array<string, ShapeDescriptor>, optionalOutputShape: array<string, ShapeDescriptor>}> + * @return array<string,array{name: string, description: string, inputShape: ShapeDescriptor[], optionalInputShape: array<string, ShapeDescriptor>, outputShape: array<string, ShapeDescriptor>, optionalOutputShape: array<string, ShapeDescriptor>}> * @since 30.0.0 */ public function getAvailableTaskTypes(): array; @@ -109,6 +109,7 @@ interface IManager { * @throws ValidationException * @throws Exception * @throws NotFoundException + * @since 30.0.0 */ public function setTaskProgress(int $id, float $progress): bool; @@ -152,6 +153,7 @@ interface IManager { * @throws GenericFileException * @throws LockedException * @throws ValidationException + * @since 30.0.0 */ public function prepareInputData(Task $task): array; } diff --git a/lib/public/TaskProcessing/IProvider.php b/lib/public/TaskProcessing/IProvider.php index be6aa33d125..5768294fd96 100644 --- a/lib/public/TaskProcessing/IProvider.php +++ b/lib/public/TaskProcessing/IProvider.php @@ -26,9 +26,6 @@ declare(strict_types=1); namespace OCP\TaskProcessing; -use OCP\TextProcessing\ITaskType; -use RuntimeException; - /** * This is the interface that is implemented by apps that * implement a task processing provider @@ -66,7 +63,7 @@ interface IProvider { * Returns the shape of optional input parameters * * @since 30.0.0 - * @psalm-return array{string, ShapeDescriptor} + * @psalm-return ShapeDescriptor[] */ public function getOptionalInputShape(): array; @@ -74,7 +71,7 @@ interface IProvider { * Returns the shape of optional output parameters * * @since 30.0.0 - * @psalm-return array{string, ShapeDescriptor} + * @psalm-return ShapeDescriptor[] */ public function getOptionalOutputShape(): array; } diff --git a/lib/public/TaskProcessing/ITaskType.php b/lib/public/TaskProcessing/ITaskType.php index bdac1ec397e..a1c6f002433 100644 --- a/lib/public/TaskProcessing/ITaskType.php +++ b/lib/public/TaskProcessing/ITaskType.php @@ -59,7 +59,7 @@ interface ITaskType { * Returns the shape of the input array * * @since 30.0.0 - * @psalm-return array{string, ShapeDescriptor} + * @psalm-return ShapeDescriptor[] */ public function getInputShape(): array; @@ -67,7 +67,7 @@ interface ITaskType { * Returns the shape of the output array * * @since 30.0.0 - * @psalm-return array{string, ShapeDescriptor} + * @psalm-return ShapeDescriptor[] */ public function getOutputShape(): array; } diff --git a/lib/public/TaskProcessing/ShapeDescriptor.php b/lib/public/TaskProcessing/ShapeDescriptor.php index 0c770b7d07e..58d4b5d8e7f 100644 --- a/lib/public/TaskProcessing/ShapeDescriptor.php +++ b/lib/public/TaskProcessing/ShapeDescriptor.php @@ -2,7 +2,17 @@ namespace OCP\TaskProcessing; +/** + * Data object for input output shape entries + * @since 30.0.0 + */ class ShapeDescriptor { + /** + * @param string $name + * @param string $description + * @param EShapeType $shapeType + * @since 30.0.0 + */ public function __construct( private string $name, private string $description, @@ -10,14 +20,26 @@ class ShapeDescriptor { ) { } + /** + * @return string + * @since 30.0.0 + */ public function getName(): string { return $this->name; } + /** + * @return string + * @since 30.0.0 + */ public function getDescription(): string { return $this->description; } + /** + * @return EShapeType + * @since 30.0.0 + */ public function getShapeType(): EShapeType { return $this->shapeType; } diff --git a/lib/public/TaskProcessing/Task.php b/lib/public/TaskProcessing/Task.php index a467c0d57d0..71b5dae84ca 100644 --- a/lib/public/TaskProcessing/Task.php +++ b/lib/public/TaskProcessing/Task.php @@ -26,11 +26,6 @@ declare(strict_types=1); namespace OCP\TaskProcessing; use DateTime; -use OCP\Files\AppData\IAppDataFactory; -use OCP\Files\NotFoundException; -use OCP\Files\NotPermittedException; -use OCP\IImage; -use OCP\Image; use OCP\TaskProcessing\Exception\ValidationException; /** @@ -158,6 +153,7 @@ final class Task implements \JsonSerializable { } /** + * @return array<string, mixed>|null * @since 30.0.0 */ final public function getOutput(): ?array { @@ -165,7 +161,7 @@ final class Task implements \JsonSerializable { } /** - * @return string + * @return array<string, mixed> * @since 30.0.0 */ final public function getInput(): array { diff --git a/lib/public/TaskProcessing/TaskTypes/AudioToText.php b/lib/public/TaskProcessing/TaskTypes/AudioToText.php index c074c154341..604b99729a4 100644 --- a/lib/public/TaskProcessing/TaskTypes/AudioToText.php +++ b/lib/public/TaskProcessing/TaskTypes/AudioToText.php @@ -36,7 +36,10 @@ use OCP\TaskProcessing\ShapeDescriptor; * @since 30.0.0 */ class AudioToText implements ITaskType { - const ID = 'core:audio2text'; + /** + * @since 30.0.0 + */ + public const ID = 'core:audio2text'; private IL10N $l; @@ -67,10 +70,18 @@ class AudioToText implements ITaskType { return $this->l->t('Transcribe the things said in an audio'); } + /** + * @return string + * @since 30.0.0 + */ public function getId(): string { return self::ID; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getInputShape(): array { return [ 'input' => new ShapeDescriptor( @@ -81,6 +92,10 @@ class AudioToText implements ITaskType { ]; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getOutputShape(): array { return [ 'output' => new ShapeDescriptor( diff --git a/lib/public/TaskProcessing/TaskTypes/TextToImage.php b/lib/public/TaskProcessing/TaskTypes/TextToImage.php index 264238afee5..0b52524b7d3 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToImage.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToImage.php @@ -36,7 +36,10 @@ use OCP\TaskProcessing\ShapeDescriptor; * @since 30.0.0 */ class TextToImage implements ITaskType { - const ID = 'core:text2image'; + /** + * @since 30.0.0 + */ + public const ID = 'core:text2image'; private IL10N $l; @@ -67,10 +70,18 @@ class TextToImage implements ITaskType { return $this->l->t('Generate an image from a text prompt'); } + /** + * @return string + * @since 30.0.0 + */ public function getId(): string { return self::ID; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getInputShape(): array { return [ 'input' => new ShapeDescriptor( @@ -86,6 +97,10 @@ class TextToImage implements ITaskType { ]; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getOutputShape(): array { return [ 'images' => new ShapeDescriptor( diff --git a/lib/public/TaskProcessing/TaskTypes/TextToText.php b/lib/public/TaskProcessing/TaskTypes/TextToText.php index 436c47aa8ee..76cc5d2781d 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToText.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToText.php @@ -36,7 +36,10 @@ use OCP\TaskProcessing\ShapeDescriptor; * @since 30.0.0 */ class TextToText implements ITaskType { - const ID = 'core:text2text'; + /** + * @since 30.0.0 + */ + public const ID = 'core:text2text'; private IL10N $l; @@ -67,10 +70,18 @@ class TextToText implements ITaskType { return $this->l->t('Runs an arbitrary prompt through a language model that retuns a reply'); } + /** + * @return string + * @since 30.0.0 + */ public function getId(): string { return self::ID; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getInputShape(): array { return [ 'input' => new ShapeDescriptor( @@ -81,6 +92,10 @@ class TextToText implements ITaskType { ]; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getOutputShape(): array { return [ 'output' => new ShapeDescriptor( diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextHeadline.php b/lib/public/TaskProcessing/TaskTypes/TextToTextHeadline.php index e524c83fe55..219f6272cc9 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextHeadline.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextHeadline.php @@ -36,7 +36,10 @@ use OCP\TaskProcessing\ShapeDescriptor; * @since 30.0.0 */ class TextToTextHeadline implements ITaskType { - const ID = 'core:text2text:headline'; + /** + * @since 30.0.0 + */ + public const ID = 'core:text2text:headline'; private IL10N $l; @@ -67,10 +70,18 @@ class TextToTextHeadline implements ITaskType { return $this->l->t('Generates a possible headline for a text.'); } + /** + * @return string + * @since 30.0.0 + */ public function getId(): string { return self::ID; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getInputShape(): array { return [ 'input' => new ShapeDescriptor( @@ -81,6 +92,10 @@ class TextToTextHeadline implements ITaskType { ]; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getOutputShape(): array { return [ 'output' => new ShapeDescriptor( diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php b/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php index 4db13b24a24..7564ed7cd0b 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php @@ -36,7 +36,10 @@ use OCP\TaskProcessing\ShapeDescriptor; * @since 30.0.0 */ class TextToTextSummary implements ITaskType { - const ID = 'core:text2text:summary'; + /** + * @since 30.0.0 + */ + public const ID = 'core:text2text:summary'; private IL10N $l; /** @@ -66,10 +69,18 @@ class TextToTextSummary implements ITaskType { return $this->l->t('Summarizes a text'); } + /** + * @return string + * @since 30.0.0 + */ public function getId(): string { return self::ID; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getInputShape(): array { return [ 'input' => new ShapeDescriptor( @@ -80,6 +91,10 @@ class TextToTextSummary implements ITaskType { ]; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getOutputShape(): array { return [ 'output' => new ShapeDescriptor( diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php b/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php index f2f0c5c1b7d..b0376968c24 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php @@ -36,7 +36,10 @@ use OCP\TaskProcessing\ShapeDescriptor; * @since 30.0.0 */ class TextToTextTopics implements ITaskType { - const ID = 'core:text2text:topics'; + /** + * @since 30.0.0 + */ + public const ID = 'core:text2text:topics'; private IL10N $l; @@ -67,10 +70,18 @@ class TextToTextTopics implements ITaskType { return $this->l->t('Extracts topics from a text and outputs them separated by commas'); } + /** + * @return string + * @since 30.0.0 + */ public function getId(): string { return self::ID; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getInputShape(): array { return [ 'input' => new ShapeDescriptor( @@ -81,6 +92,10 @@ class TextToTextTopics implements ITaskType { ]; } + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ public function getOutputShape(): array { return [ 'output' => new ShapeDescriptor( diff --git a/tests/lib/TaskProcessing/TaskProcessingTest.php b/tests/lib/TaskProcessing/TaskProcessingTest.php index 65ee5382883..01bb0253853 100644 --- a/tests/lib/TaskProcessing/TaskProcessingTest.php +++ b/tests/lib/TaskProcessing/TaskProcessingTest.php @@ -13,9 +13,7 @@ use OC\AppFramework\Bootstrap\RegistrationContext; use OC\AppFramework\Bootstrap\ServiceRegistration; use OC\EventDispatcher\EventDispatcher; use OC\TaskProcessing\Db\TaskMapper; -use OC\TaskProcessing\Db\Task as DbTask; use OC\TaskProcessing\Manager; -use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\IJobList; use OCP\EventDispatcher\IEventDispatcher; @@ -43,7 +41,7 @@ use Psr\Log\LoggerInterface; use Test\BackgroundJob\DummyJobList; class AudioToImage implements ITaskType { - const ID = 'test:audiotoimage'; + public const ID = 'test:audiotoimage'; public function getId(): string { return self::ID; @@ -135,7 +133,7 @@ class SuccessfulSyncProvider implements IProvider, ISynchronousProvider { } class FailingSyncProvider implements IProvider, ISynchronousProvider { - const ERROR_MESSAGE = 'Failure'; + public const ERROR_MESSAGE = 'Failure'; public function getId(): string { return 'test:sync:fail'; } @@ -258,7 +256,7 @@ class TaskProcessingTest extends \Test\TestCase { ->with('core', 'ai.textprocessing_provider_preferences', '') ->willReturn(''); - $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); $this->manager = new Manager( $this->coordinator, |