From 587a5bc574249625b77326b2d097016513ce9501 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Mon, 29 Dec 2025 17:30:02 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20allow=20starting=20both?= =?UTF-8?q?=20a=20recording=20and=20a=20transcription?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major user feature request: allow starting recording and transcription simultaneously. Inspired by Google Meet UX, add a subtle checkbox letting users start a recording alongside transcription. The backend support for this feature is not yet implemented and will come in upcoming commits, I can only pass the options to the API. The update of the notification service will be handled later. We’re half way with a functional feature. This is not enabled by default because screen recording is resource-intensive. I prefer users opt in rather than making it their default choice until feature usage and performance stabilize. --- src/backend/core/api/serializers.py | 6 ++++++ src/backend/core/api/viewsets.py | 5 ++++- .../features/recording/api/startRecording.ts | 3 +++ .../components/TranscriptSidePanel.tsx | 19 ++++++++++++++++++- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/backend/core/api/serializers.py b/src/backend/core/api/serializers.py index b1fd406b..d4ce5905 100644 --- a/src/backend/core/api/serializers.py +++ b/src/backend/core/api/serializers.py @@ -181,6 +181,7 @@ class RecordingSerializer(serializers.ModelSerializer): "updated_at", "status", "mode", + "options", "key", "is_expired", "expired_at", @@ -212,6 +213,11 @@ class StartRecordingSerializer(BaseValidationOnlySerializer): "screen_recording or transcript.", }, ) + options = serializers.JSONField( + required=False, + allow_null=True, + default=dict, + ) class RequestEntrySerializer(BaseValidationOnlySerializer): diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 55578e9e..0d1349ed 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -308,10 +308,13 @@ class RoomViewSet( ) mode = serializer.validated_data["mode"] + options = serializer.validated_data["options"] room = self.get_object() # May raise exception if an active or initiated recording already exist for the room - recording = models.Recording.objects.create(room=room, mode=mode) + recording = models.Recording.objects.create( + room=room, mode=mode, options=options + ) models.RecordingAccess.objects.create( user=self.request.user, role=models.RoleChoices.OWNER, recording=recording diff --git a/src/frontend/src/features/recording/api/startRecording.ts b/src/frontend/src/features/recording/api/startRecording.ts index 9924f9b0..d6ba26ac 100644 --- a/src/frontend/src/features/recording/api/startRecording.ts +++ b/src/frontend/src/features/recording/api/startRecording.ts @@ -7,16 +7,19 @@ import { RecordingMode } from '../types' export interface StartRecordingParams { id: string mode?: RecordingMode + options?: Record } const startRecording = ({ id, mode = RecordingMode.Transcript, + options, }: StartRecordingParams): Promise => { return fetchApi(`rooms/${id}/start-recording/`, { method: 'POST', body: JSON.stringify({ mode: mode, + options: options, }), }) } diff --git a/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx b/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx index 16467365..57900df5 100644 --- a/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx +++ b/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx @@ -40,6 +40,7 @@ export const TranscriptSidePanel = () => { const { t } = useTranslation('rooms', { keyPrefix: 'transcript' }) const [isErrorDialogOpen, setIsErrorDialogOpen] = useState('') + const [includeScreenRecording, setIncludeScreenRecording] = useState(false) const recordingSnap = useSnapshot(recordingStore) @@ -99,6 +100,7 @@ export const TranscriptSidePanel = () => { setIsLoading(true) if (room.isRecording) { await stopRecordingRoom({ id: roomId }) + setIncludeScreenRecording(false) recordingStore.status = RecordingStatus.TRANSCRIPT_STOPPING await notifyParticipants({ type: NotificationType.TranscriptionStopped, @@ -108,7 +110,20 @@ export const TranscriptSidePanel = () => { room.localParticipant ) } else { - await startRecordingRoom({ id: roomId, mode: RecordingMode.Transcript }) + const recordingMode = includeScreenRecording + ? RecordingMode.ScreenRecording + : RecordingMode.Transcript + + const recordingOptions = { + language: 'fr', // fix hardcoded language + ...(includeScreenRecording && { transcribe: true }), + } + + await startRecordingRoom({ + id: roomId, + mode: recordingMode, + options: recordingOptions, + }) recordingStore.status = RecordingStatus.TRANSCRIPT_STARTING await notifyParticipants({ type: NotificationType.TranscriptionStarted, @@ -454,6 +469,8 @@ export const TranscriptSidePanel = () => { >