diff --git a/docs/settings.md b/docs/settings.md
index ad2543d8412..dc2cfe836c1 100644
--- a/docs/settings.md
+++ b/docs/settings.md
@@ -103,7 +103,8 @@ Legend:
| `calls_start_without_media` | string
`yes` or `no` | `no` | Yes | | Whether participants start with enabled or disabled audio and video by default |
| `breakout_rooms` | string
`yes` or `no` | `yes` | Yes | | Whether or not breakout rooms are allowed (Will only prevent creating new breakout rooms. Existing conversations are not modified.) |
| `call_recording` | string
`yes` or `no` | `yes` | Yes | | Enable call recording |
-| `call_recording_transcription` | string
`yes` or `no` | `no` | No | | Whether call recordings should automatically be transcripted when a transcription provider is enabled. |
+| `call_recording_summary` | string
`yes` or `no` | `no` | No | | Whether call recordings should automatically be summarized when a transcription and summary provider is enabled. |
+| `call_recording_transcription` | string
`yes` or `no` | `no` | No | | Whether call recordings should automatically be transcribed when a transcription provider is enabled. |
| `sip_dialout` | string
`yes` or `no` | `no` | Yes | | SIP dial-out is allowed when a SIP bridge is configured |
| `federation_enabled` | string
`yes` or `no` | `no` | Yes | | 🏗️ *Work in progress:* Whether or not federation with this instance is allowed |
| `federation_incoming_enabled` | string
`1` or `0` | `1` | Yes | | 🏗️ *Work in progress:* Whether users of this instance can be invited to federated conversations |
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 2a54aca97bc..38499f63e67 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -148,8 +148,8 @@
use OCP\Share\Events\BeforeShareCreatedEvent;
use OCP\Share\Events\ShareCreatedEvent;
use OCP\Share\Events\VerifyMountPointEvent;
-use OCP\SpeechToText\Events\TranscriptionFailedEvent;
-use OCP\SpeechToText\Events\TranscriptionSuccessfulEvent;
+use OCP\TaskProcessing\Events\TaskFailedEvent;
+use OCP\TaskProcessing\Events\TaskSuccessfulEvent;
use OCP\User\Events\BeforeUserLoggedOutEvent;
use OCP\User\Events\UserChangedEvent;
use OCP\User\Events\UserDeletedEvent;
@@ -273,8 +273,8 @@ public function register(IRegistrationContext $context): void {
$context->registerEventListener(RoomDeletedEvent::class, RecordingListener::class);
$context->registerEventListener(CallEndedEvent::class, RecordingListener::class);
$context->registerEventListener(CallEndedForEveryoneEvent::class, RecordingListener::class);
- $context->registerEventListener(TranscriptionSuccessfulEvent::class, RecordingListener::class);
- $context->registerEventListener(TranscriptionFailedEvent::class, RecordingListener::class);
+ $context->registerEventListener(TaskSuccessfulEvent::class, RecordingListener::class);
+ $context->registerEventListener(TaskFailedEvent::class, RecordingListener::class);
// Federation listeners
$context->registerEventListener(BeforeRoomDeletedEvent::class, TalkV1BeforeRoomDeletedListener::class);
diff --git a/lib/Controller/RecordingController.php b/lib/Controller/RecordingController.php
index f42caa1c535..665ba5faa0f 100644
--- a/lib/Controller/RecordingController.php
+++ b/lib/Controller/RecordingController.php
@@ -418,7 +418,8 @@ public function notificationDismiss(int $timestamp): DataResponse {
$this->recordingService->notificationDismiss(
$this->getRoom(),
$this->participant,
- $timestamp
+ $timestamp,
+ null, // FIXME we would/should extend the URL, but the iOS app is crafting it manually atm due to OS limitations
);
} catch (InvalidArgumentException $e) {
return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
@@ -446,7 +447,7 @@ public function shareToChat(int $fileId, int $timestamp): DataResponse {
$this->getRoom(),
$this->participant,
$fileId,
- $timestamp
+ $timestamp,
);
} catch (InvalidArgumentException $e) {
return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
diff --git a/lib/Notification/Notifier.php b/lib/Notification/Notifier.php
index f6ff48d2cf9..4e49f78ecfa 100644
--- a/lib/Notification/Notifier.php
+++ b/lib/Notification/Notifier.php
@@ -240,7 +240,7 @@ public function prepare(INotification $notification, string $languageCode): INot
->setLink($this->url->linkToRouteAbsolute('spreed.Page.showCall', ['token' => $room->getToken()]));
$subject = $notification->getSubject();
- if ($subject === 'record_file_stored' || $subject === 'transcript_file_stored' || $subject === 'transcript_failed') {
+ if ($subject === 'record_file_stored' || $subject === 'transcript_file_stored' || $subject === 'transcript_failed' || $subject === 'summary_file_stored' || $subject === 'summary_failed') {
return $this->parseStoredRecording($notification, $room, $participant, $l);
}
if ($subject === 'record_file_store_fail') {
@@ -363,9 +363,15 @@ protected function parseStoredRecording(
} elseif ($notification->getSubject() === 'transcript_file_stored') {
$subject = $l->t('Transcript now available');
$message = $l->t('The transcript for the call in {call} was uploaded to {file}.');
- } else {
+ } elseif ($notification->getSubject() === 'transcript_failed') {
$subject = $l->t('Failed to transcript call recording');
$message = $l->t('The server failed to transcript the recording at {file} for the call in {call}. Please reach out to the administration.');
+ } elseif ($notification->getSubject() === 'summary_file_stored') {
+ $subject = $l->t('Call summary now available');
+ $message = $l->t('The summary for the call in {call} was uploaded to {file}.');
+ } else {
+ $subject = $l->t('Failed to summarize call recording');
+ $message = $l->t('The server failed to summarize the recording at {file} for the call in {call}. Please reach out to the administration.');
}
$notification
diff --git a/lib/Recording/Listener.php b/lib/Recording/Listener.php
index 75650197ce1..b384cafb4fe 100644
--- a/lib/Recording/Listener.php
+++ b/lib/Recording/Listener.php
@@ -20,11 +20,11 @@
use OCA\Talk\Service\RecordingService;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
-use OCP\Files\File;
use OCP\Files\IRootFolder;
-use OCP\SpeechToText\Events\AbstractTranscriptionEvent;
-use OCP\SpeechToText\Events\TranscriptionFailedEvent;
-use OCP\SpeechToText\Events\TranscriptionSuccessfulEvent;
+use OCP\TaskProcessing\Events\AbstractTaskProcessingEvent;
+use OCP\TaskProcessing\Events\TaskFailedEvent;
+use OCP\TaskProcessing\Events\TaskSuccessfulEvent;
+use Psr\Log\LoggerInterface;
/**
* @template-implements IEventListener
@@ -34,12 +34,17 @@ public function __construct(
protected RecordingService $recordingService,
protected ConsentService $consentService,
protected IRootFolder $rootFolder,
+ protected LoggerInterface $logger,
) {
}
public function handle(Event $event): void {
- if ($event instanceof AbstractTranscriptionEvent) {
- $this->handleTranscriptionEvents($event);
+ if ($event instanceof AbstractTaskProcessingEvent) {
+ try {
+ $this->handleTranscriptionEvents($event);
+ } catch (\Throwable $e) {
+ $this->logger->error('An error occurred while processing recording AI follow-up task', ['exception' => $e]);
+ }
return;
}
@@ -54,40 +59,40 @@ public function handle(Event $event): void {
};
}
- public function handleTranscriptionEvents(AbstractTranscriptionEvent $event): void {
- if ($event->getAppId() !== Application::APP_ID) {
+ public function handleTranscriptionEvents(AbstractTaskProcessingEvent $event): void {
+ $task = $event->getTask();
+ if ($task->getAppId() !== Application::APP_ID) {
return;
}
- if ($event instanceof TranscriptionSuccessfulEvent) {
- $this->successfulTranscript($event->getUserId(), $event->getFile(), $event->getTranscript());
- } elseif ($event instanceof TranscriptionFailedEvent) {
- $this->failedTranscript($event->getUserId(), $event->getFile());
- }
- }
-
- protected function successfulTranscript(?string $owner, ?File $fileNode, string $transcript): void {
- if (!$fileNode instanceof File) {
+ // 'call/transcription/' . $room->getToken()
+ $customId = $task->getCustomId();
+ if (str_starts_with($customId, 'call/transcription/')) {
+ $aiType = 'transcript';
+ $roomToken = substr($customId, strlen('call/transcription/'));
+
+ $fileId = (int)($task->getInput()['input'] ?? null);
+ } elseif (str_starts_with($customId, 'call/summary/')) {
+ $aiType = 'summary';
+ [$roomToken, $fileId] = explode('/', substr($customId, strlen('call/summary/')));
+ $fileId = (int)$fileId;
+ } else {
return;
}
- if ($owner === null) {
+ if ($fileId === 0) {
return;
}
- $this->recordingService->storeTranscript($owner, $fileNode, $transcript);
- }
-
- protected function failedTranscript(?string $owner, ?File $fileNode): void {
- if (!$fileNode instanceof File) {
+ if ($task->getUserId() === null) {
return;
}
- if ($owner === null) {
- return;
+ if ($event instanceof TaskSuccessfulEvent) {
+ $this->recordingService->storeTranscript($task->getUserId(), $roomToken, $fileId, $task->getOutput()['output'] ?? '', $aiType);
+ } elseif ($event instanceof TaskFailedEvent) {
+ $this->recordingService->notifyAboutFailedTranscript($task->getUserId(), $roomToken, $fileId, $aiType);
}
-
- $this->recordingService->notifyAboutFailedTranscript($owner, $fileNode);
}
protected function roomDeleted(RoomDeletedEvent $event): void {
diff --git a/lib/Service/RecordingService.php b/lib/Service/RecordingService.php
index f0ab59f0da0..448e31e01da 100644
--- a/lib/Service/RecordingService.php
+++ b/lib/Service/RecordingService.php
@@ -29,10 +29,13 @@
use OCP\Files\NotPermittedException;
use OCP\IConfig;
use OCP\Notification\IManager;
-use OCP\PreConditionNotMetException;
use OCP\Share\IManager as ShareManager;
use OCP\Share\IShare;
-use OCP\SpeechToText\ISpeechToTextManager;
+use OCP\TaskProcessing\Exception\Exception;
+use OCP\TaskProcessing\IManager as ITaskProcessingManager;
+use OCP\TaskProcessing\Task;
+use OCP\TaskProcessing\TaskTypes\AudioToText;
+use OCP\TaskProcessing\TaskTypes\TextToTextSummary;
use Psr\Log\LoggerInterface;
class RecordingService {
@@ -73,7 +76,7 @@ public function __construct(
protected ChatManager $chatManager,
protected LoggerInterface $logger,
protected BackendNotifier $backendNotifier,
- protected ISpeechToTextManager $speechToTextManager,
+ protected ITaskProcessingManager $taskProcessingManager,
) {
}
@@ -139,42 +142,120 @@ public function store(Room $room, string $owner, array $file): void {
throw new InvalidArgumentException('owner_permission');
}
- if ($this->serverConfig->getAppValue('spreed', 'call_recording_transcription', 'no') === 'no') {
+ $shouldTranscribe = $this->serverConfig->getAppValue('spreed', 'call_recording_transcription', 'no') === 'yes';
+ $shouldSummarize = $this->serverConfig->getAppValue('spreed', 'call_recording_summary', 'no') === 'yes';
+ if (!$shouldTranscribe && !$shouldSummarize) {
+ $this->logger->debug('Skipping transcription and summary of call recording, as both are disabled');
return;
}
+ $supportedTaskTypes = $this->taskProcessingManager->getAvailableTaskTypes();
+ if (!isset($supportedTaskTypes[AudioToText::ID])) {
+ $this->logger->error('Can not transcribe call recording as no Audio2Text task provider is available');
+ return;
+ }
+
+ $task = new Task(
+ AudioToText::ID,
+ ['input' => $fileNode->getId()],
+ Application::APP_ID,
+ $owner,
+ 'call/transcription/' . $room->getToken(),
+ );
+
try {
- $this->speechToTextManager->scheduleFileTranscription($fileNode, $owner, Application::APP_ID);
- $this->logger->debug('Scheduled transcription of call recording');
- } catch (PreConditionNotMetException $e) {
- // No Speech-to-text provider installed
- $this->logger->debug('Could not generate transcript of call recording', ['exception' => $e]);
- } catch (InvalidArgumentException $e) {
- $this->logger->warning('Could not generate transcript of call recording', ['exception' => $e]);
+ $this->taskProcessingManager->scheduleTask($task);
+ $this->logger->debug('Scheduled call recording transcript');
+ } catch (Exception $e) {
+ $this->logger->error('An error occurred while trying to transcribe the call recording', ['exception' => $e]);
}
}
- public function storeTranscript(string $owner, File $recording, string $transcript): void {
+ /**
+ * @param 'transcript'|'summary' $aiTask
+ */
+ public function storeTranscript(string $owner, string $roomToken, int $recordingFileId, string $output, string $aiTask): void {
+ $userFolder = $this->rootFolder->getUserFolder($owner);
+ $recordingNodes = $userFolder->getById($recordingFileId);
+
+ if (empty($recordingNodes)) {
+ $this->logger->warning("Could not save recording $aiTask as the recording could not be found", [
+ 'owner' => $owner,
+ 'roomToken' => $roomToken,
+ 'recordingFileId' => $recordingFileId,
+ ]);
+ throw new InvalidArgumentException('owner_participant');
+ }
+ $recording = array_pop($recordingNodes);
$recordingFolder = $recording->getParent();
- $roomToken = $recordingFolder->getName();
+
+ if ($recordingFolder->getName() !== $roomToken) {
+ $this->logger->warning("Could not determinate conversation when trying to store $aiTask of call recording, as folder name did not match customId conversation token");
+ throw new InvalidArgumentException('owner_participant');
+ }
try {
$room = $this->roomManager->getRoomForUserByToken($roomToken, $owner);
$participant = $this->participantService->getParticipant($room, $owner);
} catch (ParticipantNotFoundException) {
- $this->logger->warning('Could not determinate conversation when trying to store transcription of call recording');
+ $this->logger->warning("Could not determinate conversation when trying to store $aiTask of call recording");
throw new InvalidArgumentException('owner_participant');
}
- $transcriptFileName = pathinfo($recording->getName(), PATHINFO_FILENAME) . '.md';
+ $shouldTranscribe = $this->serverConfig->getAppValue('spreed', 'call_recording_transcription', 'no') === 'yes';
+ $shouldSummarize = $this->serverConfig->getAppValue('spreed', 'call_recording_summary', 'no') === 'yes';
+
+ if ($aiTask === 'transcript') {
+ $transcriptFileName = pathinfo($recording->getName(), PATHINFO_FILENAME) . '.md';
+ if (!$shouldTranscribe) {
+ $this->logger->debug('Skipping saving of transcript for call recording as it is disabled');
+ }
+ } else {
+ $transcriptFileName = pathinfo($recording->getName(), PATHINFO_FILENAME) . ' - ' . $aiTask . '.md';
+ }
+
+ if (($shouldTranscribe && $aiTask === 'transcript')
+ || ($shouldSummarize && $aiTask === 'summary')) {
+ try {
+ $fileNode = $recordingFolder->newFile($transcriptFileName, $output);
+ $this->notifyStoredTranscript($room, $participant, $fileNode, $aiTask);
+ } catch (NoUserException) {
+ throw new InvalidArgumentException('owner_invalid');
+ } catch (NotPermittedException) {
+ throw new InvalidArgumentException('owner_permission');
+ }
+ }
+
+ if (!$shouldSummarize) {
+ // If summary is off skip scheduling it
+ $this->logger->debug('Skipping scheduling summary of call recording as it is disabled');
+ return;
+ }
+
+ if ($aiTask === 'summary') {
+ // After saving the summary there is nothing more to do
+ return;
+ }
+
+ $supportedTaskTypes = $this->taskProcessingManager->getAvailableTaskTypes();
+ if (!isset($supportedTaskTypes[TextToTextSummary::ID])) {
+ $this->logger->error('Can not summarize call recording as no TextToTextSummary task provider is available');
+ return;
+ }
+
+ $task = new Task(
+ TextToTextSummary::ID,
+ ['input' => $output],
+ Application::APP_ID,
+ $owner,
+ 'call/summary/' . $room->getToken() . '/' . $recordingFileId,
+ );
try {
- $fileNode = $recordingFolder->newFile($transcriptFileName, $transcript);
- $this->notifyStoredTranscript($room, $participant, $fileNode);
- } catch (NoUserException) {
- throw new InvalidArgumentException('owner_invalid');
- } catch (NotPermittedException) {
- throw new InvalidArgumentException('owner_permission');
+ $this->taskProcessingManager->scheduleTask($task);
+ $this->logger->debug('Scheduled call recording summary');
+ } catch (Exception $e) {
+ $this->logger->error('An error occurred while trying to summarize the call recording', ['exception' => $e]);
}
}
@@ -207,15 +288,31 @@ public function notifyAboutFailedStore(Room $room): void {
$this->notificationManager->notify($notification);
}
- public function notifyAboutFailedTranscript(string $owner, File $recording): void {
+ public function notifyAboutFailedTranscript(string $owner, string $roomToken, int $recordingFileId, string $aiType): void {
+ $userFolder = $this->rootFolder->getUserFolder($owner);
+ $recordingNodes = $userFolder->getById($recordingFileId);
+
+ if (empty($recordingNodes)) {
+ $this->logger->warning("Could not trying to notify about failed $aiType as the recording could not be found", [
+ 'owner' => $owner,
+ 'roomToken' => $roomToken,
+ 'recordingFileId' => $recordingFileId,
+ ]);
+ throw new InvalidArgumentException('owner_participant');
+ }
+ $recording = array_pop($recordingNodes);
$recordingFolder = $recording->getParent();
- $roomToken = $recordingFolder->getName();
+
+ if ($recordingFolder->getName() !== $roomToken) {
+ $this->logger->warning("Could not determinate conversation when trying to notify about failed $aiType, as folder name did not match customId conversation token");
+ throw new InvalidArgumentException('owner_participant');
+ }
try {
$room = $this->roomManager->getRoomForUserByToken($roomToken, $owner);
$participant = $this->participantService->getParticipant($room, $owner);
} catch (ParticipantNotFoundException) {
- $this->logger->warning('Could not determinate conversation when trying to notify about failed transcription of call recording');
+ $this->logger->warning("Could not determinate conversation when trying to notify about failed $aiType of call recording");
throw new InvalidArgumentException('owner_participant');
}
@@ -228,7 +325,7 @@ public function notifyAboutFailedTranscript(string $owner, File $recording): voi
->setDateTime($this->timeFactory->getDateTime())
->setObject('recording', $room->getToken())
->setUser($attendee->getActorId())
- ->setSubject('transcript_failed', [
+ ->setSubject($aiType === 'transcript' ? 'transcript_failed' : 'summary_failed', [
'objectId' => $recording->getId(),
]);
$this->notificationManager->notify($notification);
@@ -342,7 +439,10 @@ public function notifyStoredRecording(Room $room, Participant $participant, File
}
- public function notifyStoredTranscript(Room $room, Participant $participant, File $file): void {
+ /**
+ * @param 'transcript'|'summary' $aiType
+ */
+ public function notifyStoredTranscript(Room $room, Participant $participant, File $file, string $aiType): void {
$attendee = $participant->getAttendee();
$notification = $this->notificationManager->createNotification();
@@ -352,20 +452,26 @@ public function notifyStoredTranscript(Room $room, Participant $participant, Fil
->setDateTime($this->timeFactory->getDateTime())
->setObject('recording', $room->getToken())
->setUser($attendee->getActorId())
- ->setSubject('transcript_file_stored', [
+ ->setSubject($aiType === 'transcript' ? 'transcript_file_stored' : 'summary_file_stored', [
'objectId' => $file->getId(),
]);
$this->notificationManager->notify($notification);
}
- public function notificationDismiss(Room $room, Participant $participant, int $timestamp): void {
+ public function notificationDismiss(Room $room, Participant $participant, int $timestamp, ?string $notificationSubject): void {
$notification = $this->notificationManager->createNotification();
$notification->setApp('spreed')
->setObject('recording', $room->getToken())
->setDateTime($this->timeFactory->getDateTime('@' . $timestamp))
->setUser($participant->getAttendee()->getActorId());
- foreach (['record_file_stored', 'transcript_file_stored'] as $subject) {
+ if ($notificationSubject === null) {
+ $subjects = ['record_file_stored', 'transcript_file_stored', 'summary_file_stored'];
+ } else {
+ $subjects = [$notificationSubject];
+ }
+
+ foreach ($subjects as $subject) {
$notification->setSubject($subject);
$this->notificationManager->markProcessed($notification);
}
@@ -383,8 +489,8 @@ public function shareToChat(Room $room, Participant $participant, int $fileId, i
$userFolder = $this->rootFolder->getUserFolder(
$participant->getAttendee()->getActorId()
);
- /** @var \OCP\Files\File[] */
$files = $userFolder->getById($fileId);
+ /** @var \OCP\Files\File $file */
$file = array_shift($files);
} catch (\Throwable $th) {
throw new InvalidArgumentException('file');
@@ -401,6 +507,15 @@ public function shareToChat(Room $room, Participant $participant, int $fileId, i
->setSharedWith($room->getToken())
->setPermissions(\OCP\Constants::PERMISSION_READ);
+ $removeNotification = null;
+ if (!str_ends_with($file->getName(), '.md')) {
+ $removeNotification = 'record_file_stored';
+ } elseif (!str_ends_with($file->getName(), ' - summary.md')) {
+ $removeNotification = 'transcript_file_stored';
+ } elseif (str_ends_with($file->getName(), ' - summary.md')) {
+ $removeNotification = 'summary_file_stored';
+ }
+
$share = $this->shareManager->createShare($share);
$message = json_encode([
@@ -427,6 +542,6 @@ public function shareToChat(Room $room, Participant $participant, int $fileId, i
$this->logger->error($e->getMessage(), ['exception' => $e]);
throw new InvalidArgumentException('system');
}
- $this->notificationDismiss($room, $participant, $timestamp);
+ $this->notificationDismiss($room, $participant, $timestamp, $removeNotification);
}
}
diff --git a/tests/integration/features/bootstrap/FeatureContext.php b/tests/integration/features/bootstrap/FeatureContext.php
index 3b894166848..7907c70dcf7 100644
--- a/tests/integration/features/bootstrap/FeatureContext.php
+++ b/tests/integration/features/bootstrap/FeatureContext.php
@@ -3943,6 +3943,7 @@ public function enableTestingApp(): void {
$this->taskProcessingProviderPreference[$this->currentServer] = $this->lastStdOut;
$preferences = json_decode($this->lastStdOut ?: '[]', true, flags: JSON_THROW_ON_ERROR);
$preferences['core:text2text:summary'] = 'testing-text2text-summary';
+ $preferences['core:audio2text'] = 'testing-audio2text';
$this->runOcc(['config:app:set', 'core', 'ai.taskprocessing_provider_preferences', '--value', json_encode($preferences)]);
$this->setCurrentUser($currentUser);
diff --git a/tests/integration/features/callapi/recording.feature b/tests/integration/features/callapi/recording.feature
index 66d548b7d3f..f3081cca87f 100644
--- a/tests/integration/features/callapi/recording.feature
+++ b/tests/integration/features/callapi/recording.feature
@@ -448,8 +448,10 @@ Feature: callapi/recording
| 2 | room1 | 0 |
Scenario: Store recording with success and create transcript
+ Given Fake summary task provider is enabled
Given the following spreed app config is set
| call_recording_transcription | yes |
+ | call_recording_summary | yes |
Given user "participant1" creates room "room1" (v4)
| roomType | 2 |
| roomName | room1 |
@@ -461,9 +463,10 @@ Feature: callapi/recording
And user "participant1" is participant of the following unordered rooms (v4)
| type | name | callRecording |
| 2 | room1 | 0 |
- When run "OC\SpeechToText\TranscriptionJob" background jobs
+ And repeating run "OC\TaskProcessing\SynchronousBackgroundJob" background jobs
Then user "participant1" has the following notifications
| app | object_type | object_id | subject | message |
+ | spreed | recording | room1 | Call summary now available | The summary for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/join_call - summary.md. |
| spreed | recording | room1 | Transcript now available | The transcript for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/join_call.md. |
| spreed | recording | room1 | Call recording now available | The recording for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/join_call.ogg. |
When user "participant1" shares file from the last notification to room "room1" with 200 (v1)
@@ -475,7 +478,12 @@ Feature: callapi/recording
| room1 | users | participant1 | participant1-displayname | record-audio | {file} | "IGNORE" |
Then user "participant1" has the following notifications
| app | object_type | object_id | subject | message |
+ | spreed | recording | room1 | Call summary now available | The summary for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/join_call - summary.md. |
| spreed | recording | room1 | Transcript now available | The transcript for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/join_call.md. |
+ When user "participant1" shares file from the last notification to room "room1" with 200 (v1)
+ Then user "participant1" has the following notifications
+ | app | object_type | object_id | subject | message |
+ | spreed | recording | room1 | Call summary now available | The summary for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/join_call - summary.md. |
When user "participant1" shares file from the first notification to room "room1" with 200 (v1)
Then user "participant1" has the following notifications
| app | object_type | object_id | subject | message |
@@ -486,15 +494,19 @@ Feature: callapi/recording
| room | actorType | actorId | actorDisplayName | messageType | message | messageParameters |
| room1 | users | participant1 | participant1-displayname | record-audio | {file} | "IGNORE" |
| room1 | users | participant1 | participant1-displayname | record-audio | {file} | "IGNORE" |
+ | room1 | users | participant1 | participant1-displayname | record-audio | {file} | "IGNORE" |
Scenario: Store recording with success but fail to transcript
+ Given Fake summary task provider is enabled
Given the following spreed app config is set
| call_recording_transcription | yes |
+ | call_recording_summary | yes |
+ Given the following testing app config is set
+ | fail-testing-audio2text | yes |
Given user "participant1" creates room "room1" (v4)
| roomType | 2 |
| roomName | room1 |
And user "participant1" joins room "room1" with 200 (v4)
- # "leave" is used here as the file name makes the fake transcript provider fail
When user "participant1" store recording file "/img/leave_call.ogg" in room "room1" with 200 (v1)
Then user "participant1" has the following notifications
| app | object_type | object_id | subject | message |
@@ -502,12 +514,81 @@ Feature: callapi/recording
And user "participant1" is participant of the following unordered rooms (v4)
| type | name | callRecording |
| 2 | room1 | 0 |
- When run "OC\SpeechToText\TranscriptionJob" background jobs
+ And repeating run "OC\TaskProcessing\SynchronousBackgroundJob" background jobs
Then user "participant1" has the following notifications
| app | object_type | object_id | subject | message |
| spreed | recording | room1 | Failed to transcript call recording | The server failed to transcript the recording at /Talk/Recording/ROOM(room1)/leave_call.ogg for the call in room1. Please reach out to the administration. |
| spreed | recording | room1 | Call recording now available | The recording for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/leave_call.ogg. |
+ Scenario: Store recording and transcript with success but fail to summarize
+ Given Fake summary task provider is enabled
+ Given the following spreed app config is set
+ | call_recording_transcription | yes |
+ | call_recording_summary | yes |
+ Given the following testing app config is set
+ | fail-testing-text2text-summary | yes |
+ Given user "participant1" creates room "room1" (v4)
+ | roomType | 2 |
+ | roomName | room1 |
+ And user "participant1" joins room "room1" with 200 (v4)
+ When user "participant1" store recording file "/img/leave_call.ogg" in room "room1" with 200 (v1)
+ Then user "participant1" has the following notifications
+ | app | object_type | object_id | subject | message |
+ | spreed | recording | room1 | Call recording now available | The recording for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/leave_call.ogg. |
+ And user "participant1" is participant of the following unordered rooms (v4)
+ | type | name | callRecording |
+ | 2 | room1 | 0 |
+ And repeating run "OC\TaskProcessing\SynchronousBackgroundJob" background jobs
+ Then user "participant1" has the following notifications
+ | app | object_type | object_id | subject | message |
+ | spreed | recording | room1 | Failed to summarize call recording | The server failed to summarize the recording at /Talk/Recording/ROOM(room1)/leave_call.ogg for the call in room1. Please reach out to the administration. |
+ | spreed | recording | room1 | Transcript now available | The transcript for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/leave_call.md. |
+ | spreed | recording | room1 | Call recording now available | The recording for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/leave_call.ogg. |
+
+ Scenario: Store recording and transcript with success but summarize is off
+ Given Fake summary task provider is enabled
+ Given the following spreed app config is set
+ | call_recording_transcription | yes |
+ | call_recording_summary | no |
+ Given user "participant1" creates room "room1" (v4)
+ | roomType | 2 |
+ | roomName | room1 |
+ And user "participant1" joins room "room1" with 200 (v4)
+ When user "participant1" store recording file "/img/leave_call.ogg" in room "room1" with 200 (v1)
+ Then user "participant1" has the following notifications
+ | app | object_type | object_id | subject | message |
+ | spreed | recording | room1 | Call recording now available | The recording for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/leave_call.ogg. |
+ And user "participant1" is participant of the following unordered rooms (v4)
+ | type | name | callRecording |
+ | 2 | room1 | 0 |
+ And repeating run "OC\TaskProcessing\SynchronousBackgroundJob" background jobs
+ Then user "participant1" has the following notifications
+ | app | object_type | object_id | subject | message |
+ | spreed | recording | room1 | Transcript now available | The transcript for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/leave_call.md. |
+ | spreed | recording | room1 | Call recording now available | The recording for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/leave_call.ogg. |
+
+ Scenario: Store recording and summarize with success but transcript is off
+ Given Fake summary task provider is enabled
+ Given the following spreed app config is set
+ | call_recording_transcription | no |
+ | call_recording_summary | yes |
+ Given user "participant1" creates room "room1" (v4)
+ | roomType | 2 |
+ | roomName | room1 |
+ And user "participant1" joins room "room1" with 200 (v4)
+ When user "participant1" store recording file "/img/join_call.ogg" in room "room1" with 200 (v1)
+ Then user "participant1" has the following notifications
+ | app | object_type | object_id | subject | message |
+ | spreed | recording | room1 | Call recording now available | The recording for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/join_call.ogg. |
+ And user "participant1" is participant of the following unordered rooms (v4)
+ | type | name | callRecording |
+ | 2 | room1 | 0 |
+ And repeating run "OC\TaskProcessing\SynchronousBackgroundJob" background jobs
+ Then user "participant1" has the following notifications
+ | app | object_type | object_id | subject | message |
+ | spreed | recording | room1 | Call summary now available | The summary for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/join_call - summary.md. |
+ | spreed | recording | room1 | Call recording now available | The recording for the call in room1 was uploaded to /Talk/Recording/ROOM(room1)/join_call.ogg. |
+
Scenario: Store recording with failure exceeding the upload_max_filesize
Given user "participant1" creates room "room1" (v4)
| roomType | 2 |
diff --git a/tests/php/Service/RecordingServiceTest.php b/tests/php/Service/RecordingServiceTest.php
index 4fe8c62c351..1503a0ac2fa 100644
--- a/tests/php/Service/RecordingServiceTest.php
+++ b/tests/php/Service/RecordingServiceTest.php
@@ -35,7 +35,7 @@ function is_uploaded_file($filename) {
use OCP\IConfig;
use OCP\Notification\IManager;
use OCP\Share\IManager as ShareManager;
-use OCP\SpeechToText\ISpeechToTextManager;
+use OCP\TaskProcessing\IManager as ITaskProcessingManager;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Test\TestCase;
@@ -55,7 +55,7 @@ class RecordingServiceTest extends TestCase {
protected ChatManager&MockObject $chatManager;
protected LoggerInterface&MockObject $logger;
protected BackendNotifier&MockObject $backendNotifier;
- protected ISpeechToTextManager&MockObject $speechToTextManager;
+ protected ITaskProcessingManager&MockObject $taskProcessingManager;
protected RecordingService $recordingService;
public function setUp(): void {
@@ -75,7 +75,7 @@ public function setUp(): void {
$this->chatManager = $this->createMock(ChatManager::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->backendNotifier = $this->createMock(BackendNotifier::class);
- $this->speechToTextManager = $this->createMock(ISpeechToTextManager::class);
+ $this->taskProcessingManager = $this->createMock(ITaskProcessingManager::class);
$this->recordingService = new RecordingService(
$this->mimeTypeDetector,
@@ -92,7 +92,7 @@ public function setUp(): void {
$this->chatManager,
$this->logger,
$this->backendNotifier,
- $this->speechToTextManager,
+ $this->taskProcessingManager,
);
}