diff --git a/.github/workflows/appstore-build-publish.yml b/.github/workflows/appstore-build-publish.yml
index 277cf3ed..7edf30c4 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.1
+ PHP_VERSION: 8.2
jobs:
build_and_publish:
diff --git a/appinfo/info.xml b/appinfo/info.xml
index bf8fad0b..ab271f6c 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -62,7 +62,7 @@ Known providers:
More details on how to set this up in the [admin docs](https://docs.nextcloud.com/server/latest/admin_manual/ai/index.html)
]]>
- 2.10.0
+ 2.11.0-dev
agpl
Julien Veyssier
Assistant
diff --git a/composer.lock b/composer.lock
index 7abcf318..9f640298 100644
--- a/composer.lock
+++ b/composer.lock
@@ -143,16 +143,16 @@
},
{
"name": "phpoffice/math",
- "version": "0.2.0",
+ "version": "0.3.0",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/Math.git",
- "reference": "fc2eb6d1a61b058d5dac77197059db30ee3c8329"
+ "reference": "fc31c8f57a7a81f962cbf389fd89f4d9d06fc99a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHPOffice/Math/zipball/fc2eb6d1a61b058d5dac77197059db30ee3c8329",
- "reference": "fc2eb6d1a61b058d5dac77197059db30ee3c8329",
+ "url": "https://api.github.com/repos/PHPOffice/Math/zipball/fc31c8f57a7a81f962cbf389fd89f4d9d06fc99a",
+ "reference": "fc31c8f57a7a81f962cbf389fd89f4d9d06fc99a",
"shasum": ""
},
"require": {
@@ -189,50 +189,49 @@
],
"support": {
"issues": "https://github.com/PHPOffice/Math/issues",
- "source": "https://github.com/PHPOffice/Math/tree/0.2.0"
+ "source": "https://github.com/PHPOffice/Math/tree/0.3.0"
},
- "time": "2024-08-12T07:30:45+00:00"
+ "time": "2025-05-29T08:31:49+00:00"
},
{
"name": "phpoffice/phpword",
- "version": "1.3.0",
+ "version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PHPWord.git",
- "reference": "8392134ce4b5dba65130ba956231a1602b848b7f"
+ "reference": "6d75328229bc93790b37e93741adf70646cea958"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHPOffice/PHPWord/zipball/8392134ce4b5dba65130ba956231a1602b848b7f",
- "reference": "8392134ce4b5dba65130ba956231a1602b848b7f",
+ "url": "https://api.github.com/repos/PHPOffice/PHPWord/zipball/6d75328229bc93790b37e93741adf70646cea958",
+ "reference": "6d75328229bc93790b37e93741adf70646cea958",
"shasum": ""
},
"require": {
"ext-dom": "*",
+ "ext-gd": "*",
"ext-json": "*",
"ext-xml": "*",
+ "ext-zip": "*",
"php": "^7.1|^8.0",
- "phpoffice/math": "^0.2"
+ "phpoffice/math": "^0.3"
},
"require-dev": {
- "dompdf/dompdf": "^2.0",
- "ext-gd": "*",
+ "dompdf/dompdf": "^2.0 || ^3.0",
"ext-libxml": "*",
- "ext-zip": "*",
"friendsofphp/php-cs-fixer": "^3.3",
- "mpdf/mpdf": "^8.1",
+ "mpdf/mpdf": "^7.0 || ^8.0",
"phpmd/phpmd": "^2.13",
- "phpstan/phpstan-phpunit": "@stable",
+ "phpstan/phpstan": "^0.12.88 || ^1.0.0",
+ "phpstan/phpstan-phpunit": "^1.0 || ^2.0",
"phpunit/phpunit": ">=7.0",
"symfony/process": "^4.4 || ^5.0",
"tecnickcom/tcpdf": "^6.5"
},
"suggest": {
"dompdf/dompdf": "Allows writing PDF",
- "ext-gd2": "Allows adding images",
"ext-xmlwriter": "Allows writing OOXML and ODF",
- "ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template",
- "ext-zip": "Allows writing OOXML and ODF"
+ "ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template"
},
"type": "library",
"autoload": {
@@ -242,7 +241,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "LGPL-3.0"
+ "LGPL-3.0-only"
],
"authors": [
{
@@ -298,9 +297,9 @@
],
"support": {
"issues": "https://github.com/PHPOffice/PHPWord/issues",
- "source": "https://github.com/PHPOffice/PHPWord/tree/1.3.0"
+ "source": "https://github.com/PHPOffice/PHPWord/tree/1.4.0"
},
- "time": "2024-08-30T18:03:42+00:00"
+ "time": "2025-06-05T10:32:36+00:00"
},
{
"name": "ralouphie/mimey",
@@ -790,12 +789,12 @@
"source": {
"type": "git",
"url": "https://github.com/nextcloud-deps/ocp.git",
- "reference": "869be299538564cdcd8b88682d028297212ec8e8"
+ "reference": "f2c8f4bc174bed3f1c8edebb5b61bdd1e4fd8efe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/869be299538564cdcd8b88682d028297212ec8e8",
- "reference": "869be299538564cdcd8b88682d028297212ec8e8",
+ "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/f2c8f4bc174bed3f1c8edebb5b61bdd1e4fd8efe",
+ "reference": "f2c8f4bc174bed3f1c8edebb5b61bdd1e4fd8efe",
"shasum": ""
},
"require": {
@@ -831,7 +830,7 @@
"issues": "https://github.com/nextcloud-deps/ocp/issues",
"source": "https://github.com/nextcloud-deps/ocp/tree/master"
},
- "time": "2025-12-02T00:53:42+00:00"
+ "time": "2025-12-03T00:53:16+00:00"
},
{
"name": "nextcloud/openapi-extractor",
@@ -2832,89 +2831,6 @@
],
"time": "2020-09-28T06:39:44+00:00"
},
- {
- "name": "symfony/polyfill-ctype",
- "version": "v1.33.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "provide": {
- "ext-ctype": "*"
- },
- "suggest": {
- "ext-ctype": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Ctype\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Gert de Pagter",
- "email": "BackEndTea@gmail.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for ctype functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "ctype",
- "polyfill",
- "portable"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-09T11:45:10+00:00"
- },
{
"name": "theseer/tokenizer",
"version": "1.3.1",
diff --git a/lib/Listener/CSPListener.php b/lib/Listener/CSPListener.php
index 22a680bc..82d19fd7 100644
--- a/lib/Listener/CSPListener.php
+++ b/lib/Listener/CSPListener.php
@@ -30,6 +30,7 @@ public function handle(Event $event): void {
$csp = new ContentSecurityPolicy();
$csp->addAllowedWorkerSrcDomain('blob:');
+ $csp->addAllowedConnectDomain('blob:');
$event->addPolicy($csp);
}
}
diff --git a/lib/TaskProcessing/AudioToAudioChatProvider.php b/lib/TaskProcessing/AudioToAudioChatProvider.php
index 336e72e3..61c7576a 100644
--- a/lib/TaskProcessing/AudioToAudioChatProvider.php
+++ b/lib/TaskProcessing/AudioToAudioChatProvider.php
@@ -143,6 +143,10 @@ public function process(?string $userId, array $input, callable $reportProgress)
Application::APP_ID . ':internal',
$userId,
);
+ // the setIncludeWatermark method was introduced in NC 33
+ if (method_exists($task, 'setIncludeWatermark')) {
+ $task->setIncludeWatermark(false);
+ }
$taskOutput = $this->taskProcessingService->runTaskProcessingTask($task);
$outputAudioFileId = $taskOutput['speech'];
diff --git a/lib/TaskProcessing/ContextAgentAudioInteractionProvider.php b/lib/TaskProcessing/ContextAgentAudioInteractionProvider.php
index fae2a81f..07288a33 100644
--- a/lib/TaskProcessing/ContextAgentAudioInteractionProvider.php
+++ b/lib/TaskProcessing/ContextAgentAudioInteractionProvider.php
@@ -143,6 +143,10 @@ public function process(?string $userId, array $input, callable $reportProgress)
Application::APP_ID . ':internal',
$userId,
);
+ // the setIncludeWatermark method was introduced in NC 33
+ if (method_exists($task, 'setIncludeWatermark')) {
+ $task->setIncludeWatermark(false);
+ }
$ttsTaskOutput = $this->taskProcessingService->runTaskProcessingTask($task);
$outputAudioFileId = $ttsTaskOutput['speech'];
$outputAudioFileContent = $this->taskProcessingService->getOutputFileContent($outputAudioFileId);
diff --git a/src/audioUtils.js b/src/audioUtils.js
deleted file mode 100644
index 79caff3a..00000000
--- a/src/audioUtils.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-import * as lamejs from '@breezystack/lamejs'
-
-export function convertWavToMp3(wavBlob) {
- return new Promise((resolve, reject) => {
- const reader = new FileReader()
-
- reader.onload = function() {
- const arrayBuffer = this.result
-
- // Create a WAV decoder
- const wavDecoder = lamejs.WavHeader.readHeader(new DataView(arrayBuffer))
-
- // Get the WAV audio data as an array of samples
- const wavSamples = new Int16Array(arrayBuffer, wavDecoder.dataOffset, wavDecoder.dataLen / 2)
-
- // Create an MP3 encoder
- const mp3Encoder = new lamejs.Mp3Encoder(wavDecoder.channels, wavDecoder.sampleRate, 128)
-
- // Encode the WAV samples to MP3
- const mp3Buffer = mp3Encoder.encodeBuffer(wavSamples)
-
- // Finalize the MP3 encoding
- const mp3Data = mp3Encoder.flush()
-
- // Combine the MP3 header and data into a new ArrayBuffer
- const mp3BufferWithHeader = new Uint8Array(mp3Buffer.length + mp3Data.length)
- mp3BufferWithHeader.set(mp3Buffer, 0)
- mp3BufferWithHeader.set(mp3Data, mp3Buffer.length)
-
- // Create a Blob from the ArrayBuffer
- const mp3Blob = new Blob([mp3BufferWithHeader], { type: 'audio/mp3' })
-
- resolve(mp3Blob)
- }
-
- reader.onerror = function(error) {
- reject(error)
- }
-
- // Read the input blob as an ArrayBuffer
- reader.readAsArrayBuffer(wavBlob)
- })
-}
diff --git a/src/components/ChattyLLM/InputArea.vue b/src/components/ChattyLLM/InputArea.vue
index d7927ee7..95941711 100644
--- a/src/components/ChattyLLM/InputArea.vue
+++ b/src/components/ChattyLLM/InputArea.vue
@@ -132,7 +132,7 @@ export default {
const url = generateOcsUrl('/apps/assistant/api/v1/input-file')
const formData = new FormData()
formData.append('data', blob)
- formData.append('filename', 'chat-input.mp3')
+ formData.append('filename', 'chat-input.wav')
axios.post(url, formData).then(response => {
this.$emit('submit-audio', response.data.ocs.data.fileId)
}).catch(error => {
diff --git a/src/components/fields/AudioRecorderWrapper.vue b/src/components/fields/AudioRecorderWrapper.vue
index 2043d7ca..8862d83a 100644
--- a/src/components/fields/AudioRecorderWrapper.vue
+++ b/src/components/fields/AudioRecorderWrapper.vue
@@ -49,7 +49,6 @@ import NcButton from '@nextcloud/vue/components/NcButton'
import { showError } from '@nextcloud/dialogs'
-import { convertWavToMp3 } from '../../audioUtils.js'
import { MediaRecorder, register } from 'extendable-media-recorder'
import { connect } from 'extendable-media-recorder-wav-encoder'
@@ -210,8 +209,7 @@ export default {
this.killStreams()
if (!this.aborted) {
const wavBlob = new Blob(this.chunks, { type: this.mediaRecorder.mimeType })
- const mp3Blob = await convertWavToMp3(wavBlob)
- this.$emit('new-recording', mp3Blob)
+ this.$emit('new-recording', wavBlob)
this.$emit('update:is-recording', false)
}
this.resetComponentData()
diff --git a/src/components/fields/ListOfMediaField.vue b/src/components/fields/ListOfMediaField.vue
index b3718b11..05443bf9 100644
--- a/src/components/fields/ListOfMediaField.vue
+++ b/src/components/fields/ListOfMediaField.vue
@@ -218,7 +218,7 @@ export default {
const url = generateOcsUrl('/apps/assistant/api/v1/input-file')
const formData = new FormData()
formData.append('data', blob)
- formData.append('filename', 'recording.mp3')
+ formData.append('filename', 'recording.wav')
axios.post(url, formData).then(response => {
const fileId = response.data.ocs.data.fileId
if (this.value === null) {
diff --git a/src/components/fields/MediaField.vue b/src/components/fields/MediaField.vue
index 220bffaf..c6104e69 100644
--- a/src/components/fields/MediaField.vue
+++ b/src/components/fields/MediaField.vue
@@ -194,7 +194,7 @@ export default {
const url = generateOcsUrl('/apps/assistant/api/v1/input-file')
const formData = new FormData()
formData.append('data', blob)
- formData.append('filename', 'recording.mp3')
+ formData.append('filename', 'recording.wav')
axios.post(url, formData).then(response => {
this.$emit('update:value', response.data.ocs.data.fileId)
this.filePath = response.data.ocs.data.filePath