diff --git a/server/reflector/app.py b/server/reflector/app.py index 84ed2ea8..cebe3b36 100644 --- a/server/reflector/app.py +++ b/server/reflector/app.py @@ -11,7 +11,6 @@ from reflector.events import subscribers_shutdown, subscribers_startup from reflector.logger import logger from reflector.metrics import metrics_init from reflector.settings import settings -from reflector.views.meetings import router as meetings_router from reflector.views.rooms import router as rooms_router from reflector.views.rtc_offer import router as rtc_offer_router from reflector.views.transcripts import router as transcripts_router @@ -70,7 +69,6 @@ metrics_init(app, instrumentator) # register views app.include_router(rtc_offer_router) -app.include_router(meetings_router, prefix="/v1") app.include_router(rooms_router, prefix="/v1") app.include_router(transcripts_router, prefix="/v1") app.include_router(transcripts_audio_router, prefix="/v1") diff --git a/server/reflector/db/__init__.py b/server/reflector/db/__init__.py index 3378d0c0..4806e377 100644 --- a/server/reflector/db/__init__.py +++ b/server/reflector/db/__init__.py @@ -7,7 +7,6 @@ database = databases.Database(settings.DATABASE_URL) metadata = sqlalchemy.MetaData() # import models -import reflector.db.meetings # noqa import reflector.db.rooms # noqa import reflector.db.transcripts # noqa diff --git a/server/reflector/settings.py b/server/reflector/settings.py index a8b232d0..d5032e58 100644 --- a/server/reflector/settings.py +++ b/server/reflector/settings.py @@ -137,5 +137,9 @@ class Settings(BaseSettings): WHEREBY_API_KEY: str | None = None + AWS_WHEREBY_S3_BUCKET: str | None = None + AWS_WHEREBY_ACCESS_KEY_ID: str | None = None + AWS_WHEREBY_ACCESS_KEY_SECRET: str | None = None + settings = Settings() diff --git a/server/reflector/views/meetings.py b/server/reflector/views/meetings.py deleted file mode 100644 index d3a79a8c..00000000 --- a/server/reflector/views/meetings.py +++ /dev/null @@ -1,56 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import Annotated, Optional - -import reflector.auth as auth -from fastapi import APIRouter, Depends -from pydantic import BaseModel -from reflector.db.meetings import meetings_controller -from reflector.whereby import create_meeting - -router = APIRouter() - - -class GetMeeting(BaseModel): - id: str - room_name: str - room_url: str - host_room_url: str - viewer_room_url: str - start_date: datetime - end_date: datetime - - -@router.get("/meetings/{meeting_id}", response_model=GetMeeting) -async def meeting_get( - meeting_id: str, - user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)], -): - user_id = user["sub"] if user else None - return await meetings_controller.get_by_id_for_http(meeting_id, user_id=user_id) - - -@router.post("/meetings/", response_model=GetMeeting) -async def meeting_create( - room_id: str, - user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)], -): - user_id = user["sub"] if user else None - meeting = await meetings_controller.get_latest(room_id) - if meeting is None: - start_date = datetime.now(timezone.utc) - end_date = start_date + timedelta(hours=1) - meeting = await create_meeting("", start_date=start_date, end_date=end_date) - - meeting = await meetings_controller.add( - id=meeting["meetingId"], - room_name=meeting["roomName"], - room_url=meeting["roomUrl"], - host_room_url=meeting["hostRoomUrl"], - viewer_room_url=meeting["viewerRoomUrl"], - start_date=datetime.fromisoformat(meeting["startDate"]), - end_date=datetime.fromisoformat(meeting["endDate"]), - user_id=user_id, - room_id=room_id, - ) - - return await meetings_controller.get_by_id_for_http(meeting.id, user_id=user_id) diff --git a/server/reflector/views/rooms.py b/server/reflector/views/rooms.py index a122dbe4..116183cd 100644 --- a/server/reflector/views/rooms.py +++ b/server/reflector/views/rooms.py @@ -11,7 +11,6 @@ from reflector.db import database from reflector.db.meetings import meetings_controller from reflector.db.rooms import rooms_controller from reflector.settings import settings -from reflector.views.meetings import GetMeeting from reflector.whereby import create_meeting router = APIRouter() @@ -24,6 +23,16 @@ class Room(BaseModel): created_at: datetime +class Meeting(BaseModel): + id: str + room_name: str + room_url: str + host_room_url: str + viewer_room_url: str + start_date: datetime + end_date: datetime + + class CreateRoom(BaseModel): name: str @@ -76,7 +85,7 @@ async def rooms_delete( return DeletionStatus(status="ok") -@router.post("/rooms/{room_name}/meeting", response_model=GetMeeting) +@router.post("/rooms/{room_name}/meeting", response_model=Meeting) async def rooms_create_meeting( room_name: str, user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)], diff --git a/server/reflector/views/transcripts.py b/server/reflector/views/transcripts.py index 0ef17c88..354862c4 100644 --- a/server/reflector/views/transcripts.py +++ b/server/reflector/views/transcripts.py @@ -7,7 +7,6 @@ from fastapi_pagination import Page from fastapi_pagination.ext.databases import paginate from jose import jwt from pydantic import BaseModel, Field -from reflector.db.meetings import meetings_controller from reflector.db.transcripts import ( TranscriptParticipant, TranscriptTopic, @@ -111,37 +110,6 @@ async def transcripts_create( ) -@router.post("/transcripts/meeting", response_model=GetTranscript) -async def transcripts_create_meeting( - info: CreateTranscript, - user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)], -): - user_id = user["sub"] if user else None - start_date = datetime.now(timezone.utc) - end_date = start_date + timedelta(hours=1) - meeting = await create_meeting("", start_date=start_date, end_date=end_date) - - meeting = await meetings_controller.create( - id=meeting["meetingId"], - room_name=meeting["roomName"], - room_url=meeting["roomUrl"], - host_room_url=meeting["hostRoomUrl"], - viewer_room_url=meeting["viewerRoomUrl"], - start_date=datetime.fromisoformat(meeting["startDate"]), - end_date=datetime.fromisoformat(meeting["endDate"]), - user_id=user_id, - ) - - return await transcripts_controller.add( - "", - source_language=info.source_language, - target_language=info.target_language, - user_id=user_id, - meeting_id=meeting.id, - share_mode="public", - ) - - # ============================================================== # Single transcript # ============================================================== diff --git a/server/reflector/whereby.py b/server/reflector/whereby.py index 46fdbff9..2f1efeb0 100644 --- a/server/reflector/whereby.py +++ b/server/reflector/whereby.py @@ -19,6 +19,17 @@ async def create_meeting( "roomMode": "normal", "startDate": start_date.isoformat(), "endDate": end_date.isoformat(), + "recording": { + "type": "cloud", + "destination": { + "provider": "s3", + "bucket": settings.AWS_WHEREBY_S3_BUCKET, + "accessKeyId": settings.AWS_WHEREBY_ACCESS_KEY_ID, + "accessKeySecret": settings.AWS_WHEREBY_ACCESS_KEY_SECRET, + "fileFormat": "mp4", + }, + "startTrigger": "automatic-2nd-participant", + }, } async with httpx.AsyncClient() as client: diff --git a/server/reflector/worker/process.py b/server/reflector/worker/process.py index 7541b6cd..614f7c4c 100644 --- a/server/reflector/worker/process.py +++ b/server/reflector/worker/process.py @@ -64,16 +64,14 @@ async def process_recording(bucket_name: str, object_key: str): # extract a guid from the object key room_name = f"/{object_key[:36]}" meeting = await meetings_controller.get_by_room_name(room_name) - transcript = await transcripts_controller.get_by_meeting_id(meeting.id) - if transcript is None: - transcript = await transcripts_controller.add( - "", - source_language="en", - target_language="en", - user_id=meeting.user_id, - meeting_id=meeting.id, - share_mode="public", - ) + transcript = await transcripts_controller.add( + "", + source_language="en", + target_language="en", + user_id=meeting.user_id, + meeting_id=meeting.id, + share_mode="public", + ) _, extension = os.path.splitext(object_key) upload_filename = transcript.data_path / f"upload{extension}" diff --git a/www/app/[domain]/transcripts/[transcriptId]/meeting/page.tsx b/www/app/[domain]/transcripts/[transcriptId]/meeting/page.tsx deleted file mode 100644 index 6dde62f1..00000000 --- a/www/app/[domain]/transcripts/[transcriptId]/meeting/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -"use client"; - -import "@whereby.com/browser-sdk/embed"; -import { useCallback, useEffect, useRef } from "react"; -import useTranscript from "../../useTranscript"; -import useMeeting from "../../useMeeting"; - -export type TranscriptDetails = { - params: { - transcriptId: string; - }; -}; - -export default function TranscriptMeeting(details: TranscriptDetails) { - const wherebyRef = useRef(null); - - const transcript = useTranscript(details.params.transcriptId); - const meeting = useMeeting(transcript?.response?.meeting_id); - const roomUrl = meeting?.response?.host_room_url - ? meeting?.response?.host_room_url - : meeting?.response?.room_url; - - return ( - <> - {roomUrl && ( - - )} - - ); -} diff --git a/www/app/[domain]/transcripts/createTranscript.ts b/www/app/[domain]/transcripts/createTranscript.ts index 8bf2aee8..015c82de 100644 --- a/www/app/[domain]/transcripts/createTranscript.ts +++ b/www/app/[domain]/transcripts/createTranscript.ts @@ -9,7 +9,6 @@ type UseCreateTranscript = { loading: boolean; error: Error | null; create: (transcriptCreationDetails: CreateTranscript) => void; - createMeeting: (transcriptCreationDetails: CreateTranscript) => void; }; const useCreateTranscript = (): UseCreateTranscript => { @@ -40,28 +39,7 @@ const useCreateTranscript = (): UseCreateTranscript => { }); }; - const createMeeting = (transcriptCreationDetails: CreateTranscript) => { - if (loading || !api) return; - - setLoading(true); - - api - .v1TranscriptsCreateMeeting({ requestBody: transcriptCreationDetails }) - .then((transcript) => { - setTranscript(transcript); - setLoading(false); - }) - .catch((err) => { - setError( - err, - "There was an issue creating a transcript, please try again.", - ); - setErrorState(err); - setLoading(false); - }); - }; - - return { transcript, loading, error, create, createMeeting }; + return { transcript, loading, error, create }; }; export default useCreateTranscript; diff --git a/www/app/[domain]/transcripts/new/page.tsx b/www/app/[domain]/transcripts/new/page.tsx index b958fef0..4297a948 100644 --- a/www/app/[domain]/transcripts/new/page.tsx +++ b/www/app/[domain]/transcripts/new/page.tsx @@ -32,7 +32,6 @@ const TranscriptCreate = () => { const [loadingRecord, setLoadingRecord] = useState(false); const [loadingUpload, setLoadingUpload] = useState(false); - const [loadingMeeting, setLoadingMeeting] = useState(false); const send = () => { if (loadingRecord || createTranscript.loading || permissionDenied) return; @@ -46,16 +45,9 @@ const TranscriptCreate = () => { createTranscript.create({ name, target_language: targetLanguage }); }; - const startMeeting = () => { - if (loadingMeeting || createTranscript.loading || permissionDenied) return; - setLoadingMeeting(true); - createTranscript.createMeeting({ name, target_language: targetLanguage }); - }; - useEffect(() => { let action = "record"; if (loadingUpload) action = "upload"; - if (loadingMeeting) action = "meeting"; createTranscript.transcript && router.push(`/transcripts/${createTranscript.transcript.id}/${action}`); @@ -162,23 +154,6 @@ const TranscriptCreate = () => { > {loadingUpload ? "Loading..." : "Upload File"} - - {requireLogin && ( - <> - - OR - - - - )} )} diff --git a/www/app/[domain]/transcripts/useMeeting.ts b/www/app/[domain]/transcripts/useMeeting.ts deleted file mode 100644 index f99b5ca8..00000000 --- a/www/app/[domain]/transcripts/useMeeting.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { useEffect, useState } from "react"; -import { useError } from "../../(errors)/errorContext"; -import { GetMeeting } from "../../api"; -import { shouldShowError } from "../../lib/errorUtils"; -import useApi from "../../lib/useApi"; - -type ErrorMeeting = { - error: Error; - loading: false; - response: null; - reload: () => void; -}; - -type LoadingMeeting = { - response: null; - loading: true; - error: false; - reload: () => void; -}; - -type SuccessMeeting = { - response: GetMeeting; - loading: false; - error: null; - reload: () => void; -}; - -const useMeeting = ( - id: string | null | undefined, -): ErrorMeeting | LoadingMeeting | SuccessMeeting => { - const [response, setResponse] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setErrorState] = useState(null); - const [reload, setReload] = useState(0); - const { setError } = useError(); - const api = useApi(); - const reloadHandler = () => setReload((prev) => prev + 1); - - useEffect(() => { - if (!id || !api) return; - - if (!response) { - setLoading(true); - } - - api - .v1MeetingGet({ meetingId: id }) - .then((result) => { - setResponse(result); - setLoading(false); - console.debug("Meeting Loaded:", result); - }) - .catch((error) => { - const shouldShowHuman = shouldShowError(error); - if (shouldShowHuman) { - setError(error, "There was an error loading the meeting"); - } else { - setError(error); - } - setErrorState(error); - }); - }, [id, !api, reload]); - - return { response, loading, error, reload: reloadHandler } as - | ErrorMeeting - | LoadingMeeting - | SuccessMeeting; -}; - -export default useMeeting; diff --git a/www/app/api/schemas.gen.ts b/www/app/api/schemas.gen.ts index 513ffbec..7aac08d7 100644 --- a/www/app/api/schemas.gen.ts +++ b/www/app/api/schemas.gen.ts @@ -99,52 +99,6 @@ export const $DeletionStatus = { title: "DeletionStatus", } as const; -export const $GetMeeting = { - properties: { - id: { - type: "string", - title: "Id", - }, - room_name: { - type: "string", - title: "Room Name", - }, - room_url: { - type: "string", - title: "Room Url", - }, - host_room_url: { - type: "string", - title: "Host Room Url", - }, - viewer_room_url: { - type: "string", - title: "Viewer Room Url", - }, - start_date: { - type: "string", - format: "date-time", - title: "Start Date", - }, - end_date: { - type: "string", - format: "date-time", - title: "End Date", - }, - }, - type: "object", - required: [ - "id", - "room_name", - "room_url", - "host_room_url", - "viewer_room_url", - "start_date", - "end_date", - ], - title: "GetMeeting", -} as const; - export const $GetTranscript = { properties: { id: { @@ -485,6 +439,52 @@ export const $HTTPValidationError = { title: "HTTPValidationError", } as const; +export const $Meeting = { + properties: { + id: { + type: "string", + title: "Id", + }, + room_name: { + type: "string", + title: "Room Name", + }, + room_url: { + type: "string", + title: "Room Url", + }, + host_room_url: { + type: "string", + title: "Host Room Url", + }, + viewer_room_url: { + type: "string", + title: "Viewer Room Url", + }, + start_date: { + type: "string", + format: "date-time", + title: "Start Date", + }, + end_date: { + type: "string", + format: "date-time", + title: "End Date", + }, + }, + type: "object", + required: [ + "id", + "room_name", + "room_url", + "host_room_url", + "viewer_room_url", + "start_date", + "end_date", + ], + title: "Meeting", +} as const; + export const $Page_GetTranscript_ = { properties: { items: { diff --git a/www/app/api/services.gen.ts b/www/app/api/services.gen.ts index 91eeb7bd..ec677555 100644 --- a/www/app/api/services.gen.ts +++ b/www/app/api/services.gen.ts @@ -4,10 +4,6 @@ import type { CancelablePromise } from "./core/CancelablePromise"; import type { BaseHttpRequest } from "./core/BaseHttpRequest"; import type { MetricsResponse, - V1MeetingGetData, - V1MeetingGetResponse, - V1MeetingCreateData, - V1MeetingCreateResponse, V1RoomsListData, V1RoomsListResponse, V1RoomsCreateData, @@ -20,8 +16,6 @@ import type { V1TranscriptsListResponse, V1TranscriptsCreateData, V1TranscriptsCreateResponse, - V1TranscriptsCreateMeetingData, - V1TranscriptsCreateMeetingResponse, V1TranscriptGetData, V1TranscriptGetResponse, V1TranscriptUpdateData, @@ -81,50 +75,6 @@ export class DefaultService { }); } - /** - * Meeting Get - * @param data The data for the request. - * @param data.meetingId - * @returns GetMeeting Successful Response - * @throws ApiError - */ - public v1MeetingGet( - data: V1MeetingGetData, - ): CancelablePromise { - return this.httpRequest.request({ - method: "GET", - url: "/v1/meetings/{meeting_id}", - path: { - meeting_id: data.meetingId, - }, - errors: { - 422: "Validation Error", - }, - }); - } - - /** - * Meeting Create - * @param data The data for the request. - * @param data.roomId - * @returns GetMeeting Successful Response - * @throws ApiError - */ - public v1MeetingCreate( - data: V1MeetingCreateData, - ): CancelablePromise { - return this.httpRequest.request({ - method: "POST", - url: "/v1/meetings/", - query: { - room_id: data.roomId, - }, - errors: { - 422: "Validation Error", - }, - }); - } - /** * Rooms List * @param data The data for the request. @@ -196,7 +146,7 @@ export class DefaultService { * Rooms Create Meeting * @param data The data for the request. * @param data.roomName - * @returns GetMeeting Successful Response + * @returns Meeting Successful Response * @throws ApiError */ public v1RoomsCreateMeeting( @@ -259,27 +209,6 @@ export class DefaultService { }); } - /** - * Transcripts Create Meeting - * @param data The data for the request. - * @param data.requestBody - * @returns GetTranscript Successful Response - * @throws ApiError - */ - public v1TranscriptsCreateMeeting( - data: V1TranscriptsCreateMeetingData, - ): CancelablePromise { - return this.httpRequest.request({ - method: "POST", - url: "/v1/transcripts/meeting", - body: data.requestBody, - mediaType: "application/json", - errors: { - 422: "Validation Error", - }, - }); - } - /** * Transcript Get * @param data The data for the request. diff --git a/www/app/api/types.gen.ts b/www/app/api/types.gen.ts index e0fd3f78..fcf77c05 100644 --- a/www/app/api/types.gen.ts +++ b/www/app/api/types.gen.ts @@ -28,16 +28,6 @@ export type DeletionStatus = { status: string; }; -export type GetMeeting = { - id: string; - room_name: string; - room_url: string; - host_room_url: string; - viewer_room_url: string; - start_date: string; - end_date: string; -}; - export type GetTranscript = { id: string; user_id: string | null; @@ -99,6 +89,16 @@ export type HTTPValidationError = { detail?: Array; }; +export type Meeting = { + id: string; + room_name: string; + room_url: string; + host_room_url: string; + viewer_room_url: string; + start_date: string; + end_date: string; +}; + export type Page_GetTranscript_ = { items: Array; total: number; @@ -197,18 +197,6 @@ export type Word = { export type MetricsResponse = unknown; -export type V1MeetingGetData = { - meetingId: string; -}; - -export type V1MeetingGetResponse = GetMeeting; - -export type V1MeetingCreateData = { - roomId: string; -}; - -export type V1MeetingCreateResponse = GetMeeting; - export type V1RoomsListData = { /** * Page number @@ -238,7 +226,7 @@ export type V1RoomsCreateMeetingData = { roomName: string; }; -export type V1RoomsCreateMeetingResponse = GetMeeting; +export type V1RoomsCreateMeetingResponse = Meeting; export type V1TranscriptsListData = { /** @@ -259,12 +247,6 @@ export type V1TranscriptsCreateData = { export type V1TranscriptsCreateResponse = GetTranscript; -export type V1TranscriptsCreateMeetingData = { - requestBody: CreateTranscript; -}; - -export type V1TranscriptsCreateMeetingResponse = GetTranscript; - export type V1TranscriptGetData = { transcriptId: string; }; @@ -415,36 +397,6 @@ export type $OpenApiTs = { }; }; }; - "/v1/meetings/{meeting_id}": { - get: { - req: V1MeetingGetData; - res: { - /** - * Successful Response - */ - 200: GetMeeting; - /** - * Validation Error - */ - 422: HTTPValidationError; - }; - }; - }; - "/v1/meetings/": { - post: { - req: V1MeetingCreateData; - res: { - /** - * Successful Response - */ - 200: GetMeeting; - /** - * Validation Error - */ - 422: HTTPValidationError; - }; - }; - }; "/v1/rooms": { get: { req: V1RoomsListData; @@ -495,7 +447,7 @@ export type $OpenApiTs = { /** * Successful Response */ - 200: GetMeeting; + 200: Meeting; /** * Validation Error */ @@ -531,21 +483,6 @@ export type $OpenApiTs = { }; }; }; - "/v1/transcripts/meeting": { - post: { - req: V1TranscriptsCreateMeetingData; - res: { - /** - * Successful Response - */ - 200: GetTranscript; - /** - * Validation Error - */ - 422: HTTPValidationError; - }; - }; - }; "/v1/transcripts/{transcript_id}": { get: { req: V1TranscriptGetData;