From 799ee8fd5180e22724d0c188d03ab2a1278b3e1d Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Wed, 24 Jul 2024 15:34:51 +0200 Subject: [PATCH 01/11] feat(TaskProcessing): Implement enums and default values Signed-off-by: Marcel Klehr --- .../TaskProcessingApiController.php | 48 +++-- core/ResponseDefinitions.php | 14 +- lib/private/TaskProcessing/Manager.php | 196 ++++++++++++++---- lib/public/TaskProcessing/EShapeType.php | 31 +++ lib/public/TaskProcessing/IManager.php | 2 +- lib/public/TaskProcessing/IProvider.php | 48 +++++ lib/public/TaskProcessing/ShapeDescriptor.php | 4 +- lib/public/TaskProcessing/ShapeEnumValue.php | 43 ++++ .../lib/TaskProcessing/TaskProcessingTest.php | 96 +++++++++ 9 files changed, 423 insertions(+), 59 deletions(-) create mode 100644 lib/public/TaskProcessing/ShapeEnumValue.php diff --git a/core/Controller/TaskProcessingApiController.php b/core/Controller/TaskProcessingApiController.php index 6e2a039606ffa..3bab6bf6fd228 100644 --- a/core/Controller/TaskProcessingApiController.php +++ b/core/Controller/TaskProcessingApiController.php @@ -37,6 +37,7 @@ use OCP\TaskProcessing\Exception\ValidationException; use OCP\TaskProcessing\IManager; use OCP\TaskProcessing\ShapeDescriptor; +use OCP\TaskProcessing\ShapeEnumValue; use OCP\TaskProcessing\Task; use RuntimeException; @@ -67,26 +68,35 @@ public function __construct( #[PublicPage] #[ApiRoute(verb: 'GET', url: '/tasktypes', root: '/taskprocessing')] public function taskTypes(): DataResponse { - $taskTypes = $this->taskProcessingManager->getAvailableTaskTypes(); - - $serializedTaskTypes = []; - foreach ($taskTypes as $key => $taskType) { - $serializedTaskTypes[$key] = [ - 'name' => $taskType['name'], - 'description' => $taskType['description'], - 'inputShape' => array_map(fn (ShapeDescriptor $descriptor) => - $descriptor->jsonSerialize() + ['mandatory' => true], $taskType['inputShape']) - + array_map(fn (ShapeDescriptor $descriptor) => - $descriptor->jsonSerialize() + ['mandatory' => false], $taskType['optionalInputShape']), - 'outputShape' => array_map(fn (ShapeDescriptor $descriptor) => - $descriptor->jsonSerialize() + ['mandatory' => true], $taskType['outputShape']) - + array_map(fn (ShapeDescriptor $descriptor) => - $descriptor->jsonSerialize() + ['mandatory' => false], $taskType['optionalOutputShape']), - ]; - } - + $taskTypes = array_map(function(array $tt) { + $tt['inputShape'] = array_map(function($descriptor) { + return $descriptor->jsonSerialize(); + }, $tt['inputShape']); + $tt['outputShape'] = array_map(function($descriptor) { + return $descriptor->jsonSerialize(); + }, $tt['outputShape']); + $tt['optionalInputShape'] = array_map(function($descriptor) { + return $descriptor->jsonSerialize(); + }, $tt['optionalInputShape']); + $tt['optionalOutputShape'] = array_map(function($descriptor) { + return $descriptor->jsonSerialize(); + }, $tt['optionalOutputShape']); + $tt['inputShapeEnumValues'] = array_map(function(array $enumValues) { + return array_map(fn(ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); + }, $tt['inputShapeEnumValues']); + $tt['optionalInputShapeEnumValues'] = array_map(function(array $enumValues) { + return array_map(fn(ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); + }, $tt['optionalInputShapeEnumValues']); + $tt['outputShapeEnumValues'] = array_map(function(array $enumValues) { + return array_map(fn(ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); + }, $tt['outputShapeEnumValues']); + $tt['optionalOutputShapeEnumValues'] = array_map(function(array $enumValues) { + return array_map(fn(ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); + }, $tt['optionalOutputShapeEnumValues']); + return $tt; + }, $this->taskProcessingManager->getAvailableTaskTypes()); return new DataResponse([ - 'types' => $serializedTaskTypes, + 'types' => $taskTypes, ]); } diff --git a/core/ResponseDefinitions.php b/core/ResponseDefinitions.php index 1108e8013a6d8..10386748c8dd3 100644 --- a/core/ResponseDefinitions.php +++ b/core/ResponseDefinitions.php @@ -9,6 +9,9 @@ namespace OC\Core; +use OCP\TaskProcessing\ShapeDescriptor; +use OCP\TaskProcessing\ShapeEnumValue; + /** * @psalm-type CoreLoginFlowV2Credentials = array{ * server: string, @@ -165,15 +168,22 @@ * @psalm-type CoreTaskProcessingShape = array{ * name: string, * description: string, - * type: "Number"|"Text"|"Audio"|"Image"|"Video"|"File"|"ListOfNumbers"|"ListOfTexts"|"ListOfImages"|"ListOfAudios"|"ListOfVideos"|"ListOfFiles", - * mandatory: bool, + * type: "Number"|"Text"|"Audio"|"Image"|"Video"|"File"|"Enum"|"ListOfNumbers"|"ListOfTexts"|"ListOfImages"|"ListOfAudios"|"ListOfVideos"|"ListOfFiles", * } * * @psalm-type CoreTaskProcessingTaskType = array{ * name: string, * description: string, * inputShape: CoreTaskProcessingShape[], + * inputShapeEnumValues: array{name: string, value: string}[][], + * inputShapeDefaults: array, + * optionalInputShape: CoreTaskProcessingShape[], + * optionalInputShapeEnumValues: array{name: string, value: string}[][], + * optionalInputShapeDefaults: array, * outputShape: CoreTaskProcessingShape[], + * outputShapeEnumValues: array{name: string, value: string}[][], + * optionalOutputShape: CoreTaskProcessingShape[], + * optionalOutputShapeEnumValues: array{name: string, value: string}[][]} * } * * @psalm-type CoreTaskProcessingIO = array|string|list> diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index ad690acefd77f..f62e264ea693b 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -50,6 +50,7 @@ use OCP\TaskProcessing\ISynchronousProvider; use OCP\TaskProcessing\ITaskType; use OCP\TaskProcessing\ShapeDescriptor; +use OCP\TaskProcessing\ShapeEnumValue; use OCP\TaskProcessing\Task; use OCP\TaskProcessing\TaskTypes\AudioToText; use OCP\TaskProcessing\TaskTypes\TextToImage; @@ -70,34 +71,33 @@ class Manager implements IManager { /** @var list|null */ private ?array $providers = null; - /** @var array, optionalInputShape: array, outputShape: array, optionalOutputShape: array}>|null */ + /** + * @var array, optionalInputShape: ShapeDescriptor[], optionalInputShapeEnumValues: ShapeEnumValue[][], optionalInputShapeDefaults: array, outputShape: ShapeDescriptor[], outputShapeEnumValues: ShapeEnumValue[][], optionalOutputShape: ShapeDescriptor[], optionalOutputShapeEnumValues: ShapeEnumValue[][]}> + */ private ?array $availableTaskTypes = null; private IAppData $appData; - public function __construct( - private IConfig $config, - private Coordinator $coordinator, - private IServerContainer $serverContainer, - private LoggerInterface $logger, - private TaskMapper $taskMapper, - private IJobList $jobList, - private IEventDispatcher $dispatcher, - IAppDataFactory $appDataFactory, - private IRootFolder $rootFolder, - private \OCP\TextProcessing\IManager $textProcessingManager, - private \OCP\TextToImage\IManager $textToImageManager, - private \OCP\SpeechToText\ISpeechToTextManager $speechToTextManager, - private IUserMountCache $userMountCache, - private IClientService $clientService, - private IAppManager $appManager, - ) { - $this->appData = $appDataFactory->get('core'); + private IConfig $config, + private Coordinator $coordinator, + private IServerContainer $serverContainer, + private LoggerInterface $logger, + private TaskMapper $taskMapper, + private IJobList $jobList, + private IEventDispatcher $dispatcher, + IAppDataFactory $appDataFactory, + private IRootFolder $rootFolder, + private \OCP\TextProcessing\IManager $textProcessingManager, + private \OCP\TextToImage\IManager $textToImageManager, + private \OCP\SpeechToText\ISpeechToTextManager $speechToTextManager, + private IUserMountCache $userMountCache, + private IClientService $clientService, + private IAppManager $appManager, + ) { + $this->appData = $appDataFactory->get('core'); } - /** - * @return IProvider[] - */ + private function _getTextProcessingProviders(): array { $oldProviders = $this->textProcessingManager->getProviders(); $newProviders = []; @@ -155,6 +155,30 @@ public function process(?string $userId, array $input, callable $reportProgress) throw new ProcessingException($e->getMessage(), 0, $e); } } + + public function getInputShapeEnumValues(): array { + return []; + } + + public function getInputShapeDefaults(): array { + return []; + } + + public function getOptionalInputShapeEnumValues(): array { + return []; + } + + public function getOptionalInputShapeDefaults(): array { + return []; + } + + public function getOutputShapeEnumValues(): array { + return []; + } + + public function getOptionalOutputShapeEnumValues(): array { + return []; + } }; $newProviders[$provider->getId()] = $provider; } @@ -289,6 +313,30 @@ public function process(?string $userId, array $input, callable $reportProgress) } return ['images' => array_map(fn (ISimpleFile $file) => $file->getContent(), $files)]; } + + public function getInputShapeEnumValues(): array { + return []; + } + + public function getInputShapeDefaults(): array { + return []; + } + + public function getOptionalInputShapeEnumValues(): array { + return []; + } + + public function getOptionalInputShapeDefaults(): array { + return []; + } + + public function getOutputShapeEnumValues(): array { + return []; + } + + public function getOptionalOutputShapeEnumValues(): array { + return []; + } }; $newProviders[$newProvider->getId()] = $newProvider; } @@ -351,6 +399,30 @@ public function process(?string $userId, array $input, callable $reportProgress) } return ['output' => $result]; } + + public function getInputShapeEnumValues(): array { + return []; + } + + public function getInputShapeDefaults(): array { + return []; + } + + public function getOptionalInputShapeEnumValues(): array { + return []; + } + + public function getOptionalInputShapeDefaults(): array { + return []; + } + + public function getOutputShapeEnumValues(): array { + return []; + } + + public function getOptionalOutputShapeEnumValues(): array { + return []; + } }; $newProviders[$newProvider->getId()] = $newProvider; } @@ -439,35 +511,64 @@ private function _getTaskTypes(): array { /** * @param ShapeDescriptor[] $spec + * @param array $defaults + * @param array $enumValues * @param array $io + * @param bool $optional * @return void * @throws ValidationException */ - private function validateInput(array $spec, array $io, bool $optional = false): void { + private static function validateInput(array $spec, array $defaults, array $enumValues, array $io, bool $optional = false): void { foreach ($spec as $key => $descriptor) { $type = $descriptor->getShapeType(); if (!isset($io[$key])) { if ($optional) { continue; } + if (isset($defaults[$key])) { + if (EShapeType::getScalarType($type) !== $type) { + throw new ValidationException('Provider tried to set a default value for a non-scalar slot'); + } + if (EShapeType::isFileType($type)) { + throw new ValidationException('Provider tried to set a default value for a slot that is not text or number'); + } + $type->validateInput($defaults[$key]); + continue; + } throw new ValidationException('Missing key: "' . $key . '"'); } try { $type->validateInput($io[$key]); + if (isset($enumValues[$key])) { + $type->validateEnum($io[$key], $enumValues[$key]); + } } catch (ValidationException $e) { throw new ValidationException('Failed to validate input key "' . $key . '": ' . $e->getMessage()); } } } + /** + * Takes task input data and replaces fileIds with File objects + * + * @param array|numeric|string> $input + * @param array ...$defaultSpecs the specs + * @return array|numeric|string> + */ + public function fillInputDefaults(array $input, ...$defaultSpecs): array { + $spec = array_reduce($defaultSpecs, fn ($carry, $spec) => $carry + $spec, []); + return $spec + $input; + } + /** * @param ShapeDescriptor[] $spec + * @param array $enumValues * @param array $io * @param bool $optional * @return void * @throws ValidationException */ - private function validateOutputWithFileIds(array $spec, array $io, bool $optional = false): void { + private static function validateOutputWithFileIds(array $spec, array $enumValues, array $io, bool $optional = false): void { foreach ($spec as $key => $descriptor) { $type = $descriptor->getShapeType(); if (!isset($io[$key])) { @@ -478,6 +579,9 @@ private function validateOutputWithFileIds(array $spec, array $io, bool $optiona } try { $type->validateOutputWithFileIds($io[$key]); + if (isset($enumValues[$key])) { + $type->validateEnum($io[$key], $enumValues[$key]); + } } catch (ValidationException $e) { throw new ValidationException('Failed to validate output key "' . $key . '": ' . $e->getMessage()); } @@ -486,12 +590,13 @@ private function validateOutputWithFileIds(array $spec, array $io, bool $optiona /** * @param ShapeDescriptor[] $spec + * @param array $enumValues * @param array $io * @param bool $optional * @return void * @throws ValidationException */ - private function validateOutputWithFileData(array $spec, array $io, bool $optional = false): void { + private static function validateOutputWithFileData(array $spec, array $enumValues, array $io, bool $optional = false): void { foreach ($spec as $key => $descriptor) { $type = $descriptor->getShapeType(); if (!isset($io[$key])) { @@ -502,6 +607,9 @@ private function validateOutputWithFileData(array $spec, array $io, bool $option } try { $type->validateOutputWithFileData($io[$key]); + if (isset($enumValues[$key])) { + $type->validateEnum($io[$key], $enumValues[$key]); + } } catch (ValidationException $e) { throw new ValidationException('Failed to validate output key "' . $key . '": ' . $e->getMessage()); } @@ -569,10 +677,16 @@ public function getAvailableTaskTypes(): array { $availableTaskTypes[$provider->getTaskTypeId()] = [ 'name' => $taskType->getName(), 'description' => $taskType->getDescription(), - 'inputShape' => $taskType->getInputShape(), 'optionalInputShape' => $provider->getOptionalInputShape(), + 'inputShapeEnumValues' => $provider->getInputShapeEnumValues(), + 'inputShapeDefaults' => $provider->getInputShapeDefaults(), + 'inputShape' => $taskType->getInputShape(), + 'optionalInputShapeEnumValues' => $provider->getOptionalInputShapeEnumValues(), + 'optionalInputShapeDefaults' => $provider->getOptionalInputShapeDefaults(), 'outputShape' => $taskType->getOutputShape(), + 'outputShapeEnumValues' => $provider->getOutputShapeEnumValues(), 'optionalOutputShape' => $provider->getOptionalOutputShape(), + 'optionalOutputShapeEnumValues' => $provider->getOptionalOutputShapeEnumValues(), ]; } @@ -592,10 +706,14 @@ public function scheduleTask(Task $task): void { } $taskTypes = $this->getAvailableTaskTypes(); $inputShape = $taskTypes[$task->getTaskTypeId()]['inputShape']; + $inputShapeDefaults = $taskTypes[$task->getTaskTypeId()]['inputShapeDefaults']; + $inputShapeEnumValues = $taskTypes[$task->getTaskTypeId()]['inputShapeEnumValues']; $optionalInputShape = $taskTypes[$task->getTaskTypeId()]['optionalInputShape']; + $optionalInputShapeEnumValues = $taskTypes[$task->getTaskTypeId()]['optionalInputShapeEnumValues']; + $optionalInputShapeDefaults = $taskTypes[$task->getTaskTypeId()]['optionalInputShapeDefaults']; // validate input - $this->validateInput($inputShape, $task->getInput()); - $this->validateInput($optionalInputShape, $task->getInput(), true); + $this->validateInput($inputShape, $inputShapeDefaults, $inputShapeEnumValues, $task->getInput()); + $this->validateInput($optionalInputShape, $optionalInputShapeDefaults, $optionalInputShapeEnumValues, $task->getInput(), true); // authenticate access to mentioned files $ids = []; foreach ($inputShape + $optionalInputShape as $key => $descriptor) { @@ -614,7 +732,9 @@ public function scheduleTask(Task $task): void { $this->validateUserAccessToFile($fileId, $task->getUserId()); } // remove superfluous keys and set input - $task->setInput($this->removeSuperfluousArrayKeys($task->getInput(), $inputShape, $optionalInputShape)); + $input = $this->removeSuperfluousArrayKeys($task->getInput(), $inputShape, $optionalInputShape); + $inputWithDefaults = $this->fillInputDefaults($input, $inputShapeDefaults, $optionalInputShapeDefaults); + $task->setInput($inputWithDefaults); $task->setStatus(Task::STATUS_SCHEDULED); $task->setScheduledAt(time()); $provider = $this->getPreferredProvider($task->getTaskTypeId()); @@ -703,15 +823,17 @@ public function setTaskResult(int $id, ?string $error, ?array $result, bool $isU } elseif ($result !== null) { $taskTypes = $this->getAvailableTaskTypes(); $outputShape = $taskTypes[$task->getTaskTypeId()]['outputShape']; + $outputShapeEnumValues = $taskTypes[$task->getTaskTypeId()]['outputShapeEnumValues']; $optionalOutputShape = $taskTypes[$task->getTaskTypeId()]['optionalOutputShape']; + $optionalOutputShapeEnumValues = $taskTypes[$task->getTaskTypeId()]['optionalOutputShapeEnumValues']; try { // validate output if (!$isUsingFileIds) { - $this->validateOutputWithFileData($outputShape, $result); - $this->validateOutputWithFileData($optionalOutputShape, $result, true); + $this->validateOutputWithFileData($outputShape, $outputShapeEnumValues, $result); + $this->validateOutputWithFileData($optionalOutputShape, $optionalOutputShapeEnumValues, $result, true); } else { - $this->validateOutputWithFileIds($outputShape, $result); - $this->validateOutputWithFileIds($optionalOutputShape, $result, true); + $this->validateOutputWithFileIds($outputShape, $outputShapeEnumValues, $result); + $this->validateOutputWithFileIds($optionalOutputShape, $optionalOutputShapeEnumValues, $result, true); } $output = $this->removeSuperfluousArrayKeys($result, $outputShape, $optionalOutputShape); // extract raw data and put it in files, replace it with file ids @@ -927,11 +1049,15 @@ public function encapsulateOutputFileData(array $output, ...$specs): array { public function prepareInputData(Task $task): array { $taskTypes = $this->getAvailableTaskTypes(); $inputShape = $taskTypes[$task->getTaskTypeId()]['inputShape']; + $inputShapeDefaults = $taskTypes[$task->getTaskTypeId()]['inputShapeDefaults']; + $inputShapeEnumValues = $taskTypes[$task->getTaskTypeId()]['inputShapeEnumValues']; $optionalInputShape = $taskTypes[$task->getTaskTypeId()]['optionalInputShape']; + $optionalInputShapeEnumValues = $taskTypes[$task->getTaskTypeId()]['optionalInputShapeEnumValues']; + $optionalInputShapeDefaults = $taskTypes[$task->getTaskTypeId()]['optionalInputShapeDefaults']; $input = $task->getInput(); // validate input, again for good measure (should have been validated in scheduleTask) - $this->validateInput($inputShape, $input); - $this->validateInput($optionalInputShape, $input, true); + $this->validateInput($inputShape, $inputShapeDefaults, $inputShapeEnumValues, $input); + $this->validateInput($optionalInputShape, $optionalInputShapeDefaults, $optionalInputShapeEnumValues, $input, true); $input = $this->removeSuperfluousArrayKeys($input, $inputShape, $optionalInputShape); $input = $this->fillInputFileData($task->getUserId(), $input, $inputShape, $optionalInputShape); return $input; diff --git a/lib/public/TaskProcessing/EShapeType.php b/lib/public/TaskProcessing/EShapeType.php index 059f9d0c3c758..504f167210084 100644 --- a/lib/public/TaskProcessing/EShapeType.php +++ b/lib/public/TaskProcessing/EShapeType.php @@ -23,6 +23,7 @@ enum EShapeType: int { case Audio = 3; case Video = 4; case File = 5; + case Enum = 6; case ListOfNumbers = 10; case ListOfTexts = 11; case ListOfImages = 12; @@ -30,6 +31,24 @@ enum EShapeType: int { case ListOfVideos = 14; case ListOfFiles = 15; + /** + * @param mixed $value + * @param ShapeEnumValue[] $enumValues + * @return void + * @throws ValidationException + */ + public function validateEnum(mixed $value, array $enumValues): void { + if ($this !== EShapeType::Enum) { + throw new ValidationException('Provider provided enum values for non-enum slot'); + } + foreach ($enumValues as $enumValue) { + if ($value === $enumValue->getValue()) { + return; + } + } + throw new ValidationException('Wrong value given for Enum slot. Got "' . $value . '", but expected one of the provided enum values: "' . implode('", "', array_map(fn($enumValue) => $enumValue->getValue(), $enumValues)) . '"'); + } + /** * @param mixed $value * @return void @@ -37,6 +56,9 @@ enum EShapeType: int { * @since 30.0.0 */ private function validateNonFileType(mixed $value): void { + if ($this === EShapeType::Enum && !is_string($value)) { + throw new ValidationException('Non-text item provided for Enum slot'); + } if ($this === EShapeType::Text && !is_string($value)) { throw new ValidationException('Non-text item provided for Text slot'); } @@ -159,4 +181,13 @@ public function validateOutputWithFileIds(mixed $value): void { public static function getScalarType(EShapeType $type): EShapeType { return EShapeType::from($type->value % 10); } + + /** + * @param EShapeType $type + * @return bool + * @since 30.0.0 + */ + public static function isFileType(EShapeType $type): bool { + return in_array(EShapeType::getScalarType($type), [EShapeType::File, EShapeType::Image, EShapeType::Audio, EShapeType::Video], true); + } } diff --git a/lib/public/TaskProcessing/IManager.php b/lib/public/TaskProcessing/IManager.php index d7cd96edc4565..e3e6b3be09da4 100644 --- a/lib/public/TaskProcessing/IManager.php +++ b/lib/public/TaskProcessing/IManager.php @@ -46,7 +46,7 @@ public function getProviders(): array; public function getPreferredProvider(string $taskType); /** - * @return array + * @return array, optionalInputShape: ShapeDescriptor[], optionalInputShapeEnumValues: ShapeEnumValue[][], optionalInputShapeDefaults: array, outputShape: ShapeDescriptor[], outputShapeEnumValues: ShapeEnumValue[][], optionalOutputShape: ShapeDescriptor[], optionalOutputShapeEnumValues: ShapeEnumValue[][]}> * @since 30.0.0 */ public function getAvailableTaskTypes(): array; diff --git a/lib/public/TaskProcessing/IProvider.php b/lib/public/TaskProcessing/IProvider.php index 68a708ca83459..a4e752216c765 100644 --- a/lib/public/TaskProcessing/IProvider.php +++ b/lib/public/TaskProcessing/IProvider.php @@ -58,4 +58,52 @@ public function getOptionalInputShape(): array; * @psalm-return ShapeDescriptor[] */ public function getOptionalOutputShape(): array; + + /** + * Returns the option list for each input shape ENUM slot + * + * @since 30.0.0 + * @psalm-return ShapeEnumValue[][] + */ + public function getInputShapeEnumValues(): array; + + /** + * Returns the default values for input shape slots + * + * @since 30.0.0 + * @psalm-return array + */ + public function getInputShapeDefaults(): array; + + /** + * Returns the option list for each optional input shape ENUM slot + * + * @since 30.0.0 + * @psalm-return ShapeEnumValue[][] + */ + public function getOptionalInputShapeEnumValues(): array; + + /** + * Returns the default values for optional input shape slots + * + * @since 30.0.0 + * @psalm-return array + */ + public function getOptionalInputShapeDefaults(): array; + + /** + * Returns the option list for each output shape ENUM slot + * + * @since 30.0.0 + * @psalm-return ShapeEnumValue[][] + */ + public function getOutputShapeEnumValues(): array; + + /** + * Returns the option list for each optional output shape ENUM slot + * + * @since 30.0.0 + * @psalm-return ShapeEnumValue[][] + */ + public function getOptionalOutputShapeEnumValues(): array; } diff --git a/lib/public/TaskProcessing/ShapeDescriptor.php b/lib/public/TaskProcessing/ShapeDescriptor.php index 5759b2608655c..19e57c8a91d82 100644 --- a/lib/public/TaskProcessing/ShapeDescriptor.php +++ b/lib/public/TaskProcessing/ShapeDescriptor.php @@ -49,11 +49,11 @@ public function getShapeType(): EShapeType { } /** - * @return array{name: string, description: string, type: "Number"|"Text"|"Audio"|"Image"|"Video"|"File"|"ListOfNumbers"|"ListOfTexts"|"ListOfImages"|"ListOfAudios"|"ListOfVideos"|"ListOfFiles"} + * @return array{name: string, description: string, type: "Number"|"Text"|"Audio"|"Image"|"Video"|"File"|"Enum"|"ListOfNumbers"|"ListOfTexts"|"ListOfImages"|"ListOfAudios"|"ListOfVideos"|"ListOfFiles"} * @since 30.0.0 */ public function jsonSerialize(): array { - /** @var "Number"|"Text"|"Audio"|"Image"|"Video"|"File"|"ListOfNumbers"|"ListOfTexts"|"ListOfImages"|"ListOfAudios"|"ListOfVideos"|"ListOfFiles" $type */ + /** @var "Number"|"Text"|"Audio"|"Image"|"Video"|"File"|"Enum"|"ListOfNumbers"|"ListOfTexts"|"ListOfImages"|"ListOfAudios"|"ListOfVideos"|"ListOfFiles" $type */ $type = $this->getShapeType()->name; return [ 'name' => $this->getName(), diff --git a/lib/public/TaskProcessing/ShapeEnumValue.php b/lib/public/TaskProcessing/ShapeEnumValue.php new file mode 100644 index 0000000000000..33bf9c99d63fb --- /dev/null +++ b/lib/public/TaskProcessing/ShapeEnumValue.php @@ -0,0 +1,43 @@ +name; + } + + /** + * @return string + * @since 30.0.0 + */ + public function getValue(): string { + return $this->value; + } + + /** + * @return array{name: string, value: string} + * @since 30.0.0 + */ + public function jsonSerialize(): array { + return [ + 'name' => $this->getName(), + 'value' => $this->getValue(), + ]; + } +} diff --git a/tests/lib/TaskProcessing/TaskProcessingTest.php b/tests/lib/TaskProcessing/TaskProcessingTest.php index c88f73a861c30..ac9dec1cd1dee 100644 --- a/tests/lib/TaskProcessing/TaskProcessingTest.php +++ b/tests/lib/TaskProcessing/TaskProcessingTest.php @@ -104,6 +104,30 @@ public function getOptionalOutputShape(): array { 'optionalKey' => new ShapeDescriptor('optional Key', 'AN optional key', EShapeType::Text), ]; } + + public function getInputShapeEnumValues(): array { + return []; + } + + public function getInputShapeDefaults(): array { + return []; + } + + public function getOptionalInputShapeEnumValues(): array { + return []; + } + + public function getOptionalInputShapeDefaults(): array { + return []; + } + + public function getOutputShapeEnumValues(): array { + return []; + } + + public function getOptionalOutputShapeEnumValues(): array { + return []; + } } class SuccessfulSyncProvider implements IProvider, ISynchronousProvider { @@ -138,6 +162,30 @@ public function getOptionalOutputShape(): array { public function process(?string $userId, array $input, callable $reportProgress): array { return ['output' => $input['input']]; } + + public function getInputShapeEnumValues(): array { + return []; + } + + public function getInputShapeDefaults(): array { + return []; + } + + public function getOptionalInputShapeEnumValues(): array { + return []; + } + + public function getOptionalInputShapeDefaults(): array { + return []; + } + + public function getOutputShapeEnumValues(): array { + return []; + } + + public function getOptionalOutputShapeEnumValues(): array { + return []; + } } class FailingSyncProvider implements IProvider, ISynchronousProvider { @@ -173,6 +221,30 @@ public function getOptionalOutputShape(): array { public function process(?string $userId, array $input, callable $reportProgress): array { throw new ProcessingException(self::ERROR_MESSAGE); } + + public function getInputShapeEnumValues(): array { + return []; + } + + public function getInputShapeDefaults(): array { + return []; + } + + public function getOptionalInputShapeEnumValues(): array { + return []; + } + + public function getOptionalInputShapeDefaults(): array { + return []; + } + + public function getOutputShapeEnumValues(): array { + return []; + } + + public function getOptionalOutputShapeEnumValues(): array { + return []; + } } class BrokenSyncProvider implements IProvider, ISynchronousProvider { @@ -207,6 +279,30 @@ public function getOptionalOutputShape(): array { public function process(?string $userId, array $input, callable $reportProgress): array { return []; } + + public function getInputShapeEnumValues(): array { + return []; + } + + public function getInputShapeDefaults(): array { + return []; + } + + public function getOptionalInputShapeEnumValues(): array { + return []; + } + + public function getOptionalInputShapeDefaults(): array { + return []; + } + + public function getOutputShapeEnumValues(): array { + return []; + } + + public function getOptionalOutputShapeEnumValues(): array { + return []; + } } class SuccessfulTextProcessingSummaryProvider implements \OCP\TextProcessing\IProvider { From 060fb266866be683ea1e8c907054a8663f96d4df Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 24 Jul 2024 15:43:01 +0200 Subject: [PATCH 02/11] fix(taskprocessing): run cs:fix Signed-off-by: Julien Veyssier --- .../TaskProcessingApiController.php | 27 +++++++-------- lib/private/TaskProcessing/Manager.php | 34 +++++++++---------- lib/public/TaskProcessing/EShapeType.php | 2 +- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/core/Controller/TaskProcessingApiController.php b/core/Controller/TaskProcessingApiController.php index 3bab6bf6fd228..e0c8eb904648b 100644 --- a/core/Controller/TaskProcessingApiController.php +++ b/core/Controller/TaskProcessingApiController.php @@ -36,7 +36,6 @@ use OCP\TaskProcessing\Exception\UnauthorizedException; use OCP\TaskProcessing\Exception\ValidationException; use OCP\TaskProcessing\IManager; -use OCP\TaskProcessing\ShapeDescriptor; use OCP\TaskProcessing\ShapeEnumValue; use OCP\TaskProcessing\Task; use RuntimeException; @@ -68,30 +67,30 @@ public function __construct( #[PublicPage] #[ApiRoute(verb: 'GET', url: '/tasktypes', root: '/taskprocessing')] public function taskTypes(): DataResponse { - $taskTypes = array_map(function(array $tt) { - $tt['inputShape'] = array_map(function($descriptor) { + $taskTypes = array_map(function (array $tt) { + $tt['inputShape'] = array_map(function ($descriptor) { return $descriptor->jsonSerialize(); }, $tt['inputShape']); - $tt['outputShape'] = array_map(function($descriptor) { + $tt['outputShape'] = array_map(function ($descriptor) { return $descriptor->jsonSerialize(); }, $tt['outputShape']); - $tt['optionalInputShape'] = array_map(function($descriptor) { + $tt['optionalInputShape'] = array_map(function ($descriptor) { return $descriptor->jsonSerialize(); }, $tt['optionalInputShape']); - $tt['optionalOutputShape'] = array_map(function($descriptor) { + $tt['optionalOutputShape'] = array_map(function ($descriptor) { return $descriptor->jsonSerialize(); }, $tt['optionalOutputShape']); - $tt['inputShapeEnumValues'] = array_map(function(array $enumValues) { - return array_map(fn(ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); + $tt['inputShapeEnumValues'] = array_map(function (array $enumValues) { + return array_map(fn (ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); }, $tt['inputShapeEnumValues']); - $tt['optionalInputShapeEnumValues'] = array_map(function(array $enumValues) { - return array_map(fn(ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); + $tt['optionalInputShapeEnumValues'] = array_map(function (array $enumValues) { + return array_map(fn (ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); }, $tt['optionalInputShapeEnumValues']); - $tt['outputShapeEnumValues'] = array_map(function(array $enumValues) { - return array_map(fn(ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); + $tt['outputShapeEnumValues'] = array_map(function (array $enumValues) { + return array_map(fn (ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); }, $tt['outputShapeEnumValues']); - $tt['optionalOutputShapeEnumValues'] = array_map(function(array $enumValues) { - return array_map(fn(ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); + $tt['optionalOutputShapeEnumValues'] = array_map(function (array $enumValues) { + return array_map(fn (ShapeEnumValue $enumValue) => $enumValue->jsonSerialize(), $enumValues); }, $tt['optionalOutputShapeEnumValues']); return $tt; }, $this->taskProcessingManager->getAvailableTaskTypes()); diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index f62e264ea693b..c0ca1b66b49d5 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -78,23 +78,23 @@ class Manager implements IManager { private IAppData $appData; public function __construct( - private IConfig $config, - private Coordinator $coordinator, - private IServerContainer $serverContainer, - private LoggerInterface $logger, - private TaskMapper $taskMapper, - private IJobList $jobList, - private IEventDispatcher $dispatcher, - IAppDataFactory $appDataFactory, - private IRootFolder $rootFolder, - private \OCP\TextProcessing\IManager $textProcessingManager, - private \OCP\TextToImage\IManager $textToImageManager, - private \OCP\SpeechToText\ISpeechToTextManager $speechToTextManager, - private IUserMountCache $userMountCache, - private IClientService $clientService, - private IAppManager $appManager, - ) { - $this->appData = $appDataFactory->get('core'); + private IConfig $config, + private Coordinator $coordinator, + private IServerContainer $serverContainer, + private LoggerInterface $logger, + private TaskMapper $taskMapper, + private IJobList $jobList, + private IEventDispatcher $dispatcher, + IAppDataFactory $appDataFactory, + private IRootFolder $rootFolder, + private \OCP\TextProcessing\IManager $textProcessingManager, + private \OCP\TextToImage\IManager $textToImageManager, + private \OCP\SpeechToText\ISpeechToTextManager $speechToTextManager, + private IUserMountCache $userMountCache, + private IClientService $clientService, + private IAppManager $appManager, + ) { + $this->appData = $appDataFactory->get('core'); } diff --git a/lib/public/TaskProcessing/EShapeType.php b/lib/public/TaskProcessing/EShapeType.php index 504f167210084..5705443263464 100644 --- a/lib/public/TaskProcessing/EShapeType.php +++ b/lib/public/TaskProcessing/EShapeType.php @@ -46,7 +46,7 @@ public function validateEnum(mixed $value, array $enumValues): void { return; } } - throw new ValidationException('Wrong value given for Enum slot. Got "' . $value . '", but expected one of the provided enum values: "' . implode('", "', array_map(fn($enumValue) => $enumValue->getValue(), $enumValues)) . '"'); + throw new ValidationException('Wrong value given for Enum slot. Got "' . $value . '", but expected one of the provided enum values: "' . implode('", "', array_map(fn ($enumValue) => $enumValue->getValue(), $enumValues)) . '"'); } /** From 0584ebf628837a81f536033c73540ffc24bc3c22 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 24 Jul 2024 15:57:04 +0200 Subject: [PATCH 03/11] fix(taskprocessing): add license Signed-off-by: Julien Veyssier --- lib/public/TaskProcessing/ShapeEnumValue.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/public/TaskProcessing/ShapeEnumValue.php b/lib/public/TaskProcessing/ShapeEnumValue.php index 33bf9c99d63fb..bc50052430447 100644 --- a/lib/public/TaskProcessing/ShapeEnumValue.php +++ b/lib/public/TaskProcessing/ShapeEnumValue.php @@ -1,7 +1,15 @@ Date: Wed, 24 Jul 2024 16:01:01 +0200 Subject: [PATCH 04/11] fix(taskprocessing): fix OpenAPI error and generate specs Signed-off-by: Julien Veyssier --- core/ResponseDefinitions.php | 4 +- core/openapi-full.json | 139 +++++++++++++++++++++++++++++++++-- core/openapi.json | 139 +++++++++++++++++++++++++++++++++-- 3 files changed, 268 insertions(+), 14 deletions(-) diff --git a/core/ResponseDefinitions.php b/core/ResponseDefinitions.php index 10386748c8dd3..7afddbe820a0f 100644 --- a/core/ResponseDefinitions.php +++ b/core/ResponseDefinitions.php @@ -176,10 +176,10 @@ * description: string, * inputShape: CoreTaskProcessingShape[], * inputShapeEnumValues: array{name: string, value: string}[][], - * inputShapeDefaults: array, + * inputShapeDefaults: array, * optionalInputShape: CoreTaskProcessingShape[], * optionalInputShapeEnumValues: array{name: string, value: string}[][], - * optionalInputShapeDefaults: array, + * optionalInputShapeDefaults: array, * outputShape: CoreTaskProcessingShape[], * outputShapeEnumValues: array{name: string, value: string}[][], * optionalOutputShape: CoreTaskProcessingShape[], diff --git a/core/openapi-full.json b/core/openapi-full.json index a90cc1efaafb5..e52b62d6fa60d 100644 --- a/core/openapi-full.json +++ b/core/openapi-full.json @@ -496,8 +496,7 @@ "required": [ "name", "description", - "type", - "mandatory" + "type" ], "properties": { "name": { @@ -515,6 +514,7 @@ "Image", "Video", "File", + "Enum", "ListOfNumbers", "ListOfTexts", "ListOfImages", @@ -522,9 +522,6 @@ "ListOfVideos", "ListOfFiles" ] - }, - "mandatory": { - "type": "boolean" } } }, @@ -602,7 +599,15 @@ "name", "description", "inputShape", - "outputShape" + "inputShapeEnumValues", + "inputShapeDefaults", + "optionalInputShape", + "optionalInputShapeEnumValues", + "optionalInputShapeDefaults", + "outputShape", + "outputShapeEnumValues", + "optionalOutputShape", + "optionalOutputShapeEnumValues" ], "properties": { "name": { @@ -617,11 +622,133 @@ "$ref": "#/components/schemas/TaskProcessingShape" } }, + "inputShapeEnumValues": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } + }, + "inputShapeDefaults": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "optionalInputShape": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskProcessingShape" + } + }, + "optionalInputShapeEnumValues": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } + }, + "optionalInputShapeDefaults": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, "outputShape": { "type": "array", "items": { "$ref": "#/components/schemas/TaskProcessingShape" } + }, + "outputShapeEnumValues": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } + }, + "optionalOutputShape": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskProcessingShape" + } + }, + "optionalOutputShapeEnumValues": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } } } }, diff --git a/core/openapi.json b/core/openapi.json index 869bc4ef2c5fe..d597796f94e24 100644 --- a/core/openapi.json +++ b/core/openapi.json @@ -496,8 +496,7 @@ "required": [ "name", "description", - "type", - "mandatory" + "type" ], "properties": { "name": { @@ -515,6 +514,7 @@ "Image", "Video", "File", + "Enum", "ListOfNumbers", "ListOfTexts", "ListOfImages", @@ -522,9 +522,6 @@ "ListOfVideos", "ListOfFiles" ] - }, - "mandatory": { - "type": "boolean" } } }, @@ -602,7 +599,15 @@ "name", "description", "inputShape", - "outputShape" + "inputShapeEnumValues", + "inputShapeDefaults", + "optionalInputShape", + "optionalInputShapeEnumValues", + "optionalInputShapeDefaults", + "outputShape", + "outputShapeEnumValues", + "optionalOutputShape", + "optionalOutputShapeEnumValues" ], "properties": { "name": { @@ -617,11 +622,133 @@ "$ref": "#/components/schemas/TaskProcessingShape" } }, + "inputShapeEnumValues": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } + }, + "inputShapeDefaults": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "optionalInputShape": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskProcessingShape" + } + }, + "optionalInputShapeEnumValues": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } + }, + "optionalInputShapeDefaults": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, "outputShape": { "type": "array", "items": { "$ref": "#/components/schemas/TaskProcessingShape" } + }, + "outputShapeEnumValues": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } + }, + "optionalOutputShape": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskProcessingShape" + } + }, + "optionalOutputShapeEnumValues": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } } } }, From c23f126c41e353f52bbb9982f62d4f4dd1adfaff Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 24 Jul 2024 16:48:14 +0200 Subject: [PATCH 05/11] fix(taskprocessing): fix cs issues and generate autoloaders Signed-off-by: Julien Veyssier --- core/ResponseDefinitions.php | 3 --- lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/ResponseDefinitions.php b/core/ResponseDefinitions.php index 7afddbe820a0f..4edde2dde3608 100644 --- a/core/ResponseDefinitions.php +++ b/core/ResponseDefinitions.php @@ -9,9 +9,6 @@ namespace OC\Core; -use OCP\TaskProcessing\ShapeDescriptor; -use OCP\TaskProcessing\ShapeEnumValue; - /** * @psalm-type CoreLoginFlowV2Credentials = array{ * server: string, diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 379a1edbe6338..70af8dc7f9286 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -749,6 +749,7 @@ 'OCP\\TaskProcessing\\ISynchronousProvider' => $baseDir . '/lib/public/TaskProcessing/ISynchronousProvider.php', 'OCP\\TaskProcessing\\ITaskType' => $baseDir . '/lib/public/TaskProcessing/ITaskType.php', 'OCP\\TaskProcessing\\ShapeDescriptor' => $baseDir . '/lib/public/TaskProcessing/ShapeDescriptor.php', + 'OCP\\TaskProcessing\\ShapeEnumValue' => $baseDir . '/lib/public/TaskProcessing/ShapeEnumValue.php', 'OCP\\TaskProcessing\\Task' => $baseDir . '/lib/public/TaskProcessing/Task.php', 'OCP\\TaskProcessing\\TaskTypes\\AudioToText' => $baseDir . '/lib/public/TaskProcessing/TaskTypes/AudioToText.php', 'OCP\\TaskProcessing\\TaskTypes\\ContextWrite' => $baseDir . '/lib/public/TaskProcessing/TaskTypes/ContextWrite.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 41109fd5f3d2b..6592103cf2875 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -782,6 +782,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\TaskProcessing\\ISynchronousProvider' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/ISynchronousProvider.php', 'OCP\\TaskProcessing\\ITaskType' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/ITaskType.php', 'OCP\\TaskProcessing\\ShapeDescriptor' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/ShapeDescriptor.php', + 'OCP\\TaskProcessing\\ShapeEnumValue' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/ShapeEnumValue.php', 'OCP\\TaskProcessing\\Task' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/Task.php', 'OCP\\TaskProcessing\\TaskTypes\\AudioToText' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/TaskTypes/AudioToText.php', 'OCP\\TaskProcessing\\TaskTypes\\ContextWrite' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/TaskTypes/ContextWrite.php', From 9306ddeb695964ed4cbb38253a33be2dff9f94da Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 24 Jul 2024 19:25:34 +0200 Subject: [PATCH 06/11] fix(taskprocessing): fix psalm issue Signed-off-by: Julien Veyssier --- lib/public/TaskProcessing/EShapeType.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/public/TaskProcessing/EShapeType.php b/lib/public/TaskProcessing/EShapeType.php index 5705443263464..cd8d6d837dae8 100644 --- a/lib/public/TaskProcessing/EShapeType.php +++ b/lib/public/TaskProcessing/EShapeType.php @@ -36,6 +36,7 @@ enum EShapeType: int { * @param ShapeEnumValue[] $enumValues * @return void * @throws ValidationException + * @since 30.0.0 */ public function validateEnum(mixed $value, array $enumValues): void { if ($this !== EShapeType::Enum) { From 6363437ccb965eec5ac2dd16dfe46be5f461df48 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 25 Jul 2024 08:06:04 +0200 Subject: [PATCH 07/11] fix(taskprocessing): Update lib/private/TaskProcessing/Manager.php Co-authored-by: Julien Veyssier Signed-off-by: Marcel Klehr --- lib/private/TaskProcessing/Manager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index c0ca1b66b49d5..40ad33d5929b9 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -556,8 +556,8 @@ private static function validateInput(array $spec, array $defaults, array $enumV * @return array|numeric|string> */ public function fillInputDefaults(array $input, ...$defaultSpecs): array { - $spec = array_reduce($defaultSpecs, fn ($carry, $spec) => $carry + $spec, []); - return $spec + $input; + $spec = array_reduce($defaultSpecs, fn ($carry, $spec) => array_merge($carry, $spec), []); + return array_merge($spec, $input); } /** From aaa8af4b495a5c079c78af1908a5086ecb7b64df Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 25 Jul 2024 10:23:53 +0200 Subject: [PATCH 08/11] fix: Make sure provider provides enum values Signed-off-by: Marcel Klehr --- lib/private/TaskProcessing/Manager.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 40ad33d5929b9..2e67d12029a07 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -539,7 +539,10 @@ private static function validateInput(array $spec, array $defaults, array $enumV } try { $type->validateInput($io[$key]); - if (isset($enumValues[$key])) { + if ($type === EShapeType::Enum) { + if (!isset($enumValues[$key])) { + throw new ValidationException('Provider did not provide enum values for an enum slot: "' . $key .'"'); + } $type->validateEnum($io[$key], $enumValues[$key]); } } catch (ValidationException $e) { From 46c518f712ccdb95afb438b4bdaa7e68c1d0a8b8 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 25 Jul 2024 10:27:45 +0200 Subject: [PATCH 09/11] fix: Don't validate input again upon running a task Signed-off-by: Marcel Klehr --- lib/private/TaskProcessing/Manager.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 2e67d12029a07..73086b55e5617 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -1052,15 +1052,8 @@ public function encapsulateOutputFileData(array $output, ...$specs): array { public function prepareInputData(Task $task): array { $taskTypes = $this->getAvailableTaskTypes(); $inputShape = $taskTypes[$task->getTaskTypeId()]['inputShape']; - $inputShapeDefaults = $taskTypes[$task->getTaskTypeId()]['inputShapeDefaults']; - $inputShapeEnumValues = $taskTypes[$task->getTaskTypeId()]['inputShapeEnumValues']; $optionalInputShape = $taskTypes[$task->getTaskTypeId()]['optionalInputShape']; - $optionalInputShapeEnumValues = $taskTypes[$task->getTaskTypeId()]['optionalInputShapeEnumValues']; - $optionalInputShapeDefaults = $taskTypes[$task->getTaskTypeId()]['optionalInputShapeDefaults']; $input = $task->getInput(); - // validate input, again for good measure (should have been validated in scheduleTask) - $this->validateInput($inputShape, $inputShapeDefaults, $inputShapeEnumValues, $input); - $this->validateInput($optionalInputShape, $optionalInputShapeDefaults, $optionalInputShapeEnumValues, $input, true); $input = $this->removeSuperfluousArrayKeys($input, $inputShape, $optionalInputShape); $input = $this->fillInputFileData($task->getUserId(), $input, $inputShape, $optionalInputShape); return $input; From 5ed55b0634799cfe1fa834e3f358acb4ac9ff895 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Thu, 25 Jul 2024 10:37:36 +0200 Subject: [PATCH 10/11] feat(taskprocessing): add translate task type Signed-off-by: Julien Veyssier --- lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + .../TaskTypes/TextToTextTranslate.php | 102 ++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 70af8dc7f9286..4abb976e1a9ba 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -763,6 +763,7 @@ 'OCP\\TaskProcessing\\TaskTypes\\TextToTextSimplification' => $baseDir . '/lib/public/TaskProcessing/TaskTypes/TextToTextSimplification.php', 'OCP\\TaskProcessing\\TaskTypes\\TextToTextSummary' => $baseDir . '/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php', 'OCP\\TaskProcessing\\TaskTypes\\TextToTextTopics' => $baseDir . '/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php', + 'OCP\\TaskProcessing\\TaskTypes\\TextToTextTranslate' => $baseDir . '/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php', 'OCP\\Teams\\ITeamManager' => $baseDir . '/lib/public/Teams/ITeamManager.php', 'OCP\\Teams\\ITeamResourceProvider' => $baseDir . '/lib/public/Teams/ITeamResourceProvider.php', 'OCP\\Teams\\Team' => $baseDir . '/lib/public/Teams/Team.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 6592103cf2875..d7a58bff1a289 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -796,6 +796,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\TaskProcessing\\TaskTypes\\TextToTextSimplification' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/TaskTypes/TextToTextSimplification.php', 'OCP\\TaskProcessing\\TaskTypes\\TextToTextSummary' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php', 'OCP\\TaskProcessing\\TaskTypes\\TextToTextTopics' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php', + 'OCP\\TaskProcessing\\TaskTypes\\TextToTextTranslate' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php', 'OCP\\Teams\\ITeamManager' => __DIR__ . '/../../..' . '/lib/public/Teams/ITeamManager.php', 'OCP\\Teams\\ITeamResourceProvider' => __DIR__ . '/../../..' . '/lib/public/Teams/ITeamResourceProvider.php', 'OCP\\Teams\\Team' => __DIR__ . '/../../..' . '/lib/public/Teams/Team.php', diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php b/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php new file mode 100644 index 0000000000000..11b71ec3eb2a2 --- /dev/null +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php @@ -0,0 +1,102 @@ +l = $l10nFactory->get('core'); + } + + + /** + * @inheritDoc + * @since 30.0.0 + */ + public function getName(): string { + return $this->l->t('Translate'); + } + + /** + * @inheritDoc + * @since 30.0.0 + */ + public function getDescription(): string { + return $this->l->t('Translate text from one language to another'); + } + + /** + * @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( + $this->l->t('Origin text'), + $this->l->t('The text to translate'), + EShapeType::Text + ), + 'origin_language' => new ShapeDescriptor( + $this->l->t('Origin language'), + $this->l->t('The language of the origin text'), + EShapeType::Enum + ), + 'target_language' => new ShapeDescriptor( + $this->l->t('Target language'), + $this->l->t('The desired language to translate the origin text in'), + EShapeType::Enum + ), + ]; + } + + /** + * @return ShapeDescriptor[] + * @since 30.0.0 + */ + public function getOutputShape(): array { + return [ + 'output' => new ShapeDescriptor( + $this->l->t('Result'), + $this->l->t('The translated text'), + EShapeType::Text + ), + ]; + } +} From 0b04a6aa48fb3cf54903beb549429abc486c3842 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Thu, 25 Jul 2024 10:38:19 +0200 Subject: [PATCH 11/11] fix(taskprocessing): fix typo in text2text task type Signed-off-by: Julien Veyssier --- lib/public/TaskProcessing/TaskTypes/TextToText.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/public/TaskProcessing/TaskTypes/TextToText.php b/lib/public/TaskProcessing/TaskTypes/TextToText.php index 7ac7f2eca05d9..92eaf5629e8c7 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToText.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToText.php @@ -51,7 +51,7 @@ public function getName(): string { * @since 30.0.0 */ public function getDescription(): string { - return $this->l->t('Runs an arbitrary prompt through a language model that retuns a reply'); + return $this->l->t('Runs an arbitrary prompt through a language model that returns a reply'); } /**