From 7665de1d0ca7b3c51a7960517ad53fffe62609ea Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Fri, 10 Oct 2025 23:34:03 +0200 Subject: [PATCH] wip create a temporary service to trigger the metadata agent --- src/backend/core/api/viewsets.py | 13 +++ .../recording/services/metadata_extractor.py | 97 +++++++++++++++++++ src/backend/core/services/livekit_events.py | 15 ++- src/backend/meet/settings.py | 10 ++ .../dev-keycloak/values.meet.yaml.gotmpl | 1 + 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/backend/core/recording/services/metadata_extractor.py diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 55578e9e..3bbcf25b 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -31,6 +31,10 @@ from core.recording.event.exceptions import ( ) from core.recording.event.notification import notification_service from core.recording.event.parsers import get_parser +from core.recording.services.metadata_extractor import ( + MetadataExtractorException, + MetadataExtractorService, +) from core.recording.worker.exceptions import ( RecordingStartError, RecordingStopError, @@ -328,6 +332,15 @@ class RoomViewSet( status=drf_status.HTTP_500_INTERNAL_SERVER_ERROR, ) + if ( + settings.ROOM_METADATA_EXTRACTOR_ENABLED + and recording.mode == models.RecordingModeChoices.TRANSCRIPT + ): + try: + MetadataExtractorService().start(recording) + except MetadataExtractorException: + pass + return drf_response.Response( {"message": f"Recording successfully started for room {room.slug}"}, status=drf_status.HTTP_201_CREATED, diff --git a/src/backend/core/recording/services/metadata_extractor.py b/src/backend/core/recording/services/metadata_extractor.py new file mode 100644 index 00000000..5b6ae881 --- /dev/null +++ b/src/backend/core/recording/services/metadata_extractor.py @@ -0,0 +1,97 @@ +"""Wip.""" + +from logging import getLogger + +from django.conf import settings + +from asgiref.sync import async_to_sync +from livekit.protocol.agent_dispatch import ( + CreateAgentDispatchRequest, +) + +from core import utils + +logger = getLogger(__name__) + + +class MetadataExtractorException(Exception): + """Wip.""" + + +class MetadataExtractorService: + """Wip.""" + + @async_to_sync + async def start(self, recording): + """Wip.""" + + lkapi = utils.create_livekit_client() + room_id = str(recording.room.id) + + try: + response = await lkapi.agent_dispatch.create_dispatch( + CreateAgentDispatchRequest( + agent_name=settings.ROOM_METADATA_EXTRACTOR_AGENT_NAME, + room=room_id, + metadata=str(recording.id), + ) + ) + except Exception as e: + logger.exception( + "Failed to create metadata extractor agent for room %s", room_id + ) + raise MetadataExtractorException( + "Failed to create metadata extractor agent" + ) from e + finally: + await lkapi.aclose() + + dispatch_id = getattr(response, "id", None) + + if not dispatch_id: + logger.error("LiveKit response missing dispatch ID for room %s", room_id) + raise MetadataExtractorException( + f"LiveKit did not return a dispatch_id for room {room_id}" + ) + + return dispatch_id + + @async_to_sync + async def stop(self, recording): + """Wip.""" + + room_name = str(recording.room.id) + lkapi = utils.create_livekit_client() + + try: + dispatches = await lkapi.agent_dispatch.list_dispatch(room_name=room_name) + + dispatch_id = next( + ( + d.id + for d in dispatches + if d.agent_name == settings.ROOM_METADATA_EXTRACTOR_AGENT_NAME + ), + None, + ) + + if not dispatch_id: + logger.warning( + "No metadata extractor agent found for room %s", room_name + ) + return None + + await lkapi.agent_dispatch.delete_dispatch( + dispatch_id=str(dispatch_id), room_name=room_name + ) + + except Exception as e: + logger.exception( + "Failed to stop metadata extractor agent dispatch for room %s", + room_name, + ) + raise MetadataExtractorException( + f"Failed to stop metadata metadata extractor agent for room {room_name}" + ) from e + finally: + await lkapi.aclose() diff --git a/src/backend/core/services/livekit_events.py b/src/backend/core/services/livekit_events.py index 980c49c9..2d588274 100644 --- a/src/backend/core/services/livekit_events.py +++ b/src/backend/core/services/livekit_events.py @@ -11,6 +11,10 @@ from django.conf import settings from livekit import api from core import models +from core.recording.services.metadata_extractor import ( + MetadataExtractorException, + MetadataExtractorService, +) from core.recording.services.recording_events import ( RecordingEventsError, RecordingEventsService, @@ -126,7 +130,7 @@ class LiveKitEventsService: """Handle 'egress_ended' event.""" try: - recording = models.Recording.objects.get( + recording = models.Recording.objects.select_related("room").get( worker_id=data.egress_info.egress_id ) except models.Recording.DoesNotExist as err: @@ -134,6 +138,15 @@ class LiveKitEventsService: f"Recording with worker ID {data.egress_info.egress_id} does not exist" ) from err + if ( + settings.ROOM_METADATA_EXTRACTOR_ENABLED + and recording.mode == models.RecordingModeChoices.TRANSCRIPT + ): + try: + MetadataExtractorService().stop(recording) + except MetadataExtractorException: + pass + if ( data.egress_info.status == api.EgressStatus.EGRESS_LIMIT_REACHED and recording.status == models.RecordingStatusChoices.ACTIVE diff --git a/src/backend/meet/settings.py b/src/backend/meet/settings.py index f835d209..eddc757f 100755 --- a/src/backend/meet/settings.py +++ b/src/backend/meet/settings.py @@ -668,6 +668,16 @@ class Base(Configuration): environ_prefix=None, ) + # Metadata Extractor settings + ROOM_METADATA_EXTRACTOR_ENABLED = values.BooleanValue( + False, environ_name="ROOM_METADATA_EXTRACTOR_ENABLED", environ_prefix=None + ) + ROOM_METADATA_EXTRACTOR_AGENT_NAME = values.Value( + "metadata-extractor", + environ_name="ROOM_METADATA_EXTRACTOR_AGENT_NAME", + environ_prefix=None, + ) + # External Applications APPLICATION_CLIENT_ID_LENGTH = values.PositiveIntegerValue( 40, diff --git a/src/helm/env.d/dev-keycloak/values.meet.yaml.gotmpl b/src/helm/env.d/dev-keycloak/values.meet.yaml.gotmpl index 98cd9f7e..d08c1d29 100644 --- a/src/helm/env.d/dev-keycloak/values.meet.yaml.gotmpl +++ b/src/helm/env.d/dev-keycloak/values.meet.yaml.gotmpl @@ -73,6 +73,7 @@ backend: ROOM_TELEPHONY_PHONE_NUMBER: '+33901020304' SSL_CERT_FILE: /usr/local/lib/python3.13/site-packages/certifi/cacert.pem ROOM_SUBTITLE_ENABLED: True + ROOM_METADATA_EXTRACTOR_ENABLED: True migrate: