From 317521b607e3a14364f5d486630cf1e5181053e4 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Tue, 11 Apr 2023 14:59:57 +0200 Subject: [PATCH 01/26] feat(SpeechToText): Add SpeechToText provider API Signed-off-by: Marcel Klehr --- .../Bootstrap/RegistrationContext.php | 22 ++++ lib/private/Server.php | 4 + .../SpeechToText/SpeechToTextManager.php | 107 ++++++++++++++++++ lib/private/SpeechToText/TranscriptionJob.php | 47 ++++++++ .../Bootstrap/IRegistrationContext.php | 11 ++ .../Events/TranscriptionFinishedEvent.php | 74 ++++++++++++ .../SpeechToText/ISpeechToTextManager.php | 62 ++++++++++ .../SpeechToText/ISpeechToTextProvider.php | 45 ++++++++ 8 files changed, 372 insertions(+) create mode 100644 lib/private/SpeechToText/SpeechToTextManager.php create mode 100644 lib/private/SpeechToText/TranscriptionJob.php create mode 100644 lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php create mode 100644 lib/public/SpeechToText/ISpeechToTextManager.php create mode 100644 lib/public/SpeechToText/ISpeechToTextProvider.php diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php index 9a6c298419a60..8fcafab2d87db 100644 --- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php +++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php @@ -33,6 +33,7 @@ use OCP\Calendar\Resource\IBackend as IResourceBackend; use OCP\Calendar\Room\IBackend as IRoomBackend; use OCP\Collaboration\Reference\IReferenceProvider; +use OCP\SpeechToText\ISpeechToTextProvider; use OCP\Talk\ITalkBackend; use OCP\Translation\ITranslationProvider; use RuntimeException; @@ -111,6 +112,9 @@ class RegistrationContext { /** @var ServiceRegistration[] */ private $wellKnownHandlers = []; + /** @var ServiceRegistration[] */ + private $speechToTextProviders = []; + /** @var ServiceRegistration[] */ private $templateProviders = []; @@ -252,6 +256,13 @@ public function registerWellKnownHandler(string $class): void { ); } + public function registerSpeechToTextProvider(string $providerClass): void { + $this->context->registerSpeechToTextProvider( + $this->appId, + $providerClass + ); + } + public function registerTemplateProvider(string $providerClass): void { $this->context->registerTemplateProvider( $this->appId, @@ -414,6 +425,10 @@ public function registerWellKnown(string $appId, string $class): void { $this->wellKnownHandlers[] = new ServiceRegistration($appId, $class); } + public function registerSpeechToTextProvider(string $appId, string $class): void { + $this->speechToTextProviders[] = new ServiceRegistration($appId, $class); + } + public function registerTemplateProvider(string $appId, string $class): void { $this->templateProviders[] = new ServiceRegistration($appId, $class); } @@ -685,6 +700,13 @@ public function getWellKnownHandlers(): array { return $this->wellKnownHandlers; } + /** + * @return ServiceRegistration[] + */ + public function getSpeechToTextProviders(): array { + return $this->speechToTextProviders; + } + /** * @return ServiceRegistration[] */ diff --git a/lib/private/Server.php b/lib/private/Server.php index 78099f2a8d032..4cf278c82a92e 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -148,6 +148,7 @@ use OC\Session\CryptoWrapper; use OC\Share20\ProviderFactory; use OC\Share20\ShareHelper; +use OC\SpeechToText\SpeechToTextManager; use OC\SystemTag\ManagerFactory as SystemTagManagerFactory; use OC\Tagging\TagMapper; use OC\Talk\Broker; @@ -246,6 +247,7 @@ use OCP\Security\ITrustedDomainHelper; use OCP\Security\VerificationToken\IVerificationToken; use OCP\Share\IShareHelper; +use OCP\SpeechToText\ISpeechToTextManager; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTagObjectMapper; use OCP\Talk\IBroker; @@ -1457,6 +1459,8 @@ public function __construct($webRoot, \OC\Config $config) { $this->registerAlias(ITranslationManager::class, TranslationManager::class); + $this->registerAlias(ISpeechToTextManager::class, SpeechToTextManager::class); + $this->connectDispatcher(); } diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php new file mode 100644 index 0000000000000..2b21627034000 --- /dev/null +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -0,0 +1,107 @@ + + * @copyright Copyright (c) 2023 Marcel Klehr + * + * @author Julius Härtl + * @author Marcel Klehr + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + + +namespace OC\SpeechToText; + +use InvalidArgumentException; +use OC\AppFramework\Bootstrap\Coordinator; +use OCP\BackgroundJob\IJobList; +use OCP\IServerContainer; +use OCP\PreConditionNotMetException; +use OCP\SpeechToText\ISpeechToTextManager; +use OCP\SpeechToText\ISpeechToTextProvider; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; +use Psr\Log\LoggerInterface; +use Throwable; + +class SpeechToTextManager implements ISpeechToTextManager { + /** @var ?ISpeechToTextProvider[] */ + private ?array $providers = null; + + public function __construct( + private IServerContainer $serverContainer, + private Coordinator $coordinator, + private LoggerInterface $logger, + private IJobList $jobList, + ) { } + + public function getProviders(): array { + $context = $this->coordinator->getRegistrationContext(); + if ($context === null) { + return []; + } + + if ($this->providers !== null) { + return $this->providers; + } + + $this->providers = []; + + foreach ($context->getSpeechToTextProviders() as $providerRegistration) { + $class = $providerRegistration->getService(); + try { + $this->providers[$class] = $this->serverContainer->get($class); + } catch (NotFoundExceptionInterface|ContainerExceptionInterface|Throwable $e) { + $this->logger->error('Failed to load SpeechToText provider ' . $class, [ + 'exception' => $e + ]); + } + } + + return $this->providers; + } + + public function hasProviders(): bool { + $context = $this->coordinator->getRegistrationContext(); + if ($context === null) { + return false; + } + return !empty($context->getTranslationProviders()); + } + + public function scheduleFileTranscription(string $path, array $context): void { + if (!$this->hasProviders()) { + throw new PreConditionNotMetException('No SpeechToText providers have been registered'); + } + $this->jobList->add(TranscriptionJob::class, [ 'path' => $path, 'context' => $context]); + } + + public function transcribeFile(string $path): string { + $provider = current($this->getProviders()); + if (!$provider) { + throw new PreConditionNotMetException('No SpeechToText providers have been registered'); + } + + if (!file_exists($path)) { + throw new InvalidArgumentException('File does not exist'); + } + + return $provider->transcribeFile($path); + } +} diff --git a/lib/private/SpeechToText/TranscriptionJob.php b/lib/private/SpeechToText/TranscriptionJob.php new file mode 100644 index 0000000000000..d2cff4680244a --- /dev/null +++ b/lib/private/SpeechToText/TranscriptionJob.php @@ -0,0 +1,47 @@ +speechToTextManager->transcribeFile($argument['path']); + $this->eventDispatcher->dispatchTyped( + new TranscriptionFinishedEvent( + true, + $result, + '', + $argument['context'] + ) + ); + } catch (PreConditionNotMetException|\RuntimeException|\InvalidArgumentException $e) { + $this->eventDispatcher->dispatchTyped( + new TranscriptionFinishedEvent( + false, + '', + $e->getMessage(), + $argument['context'] + ) + ); + } + } +} diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php index f83f30c0f1c50..66cf1ef23063a 100644 --- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -39,6 +39,7 @@ use OCP\IContainer; use OCP\Notification\INotifier; use OCP\Preview\IProviderV2; +use OCP\SpeechToText\ISpeechToTextProvider; use OCP\Translation\ITranslationProvider; /** @@ -208,6 +209,16 @@ public function registerInitialStateProvider(string $class): void; */ public function registerWellKnownHandler(string $class): void; + /** + * Register a custom SpeechToText provider class that can provide transcription + * of audio through the OCP\SpeechToText APIs + * + * @param string $providerClass + * @psalm-param class-string $providerClass + * @since 27.0.0 + */ + public function registerSpeechToTextProvider(string $providerClass): void; + /** * Register a custom template provider class that is able to inject custom templates * in addition to the user defined ones diff --git a/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php b/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php new file mode 100644 index 0000000000000..376859afd1cf7 --- /dev/null +++ b/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php @@ -0,0 +1,74 @@ + + * + * @author Marcel Klehr + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCP\SpeechToText\Events; + +use OCP\EventDispatcher\Event; + +/** + * @since 27.0.0 + */ +class TranscriptionFinishedEvent extends Event { + + /** + * @since 27.0.0 + */ + public function __construct( + private bool $successful, + private string $transcription, + private string $errorMessage, + private array $context + ) { + parent::__construct(); + } + + /** + * @since 27.0.0 + */ + public function getContext(): array { + return $this->context; + } + + /** + * @since 27.0.0 + */ + public function isSuccessful(): bool { + return $this->successful; + } + + /** + * @since 27.0.0 + */ + public function getErrorMessage(): string { + return $this->errorMessage; + } + + /** + * @since 27.0.0 + */ + public function getTranscription(): string { + return $this->transcription; + } +} diff --git a/lib/public/SpeechToText/ISpeechToTextManager.php b/lib/public/SpeechToText/ISpeechToTextManager.php new file mode 100644 index 0000000000000..297be43e6db9d --- /dev/null +++ b/lib/public/SpeechToText/ISpeechToTextManager.php @@ -0,0 +1,62 @@ + + * + * @author Marcel Klehr + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + + +namespace OCP\SpeechToText; + +use InvalidArgumentException; +use OCP\PreConditionNotMetException; +use RuntimeException; + +/** + * @since 27.0.0 + */ +interface ISpeechToTextManager { + /** + * @since 27.0.0 + */ + public function hasProviders(): bool; + + /** + * Will schedule a transcription process in the background. The result will become available + * with the \OCP\SpeechToText\Events\TranscriptionFinishedEvent + * You should add context information to the context array to re-identify the transcription result as + * as belonging to your transcription request. + * + * @since 27.0.0 + * @throws PreConditionNotMetException If no provider was registered but this method was still called + * @throws InvalidArgumentException If the file could not be found or is not of a supported type + * @throws RuntimeException If the transcription failed for other reasons + */ + public function scheduleFileTranscription(string $path, array $context): void; + + /** + * @since 27.0.0 + * @throws PreConditionNotMetException If no provider was registered but this method was still called + * @throws InvalidArgumentException If the file could not be found or is not of a supported type + * @throws RuntimeException If the transcription failed for other reasons + */ + public function transcribeFile(string $path) : string; +} diff --git a/lib/public/SpeechToText/ISpeechToTextProvider.php b/lib/public/SpeechToText/ISpeechToTextProvider.php new file mode 100644 index 0000000000000..3d739408bf5d4 --- /dev/null +++ b/lib/public/SpeechToText/ISpeechToTextProvider.php @@ -0,0 +1,45 @@ + + * + * @author Marcel Klehr + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + + +namespace OCP\SpeechToText; + +use RuntimeException; + +/** + * @since 27.0.0 + */ +interface ISpeechToTextProvider { + /** + * @since 27.0.0 + */ + public function getName(): string; + + /** + * @since 27.0.0 + * @throws RuntimeException If the text could not be transcribed + */ + public function transcribeFile(string $path): string; +} From f2eb2241bb4199d979941cfa2bb244b74adf6105 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Tue, 11 Apr 2023 15:01:11 +0200 Subject: [PATCH 02/26] feat(SpeechToText): Add autoload changes Signed-off-by: Marcel Klehr --- lib/composer/composer/autoload_classmap.php | 5 +++++ lib/composer/composer/autoload_static.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index a269b440df62b..3dd2239ce7fe1 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -573,6 +573,9 @@ 'OCP\\Share_Backend' => $baseDir . '/lib/public/Share_Backend.php', 'OCP\\Share_Backend_Collection' => $baseDir . '/lib/public/Share_Backend_Collection.php', 'OCP\\Share_Backend_File_Dependent' => $baseDir . '/lib/public/Share_Backend_File_Dependent.php', + 'OCP\\SpeechToText\\Events\\TranscriptionFinishedEvent' => $baseDir . '/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php', + 'OCP\\SpeechToText\\ISpeechToTextManager' => $baseDir . '/lib/public/SpeechToText/ISpeechToTextManager.php', + 'OCP\\SpeechToText\\ISpeechToTextProvider' => $baseDir . '/lib/public/SpeechToText/ISpeechToTextProvider.php', 'OCP\\Support\\CrashReport\\ICollectBreadcrumbs' => $baseDir . '/lib/public/Support/CrashReport/ICollectBreadcrumbs.php', 'OCP\\Support\\CrashReport\\IMessageReporter' => $baseDir . '/lib/public/Support/CrashReport/IMessageReporter.php', 'OCP\\Support\\CrashReport\\IRegistry' => $baseDir . '/lib/public/Support/CrashReport/IRegistry.php', @@ -1584,6 +1587,8 @@ 'OC\\Share\\Constants' => $baseDir . '/lib/private/Share/Constants.php', 'OC\\Share\\Helper' => $baseDir . '/lib/private/Share/Helper.php', 'OC\\Share\\Share' => $baseDir . '/lib/private/Share/Share.php', + 'OC\\SpeechToText\\SpeechToTextManager' => $baseDir . '/lib/private/SpeechToText/SpeechToTextManager.php', + 'OC\\SpeechToText\\TranscriptionJob' => $baseDir . '/lib/private/SpeechToText/TranscriptionJob.php', 'OC\\StreamImage' => $baseDir . '/lib/private/StreamImage.php', 'OC\\Streamer' => $baseDir . '/lib/private/Streamer.php', 'OC\\SubAdmin' => $baseDir . '/lib/private/SubAdmin.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index bfc0f2c88ac0d..6814cc425d45e 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -606,6 +606,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Share_Backend' => __DIR__ . '/../../..' . '/lib/public/Share_Backend.php', 'OCP\\Share_Backend_Collection' => __DIR__ . '/../../..' . '/lib/public/Share_Backend_Collection.php', 'OCP\\Share_Backend_File_Dependent' => __DIR__ . '/../../..' . '/lib/public/Share_Backend_File_Dependent.php', + 'OCP\\SpeechToText\\Events\\TranscriptionFinishedEvent' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php', + 'OCP\\SpeechToText\\ISpeechToTextManager' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/ISpeechToTextManager.php', + 'OCP\\SpeechToText\\ISpeechToTextProvider' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/ISpeechToTextProvider.php', 'OCP\\Support\\CrashReport\\ICollectBreadcrumbs' => __DIR__ . '/../../..' . '/lib/public/Support/CrashReport/ICollectBreadcrumbs.php', 'OCP\\Support\\CrashReport\\IMessageReporter' => __DIR__ . '/../../..' . '/lib/public/Support/CrashReport/IMessageReporter.php', 'OCP\\Support\\CrashReport\\IRegistry' => __DIR__ . '/../../..' . '/lib/public/Support/CrashReport/IRegistry.php', @@ -1617,6 +1620,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Share\\Constants' => __DIR__ . '/../../..' . '/lib/private/Share/Constants.php', 'OC\\Share\\Helper' => __DIR__ . '/../../..' . '/lib/private/Share/Helper.php', 'OC\\Share\\Share' => __DIR__ . '/../../..' . '/lib/private/Share/Share.php', + 'OC\\SpeechToText\\SpeechToTextManager' => __DIR__ . '/../../..' . '/lib/private/SpeechToText/SpeechToTextManager.php', + 'OC\\SpeechToText\\TranscriptionJob' => __DIR__ . '/../../..' . '/lib/private/SpeechToText/TranscriptionJob.php', 'OC\\StreamImage' => __DIR__ . '/../../..' . '/lib/private/StreamImage.php', 'OC\\Streamer' => __DIR__ . '/../../..' . '/lib/private/Streamer.php', 'OC\\SubAdmin' => __DIR__ . '/../../..' . '/lib/private/SubAdmin.php', From a9b5d1f9da92c105f8998455ec1a4ab304ae60ef Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Tue, 11 Apr 2023 15:04:30 +0200 Subject: [PATCH 03/26] chore(coding style): Run cs:fix Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/SpeechToTextManager.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index 2b21627034000..2e1733d0e3673 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -49,7 +49,8 @@ public function __construct( private Coordinator $coordinator, private LoggerInterface $logger, private IJobList $jobList, - ) { } + ) { + } public function getProviders(): array { $context = $this->coordinator->getRegistrationContext(); From 1833d932ef39bb77f59cee17f194fef7d768a67c Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Tue, 11 Apr 2023 15:21:08 +0200 Subject: [PATCH 04/26] chore(coding style): Run cs:fix Signed-off-by: Marcel Klehr --- lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php b/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php index 376859afd1cf7..245ccd413e929 100644 --- a/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php @@ -31,7 +31,6 @@ * @since 27.0.0 */ class TranscriptionFinishedEvent extends Event { - /** * @since 27.0.0 */ From ef7ce88cee47ec7d05c43e55c166f8488667dc5d Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Wed, 12 Apr 2023 16:52:11 +0200 Subject: [PATCH 05/26] ISpeechToTextProvider#transcribeFile: Pass \OCP\Files\File instead of path Signed-off-by: Marcel Klehr --- .../SpeechToText/SpeechToTextManager.php | 24 +++++++++++++++---- .../SpeechToText/ISpeechToTextManager.php | 2 +- .../SpeechToText/ISpeechToTextProvider.php | 3 ++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index 2e1733d0e3673..7b50fa385c98f 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -31,6 +31,9 @@ use InvalidArgumentException; use OC\AppFramework\Bootstrap\Coordinator; use OCP\BackgroundJob\IJobList; +use OCP\Files\File; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; use OCP\IServerContainer; use OCP\PreConditionNotMetException; use OCP\SpeechToText\ISpeechToTextManager; @@ -49,6 +52,7 @@ public function __construct( private Coordinator $coordinator, private LoggerInterface $logger, private IJobList $jobList, + private IRootFolder $rootFolder, ) { } @@ -90,6 +94,14 @@ public function scheduleFileTranscription(string $path, array $context): void { if (!$this->hasProviders()) { throw new PreConditionNotMetException('No SpeechToText providers have been registered'); } + try { + $node = $this->rootFolder->get($path); + } catch (NotFoundException $e) { + throw new InvalidArgumentException('File does not exist: ' . $path); + } + if (!($node instanceof File)) { + throw new InvalidArgumentException('Path does not resolve to a file'); + } $this->jobList->add(TranscriptionJob::class, [ 'path' => $path, 'context' => $context]); } @@ -99,10 +111,14 @@ public function transcribeFile(string $path): string { throw new PreConditionNotMetException('No SpeechToText providers have been registered'); } - if (!file_exists($path)) { - throw new InvalidArgumentException('File does not exist'); + try { + $node = $this->rootFolder->get($path); + if (!($node instanceof File)) { + throw new InvalidArgumentException('Path does not resolve to a file'); + } + return $provider->transcribeFile($node); + } catch (NotFoundException $e) { + throw new InvalidArgumentException('File does not exist: ' . $path); } - - return $provider->transcribeFile($path); } } diff --git a/lib/public/SpeechToText/ISpeechToTextManager.php b/lib/public/SpeechToText/ISpeechToTextManager.php index 297be43e6db9d..7bcd60bce8c0e 100644 --- a/lib/public/SpeechToText/ISpeechToTextManager.php +++ b/lib/public/SpeechToText/ISpeechToTextManager.php @@ -43,7 +43,7 @@ public function hasProviders(): bool; * Will schedule a transcription process in the background. The result will become available * with the \OCP\SpeechToText\Events\TranscriptionFinishedEvent * You should add context information to the context array to re-identify the transcription result as - * as belonging to your transcription request. + * belonging to your transcription request. * * @since 27.0.0 * @throws PreConditionNotMetException If no provider was registered but this method was still called diff --git a/lib/public/SpeechToText/ISpeechToTextProvider.php b/lib/public/SpeechToText/ISpeechToTextProvider.php index 3d739408bf5d4..c23b75c115ea4 100644 --- a/lib/public/SpeechToText/ISpeechToTextProvider.php +++ b/lib/public/SpeechToText/ISpeechToTextProvider.php @@ -26,6 +26,7 @@ namespace OCP\SpeechToText; +use OCP\Files\File; use RuntimeException; /** @@ -41,5 +42,5 @@ public function getName(): string; * @since 27.0.0 * @throws RuntimeException If the text could not be transcribed */ - public function transcribeFile(string $path): string; + public function transcribeFile(File $file): string; } From 176f1af26a6bf7c62cadd04448b73839296653c0 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 13 Apr 2023 11:57:23 +0200 Subject: [PATCH 06/26] ISpeechToTextManager: Take File as input, drop $context Signed-off-by: Marcel Klehr --- .../SpeechToText/SpeechToTextManager.php | 27 +++++++------------ lib/private/SpeechToText/TranscriptionJob.php | 5 +++- .../SpeechToText/ISpeechToTextManager.php | 7 +++-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index 7b50fa385c98f..a734f6bb37979 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -32,6 +32,7 @@ use OC\AppFramework\Bootstrap\Coordinator; use OCP\BackgroundJob\IJobList; use OCP\Files\File; +use OCP\Files\InvalidPathException; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\IServerContainer; @@ -52,7 +53,6 @@ public function __construct( private Coordinator $coordinator, private LoggerInterface $logger, private IJobList $jobList, - private IRootFolder $rootFolder, ) { } @@ -90,35 +90,28 @@ public function hasProviders(): bool { return !empty($context->getTranslationProviders()); } - public function scheduleFileTranscription(string $path, array $context): void { + public function scheduleFileTranscription(File $file): void { if (!$this->hasProviders()) { throw new PreConditionNotMetException('No SpeechToText providers have been registered'); } try { - $node = $this->rootFolder->get($path); - } catch (NotFoundException $e) { - throw new InvalidArgumentException('File does not exist: ' . $path); + $this->jobList->add(TranscriptionJob::class, ['fileId' => $file->getId()]); + }catch(NotFoundException|InvalidPathException $e) { + throw new InvalidArgumentException('Invalid file provided for file transcription: ' . $e->getMessage()); } - if (!($node instanceof File)) { - throw new InvalidArgumentException('Path does not resolve to a file'); - } - $this->jobList->add(TranscriptionJob::class, [ 'path' => $path, 'context' => $context]); } - public function transcribeFile(string $path): string { + public function transcribeFile(File $file): string { $provider = current($this->getProviders()); if (!$provider) { throw new PreConditionNotMetException('No SpeechToText providers have been registered'); } try { - $node = $this->rootFolder->get($path); - if (!($node instanceof File)) { - throw new InvalidArgumentException('Path does not resolve to a file'); - } - return $provider->transcribeFile($node); - } catch (NotFoundException $e) { - throw new InvalidArgumentException('File does not exist: ' . $path); + return $provider->transcribeFile($file); + }catch (\Throwable $e) { + $this->logger->info('SpeechToText transcription failed', ['exception' => $e]); + throw new \RuntimeException('SpeechToText transcription failed: ' . $e->getMessage()); } } } diff --git a/lib/private/SpeechToText/TranscriptionJob.php b/lib/private/SpeechToText/TranscriptionJob.php index d2cff4680244a..296a713593b43 100644 --- a/lib/private/SpeechToText/TranscriptionJob.php +++ b/lib/private/SpeechToText/TranscriptionJob.php @@ -5,6 +5,7 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\QueuedJob; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\IRootFolder; use OCP\PreConditionNotMetException; use OCP\SpeechToText\Events\TranscriptionFinishedEvent; use OCP\SpeechToText\ISpeechToTextManager; @@ -14,6 +15,7 @@ public function __construct( ITimeFactory $timeFactory, private ISpeechToTextManager $speechToTextManager, private IEventDispatcher $eventDispatcher, + private IRootFolder $rootFolder, ) { parent::__construct($timeFactory); } @@ -24,7 +26,8 @@ public function __construct( */ protected function run($argument) { try { - $result = $this->speechToTextManager->transcribeFile($argument['path']); + $file = $this->rootFolder->getById($argument['fileId']); + $result = $this->speechToTextManager->transcribeFile($file); $this->eventDispatcher->dispatchTyped( new TranscriptionFinishedEvent( true, diff --git a/lib/public/SpeechToText/ISpeechToTextManager.php b/lib/public/SpeechToText/ISpeechToTextManager.php index 7bcd60bce8c0e..430a6cbc4507c 100644 --- a/lib/public/SpeechToText/ISpeechToTextManager.php +++ b/lib/public/SpeechToText/ISpeechToTextManager.php @@ -27,6 +27,7 @@ namespace OCP\SpeechToText; use InvalidArgumentException; +use OCP\Files\File; use OCP\PreConditionNotMetException; use RuntimeException; @@ -50,13 +51,15 @@ public function hasProviders(): bool; * @throws InvalidArgumentException If the file could not be found or is not of a supported type * @throws RuntimeException If the transcription failed for other reasons */ - public function scheduleFileTranscription(string $path, array $context): void; + public function scheduleFileTranscription(File $file): void; /** * @since 27.0.0 + * @param File $file The media file to transcribe + * @returns string The transcription of the the passed media file * @throws PreConditionNotMetException If no provider was registered but this method was still called * @throws InvalidArgumentException If the file could not be found or is not of a supported type * @throws RuntimeException If the transcription failed for other reasons */ - public function transcribeFile(string $path) : string; + public function transcribeFile(File $file) : string; } From a8d3fff648c4c6f5be3e37c09f9168e5b7c0e8f8 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 13 Apr 2023 12:12:07 +0200 Subject: [PATCH 07/26] Split TranscriptionFinishedEvent into Successful and Failed events Signed-off-by: Marcel Klehr --- .../SpeechToText/SpeechToTextManager.php | 5 ++- lib/private/SpeechToText/TranscriptionJob.php | 28 ++++++++++------ ...ent.php => AbstractTranscriptionEvent.php} | 32 +++---------------- .../Events/TranscriptionFailedEvent.php | 24 ++++++++++++++ .../Events/TranscriptionSuccessfulEvent.php | 26 +++++++++++++++ 5 files changed, 74 insertions(+), 41 deletions(-) rename lib/public/SpeechToText/Events/{TranscriptionFinishedEvent.php => AbstractTranscriptionEvent.php} (66%) create mode 100644 lib/public/SpeechToText/Events/TranscriptionFailedEvent.php create mode 100644 lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index a734f6bb37979..c4f89ed43c7d7 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -33,7 +33,6 @@ use OCP\BackgroundJob\IJobList; use OCP\Files\File; use OCP\Files\InvalidPathException; -use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\IServerContainer; use OCP\PreConditionNotMetException; @@ -96,7 +95,7 @@ public function scheduleFileTranscription(File $file): void { } try { $this->jobList->add(TranscriptionJob::class, ['fileId' => $file->getId()]); - }catch(NotFoundException|InvalidPathException $e) { + } catch (NotFoundException|InvalidPathException $e) { throw new InvalidArgumentException('Invalid file provided for file transcription: ' . $e->getMessage()); } } @@ -109,7 +108,7 @@ public function transcribeFile(File $file): string { try { return $provider->transcribeFile($file); - }catch (\Throwable $e) { + } catch (\Throwable $e) { $this->logger->info('SpeechToText transcription failed', ['exception' => $e]); throw new \RuntimeException('SpeechToText transcription failed: ' . $e->getMessage()); } diff --git a/lib/private/SpeechToText/TranscriptionJob.php b/lib/private/SpeechToText/TranscriptionJob.php index 296a713593b43..775a2a7fadcf1 100644 --- a/lib/private/SpeechToText/TranscriptionJob.php +++ b/lib/private/SpeechToText/TranscriptionJob.php @@ -5,9 +5,11 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\QueuedJob; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\File; use OCP\Files\IRootFolder; use OCP\PreConditionNotMetException; -use OCP\SpeechToText\Events\TranscriptionFinishedEvent; +use OCP\SpeechToText\Events\TranscriptionFailedEvent; +use OCP\SpeechToText\Events\TranscriptionSuccessfulEvent; use OCP\SpeechToText\ISpeechToTextManager; class TranscriptionJob extends QueuedJob { @@ -25,24 +27,30 @@ public function __construct( * @inheritDoc */ protected function run($argument) { + $fileId = $argument['fileId']; try { - $file = $this->rootFolder->getById($argument['fileId']); + $file = current($this->rootFolder->getById($fileId)); + if (!($file instanceof File)) { + $this->eventDispatcher->dispatchTyped( + new TranscriptionFailedEvent( + $fileId, + 'File not found', + ) + ); + return; + } $result = $this->speechToTextManager->transcribeFile($file); $this->eventDispatcher->dispatchTyped( - new TranscriptionFinishedEvent( - true, + new TranscriptionSuccessfulEvent( + $fileId, $result, - '', - $argument['context'] ) ); } catch (PreConditionNotMetException|\RuntimeException|\InvalidArgumentException $e) { $this->eventDispatcher->dispatchTyped( - new TranscriptionFinishedEvent( - false, - '', + new TranscriptionFailedEvent( + $fileId, $e->getMessage(), - $argument['context'] ) ); } diff --git a/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php b/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php similarity index 66% rename from lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php rename to lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php index 245ccd413e929..5b00315f74c5a 100644 --- a/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php +++ b/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php @@ -30,15 +30,12 @@ /** * @since 27.0.0 */ -class TranscriptionFinishedEvent extends Event { +abstract class AbstractTranscriptionEvent extends Event { /** * @since 27.0.0 */ public function __construct( - private bool $successful, - private string $transcription, - private string $errorMessage, - private array $context + private int $fileIdId ) { parent::__construct(); } @@ -46,28 +43,7 @@ public function __construct( /** * @since 27.0.0 */ - public function getContext(): array { - return $this->context; - } - - /** - * @since 27.0.0 - */ - public function isSuccessful(): bool { - return $this->successful; - } - - /** - * @since 27.0.0 - */ - public function getErrorMessage(): string { - return $this->errorMessage; - } - - /** - * @since 27.0.0 - */ - public function getTranscription(): string { - return $this->transcription; + public function getFileId(): int { + return $this->fileIdId; } } diff --git a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php new file mode 100644 index 0000000000000..3a490995c101e --- /dev/null +++ b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php @@ -0,0 +1,24 @@ +errorMessage; + } +} diff --git a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php new file mode 100644 index 0000000000000..63644b98f6dfa --- /dev/null +++ b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php @@ -0,0 +1,26 @@ +transcript; + } +} From 865ebfaf72fa186a18d822e0332a5c5201b9b992 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 13 Apr 2023 12:15:18 +0200 Subject: [PATCH 08/26] Add missing strict_types + author + copyright Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/TranscriptionJob.php | 24 +++++++++++++++++++ .../Events/TranscriptionFailedEvent.php | 24 +++++++++++++++++++ .../Events/TranscriptionSuccessfulEvent.php | 24 +++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/lib/private/SpeechToText/TranscriptionJob.php b/lib/private/SpeechToText/TranscriptionJob.php index 775a2a7fadcf1..d8abf9a9c34d7 100644 --- a/lib/private/SpeechToText/TranscriptionJob.php +++ b/lib/private/SpeechToText/TranscriptionJob.php @@ -1,5 +1,29 @@ + * + * @author Marcel Klehr + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + + namespace OC\SpeechToText; use OCP\AppFramework\Utility\ITimeFactory; diff --git a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php index 3a490995c101e..b7e44d91c69b1 100644 --- a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php @@ -1,5 +1,29 @@ + * + * @author Marcel Klehr + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + + namespace OCP\SpeechToText\Events; class TranscriptionFailedEvent extends AbstractTranscriptionEvent { diff --git a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php index 63644b98f6dfa..816dabafbb447 100644 --- a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php @@ -1,5 +1,29 @@ + * + * @author Marcel Klehr + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + + namespace OCP\SpeechToText\Events; use OCP\Files\File; From ad66180c3404045e4ae15e9b3a895b50a69efd75 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 13 Apr 2023 15:17:17 +0200 Subject: [PATCH 09/26] Update lib/private/SpeechToText/SpeechToTextManager.php Co-authored-by: Joas Schilling <213943+nickvergessen@users.noreply.github.com> Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/SpeechToTextManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index c4f89ed43c7d7..0c41c3cb60099 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -86,7 +86,7 @@ public function hasProviders(): bool { if ($context === null) { return false; } - return !empty($context->getTranslationProviders()); + return !empty($context->getSpeechToTextProviders()); } public function scheduleFileTranscription(File $file): void { From 71523b9816b1162f30ca8d682b8d410edc6d9cfc Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Mon, 17 Apr 2023 14:45:18 +0200 Subject: [PATCH 10/26] AbstractTranscriptionEvent: Add File param Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/TranscriptionJob.php | 8 ++++++++ .../Events/AbstractTranscriptionEvent.php | 11 ++++++++++- .../SpeechToText/Events/TranscriptionFailedEvent.php | 5 ++++- .../Events/TranscriptionSuccessfulEvent.php | 3 ++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/private/SpeechToText/TranscriptionJob.php b/lib/private/SpeechToText/TranscriptionJob.php index d8abf9a9c34d7..fd175e774a545 100644 --- a/lib/private/SpeechToText/TranscriptionJob.php +++ b/lib/private/SpeechToText/TranscriptionJob.php @@ -35,6 +35,7 @@ use OCP\SpeechToText\Events\TranscriptionFailedEvent; use OCP\SpeechToText\Events\TranscriptionSuccessfulEvent; use OCP\SpeechToText\ISpeechToTextManager; +use Psr\Log\LoggerInterface; class TranscriptionJob extends QueuedJob { public function __construct( @@ -42,6 +43,7 @@ public function __construct( private ISpeechToTextManager $speechToTextManager, private IEventDispatcher $eventDispatcher, private IRootFolder $rootFolder, + private LoggerInterface $logger, ) { parent::__construct($timeFactory); } @@ -52,12 +54,15 @@ public function __construct( */ protected function run($argument) { $fileId = $argument['fileId']; + $file = null; try { $file = current($this->rootFolder->getById($fileId)); if (!($file instanceof File)) { + $this->logger->warning('Transcription of file ' . $fileId . ' failed. The file could not be found'); $this->eventDispatcher->dispatchTyped( new TranscriptionFailedEvent( $fileId, + null, 'File not found', ) ); @@ -67,13 +72,16 @@ protected function run($argument) { $this->eventDispatcher->dispatchTyped( new TranscriptionSuccessfulEvent( $fileId, + $file, $result, ) ); } catch (PreConditionNotMetException|\RuntimeException|\InvalidArgumentException $e) { + $this->logger->warning('Transcription of file ' . $fileId . ' failed', ['exception' => $e]); $this->eventDispatcher->dispatchTyped( new TranscriptionFailedEvent( $fileId, + $file, $e->getMessage(), ) ); diff --git a/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php b/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php index 5b00315f74c5a..0f906a7604b07 100644 --- a/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php +++ b/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php @@ -26,6 +26,7 @@ namespace OCP\SpeechToText\Events; use OCP\EventDispatcher\Event; +use OCP\Files\File; /** * @since 27.0.0 @@ -35,7 +36,8 @@ abstract class AbstractTranscriptionEvent extends Event { * @since 27.0.0 */ public function __construct( - private int $fileIdId + private int $fileIdId, + private ?File $file, ) { parent::__construct(); } @@ -46,4 +48,11 @@ public function __construct( public function getFileId(): int { return $this->fileIdId; } + + /** + * @since 27.0.0 + */ + public function getFile(): ?File { + return $this->file; + } } diff --git a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php index b7e44d91c69b1..02777b7ebc098 100644 --- a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php @@ -26,6 +26,8 @@ namespace OCP\SpeechToText\Events; +use OCP\Files\File; + class TranscriptionFailedEvent extends AbstractTranscriptionEvent { /** @@ -33,9 +35,10 @@ class TranscriptionFailedEvent extends AbstractTranscriptionEvent { */ public function __construct( int $fileId, + ?File $file, private string $errorMessage ) { - parent::__construct($fileId); + parent::__construct($fileId, $file); } /** diff --git a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php index 816dabafbb447..b37a07e3a2217 100644 --- a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php @@ -35,9 +35,10 @@ class TranscriptionSuccessfulEvent extends AbstractTranscriptionEvent { */ public function __construct( int $fileId, + ?File $file, private string $transcript ) { - parent::__construct($fileId); + parent::__construct($fileId, $file); } /** From ad1a0d88ef4a086eb20a743d04f322b9dd888636 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Mon, 17 Apr 2023 14:47:21 +0200 Subject: [PATCH 11/26] Transcription*Event: Add doc block Signed-off-by: Marcel Klehr --- lib/public/SpeechToText/Events/TranscriptionFailedEvent.php | 4 ++++ .../SpeechToText/Events/TranscriptionSuccessfulEvent.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php index 02777b7ebc098..e9a096cfb8308 100644 --- a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php @@ -28,6 +28,10 @@ use OCP\Files\File; +/** + * This Event is emitted if a transcription of a media file using a Speech-To-Text provider failed + * @since 27.0.0 + */ class TranscriptionFailedEvent extends AbstractTranscriptionEvent { /** diff --git a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php index b37a07e3a2217..66e24b0566d4d 100644 --- a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php @@ -28,6 +28,10 @@ use OCP\Files\File; +/** + * This Event is emitted when a transcription of a media file happened successfully + * @since 27.0.0 + */ class TranscriptionSuccessfulEvent extends AbstractTranscriptionEvent { /** From 3779cc3d88ffa65ce312588cccc602a5fbe341f4 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Mon, 17 Apr 2023 14:49:20 +0200 Subject: [PATCH 12/26] SpeechToTextManager: Deduplicate transcription jobs Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/SpeechToTextManager.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index 0c41c3cb60099..93a74711e3202 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -94,6 +94,9 @@ public function scheduleFileTranscription(File $file): void { throw new PreConditionNotMetException('No SpeechToText providers have been registered'); } try { + if ($this->jobList->has(TranscriptionJob::class, ['fileId' => $file->getId()])) { + return; + } $this->jobList->add(TranscriptionJob::class, ['fileId' => $file->getId()]); } catch (NotFoundException|InvalidPathException $e) { throw new InvalidArgumentException('Invalid file provided for file transcription: ' . $e->getMessage()); From 6e9f260348b70cede507764db6d46ba72898973f Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Mon, 17 Apr 2023 15:49:50 +0200 Subject: [PATCH 13/26] Update lib/private/SpeechToText/SpeechToTextManager.php Co-authored-by: Joas Schilling <213943+nickvergessen@users.noreply.github.com> Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/SpeechToTextManager.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index 93a74711e3202..0c41c3cb60099 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -94,9 +94,6 @@ public function scheduleFileTranscription(File $file): void { throw new PreConditionNotMetException('No SpeechToText providers have been registered'); } try { - if ($this->jobList->has(TranscriptionJob::class, ['fileId' => $file->getId()])) { - return; - } $this->jobList->add(TranscriptionJob::class, ['fileId' => $file->getId()]); } catch (NotFoundException|InvalidPathException $e) { throw new InvalidArgumentException('Invalid file provided for file transcription: ' . $e->getMessage()); From aac6a186c105f4fcb492078511d85d6588aa692f Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Mon, 17 Apr 2023 16:43:19 +0200 Subject: [PATCH 14/26] Update lib/public/SpeechToText/ISpeechToTextManager.php Co-authored-by: Joas Schilling <213943+nickvergessen@users.noreply.github.com> Signed-off-by: Marcel Klehr --- lib/public/SpeechToText/ISpeechToTextManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/public/SpeechToText/ISpeechToTextManager.php b/lib/public/SpeechToText/ISpeechToTextManager.php index 430a6cbc4507c..062f500b59c08 100644 --- a/lib/public/SpeechToText/ISpeechToTextManager.php +++ b/lib/public/SpeechToText/ISpeechToTextManager.php @@ -61,5 +61,5 @@ public function scheduleFileTranscription(File $file): void; * @throws InvalidArgumentException If the file could not be found or is not of a supported type * @throws RuntimeException If the transcription failed for other reasons */ - public function transcribeFile(File $file) : string; + public function transcribeFile(File $file): string; } From b0826572521c21ebf17b00422cca5dd65f7a69cd Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Mon, 17 Apr 2023 16:43:28 +0200 Subject: [PATCH 15/26] Update lib/public/SpeechToText/ISpeechToTextManager.php Co-authored-by: Joas Schilling <213943+nickvergessen@users.noreply.github.com> Signed-off-by: Marcel Klehr --- lib/public/SpeechToText/ISpeechToTextManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/public/SpeechToText/ISpeechToTextManager.php b/lib/public/SpeechToText/ISpeechToTextManager.php index 062f500b59c08..db1502a4e712f 100644 --- a/lib/public/SpeechToText/ISpeechToTextManager.php +++ b/lib/public/SpeechToText/ISpeechToTextManager.php @@ -56,7 +56,7 @@ public function scheduleFileTranscription(File $file): void; /** * @since 27.0.0 * @param File $file The media file to transcribe - * @returns string The transcription of the the passed media file + * @returns string The transcription of the passed media file * @throws PreConditionNotMetException If no provider was registered but this method was still called * @throws InvalidArgumentException If the file could not be found or is not of a supported type * @throws RuntimeException If the transcription failed for other reasons From 47cff5d651653da5c7cde1ea2eccaccca2f2add1 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Mon, 17 Apr 2023 16:43:43 +0200 Subject: [PATCH 16/26] Update lib/public/SpeechToText/ISpeechToTextManager.php Co-authored-by: Joas Schilling <213943+nickvergessen@users.noreply.github.com> Signed-off-by: Marcel Klehr --- lib/public/SpeechToText/ISpeechToTextManager.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/public/SpeechToText/ISpeechToTextManager.php b/lib/public/SpeechToText/ISpeechToTextManager.php index db1502a4e712f..9cf970d88cab2 100644 --- a/lib/public/SpeechToText/ISpeechToTextManager.php +++ b/lib/public/SpeechToText/ISpeechToTextManager.php @@ -49,7 +49,6 @@ public function hasProviders(): bool; * @since 27.0.0 * @throws PreConditionNotMetException If no provider was registered but this method was still called * @throws InvalidArgumentException If the file could not be found or is not of a supported type - * @throws RuntimeException If the transcription failed for other reasons */ public function scheduleFileTranscription(File $file): void; From 3f57725a7c68bd90b281a3f97639270cad25b072 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Mon, 17 Apr 2023 16:58:14 +0200 Subject: [PATCH 17/26] SpeechToTextManager#transcribeFile: Try next provider if one fails Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/SpeechToTextManager.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index 0c41c3cb60099..146d7f8f8b19c 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -101,16 +101,18 @@ public function scheduleFileTranscription(File $file): void { } public function transcribeFile(File $file): string { - $provider = current($this->getProviders()); - if (!$provider) { + if (!$this->hasProviders()) { throw new PreConditionNotMetException('No SpeechToText providers have been registered'); } - try { - return $provider->transcribeFile($file); - } catch (\Throwable $e) { - $this->logger->info('SpeechToText transcription failed', ['exception' => $e]); - throw new \RuntimeException('SpeechToText transcription failed: ' . $e->getMessage()); + foreach ($this->getProviders() as $provider) { + try { + return $provider->transcribeFile($file); + } catch (\Throwable $e) { + $this->logger->info('SpeechToText transcription using provider ' . $provider->getName() . ' failed', ['exception' => $e]); + } } + + throw new RuntimeException('Could not transcribe file'); } } From bef4cf0ad18c1ce4f31e6763835c6fe3d81dbf8a Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 18 Apr 2023 10:01:00 +0200 Subject: [PATCH 18/26] Fix missing import Signed-off-by: Joas Schilling --- lib/private/SpeechToText/SpeechToTextManager.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index 146d7f8f8b19c..f147b245ea8ff 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -41,6 +41,7 @@ use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; use Psr\Log\LoggerInterface; +use RuntimeException; use Throwable; class SpeechToTextManager implements ISpeechToTextManager { @@ -73,7 +74,7 @@ public function getProviders(): array { $this->providers[$class] = $this->serverContainer->get($class); } catch (NotFoundExceptionInterface|ContainerExceptionInterface|Throwable $e) { $this->logger->error('Failed to load SpeechToText provider ' . $class, [ - 'exception' => $e + 'exception' => $e, ]); } } From 9649f91892beaf663c5615a2cffdc6a8d5a5a1a7 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Tue, 18 Apr 2023 15:24:14 +0200 Subject: [PATCH 19/26] Update lib/private/SpeechToText/SpeechToTextManager.php Co-authored-by: Julien Veyssier Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/SpeechToTextManager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index f147b245ea8ff..9ab53a8013d31 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -68,8 +68,8 @@ public function getProviders(): array { $this->providers = []; - foreach ($context->getSpeechToTextProviders() as $providerRegistration) { - $class = $providerRegistration->getService(); + foreach ($context->getSpeechToTextProviders() as $providerServiceRegistration) { + $class = $providerServiceRegistration->getService(); try { $this->providers[$class] = $this->serverContainer->get($class); } catch (NotFoundExceptionInterface|ContainerExceptionInterface|Throwable $e) { From ce651e53b9f5e8942b73505eba2f0f3b55dade6d Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Tue, 18 Apr 2023 15:47:45 +0200 Subject: [PATCH 20/26] Run cs:fix Signed-off-by: Marcel Klehr --- lib/public/SpeechToText/Events/TranscriptionFailedEvent.php | 1 - lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php index e9a096cfb8308..c29f276596ec6 100644 --- a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php @@ -33,7 +33,6 @@ * @since 27.0.0 */ class TranscriptionFailedEvent extends AbstractTranscriptionEvent { - /** * @since 27.0.0 */ diff --git a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php index 66e24b0566d4d..599e98a47bece 100644 --- a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php @@ -33,7 +33,6 @@ * @since 27.0.0 */ class TranscriptionSuccessfulEvent extends AbstractTranscriptionEvent { - /** * @since 27.0.0 */ From eb996cbbb0149b82f7fefc5430b2f3629d7930ba Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Tue, 18 Apr 2023 16:23:45 +0200 Subject: [PATCH 21/26] TranscriptionJob: Ensure filesystem is setup before trying to retrieve file Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/TranscriptionJob.php | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/lib/private/SpeechToText/TranscriptionJob.php b/lib/private/SpeechToText/TranscriptionJob.php index fd175e774a545..223697d4bb5df 100644 --- a/lib/private/SpeechToText/TranscriptionJob.php +++ b/lib/private/SpeechToText/TranscriptionJob.php @@ -29,8 +29,13 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\QueuedJob; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Config\ICachedMountFileInfo; +use OCP\Files\Config\IUserMountCache; use OCP\Files\File; use OCP\Files\IRootFolder; +use OCP\Files\Node; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; use OCP\PreConditionNotMetException; use OCP\SpeechToText\Events\TranscriptionFailedEvent; use OCP\SpeechToText\Events\TranscriptionSuccessfulEvent; @@ -44,6 +49,7 @@ public function __construct( private IEventDispatcher $eventDispatcher, private IRootFolder $rootFolder, private LoggerInterface $logger, + private IUserMountCache $userMountCache, ) { parent::__construct($timeFactory); } @@ -56,7 +62,7 @@ protected function run($argument) { $fileId = $argument['fileId']; $file = null; try { - $file = current($this->rootFolder->getById($fileId)); + $file = $this->getFileFromId($fileId); if (!($file instanceof File)) { $this->logger->warning('Transcription of file ' . $fileId . ' failed. The file could not be found'); $this->eventDispatcher->dispatchTyped( @@ -76,7 +82,7 @@ protected function run($argument) { $result, ) ); - } catch (PreConditionNotMetException|\RuntimeException|\InvalidArgumentException $e) { + } catch (PreConditionNotMetException|\RuntimeException|\InvalidArgumentException|NotFoundException $e) { $this->logger->warning('Transcription of file ' . $fileId . ' failed', ['exception' => $e]); $this->eventDispatcher->dispatchTyped( new TranscriptionFailedEvent( @@ -87,4 +93,50 @@ protected function run($argument) { ); } } + + /** + * @throws NotFoundException + */ + private function getFileFromId(int $fileId): Node { + $mountPoints = $this->userMountCache->getMountsForFileId($fileId); + if (empty($mountPoints)) { + throw new NotFoundException("No mount points found for file $fileId"); + } + + foreach ($mountPoints as $mountPoint) { + try { + return $this->getCreatableNodeFromMountPoint($mountPoint, $fileId); + } catch (NotPermittedException $e) { + // Check the next mount point + $this->logger->debug('Mount point ' . ($mountPoint->getMountId() ?? 'null') . ' has no delete permissions for file ' . $fileId); + } catch (NotFoundException $e) { + // Already logged explicitly inside + } + } + + throw new NotFoundException("No mount point with delete permissions found for file $fileId"); + } + + /** + * @throws NotFoundException + */ + protected function getCreatableNodeFromMountPoint(ICachedMountFileInfo $mountPoint, int $fileId): Node { + try { + $userId = $mountPoint->getUser()->getUID(); + $userFolder = $this->rootFolder->getUserFolder($userId); + \OC_Util::setupFS($userId); + } catch (\Exception $e) { + $this->logger->debug($e->getMessage(), [ + 'exception' => $e, + ]); + throw new NotFoundException('Could not get user', 0, $e); + } + + $nodes = $userFolder->getById($fileId); + if (empty($nodes)) { + throw new NotFoundException('No node for file ' . $fileId . ' and user ' . $userId); + } + + return array_shift($nodes); + } } From a8b27c91265a883aaa1563c33edf8d6917af63b1 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Wed, 19 Apr 2023 11:26:04 +0200 Subject: [PATCH 22/26] TranscriptionJob: Add owner argument to simplify filesystem setup Signed-off-by: Marcel Klehr --- .../SpeechToText/SpeechToTextManager.php | 2 +- lib/private/SpeechToText/TranscriptionJob.php | 58 ++----------------- 2 files changed, 7 insertions(+), 53 deletions(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index 9ab53a8013d31..d6f7e74c95e77 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -95,7 +95,7 @@ public function scheduleFileTranscription(File $file): void { throw new PreConditionNotMetException('No SpeechToText providers have been registered'); } try { - $this->jobList->add(TranscriptionJob::class, ['fileId' => $file->getId()]); + $this->jobList->add(TranscriptionJob::class, ['fileId' => $file->getId(), 'owner' => $file->getOwner()->getUID()]); } catch (NotFoundException|InvalidPathException $e) { throw new InvalidArgumentException('Invalid file provided for file transcription: ' . $e->getMessage()); } diff --git a/lib/private/SpeechToText/TranscriptionJob.php b/lib/private/SpeechToText/TranscriptionJob.php index 223697d4bb5df..c77ae23ac02f7 100644 --- a/lib/private/SpeechToText/TranscriptionJob.php +++ b/lib/private/SpeechToText/TranscriptionJob.php @@ -26,14 +26,12 @@ namespace OC\SpeechToText; +use OC\User\NoUserException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\QueuedJob; use OCP\EventDispatcher\IEventDispatcher; -use OCP\Files\Config\ICachedMountFileInfo; -use OCP\Files\Config\IUserMountCache; use OCP\Files\File; use OCP\Files\IRootFolder; -use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\PreConditionNotMetException; @@ -49,7 +47,6 @@ public function __construct( private IEventDispatcher $eventDispatcher, private IRootFolder $rootFolder, private LoggerInterface $logger, - private IUserMountCache $userMountCache, ) { parent::__construct($timeFactory); } @@ -60,9 +57,12 @@ public function __construct( */ protected function run($argument) { $fileId = $argument['fileId']; + $owner = $argument['owner']; $file = null; try { - $file = $this->getFileFromId($fileId); + \OC_Util::setupFS($owner); + $userFolder = $this->rootFolder->getUserFolder($owner); + $file = current($userFolder->getById($fileId)); if (!($file instanceof File)) { $this->logger->warning('Transcription of file ' . $fileId . ' failed. The file could not be found'); $this->eventDispatcher->dispatchTyped( @@ -82,7 +82,7 @@ protected function run($argument) { $result, ) ); - } catch (PreConditionNotMetException|\RuntimeException|\InvalidArgumentException|NotFoundException $e) { + } catch (PreConditionNotMetException|\RuntimeException|\InvalidArgumentException|NotFoundException|NotPermittedException|NoUserException $e) { $this->logger->warning('Transcription of file ' . $fileId . ' failed', ['exception' => $e]); $this->eventDispatcher->dispatchTyped( new TranscriptionFailedEvent( @@ -93,50 +93,4 @@ protected function run($argument) { ); } } - - /** - * @throws NotFoundException - */ - private function getFileFromId(int $fileId): Node { - $mountPoints = $this->userMountCache->getMountsForFileId($fileId); - if (empty($mountPoints)) { - throw new NotFoundException("No mount points found for file $fileId"); - } - - foreach ($mountPoints as $mountPoint) { - try { - return $this->getCreatableNodeFromMountPoint($mountPoint, $fileId); - } catch (NotPermittedException $e) { - // Check the next mount point - $this->logger->debug('Mount point ' . ($mountPoint->getMountId() ?? 'null') . ' has no delete permissions for file ' . $fileId); - } catch (NotFoundException $e) { - // Already logged explicitly inside - } - } - - throw new NotFoundException("No mount point with delete permissions found for file $fileId"); - } - - /** - * @throws NotFoundException - */ - protected function getCreatableNodeFromMountPoint(ICachedMountFileInfo $mountPoint, int $fileId): Node { - try { - $userId = $mountPoint->getUser()->getUID(); - $userFolder = $this->rootFolder->getUserFolder($userId); - \OC_Util::setupFS($userId); - } catch (\Exception $e) { - $this->logger->debug($e->getMessage(), [ - 'exception' => $e, - ]); - throw new NotFoundException('Could not get user', 0, $e); - } - - $nodes = $userFolder->getById($fileId); - if (empty($nodes)) { - throw new NotFoundException('No node for file ' . $fileId . ' and user ' . $userId); - } - - return array_shift($nodes); - } } From a2f5421fc3eb13ed28167e97483fa7eaa4e65841 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Wed, 19 Apr 2023 12:35:13 +0200 Subject: [PATCH 23/26] SpeechToTextManager#scheduleFileTranscription: Take context params and expose them on the Transcription*Events Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/SpeechToTextManager.php | 9 +++++++-- lib/private/SpeechToText/TranscriptionJob.php | 8 ++++++++ .../Events/AbstractTranscriptionEvent.php | 16 ++++++++++++++++ .../Events/TranscriptionFailedEvent.php | 6 ++++-- .../Events/TranscriptionSuccessfulEvent.php | 6 ++++-- lib/public/SpeechToText/ISpeechToTextManager.php | 5 ++++- 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index d6f7e74c95e77..95208e5b0cae8 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -90,12 +90,17 @@ public function hasProviders(): bool { return !empty($context->getSpeechToTextProviders()); } - public function scheduleFileTranscription(File $file): void { + public function scheduleFileTranscription(File $file, string $userId, string $appId): void { if (!$this->hasProviders()) { throw new PreConditionNotMetException('No SpeechToText providers have been registered'); } try { - $this->jobList->add(TranscriptionJob::class, ['fileId' => $file->getId(), 'owner' => $file->getOwner()->getUID()]); + $this->jobList->add(TranscriptionJob::class, [ + 'fileId' => $file->getId(), + 'owner' => $file->getOwner()->getUID(), + 'userId' => $userId, + 'appId' => $appId, + ]); } catch (NotFoundException|InvalidPathException $e) { throw new InvalidArgumentException('Invalid file provided for file transcription: ' . $e->getMessage()); } diff --git a/lib/private/SpeechToText/TranscriptionJob.php b/lib/private/SpeechToText/TranscriptionJob.php index c77ae23ac02f7..d5cc9ed7c38c4 100644 --- a/lib/private/SpeechToText/TranscriptionJob.php +++ b/lib/private/SpeechToText/TranscriptionJob.php @@ -58,6 +58,8 @@ public function __construct( protected function run($argument) { $fileId = $argument['fileId']; $owner = $argument['owner']; + $userId = $argument['userId']; + $appId = $argument['appId']; $file = null; try { \OC_Util::setupFS($owner); @@ -70,6 +72,8 @@ protected function run($argument) { $fileId, null, 'File not found', + $userId, + $appId, ) ); return; @@ -80,6 +84,8 @@ protected function run($argument) { $fileId, $file, $result, + $userId, + $appId, ) ); } catch (PreConditionNotMetException|\RuntimeException|\InvalidArgumentException|NotFoundException|NotPermittedException|NoUserException $e) { @@ -89,6 +95,8 @@ protected function run($argument) { $fileId, $file, $e->getMessage(), + $userId, + $appId, ) ); } diff --git a/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php b/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php index 0f906a7604b07..74164791b323d 100644 --- a/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php +++ b/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php @@ -38,6 +38,8 @@ abstract class AbstractTranscriptionEvent extends Event { public function __construct( private int $fileIdId, private ?File $file, + private string $userId, + private string $appId, ) { parent::__construct(); } @@ -55,4 +57,18 @@ public function getFileId(): int { public function getFile(): ?File { return $this->file; } + + /** + * @since 27.0.0 + */ + public function getUserId(): string { + return $this->userId; + } + + /** + * @since 27.0.0 + */ + public function getAppId(): string { + return $this->appId; + } } diff --git a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php index c29f276596ec6..0cdefdf5a4b00 100644 --- a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php @@ -39,9 +39,11 @@ class TranscriptionFailedEvent extends AbstractTranscriptionEvent { public function __construct( int $fileId, ?File $file, - private string $errorMessage + private string $errorMessage, + string $userId, + string $appId, ) { - parent::__construct($fileId, $file); + parent::__construct($fileId, $file, $userId, $appId); } /** diff --git a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php index 599e98a47bece..79f379fca4d25 100644 --- a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php @@ -39,9 +39,11 @@ class TranscriptionSuccessfulEvent extends AbstractTranscriptionEvent { public function __construct( int $fileId, ?File $file, - private string $transcript + private string $transcript, + string $userId, + string $appId, ) { - parent::__construct($fileId, $file); + parent::__construct($fileId, $file, $userId, $appId); } /** diff --git a/lib/public/SpeechToText/ISpeechToTextManager.php b/lib/public/SpeechToText/ISpeechToTextManager.php index 9cf970d88cab2..85ef299ae8e29 100644 --- a/lib/public/SpeechToText/ISpeechToTextManager.php +++ b/lib/public/SpeechToText/ISpeechToTextManager.php @@ -46,11 +46,14 @@ public function hasProviders(): bool; * You should add context information to the context array to re-identify the transcription result as * belonging to your transcription request. * + * @param File $file The media file to transcribe + * @param string $userId The user that triggered this request (only for convenience, will be available on the TranscriptEvents) + * @param string $appId The app that triggered this request (only for convenience, will be available on the TranscriptEvents) * @since 27.0.0 * @throws PreConditionNotMetException If no provider was registered but this method was still called * @throws InvalidArgumentException If the file could not be found or is not of a supported type */ - public function scheduleFileTranscription(File $file): void; + public function scheduleFileTranscription(File $file, string $userId, string $appId): void; /** * @since 27.0.0 From fbcd275acb1e77fc493767859418ca39972d227e Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Wed, 19 Apr 2023 12:39:39 +0200 Subject: [PATCH 24/26] Context params: Make userId nullable Signed-off-by: Marcel Klehr --- lib/private/SpeechToText/SpeechToTextManager.php | 2 +- lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php | 4 ++-- lib/public/SpeechToText/Events/TranscriptionFailedEvent.php | 2 +- .../SpeechToText/Events/TranscriptionSuccessfulEvent.php | 2 +- lib/public/SpeechToText/ISpeechToTextManager.php | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index 95208e5b0cae8..757fc02485e98 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -90,7 +90,7 @@ public function hasProviders(): bool { return !empty($context->getSpeechToTextProviders()); } - public function scheduleFileTranscription(File $file, string $userId, string $appId): void { + public function scheduleFileTranscription(File $file, ?string $userId, string $appId): void { if (!$this->hasProviders()) { throw new PreConditionNotMetException('No SpeechToText providers have been registered'); } diff --git a/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php b/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php index 74164791b323d..11c90fad8919e 100644 --- a/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php +++ b/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php @@ -38,7 +38,7 @@ abstract class AbstractTranscriptionEvent extends Event { public function __construct( private int $fileIdId, private ?File $file, - private string $userId, + private ?string $userId, private string $appId, ) { parent::__construct(); @@ -61,7 +61,7 @@ public function getFile(): ?File { /** * @since 27.0.0 */ - public function getUserId(): string { + public function getUserId(): ?string { return $this->userId; } diff --git a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php index 0cdefdf5a4b00..8845e240e42df 100644 --- a/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php @@ -40,7 +40,7 @@ public function __construct( int $fileId, ?File $file, private string $errorMessage, - string $userId, + ?string $userId, string $appId, ) { parent::__construct($fileId, $file, $userId, $appId); diff --git a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php index 79f379fca4d25..c75fb2da9dcb7 100644 --- a/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php +++ b/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php @@ -40,7 +40,7 @@ public function __construct( int $fileId, ?File $file, private string $transcript, - string $userId, + ?string $userId, string $appId, ) { parent::__construct($fileId, $file, $userId, $appId); diff --git a/lib/public/SpeechToText/ISpeechToTextManager.php b/lib/public/SpeechToText/ISpeechToTextManager.php index 85ef299ae8e29..167017ead603e 100644 --- a/lib/public/SpeechToText/ISpeechToTextManager.php +++ b/lib/public/SpeechToText/ISpeechToTextManager.php @@ -53,7 +53,7 @@ public function hasProviders(): bool; * @throws PreConditionNotMetException If no provider was registered but this method was still called * @throws InvalidArgumentException If the file could not be found or is not of a supported type */ - public function scheduleFileTranscription(File $file, string $userId, string $appId): void; + public function scheduleFileTranscription(File $file, ?string $userId, string $appId): void; /** * @since 27.0.0 From db9901a02e59479e44d32368d3cde377153b35fd Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Apr 2023 12:42:23 +0200 Subject: [PATCH 25/26] Fix(docs): Fix parameter type in doc block Signed-off-by: Joas Schilling --- lib/public/SpeechToText/ISpeechToTextManager.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/public/SpeechToText/ISpeechToTextManager.php b/lib/public/SpeechToText/ISpeechToTextManager.php index 167017ead603e..eff00ec0fa199 100644 --- a/lib/public/SpeechToText/ISpeechToTextManager.php +++ b/lib/public/SpeechToText/ISpeechToTextManager.php @@ -47,21 +47,21 @@ public function hasProviders(): bool; * belonging to your transcription request. * * @param File $file The media file to transcribe - * @param string $userId The user that triggered this request (only for convenience, will be available on the TranscriptEvents) + * @param ?string $userId The user that triggered this request (only for convenience, will be available on the TranscriptEvents) * @param string $appId The app that triggered this request (only for convenience, will be available on the TranscriptEvents) - * @since 27.0.0 * @throws PreConditionNotMetException If no provider was registered but this method was still called * @throws InvalidArgumentException If the file could not be found or is not of a supported type + * @since 27.0.0 */ public function scheduleFileTranscription(File $file, ?string $userId, string $appId): void; /** - * @since 27.0.0 * @param File $file The media file to transcribe * @returns string The transcription of the passed media file * @throws PreConditionNotMetException If no provider was registered but this method was still called * @throws InvalidArgumentException If the file could not be found or is not of a supported type * @throws RuntimeException If the transcription failed for other reasons + * @since 27.0.0 */ public function transcribeFile(File $file): string; } From ab7b63db84dd2c152ee2b6eb26799bde1a5f5b94 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Apr 2023 13:45:44 +0200 Subject: [PATCH 26/26] fix(autoloader): Rebuild Signed-off-by: Joas Schilling --- lib/composer/composer/autoload_classmap.php | 4 +++- lib/composer/composer/autoload_static.php | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 3dd2239ce7fe1..55b9dcaa10e03 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -573,7 +573,9 @@ 'OCP\\Share_Backend' => $baseDir . '/lib/public/Share_Backend.php', 'OCP\\Share_Backend_Collection' => $baseDir . '/lib/public/Share_Backend_Collection.php', 'OCP\\Share_Backend_File_Dependent' => $baseDir . '/lib/public/Share_Backend_File_Dependent.php', - 'OCP\\SpeechToText\\Events\\TranscriptionFinishedEvent' => $baseDir . '/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php', + 'OCP\\SpeechToText\\Events\\AbstractTranscriptionEvent' => $baseDir . '/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php', + 'OCP\\SpeechToText\\Events\\TranscriptionFailedEvent' => $baseDir . '/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php', + 'OCP\\SpeechToText\\Events\\TranscriptionSuccessfulEvent' => $baseDir . '/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php', 'OCP\\SpeechToText\\ISpeechToTextManager' => $baseDir . '/lib/public/SpeechToText/ISpeechToTextManager.php', 'OCP\\SpeechToText\\ISpeechToTextProvider' => $baseDir . '/lib/public/SpeechToText/ISpeechToTextProvider.php', 'OCP\\Support\\CrashReport\\ICollectBreadcrumbs' => $baseDir . '/lib/public/Support/CrashReport/ICollectBreadcrumbs.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 6814cc425d45e..33a43479a2f0e 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -606,7 +606,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Share_Backend' => __DIR__ . '/../../..' . '/lib/public/Share_Backend.php', 'OCP\\Share_Backend_Collection' => __DIR__ . '/../../..' . '/lib/public/Share_Backend_Collection.php', 'OCP\\Share_Backend_File_Dependent' => __DIR__ . '/../../..' . '/lib/public/Share_Backend_File_Dependent.php', - 'OCP\\SpeechToText\\Events\\TranscriptionFinishedEvent' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/Events/TranscriptionFinishedEvent.php', + 'OCP\\SpeechToText\\Events\\AbstractTranscriptionEvent' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php', + 'OCP\\SpeechToText\\Events\\TranscriptionFailedEvent' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php', + 'OCP\\SpeechToText\\Events\\TranscriptionSuccessfulEvent' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php', 'OCP\\SpeechToText\\ISpeechToTextManager' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/ISpeechToTextManager.php', 'OCP\\SpeechToText\\ISpeechToTextProvider' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/ISpeechToTextProvider.php', 'OCP\\Support\\CrashReport\\ICollectBreadcrumbs' => __DIR__ . '/../../..' . '/lib/public/Support/CrashReport/ICollectBreadcrumbs.php',