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 3bb0d9579..baaac70a8 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;
@@ -38,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;
@@ -118,6 +118,8 @@ public function register(IRegistrationContext $context): void {
// not ready yet
// $context->registerTaskProcessingTaskType(ImageToTextTranslateTaskType::class);
// $context->registerTaskProcessingProvider(ImageToTextTranslateProvider::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
new file mode 100644
index 000000000..95890d4a5
--- /dev/null
+++ b/lib/TaskProcessing/AudioToAudioTranslateProvider.php
@@ -0,0 +1,367 @@
+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 {
+ 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();
+ 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 = [];
+
+ 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 {
+ 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();
+
+ 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();
+
+ $optionalInputShapeEnumValues = [];
+
+ if (isset($translateOptionalInputShape['model']) && isset($translateEnumValues['model'])) {
+ $optionalInputShapeEnumValues['translation_model'] = $translateEnumValues['model'];
+ }
+
+ if (isset($ttsOptionalInputShape['model']) && isset($ttsEnumValues['model'])) {
+ $optionalInputShapeEnumValues['speech_model'] = $ttsEnumValues['model'];
+ }
+
+ if (isset($ttsOptionalInputShape['voice']) && isset($ttsEnumValues['voice'])) {
+ $optionalInputShapeEnumValues['speech_voice'] = $ttsEnumValues['voice'];
+ }
+
+ return $optionalInputShapeEnumValues;
+ }
+
+ public function getOptionalInputShapeDefaults(): array {
+ 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();
+
+ 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();
+
+ $optionalInputShapeDefaults = [];
+
+ if (isset($translateOptionalInputShape['model']) && isset($translateOptionalInputShapeDefaults['model'])) {
+ $optionalInputShapeDefaults['translation_model'] = $translateOptionalInputShapeDefaults['model'];
+ }
+
+ if (isset($ttsOptionalInputShape['model']) && isset($ttsOptionalInputShapeDefaults['model'])) {
+ $optionalInputShapeDefaults['speech_model'] = $ttsOptionalInputShapeDefaults['model'];
+ }
+
+ if (isset($ttsOptionalInputShape['voice']) && isset($ttsOptionalInputShapeDefaults['voice'])) {
+ $optionalInputShapeDefaults['speech_voice'] = $ttsOptionalInputShapeDefaults['voice'];
+ }
+
+ if (isset($ttsOptionalInputShape['speed']) && isset($ttsOptionalInputShapeDefaults['speed'])) {
+ $optionalInputShapeDefaults['speech_speed'] = $ttsOptionalInputShapeDefaults['speed'];
+ }
+
+ return $optionalInputShapeDefaults;
+ }
+
+ 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 ProcessingException('Invalid origin_language input');
+ }
+ if (!isset($input['target_language']) || !is_string($input['target_language'])) {
+ 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
+ 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 ProcessingException('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 {
+ $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,
+ $translationInput,
+ 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 ProcessingException('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 {
+ $ttsInput = ['input' => $translatedText];
+ if ($ttsModel !== null) {
+ $ttsInput['model'] = $ttsModel;
+ }
+ if ($ttsVoice !== null) {
+ $ttsInput['voice'] = $ttsVoice;
+ }
+ if ($ttsSpeed !== null) {
+ $ttsInput['speed'] = $ttsSpeed;
+ }
+ $task = new Task(
+ TextToSpeech::ID,
+ $ttsInput,
+ Application::APP_ID . ':internal',
+ $userId,
+ );
+ $task->setIncludeWatermark($includeWatermark);
+ $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());
+ }
+ }
+}
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"