From 64b36bd104d52e0894a120a07339c8c2253636bd Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 8 Jul 2026 13:42:31 +0200 Subject: [PATCH 1/6] feat(audio-translation): implement basic audio translation provider Signed-off-by: Julien Veyssier --- lib/AppInfo/Application.php | 6 + .../AudioToAudioTranslateProvider.php | 226 ++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 lib/TaskProcessing/AudioToAudioTranslateProvider.php diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 3bb0d9579..f61ea3cce 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -30,6 +30,7 @@ use OCA\Assistant\Reference\Text2ImageReferenceProvider; use OCA\Assistant\Reference\Text2StickerProvider; use OCA\Assistant\TaskProcessing\AudioToAudioChatProvider; +use OCA\Assistant\TaskProcessing\AudioToAudioTranslateProvider; use OCA\Assistant\TaskProcessing\ContextAgentAudioInteractionProvider; use OCA\Assistant\TaskProcessing\ImageToTextTranslateProvider; use OCA\Assistant\TaskProcessing\ImageToTextTranslateTaskType; @@ -118,6 +119,11 @@ public function register(IRegistrationContext $context): void { // not ready yet // $context->registerTaskProcessingTaskType(ImageToTextTranslateTaskType::class); // $context->registerTaskProcessingProvider(ImageToTextTranslateProvider::class); + + // AudioToAudioTranslate appeared in 35 + if (class_exists('OCP\\TaskProcessing\\TaskTypes\\AudioToAudioTranslate')) { + $context->registerTaskProcessingProvider(AudioToAudioTranslateProvider::class); + } } public function boot(IBootContext $context): void { diff --git a/lib/TaskProcessing/AudioToAudioTranslateProvider.php b/lib/TaskProcessing/AudioToAudioTranslateProvider.php new file mode 100644 index 000000000..11729ba9a --- /dev/null +++ b/lib/TaskProcessing/AudioToAudioTranslateProvider.php @@ -0,0 +1,226 @@ +l->t('Assistant'); + } + + public function getTaskTypeId(): string { + return AudioToAudioTranslate::ID; + } + + public function getExpectedRuntime(): int { + return 60; + } + + public function getInputShapeEnumValues(): array { + $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + + return [ + 'origin_language' => $translateProvider->getInputShapeEnumValues()['origin_language'], + 'target_language' => $translateProvider->getInputShapeEnumValues()['target_language'], + ]; + } + + public function getInputShapeDefaults(): array { + $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + return [ + 'origin_language' => $translateProvider->getInputShapeDefaults()['origin_language'], + ]; + } + + + public function getOptionalInputShape(): array { + return []; + } + + public function getOptionalInputShapeEnumValues(): array { + return []; + } + + public function getOptionalInputShapeDefaults(): array { + return []; + } + + public function getOutputShapeEnumValues(): array { + return []; + } + + public function getOptionalOutputShape(): array { + return [ + 'text_input' => new ShapeDescriptor( + $this->l->t('Audio transcription'), + $this->l->t('The transcribed audio input'), + EShapeType::Text, + ), + 'text_output' => new ShapeDescriptor( + $this->l->t('Text output'), + $this->l->t('The text translation'), + EShapeType::Text, + ), + ]; + } + + public function getOptionalOutputShapeEnumValues(): array { + return []; + } + + public function process( + ?string $userId, array $input, callable $reportProgress, SynchronousProviderOptions $options = new SynchronousProviderOptions(), + ): array { + $includeWatermark = $options->getIncludeWatermarks(); + $reportOutput = $options->getReportIntermediateOutput(); + $preferStreaming = $options->getPreferStreaming(); + + if (!isset($input['input']) || !$input['input'] instanceof File || !$input['input']->isReadable()) { + throw new ProcessingException('Invalid input file'); + } + + if (!isset($input['origin_language']) || !is_string($input['origin_language'])) { + throw new RuntimeException('Invalid origin_language input'); + } + if (!isset($input['target_language']) || !is_string($input['target_language'])) { + throw new RuntimeException('Invalid target_language input'); + } + + // STT + try { + $task = new Task( + AudioToText::ID, + ['input' => $input['input']->getId()], + Application::APP_ID . ':internal', + $userId, + ); + $taskOutput = $this->taskProcessingService->runTaskProcessingTask($task); + $transcription = $taskOutput['output']; + } catch (Exception $e) { + $this->logger->warning('STT sub task failed with: ' . $e->getMessage(), ['exception' => $e]); + throw new RuntimeException('STT sub task failed with: ' . $e->getMessage()); + } + + if (empty(trim($transcription))) { + throw new ProcessingException("Empty transcription result from {$input['origin_language']} to {$input['target_language']}"); + } + $watermarkSuffix = ''; + if ($includeWatermark) { + if ($userId !== null) { + $user = $this->userManager->getExistingUser($userId); + $lang = $this->l10nFactory->getUserLanguage($user); + $l = $this->l10nFactory->get(Application::APP_ID, $lang); + $watermarkSuffix = "\n\n" . $l->t('This was generated using Artificial Intelligence.'); + } else { + $watermarkSuffix = "\n\n" . $this->l->t('This was generated using Artificial Intelligence.'); + } + } + + $reportProgress(0.3); + + if ($preferStreaming) { + $running = $reportOutput([ + 'text_input' => $transcription . $watermarkSuffix, + ]); + if (!$running) { + throw new ProcessingException('Audio translation task cancelled'); + } + } + + // translation + try { + $task = new Task( + TextToTextTranslate::ID, + [ + 'input' => $transcription, + 'origin_language' => $input['origin_language'], + 'target_language' => $input['target_language'], + ], + Application::APP_ID . ':internal', + $userId, + ); + $taskOutput = $this->taskProcessingService->runTaskProcessingTask($task); + $translatedText = $taskOutput['output']; + // report progress + $reportProgress(0.6); + } catch (Exception $e) { + $this->logger->warning('Translation sub task failed with: ' . $e->getMessage(), ['exception' => $e]); + throw new RuntimeException('Translation sub task failed with: ' . $e->getMessage()); + } + + if ($preferStreaming) { + $running = $reportOutput([ + 'text_input' => $transcription . $watermarkSuffix, + 'text_output' => $translatedText . $watermarkSuffix, + ]); + if (!$running) { + throw new ProcessingException('Audio translation task cancelled'); + } + } + + // TTS + try { + // this provider is not declared if TextToSpeech does not exist so we know it's fine + /** @psalm-suppress UndefinedClass */ + $task = new Task( + TextToSpeech::ID, + ['input' => $translatedText], + Application::APP_ID . ':internal', + $userId, + ); + $task->setIncludeWatermark(true); + $taskOutput = $this->taskProcessingService->runTaskProcessingTask($task); + $outputAudioFileId = $taskOutput['speech']; + + return [ + 'text_input' => $transcription . $watermarkSuffix, + 'text_output' => $translatedText . $watermarkSuffix, + 'audio_output' => $this->taskProcessingService->getOutputFileContent($outputAudioFileId), + ]; + } catch (\Exception $e) { + $this->logger->warning('Text to speech generation failed with: ' . $e->getMessage(), ['exception' => $e]); + throw new ProcessingException('Text to speech sub task failed with: ' . $e->getMessage()); + } + } +} From e3b85448f66b91d920c1885678ffa220f964f344 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 8 Jul 2026 14:25:08 +0200 Subject: [PATCH 2/6] feat(audio-translation): forward some optional inputs of sub providers of the audio translation provider Signed-off-by: Julien Veyssier --- .../AudioToAudioTranslateProvider.php | 144 ++++++++++++++++-- 1 file changed, 129 insertions(+), 15 deletions(-) diff --git a/lib/TaskProcessing/AudioToAudioTranslateProvider.php b/lib/TaskProcessing/AudioToAudioTranslateProvider.php index 11729ba9a..d8859ee8f 100644 --- a/lib/TaskProcessing/AudioToAudioTranslateProvider.php +++ b/lib/TaskProcessing/AudioToAudioTranslateProvider.php @@ -28,7 +28,6 @@ use OCP\TaskProcessing\TaskTypes\TextToSpeech; use OCP\TaskProcessing\TaskTypes\TextToTextTranslate; use Psr\Log\LoggerInterface; -use RuntimeException; class AudioToAudioTranslateProvider implements IProvider, ISynchronousOptionsAwareProvider { @@ -75,15 +74,96 @@ public function getInputShapeDefaults(): array { public function getOptionalInputShape(): array { - return []; + $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + $translateOptionalInputShape = $translateProvider->getOptionalInputShape(); + $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); + $ttsOptionalInputShape = $ttsProvider->getOptionalInputShape(); + + $optionalInputShape = []; + + if (isset($translateOptionalInputShape['model'])) { + $optionalInputShape['translation_model'] = new ShapeDescriptor( + $this->l->t('Translation model'), + $this->l->t('The model used to translate'), + EShapeType::Enum, + ); + } + + if (isset($ttsOptionalInputShape['model'])) { + $optionalInputShape['speech_model'] = new ShapeDescriptor( + $ttsOptionalInputShape['model']->getName(), + $ttsOptionalInputShape['model']->getDescription(), + EShapeType::Enum, + ); + } + + if (isset($ttsOptionalInputShape['voice'])) { + $optionalInputShape['speech_voice'] = new ShapeDescriptor( + $ttsOptionalInputShape['voice']->getName(), + $ttsOptionalInputShape['voice']->getDescription(), + EShapeType::Enum, + ); + } + + if (isset($ttsOptionalInputShape['speed'])) { + $optionalInputShape['speech_speed'] = new ShapeDescriptor( + $ttsOptionalInputShape['speed']->getName(), + $ttsOptionalInputShape['speed']->getDescription(), + EShapeType::Number, + ); + } + + return $optionalInputShape; } public function getOptionalInputShapeEnumValues(): array { - return []; + $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + $translateOptionalInputShape = $translateProvider->getOptionalInputShape(); + $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); + $ttsOptionalInputShape = $ttsProvider->getOptionalInputShape(); + + $optionalInputShapeEnumValues = []; + + if (isset($translateOptionalInputShape['model'])) { + $optionalInputShapeEnumValues['translation_model'] = $translateProvider->getOptionalInputShapeEnumValues()['model']; + } + + if (isset($ttsOptionalInputShape['model'])) { + $optionalInputShapeEnumValues['speech_model'] = $ttsProvider->getOptionalInputShapeEnumValues()['model']; + } + + if (isset($ttsOptionalInputShape['voice'])) { + $optionalInputShapeEnumValues['speech_voice'] = $ttsProvider->getOptionalInputShapeEnumValues()['voice']; + } + + return $optionalInputShapeEnumValues; } public function getOptionalInputShapeDefaults(): array { - return []; + $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + $translateOptionalInputShape = $translateProvider->getOptionalInputShape(); + $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); + $ttsOptionalInputShape = $ttsProvider->getOptionalInputShape(); + + $optionalInputShapeDefaults = []; + + if (isset($translateOptionalInputShape['model'])) { + $optionalInputShapeDefaults['translation_model'] = $translateProvider->getOptionalInputShapeDefaults()['model']; + } + + if (isset($ttsOptionalInputShape['model'])) { + $optionalInputShapeDefaults['speech_model'] = $ttsProvider->getOptionalInputShapeDefaults()['model']; + } + + if (isset($ttsOptionalInputShape['voice'])) { + $optionalInputShapeDefaults['speech_voice'] = $ttsProvider->getOptionalInputShapeDefaults()['voice']; + } + + if (isset($ttsOptionalInputShape['speed'])) { + $optionalInputShapeDefaults['speech_speed'] = $ttsProvider->getOptionalInputShapeDefaults()['speed']; + } + + return $optionalInputShapeDefaults; } public function getOutputShapeEnumValues(): array { @@ -115,16 +195,36 @@ public function process( $includeWatermark = $options->getIncludeWatermarks(); $reportOutput = $options->getReportIntermediateOutput(); $preferStreaming = $options->getPreferStreaming(); - + if (!isset($input['input']) || !$input['input'] instanceof File || !$input['input']->isReadable()) { throw new ProcessingException('Invalid input file'); } if (!isset($input['origin_language']) || !is_string($input['origin_language'])) { - throw new RuntimeException('Invalid origin_language input'); + throw new ProcessingException('Invalid origin_language input'); } if (!isset($input['target_language']) || !is_string($input['target_language'])) { - throw new RuntimeException('Invalid target_language input'); + throw new ProcessingException('Invalid target_language input'); + } + + $translationModel = null; + if (isset($input['translation_model']) && is_string($input['translation_model'])) { + $translationModel = $input['translation_model']; + } + + $ttsModel = null; + if (isset($input['speech_model']) && is_string($input['speech_model'])) { + $ttsModel = $input['speech_model']; + } + + $ttsVoice = null; + if (isset($input['speech_voice']) && is_string($input['speech_voice'])) { + $ttsVoice = $input['speech_voice']; + } + + $ttsSpeed = null; + if (isset($input['speech_speed']) && is_numeric($input['speech_speed'])) { + $ttsSpeed = $input['speech_speed']; } // STT @@ -139,7 +239,7 @@ public function process( $transcription = $taskOutput['output']; } catch (Exception $e) { $this->logger->warning('STT sub task failed with: ' . $e->getMessage(), ['exception' => $e]); - throw new RuntimeException('STT sub task failed with: ' . $e->getMessage()); + throw new ProcessingException('STT sub task failed with: ' . $e->getMessage()); } if (empty(trim($transcription))) { @@ -170,13 +270,17 @@ public function process( // translation try { + $translationInput = [ + 'input' => $transcription, + 'origin_language' => $input['origin_language'], + 'target_language' => $input['target_language'], + ]; + if ($translationModel !== null) { + $translationInput['translation_model'] = $translationModel; + } $task = new Task( TextToTextTranslate::ID, - [ - 'input' => $transcription, - 'origin_language' => $input['origin_language'], - 'target_language' => $input['target_language'], - ], + $translationInput, Application::APP_ID . ':internal', $userId, ); @@ -186,7 +290,7 @@ public function process( $reportProgress(0.6); } catch (Exception $e) { $this->logger->warning('Translation sub task failed with: ' . $e->getMessage(), ['exception' => $e]); - throw new RuntimeException('Translation sub task failed with: ' . $e->getMessage()); + throw new ProcessingException('Translation sub task failed with: ' . $e->getMessage()); } if ($preferStreaming) { @@ -201,11 +305,21 @@ public function process( // TTS try { + $ttsInput = ['input' => $translatedText]; + if ($ttsModel !== null) { + $ttsInput['model'] = $ttsModel; + } + if ($ttsVoice !== null) { + $ttsInput['voice'] = $ttsVoice; + } + if ($ttsSpeed !== null) { + $ttsInput['speed'] = $ttsSpeed; + } // this provider is not declared if TextToSpeech does not exist so we know it's fine /** @psalm-suppress UndefinedClass */ $task = new Task( TextToSpeech::ID, - ['input' => $translatedText], + $ttsInput, Application::APP_ID . ':internal', $userId, ); From 8941f14e1251d0b8253d6cb30ecf98f10525db71 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 8 Jul 2026 14:36:29 +0200 Subject: [PATCH 3/6] bump min NC to 35, use php 8.3 in config.platform, update composer dependencies, run cs:fix Signed-off-by: Julien Veyssier --- .github/workflows/appstore-build-publish.yml | 2 +- .github/workflows/lint-php-cs.yml | 2 +- .github/workflows/phpunit.yml | 5 +- appinfo/info.xml | 2 +- composer.json | 4 +- composer.lock | 245 ++++++++++++------ lib/AppInfo/Application.php | 6 +- lib/Controller/ConfigController.php | 1 - lib/Db/ChattyLLM/Session.php | 1 - lib/Db/TaskNotification.php | 1 - .../SpeechToTextReferenceListener.php | 1 - lib/Notification/Notifier.php | 13 - lib/Reference/FreePromptReferenceProvider.php | 1 - lib/Reference/Text2ImageReferenceProvider.php | 1 - lib/Service/AssistantService.php | 1 - lib/Service/ChatService.php | 3 - lib/Service/SessionSummaryService.php | 2 - lib/Service/SystemTagService.php | 1 - lib/Service/UnauthorizedException.php | 1 + lib/Settings/Personal.php | 2 - .../AudioToAudioTranslateProvider.php | 1 - .../ContextAgentAudioInteractionProvider.php | 1 - .../ImageToTextTranslateProvider.php | 1 - lib/TaskProcessing/TextToStickerProvider.php | 1 - psalm.xml | 2 +- 25 files changed, 176 insertions(+), 125 deletions(-) diff --git a/.github/workflows/appstore-build-publish.yml b/.github/workflows/appstore-build-publish.yml index 455ea7a2e..23972052d 100644 --- a/.github/workflows/appstore-build-publish.yml +++ b/.github/workflows/appstore-build-publish.yml @@ -13,7 +13,7 @@ on: types: [published] env: - PHP_VERSION: 8.2 + PHP_VERSION: 8.3 jobs: build_and_publish: diff --git a/.github/workflows/lint-php-cs.yml b/.github/workflows/lint-php-cs.yml index 2ecdcf821..1943d55e9 100644 --- a/.github/workflows/lint-php-cs.yml +++ b/.github/workflows/lint-php-cs.yml @@ -49,7 +49,7 @@ jobs: - name: Set up php uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # v2.37.1 with: - php-version: 8.2 + php-version: 8.3 coverage: none ini-file: development env: diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 72fe7468f..e8bf475ef 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -37,10 +37,7 @@ jobs: matrix: php-versions: ['8.3'] databases: ['sqlite'] - server-versions: ['stable33', 'stable34'] - include: - - php-versions: '8.3' - server-versions: 'master' + server-versions: ['master'] name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }} diff --git a/appinfo/info.xml b/appinfo/info.xml index b29a1c2f4..0dcc790f9 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -81,7 +81,7 @@ More details on how to set this up in the [admin docs](https://docs.nextcloud.co https://github.com/nextcloud/assistant/raw/main/img/screenshots/screenshot6.png https://github.com/nextcloud/assistant/raw/main/img/screenshots/screenshot7.png - + OCA\Assistant\Settings\Admin diff --git a/composer.json b/composer.json index 6c9d816e1..848a004c4 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ } ], "require": { - "php": "^8.2", + "php": "^8.3", "erusev/parsedown": "^1.7", "henck/rtf-to-html": "^1.2", "html2text/html2text": "^4.3", @@ -41,7 +41,7 @@ "sort-packages": true, "optimize-autoloader": true, "platform": { - "php": "8.2" + "php": "8.3" }, "autoloader-suffix": "Assistant" } diff --git a/composer.lock b/composer.lock index 17bdbe874..afa85c8b9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8b9a5743024889b768ae6fc5144429d8", + "content-hash": "911cf579f09fcdf4bd71e79e6f0f2643", "packages": [ { "name": "doctrine/collections", @@ -597,16 +597,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", + "version": "v1.38.2", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", "shasum": "" }, "require": { @@ -658,7 +658,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" }, "funding": [ { @@ -678,20 +678,20 @@ "type": "tidelift" } ], - "time": "2024-12-23T08:48:59+00:00" + "time": "2026-05-27T06:59:30+00:00" }, { "name": "symfony/polyfill-php84", - "version": "v1.37.0", + "version": "v1.38.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06" + "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/88486db2c389b290bf87ff1de7ebc1e13e42bb06", - "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa", + "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa", "shasum": "" }, "require": { @@ -738,7 +738,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.37.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.38.1" }, "funding": [ { @@ -758,7 +758,7 @@ "type": "tidelift" } ], - "time": "2026-04-10T18:47:49+00:00" + "time": "2026-05-26T12:51:13+00:00" } ], "packages-dev": [ @@ -907,16 +907,16 @@ }, { "name": "kubawerlos/php-cs-fixer-custom-fixers", - "version": "v3.36.0", + "version": "v3.37.2", "source": { "type": "git", "url": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers.git", - "reference": "e1f97f6463f0b2a22e0dd320948a04132ff9c501" + "reference": "678df979ce743466b42ddb6eea46b3f4c9a7bade" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kubawerlos/php-cs-fixer-custom-fixers/zipball/e1f97f6463f0b2a22e0dd320948a04132ff9c501", - "reference": "e1f97f6463f0b2a22e0dd320948a04132ff9c501", + "url": "https://api.github.com/repos/kubawerlos/php-cs-fixer-custom-fixers/zipball/678df979ce743466b42ddb6eea46b3f4c9a7bade", + "reference": "678df979ce743466b42ddb6eea46b3f4c9a7bade", "shasum": "" }, "require": { @@ -926,7 +926,7 @@ "php": "^7.4 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^9.6.24 || ^10.5.51 || ^11.5.44" + "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.55" }, "type": "library", "autoload": { @@ -947,7 +947,7 @@ "description": "A set of custom fixers for PHP CS Fixer", "support": { "issues": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/issues", - "source": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/tree/v3.36.0" + "source": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/tree/v3.37.2" }, "funding": [ { @@ -955,7 +955,7 @@ "type": "github" } ], - "time": "2026-01-31T07:02:11+00:00" + "time": "2026-05-12T16:22:19+00:00" }, { "name": "myclabs/deep-copy", @@ -1019,16 +1019,16 @@ }, { "name": "nextcloud/coding-standard", - "version": "v1.4.0", + "version": "v1.5.0", "source": { "type": "git", "url": "https://github.com/nextcloud/coding-standard.git", - "reference": "8e06808c1423e9208d63d1bd205b9a38bd400011" + "reference": "80547a93236fbb9c783e05f0f0899043851b0dba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/8e06808c1423e9208d63d1bd205b9a38bd400011", - "reference": "8e06808c1423e9208d63d1bd205b9a38bd400011", + "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/80547a93236fbb9c783e05f0f0899043851b0dba", + "reference": "80547a93236fbb9c783e05f0f0899043851b0dba", "shasum": "" }, "require": { @@ -1058,9 +1058,9 @@ ], "support": { "issues": "https://github.com/nextcloud/coding-standard/issues", - "source": "https://github.com/nextcloud/coding-standard/tree/v1.4.0" + "source": "https://github.com/nextcloud/coding-standard/tree/v1.5.0" }, - "time": "2025-06-19T12:27:27+00:00" + "time": "2026-05-19T18:30:09+00:00" }, { "name": "nextcloud/ocp", @@ -1068,26 +1068,27 @@ "source": { "type": "git", "url": "https://github.com/nextcloud-deps/ocp.git", - "reference": "6ce31e5724b4a720bb968aafd4f6affc1f22e5c4" + "reference": "998cf3368333bba723a3365781fa5eeec3f06cbd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/6ce31e5724b4a720bb968aafd4f6affc1f22e5c4", - "reference": "6ce31e5724b4a720bb968aafd4f6affc1f22e5c4", + "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/998cf3368333bba723a3365781fa5eeec3f06cbd", + "reference": "998cf3368333bba723a3365781fa5eeec3f06cbd", "shasum": "" }, "require": { - "php": "~8.1 || ~8.2 || ~8.3 || ~8.4 || ~8.5", + "php": "~8.3 || ~8.4 || ~8.5", "psr/clock": "^1.0", "psr/container": "^2.0.2", "psr/event-dispatcher": "^1.0", + "psr/http-client": "^1.0.3", "psr/log": "^3.0.2" }, "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-master": "34.0.0-dev" + "dev-master": "35.0.0-dev" } }, "notification-url": "https://packagist.org/downloads/", @@ -1109,7 +1110,7 @@ "issues": "https://github.com/nextcloud-deps/ocp/issues", "source": "https://github.com/nextcloud-deps/ocp/tree/master" }, - "time": "2026-02-13T01:14:34+00:00" + "time": "2026-07-08T01:29:47+00:00" }, { "name": "nextcloud/openapi-extractor", @@ -1160,20 +1161,19 @@ }, { "name": "nikic/php-parser", - "version": "v5.7.0", + "version": "v5.8.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", - "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/044a6a392ff8ad0d61f14370a5fbbd0a0107152f", + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f", "shasum": "" }, "require": { - "ext-ctype": "*", "ext-json": "*", "ext-tokenizer": "*", "php": ">=7.4" @@ -1212,9 +1212,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.8.0" }, - "time": "2025-12-06T11:56:16+00:00" + "time": "2026-07-04T14:30:18+00:00" }, { "name": "phar-io/manifest", @@ -1336,16 +1336,16 @@ }, { "name": "php-cs-fixer/shim", - "version": "v3.94.0", + "version": "v3.95.12", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/shim.git", - "reference": "bf90113c2d4f349a639df42045d36e78ffc25c9a" + "reference": "b1b00fc14aa446d6ef0c7a4007a7c52bdad51000" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/bf90113c2d4f349a639df42045d36e78ffc25c9a", - "reference": "bf90113c2d4f349a639df42045d36e78ffc25c9a", + "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/b1b00fc14aa446d6ef0c7a4007a7c52bdad51000", + "reference": "b1b00fc14aa446d6ef0c7a4007a7c52bdad51000", "shasum": "" }, "require": { @@ -1382,22 +1382,22 @@ "description": "A tool to automatically fix PHP code style", "support": { "issues": "https://github.com/PHP-CS-Fixer/shim/issues", - "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.94.0" + "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.95.12" }, - "time": "2026-02-11T16:45:46+00:00" + "time": "2026-07-07T13:30:09+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "2.3.2", + "version": "2.3.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" + "reference": "fb19eedd2bb67ff8cf7a5502ad329e701d6398a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", - "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fb19eedd2bb67ff8cf7a5502ad329e701d6398a3", + "reference": "fb19eedd2bb67ff8cf7a5502ad329e701d6398a3", "shasum": "" }, "require": { @@ -1429,9 +1429,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.3" }, - "time": "2026-01-25T14:56:51+00:00" + "time": "2026-07-08T07:01:06+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1754,25 +1754,25 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.34", + "version": "9.6.35", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b36f02317466907a230d3aa1d34467041271ef4a" + "reference": "0edba2f3a0c48df3553cb9b640810b30df60302b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b36f02317466907a230d3aa1d34467041271ef4a", - "reference": "b36f02317466907a230d3aa1d34467041271ef4a", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0edba2f3a0c48df3553cb9b640810b30df60302b", + "reference": "0edba2f3a0c48df3553cb9b640810b30df60302b", "shasum": "" }, "require": { "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", + "ext-filter": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", - "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", @@ -1837,31 +1837,15 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.34" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.35" }, "funding": [ { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" + "url": "https://phpunit.de/sponsoring.html", + "type": "other" } ], - "time": "2026-01-27T05:45:00+00:00" + "time": "2026-07-06T14:48:07+00:00" }, { "name": "psalm/phar", @@ -2049,6 +2033,111 @@ }, "time": "2019-01-08T18:20:26+00:00" }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, { "name": "psr/log", "version": "3.0.2", @@ -3169,11 +3258,11 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^8.2" + "php": "^8.3" }, "platform-dev": {}, "platform-overrides": { - "php": "8.2" + "php": "8.3" }, "plugin-api-version": "2.9.0" } diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index f61ea3cce..baaac70a8 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -39,7 +39,6 @@ use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; - use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; @@ -120,10 +119,7 @@ public function register(IRegistrationContext $context): void { // $context->registerTaskProcessingTaskType(ImageToTextTranslateTaskType::class); // $context->registerTaskProcessingProvider(ImageToTextTranslateProvider::class); - // AudioToAudioTranslate appeared in 35 - if (class_exists('OCP\\TaskProcessing\\TaskTypes\\AudioToAudioTranslate')) { - $context->registerTaskProcessingProvider(AudioToAudioTranslateProvider::class); - } + $context->registerTaskProcessingProvider(AudioToAudioTranslateProvider::class); } public function boot(IBootContext $context): void { diff --git a/lib/Controller/ConfigController.php b/lib/Controller/ConfigController.php index 7709bfd8e..d800dc154 100644 --- a/lib/Controller/ConfigController.php +++ b/lib/Controller/ConfigController.php @@ -14,7 +14,6 @@ use OCP\AppFramework\Http\DataResponse; use OCP\IAppConfig; use OCP\IConfig; - use OCP\IRequest; use OCP\PreConditionNotMetException; diff --git a/lib/Db/ChattyLLM/Session.php b/lib/Db/ChattyLLM/Session.php index 0c5fc6d08..1541aaac3 100644 --- a/lib/Db/ChattyLLM/Session.php +++ b/lib/Db/ChattyLLM/Session.php @@ -63,7 +63,6 @@ class Session extends Entity implements \JsonSerializable { */ protected $assignmentId; - public static $columns = [ 'id', 'user_id', diff --git a/lib/Db/TaskNotification.php b/lib/Db/TaskNotification.php index 955387213..eb1692ad5 100644 --- a/lib/Db/TaskNotification.php +++ b/lib/Db/TaskNotification.php @@ -23,7 +23,6 @@ class TaskNotification extends Entity implements \JsonSerializable { /** @var int */ protected $timestamp; - public function __construct() { $this->addType('ocp_task_id', Types::INTEGER); $this->addType('timestamp', Types::INTEGER); diff --git a/lib/Listener/SpeechToText/SpeechToTextReferenceListener.php b/lib/Listener/SpeechToText/SpeechToTextReferenceListener.php index cc57cdc6c..b698245df 100644 --- a/lib/Listener/SpeechToText/SpeechToTextReferenceListener.php +++ b/lib/Listener/SpeechToText/SpeechToTextReferenceListener.php @@ -8,7 +8,6 @@ namespace OCA\Assistant\Listener\SpeechToText; use OCA\Assistant\AppInfo\Application; - use OCP\Collaboration\Reference\RenderReferenceEvent; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; diff --git a/lib/Notification/Notifier.php b/lib/Notification/Notifier.php index 13c778a05..9ca46af3a 100644 --- a/lib/Notification/Notifier.php +++ b/lib/Notification/Notifier.php @@ -8,13 +8,11 @@ namespace OCA\Assistant\Notification; use OCA\Assistant\AppInfo\Application; - use OCP\App\IAppManager; use OCP\IURLGenerator; use OCP\L10N\IFactory; use OCP\Notification\IAction; use OCP\Notification\INotification; - use OCP\Notification\INotifier; use OCP\Notification\UnknownNotificationException; use OCP\TaskProcessing\IManager as ITaskProcessingManager; @@ -118,7 +116,6 @@ public function prepare(INotification $notification, string $languageCode): INot } } - switch ($notification->getSubject()) { case 'success': $subject = $taskTypeName === null @@ -155,7 +152,6 @@ public function prepare(INotification $notification, string $languageCode): INot $notification->addParsedAction($action); return $notification; - case 'failure': $subject = $taskTypeName === null ? $l->t('Task for "%1$s" has failed', [$schedulingAppName]) @@ -166,7 +162,6 @@ public function prepare(INotification $notification, string $languageCode): INot $content .= $l->t('Input: %1$s', [$taskInput]); } - $link = $params['target'] ?? $this->url->linkToRouteAbsolute(Application::APP_ID . '.assistant.getAssistantTaskResultPage', ['taskId' => $params['id']]); $iconUrl = $this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/error.svg')); @@ -186,7 +181,6 @@ public function prepare(INotification $notification, string $languageCode): INot $notification->addParsedAction($action); return $notification; - case 'file_action_success': $subject = $l->t('File action has finished'); @@ -240,7 +234,6 @@ public function prepare(INotification $notification, string $languageCode): INot $notification->addParsedAction($action); return $notification; - case 'file_action_failure': $subject = $l->t('File action has failed'); @@ -274,7 +267,6 @@ public function prepare(INotification $notification, string $languageCode): INot ->setIcon($iconUrl); return $notification; - case 'new_image_file_success': $subject = $l->t('New image file has been generated'); @@ -316,7 +308,6 @@ public function prepare(INotification $notification, string $languageCode): INot $notification->addParsedAction($action); return $notification; - case 'new_image_file_failure': $subject = $l->t('Image file generation has failed'); @@ -338,7 +329,6 @@ public function prepare(INotification $notification, string $languageCode): INot ->setIcon($iconUrl); return $notification; - case 'assignment_approval_pending': $subject = $l->t('Scheduled task is pending review'); @@ -363,7 +353,6 @@ public function prepare(INotification $notification, string $languageCode): INot $notification->addParsedAction($action); return $notification; - case 'assignment_successful': $subject = $l->t('Scheduled task succeeded'); @@ -388,7 +377,6 @@ public function prepare(INotification $notification, string $languageCode): INot $notification->addParsedAction($action); return $notification; - case 'assignment_failure': $subject = $l->t('Scheduled task failed'); @@ -413,7 +401,6 @@ public function prepare(INotification $notification, string $languageCode): INot $notification->addParsedAction($action); return $notification; - default: // Unknown subject => Unknown notification => throw throw new UnknownNotificationException(); diff --git a/lib/Reference/FreePromptReferenceProvider.php b/lib/Reference/FreePromptReferenceProvider.php index 7e56e66c9..1650f2f5b 100644 --- a/lib/Reference/FreePromptReferenceProvider.php +++ b/lib/Reference/FreePromptReferenceProvider.php @@ -90,5 +90,4 @@ public function invalidateUserCache(string $userId): void { $this->referenceManager->invalidateCache($userId); } - } diff --git a/lib/Reference/Text2ImageReferenceProvider.php b/lib/Reference/Text2ImageReferenceProvider.php index b1c3058c7..64d2f490a 100644 --- a/lib/Reference/Text2ImageReferenceProvider.php +++ b/lib/Reference/Text2ImageReferenceProvider.php @@ -90,5 +90,4 @@ public function invalidateUserCache(string $userId): void { $this->referenceManager->invalidateCache($userId); } - } diff --git a/lib/Service/AssistantService.php b/lib/Service/AssistantService.php index ee6e3fbdf..28330bd14 100644 --- a/lib/Service/AssistantService.php +++ b/lib/Service/AssistantService.php @@ -935,7 +935,6 @@ private function parseDocument(string $filePath, string $mimeType): string { } } - $phpWord = IOFactory::createReader($readerType); $phpWord = $phpWord->load($filePath); $sections = $phpWord->getSections(); diff --git a/lib/Service/ChatService.php b/lib/Service/ChatService.php index ac39bd837..bda244546 100644 --- a/lib/Service/ChatService.php +++ b/lib/Service/ChatService.php @@ -364,7 +364,6 @@ public function scheduleMessageGeneration(?string $userId, int $sessionId, int $ throw new InternalException(previous: $e); } - try { $session = $this->sessionMapper->getUserSession($userId, $sessionId); } catch (DoesNotExistException $e) { @@ -475,7 +474,6 @@ public function scheduleAssignmentMessageGeneration(?string $userId, int $sessio throw new InternalException(previous: $e); } - try { $session = $this->sessionMapper->getUserSession($userId, $sessionId); } catch (DoesNotExistException $e) { @@ -554,7 +552,6 @@ public function isContextAgentAudioAvailable(): bool { return in_array(\OCP\TaskProcessing\TaskTypes\ContextAgentAudioInteraction::ID, $this->taskProcessingManager->getAvailableTaskTypeIds()); } - private function getAudioHistory(array $history): array { // history is a list of JSON strings // The content is the remote audio ID (or the transcription as fallback) diff --git a/lib/Service/SessionSummaryService.php b/lib/Service/SessionSummaryService.php index d5a604ea7..51b5b1744 100644 --- a/lib/Service/SessionSummaryService.php +++ b/lib/Service/SessionSummaryService.php @@ -140,6 +140,4 @@ public function getMemories(?string $userId): array { } } - - } diff --git a/lib/Service/SystemTagService.php b/lib/Service/SystemTagService.php index 742c31fae..b51310dde 100644 --- a/lib/Service/SystemTagService.php +++ b/lib/Service/SystemTagService.php @@ -1,6 +1,5 @@ appConfig->getValueString(Application::APP_ID, 'speech_to_text_picker_enabled', '1', lazy: true) === '1'; $speechToTextPickerEnabled = $this->config->getUserValue($this->userId, Application::APP_ID, 'speech_to_text_picker_enabled', '1') === '1'; - - $userConfig = [ 'task_processing_available' => $taskProcessingAvailable, 'assistant_available' => $assistantAvailable, diff --git a/lib/TaskProcessing/AudioToAudioTranslateProvider.php b/lib/TaskProcessing/AudioToAudioTranslateProvider.php index d8859ee8f..92f55629f 100644 --- a/lib/TaskProcessing/AudioToAudioTranslateProvider.php +++ b/lib/TaskProcessing/AudioToAudioTranslateProvider.php @@ -72,7 +72,6 @@ public function getInputShapeDefaults(): array { ]; } - public function getOptionalInputShape(): array { $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); $translateOptionalInputShape = $translateProvider->getOptionalInputShape(); diff --git a/lib/TaskProcessing/ContextAgentAudioInteractionProvider.php b/lib/TaskProcessing/ContextAgentAudioInteractionProvider.php index a195aec49..a523d72f1 100644 --- a/lib/TaskProcessing/ContextAgentAudioInteractionProvider.php +++ b/lib/TaskProcessing/ContextAgentAudioInteractionProvider.php @@ -61,7 +61,6 @@ public function getInputShapeDefaults(): array { return []; } - public function getOptionalInputShape(): array { return [ 'memories' => new ShapeDescriptor( diff --git a/lib/TaskProcessing/ImageToTextTranslateProvider.php b/lib/TaskProcessing/ImageToTextTranslateProvider.php index a364650e4..d863e7465 100644 --- a/lib/TaskProcessing/ImageToTextTranslateProvider.php +++ b/lib/TaskProcessing/ImageToTextTranslateProvider.php @@ -62,7 +62,6 @@ public function getInputShapeDefaults(): array { ]; } - public function getOptionalInputShape(): array { return []; } diff --git a/lib/TaskProcessing/TextToStickerProvider.php b/lib/TaskProcessing/TextToStickerProvider.php index ce33b578b..cad22551a 100644 --- a/lib/TaskProcessing/TextToStickerProvider.php +++ b/lib/TaskProcessing/TextToStickerProvider.php @@ -54,7 +54,6 @@ public function getInputShapeDefaults(): array { return []; } - public function getOptionalInputShape(): array { return []; } diff --git a/psalm.xml b/psalm.xml index 553377dae..5cb528f6a 100644 --- a/psalm.xml +++ b/psalm.xml @@ -11,7 +11,7 @@ resolveFromConfigFile="true" ensureOverrideAttribute="false" strictBinaryOperands="false" - phpVersion="8.2" + phpVersion="8.3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor-bin/psalm/vendor/vimeo/psalm/config.xsd" From 370e6f1d157c9f0247312f508eaf29d884255966 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Thu, 9 Jul 2026 11:47:58 +0200 Subject: [PATCH 4/6] fix: respect includeWatermark, safer optional input shape usage Signed-off-by: Julien Veyssier --- .../AudioToAudioTranslateProvider.php | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/TaskProcessing/AudioToAudioTranslateProvider.php b/lib/TaskProcessing/AudioToAudioTranslateProvider.php index 92f55629f..3a1366ef5 100644 --- a/lib/TaskProcessing/AudioToAudioTranslateProvider.php +++ b/lib/TaskProcessing/AudioToAudioTranslateProvider.php @@ -118,21 +118,24 @@ public function getOptionalInputShape(): array { public function getOptionalInputShapeEnumValues(): array { $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); $translateOptionalInputShape = $translateProvider->getOptionalInputShape(); + $translateEnumValues = $translateProvider->getOptionalInputShapeEnumValues(); + $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); $ttsOptionalInputShape = $ttsProvider->getOptionalInputShape(); + $ttsEnumValues = $ttsProvider->getOptionalInputShapeEnumValues(); $optionalInputShapeEnumValues = []; - if (isset($translateOptionalInputShape['model'])) { - $optionalInputShapeEnumValues['translation_model'] = $translateProvider->getOptionalInputShapeEnumValues()['model']; + if (isset($translateOptionalInputShape['model']) && isset($translateEnumValues['model'])) { + $optionalInputShapeEnumValues['translation_model'] = $translateEnumValues['model']; } - if (isset($ttsOptionalInputShape['model'])) { - $optionalInputShapeEnumValues['speech_model'] = $ttsProvider->getOptionalInputShapeEnumValues()['model']; + if (isset($ttsOptionalInputShape['model']) && isset($ttsEnumValues['model'])) { + $optionalInputShapeEnumValues['speech_model'] = $ttsEnumValues['model']; } - if (isset($ttsOptionalInputShape['voice'])) { - $optionalInputShapeEnumValues['speech_voice'] = $ttsProvider->getOptionalInputShapeEnumValues()['voice']; + if (isset($ttsOptionalInputShape['voice']) && isset($ttsEnumValues['voice'])) { + $optionalInputShapeEnumValues['speech_voice'] = $ttsEnumValues['voice']; } return $optionalInputShapeEnumValues; @@ -141,25 +144,28 @@ public function getOptionalInputShapeEnumValues(): array { public function getOptionalInputShapeDefaults(): array { $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); $translateOptionalInputShape = $translateProvider->getOptionalInputShape(); + $translateOptionalInputShapeDefaults = $translateProvider->getOptionalInputShapeDefaults(); + $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); $ttsOptionalInputShape = $ttsProvider->getOptionalInputShape(); + $ttsOptionalInputShapeDefaults = $ttsProvider->getOptionalInputShapeDefaults(); $optionalInputShapeDefaults = []; - if (isset($translateOptionalInputShape['model'])) { - $optionalInputShapeDefaults['translation_model'] = $translateProvider->getOptionalInputShapeDefaults()['model']; + if (isset($translateOptionalInputShape['model']) && isset($translateOptionalInputShapeDefaults['model'])) { + $optionalInputShapeDefaults['translation_model'] = $translateOptionalInputShapeDefaults['model']; } - if (isset($ttsOptionalInputShape['model'])) { - $optionalInputShapeDefaults['speech_model'] = $ttsProvider->getOptionalInputShapeDefaults()['model']; + if (isset($ttsOptionalInputShape['model']) && isset($ttsOptionalInputShapeDefaults['model'])) { + $optionalInputShapeDefaults['speech_model'] = $ttsOptionalInputShapeDefaults['model']; } - if (isset($ttsOptionalInputShape['voice'])) { - $optionalInputShapeDefaults['speech_voice'] = $ttsProvider->getOptionalInputShapeDefaults()['voice']; + if (isset($ttsOptionalInputShape['voice']) && isset($ttsOptionalInputShapeDefaults['voice'])) { + $optionalInputShapeDefaults['speech_voice'] = $ttsOptionalInputShapeDefaults['voice']; } - if (isset($ttsOptionalInputShape['speed'])) { - $optionalInputShapeDefaults['speech_speed'] = $ttsProvider->getOptionalInputShapeDefaults()['speed']; + if (isset($ttsOptionalInputShape['speed']) && isset($ttsOptionalInputShapeDefaults['speed'])) { + $optionalInputShapeDefaults['speech_speed'] = $ttsOptionalInputShapeDefaults['speed']; } return $optionalInputShapeDefaults; @@ -322,7 +328,7 @@ public function process( Application::APP_ID . ':internal', $userId, ); - $task->setIncludeWatermark(true); + $task->setIncludeWatermark($includeWatermark); $taskOutput = $this->taskProcessingService->runTaskProcessingTask($task); $outputAudioFileId = $taskOutput['speech']; From e80aeb89c1c35d83bfbaab5a30fd6b0ba90c4463 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Thu, 9 Jul 2026 11:49:48 +0200 Subject: [PATCH 5/6] fix: remove useless psalm-suppress Signed-off-by: Julien Veyssier --- lib/TaskProcessing/AudioToAudioTranslateProvider.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/TaskProcessing/AudioToAudioTranslateProvider.php b/lib/TaskProcessing/AudioToAudioTranslateProvider.php index 3a1366ef5..fcda119a5 100644 --- a/lib/TaskProcessing/AudioToAudioTranslateProvider.php +++ b/lib/TaskProcessing/AudioToAudioTranslateProvider.php @@ -320,8 +320,6 @@ public function process( if ($ttsSpeed !== null) { $ttsInput['speed'] = $ttsSpeed; } - // this provider is not declared if TextToSpeech does not exist so we know it's fine - /** @psalm-suppress UndefinedClass */ $task = new Task( TextToSpeech::ID, $ttsInput, From fa33dc241947435b4213ba86501acc7a0b0f829b Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Thu, 9 Jul 2026 13:39:43 +0200 Subject: [PATCH 6/6] fix: provide meaningful exception when a sub provider is not found in AudioToAudioTranslateProvider Signed-off-by: Julien Veyssier --- .../AudioToAudioTranslateProvider.php | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/lib/TaskProcessing/AudioToAudioTranslateProvider.php b/lib/TaskProcessing/AudioToAudioTranslateProvider.php index fcda119a5..95890d4a5 100644 --- a/lib/TaskProcessing/AudioToAudioTranslateProvider.php +++ b/lib/TaskProcessing/AudioToAudioTranslateProvider.php @@ -73,9 +73,17 @@ public function getInputShapeDefaults(): array { } public function getOptionalInputShape(): array { - $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + try { + $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + } catch (\OCP\TaskProcessing\Exception\Exception $e) { + throw new \OCP\TaskProcessing\Exception\Exception('Failed to get a provider for the translate task type', 0, $e); + } $translateOptionalInputShape = $translateProvider->getOptionalInputShape(); - $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); + try { + $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); + } catch (\OCP\TaskProcessing\Exception\Exception $e) { + throw new \OCP\TaskProcessing\Exception\Exception('Failed to get a provider for the speech-to-text task type', 0, $e); + } $ttsOptionalInputShape = $ttsProvider->getOptionalInputShape(); $optionalInputShape = []; @@ -116,11 +124,19 @@ public function getOptionalInputShape(): array { } public function getOptionalInputShapeEnumValues(): array { - $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + try { + $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + } catch (\OCP\TaskProcessing\Exception\Exception $e) { + throw new \OCP\TaskProcessing\Exception\Exception('Failed to get a provider for the translate task type', 0, $e); + } $translateOptionalInputShape = $translateProvider->getOptionalInputShape(); $translateEnumValues = $translateProvider->getOptionalInputShapeEnumValues(); - $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); + try { + $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); + } catch (\OCP\TaskProcessing\Exception\Exception $e) { + throw new \OCP\TaskProcessing\Exception\Exception('Failed to get a provider for the speech-to-text task type', 0, $e); + } $ttsOptionalInputShape = $ttsProvider->getOptionalInputShape(); $ttsEnumValues = $ttsProvider->getOptionalInputShapeEnumValues(); @@ -142,11 +158,19 @@ public function getOptionalInputShapeEnumValues(): array { } public function getOptionalInputShapeDefaults(): array { - $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + try { + $translateProvider = $this->taskProcessingService->getPreferredProvider(TextToTextTranslate::ID); + } catch (\OCP\TaskProcessing\Exception\Exception $e) { + throw new \OCP\TaskProcessing\Exception\Exception('Failed to get a provider for the translate task type', 0, $e); + } $translateOptionalInputShape = $translateProvider->getOptionalInputShape(); $translateOptionalInputShapeDefaults = $translateProvider->getOptionalInputShapeDefaults(); - $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); + try { + $ttsProvider = $this->taskProcessingService->getPreferredProvider(TextToSpeech::ID); + } catch (\OCP\TaskProcessing\Exception\Exception $e) { + throw new \OCP\TaskProcessing\Exception\Exception('Failed to get a provider for the speech-to-text task type', 0, $e); + } $ttsOptionalInputShape = $ttsProvider->getOptionalInputShape(); $ttsOptionalInputShapeDefaults = $ttsProvider->getOptionalInputShapeDefaults();