aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/Controller/TaskProcessingApiController.php48
-rw-r--r--core/ResponseDefinitions.php14
-rw-r--r--lib/private/TaskProcessing/Manager.php196
-rw-r--r--lib/public/TaskProcessing/EShapeType.php31
-rw-r--r--lib/public/TaskProcessing/IManager.php2
-rw-r--r--lib/public/TaskProcessing/IProvider.php48
-rw-r--r--lib/public/TaskProcessing/ShapeDescriptor.php4
-rw-r--r--lib/public/TaskProcessing/ShapeEnumValue.php43
-rw-r--r--tests/lib/TaskProcessing/TaskProcessingTest.php96
9 files changed, 423 insertions, 59 deletions
diff --git a/core/Controller/TaskProcessingApiController.php b/core/Controller/TaskProcessingApiController.php
index 6e2a039606f..3bab6bf6fd2 100644
--- a/core/Controller/TaskProcessingApiController.php
+++ b/core/Controller/TaskProcessingApiController.php
@@ -37,6 +37,7 @@ 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;
@@ -67,26 +68,35 @@ class TaskProcessingApiController extends \OCP\AppFramework\OCSController {
#[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 1108e8013a6..10386748c8d 100644
--- a/core/ResponseDefinitions.php
+++ b/core/ResponseDefinitions.php
@@ -9,6 +9,9 @@ declare(strict_types=1);
namespace OC\Core;
+use OCP\TaskProcessing\ShapeDescriptor;
+use OCP\TaskProcessing\ShapeEnumValue;
+
/**
* @psalm-type CoreLoginFlowV2Credentials = array{
* server: string,
@@ -165,15 +168,22 @@ namespace OC\Core;
* @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<array-key, numeric|string>,
+ * optionalInputShape: CoreTaskProcessingShape[],
+ * optionalInputShapeEnumValues: array{name: string, value: string}[][],
+ * optionalInputShapeDefaults: array<array-key, numeric|string>,
* outputShape: CoreTaskProcessingShape[],
+ * outputShapeEnumValues: array{name: string, value: string}[][],
+ * optionalOutputShape: CoreTaskProcessingShape[],
+ * optionalOutputShapeEnumValues: array{name: string, value: string}[][]}
* }
*
* @psalm-type CoreTaskProcessingIO = array<string, numeric|list<numeric>|string|list<string>>
diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php
index ad690acefd7..f62e264ea69 100644
--- a/lib/private/TaskProcessing/Manager.php
+++ b/lib/private/TaskProcessing/Manager.php
@@ -50,6 +50,7 @@ use OCP\TaskProcessing\IProvider;
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<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 */
+ /**
+ * @var array<array-key,array{name: string, description: string, inputShape: ShapeDescriptor[], inputShapeEnumValues: ShapeEnumValue[][], inputShapeDefaults: array<array-key, numeric|string>, optionalInputShape: ShapeDescriptor[], optionalInputShapeEnumValues: ShapeEnumValue[][], optionalInputShapeDefaults: array<array-key, numeric|string>, 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 @@ class Manager implements IManager {
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 @@ class Manager implements IManager {
}
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 @@ class Manager implements IManager {
}
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,21 +511,37 @@ class Manager implements IManager {
/**
* @param ShapeDescriptor[] $spec
+ * @param array<array-key, string|numeric> $defaults
+ * @param array<array-key, ShapeEnumValue[]> $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());
}
@@ -461,13 +549,26 @@ class Manager implements IManager {
}
/**
+ * Takes task input data and replaces fileIds with File objects
+ *
+ * @param array<array-key, list<numeric|string>|numeric|string> $input
+ * @param array<array-key, numeric|string> ...$defaultSpecs the specs
+ * @return array<array-key, list<numeric|string>|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<array-key, ShapeEnumValue[]> $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 @@ class Manager implements IManager {
}
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 @@ class Manager implements IManager {
/**
* @param ShapeDescriptor[] $spec
+ * @param array<array-key, ShapeEnumValue[]> $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 @@ class Manager implements IManager {
}
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 @@ class Manager implements IManager {
$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 @@ class Manager implements IManager {
}
$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 @@ class Manager implements IManager {
$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 @@ class Manager implements IManager {
} 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 @@ class Manager implements IManager {
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 059f9d0c3c7..504f1672100 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;
@@ -32,11 +33,32 @@ enum EShapeType: int {
/**
* @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
* @throws ValidationException
* @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 @@ enum EShapeType: int {
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 d7cd96edc45..e3e6b3be09d 100644
--- a/lib/public/TaskProcessing/IManager.php
+++ b/lib/public/TaskProcessing/IManager.php
@@ -46,7 +46,7 @@ interface IManager {
public function getPreferredProvider(string $taskType);
/**
- * @return array<string,array{name: string, description: string, inputShape: ShapeDescriptor[], optionalInputShape: ShapeDescriptor[], outputShape: ShapeDescriptor[], optionalOutputShape: ShapeDescriptor[]}>
+ * @return array<array-key,array{name: string, description: string, inputShape: ShapeDescriptor[], inputShapeEnumValues: ShapeEnumValue[][], inputShapeDefaults: array<array-key, numeric|string>, optionalInputShape: ShapeDescriptor[], optionalInputShapeEnumValues: ShapeEnumValue[][], optionalInputShapeDefaults: array<array-key, numeric|string>, 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 68a708ca834..a4e752216c7 100644
--- a/lib/public/TaskProcessing/IProvider.php
+++ b/lib/public/TaskProcessing/IProvider.php
@@ -58,4 +58,52 @@ interface IProvider {
* @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<array-key, string|numeric>
+ */
+ 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<array-key, string|numeric>
+ */
+ 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 5759b260865..19e57c8a91d 100644
--- a/lib/public/TaskProcessing/ShapeDescriptor.php
+++ b/lib/public/TaskProcessing/ShapeDescriptor.php
@@ -49,11 +49,11 @@ class ShapeDescriptor implements \JsonSerializable {
}
/**
- * @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 00000000000..33bf9c99d63
--- /dev/null
+++ b/lib/public/TaskProcessing/ShapeEnumValue.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace OCP\TaskProcessing;
+
+class ShapeEnumValue implements \JsonSerializable {
+ /**
+ * @param string $name
+ * @param string $value
+ * @since 30.0.0
+ */
+ public function __construct(
+ private string $name,
+ private string $value,
+ ) {
+ }
+
+ /**
+ * @return string
+ * @since 30.0.0
+ */
+ public function getName(): string {
+ return $this->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 c88f73a861c..ac9dec1cd1d 100644
--- a/tests/lib/TaskProcessing/TaskProcessingTest.php
+++ b/tests/lib/TaskProcessing/TaskProcessingTest.php
@@ -104,6 +104,30 @@ class AsyncProvider implements IProvider {
'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 @@ class SuccessfulSyncProvider implements IProvider, ISynchronousProvider {
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 @@ class FailingSyncProvider implements IProvider, ISynchronousProvider {
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 @@ class BrokenSyncProvider implements IProvider, ISynchronousProvider {
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 {