import uuid from datetime import datetime from typing import Sequence from app.adapters.db.base import DB from app.adapters.opus_clip.client import OpusClipClient from app.adapters.opus_clip.enums import ClipDuration, LayoutAspectRatio, ProjectStage from app.adapters.opus_clip.models import ( OpusClipProjectParams, ImportPref, ) from app.assets.models import Asset from app.config import Settings from anydi import singleton from app.opus_clip.models import OpusClipProject, OpusClipClip from app.opus_clip.repositories import OpusClipProjectRepository, ClipsPerAsset from pydantic import BaseModel class ClipGenerationRequest(BaseModel): title: str description: str layout: LayoutAspectRatio duration: ClipDuration prompt: str @singleton class OpusClipService: def __init__( self, # s3_client: S3Client, client: OpusClipClient, db: DB, project_repository: OpusClipProjectRepository, settings: Settings, ) -> None: # self.s3_client = s3_client self.client = client self.db = db self.project_repository = project_repository self.settings = settings def find_projects_by_asset_id(self, asset_id: str) -> Sequence[OpusClipProject]: return self.project_repository.find_by_asset_id(asset_id=asset_id) def find_number_of_clips_per_asset_id(self) -> Sequence[ClipsPerAsset]: return self.project_repository.find_number_of_clips_per_asset_id() def create_clip_project( self, asset: Asset, request: ClipGenerationRequest ) -> OpusClipProject: params = { "video_url": asset.s3_key, "uploaded_video_attr": { "title": request.title, "description": request.description, }, "curation_pref": { "clip_durations": [request.duration.to_api_value()], "custom_prompt": request.prompt, }, "import_pref": ImportPref().model_dump(), "render_pref": {"layout_aspect_ratio": request.layout}, } response = self.client.create_project( params=OpusClipProjectParams.model_validate(params) ) project = OpusClipProject( external_id=response.id, name=request.title, description=request.description, parameters=params, status=response.stage, asset_id=asset.id, created_at=response.created_at, updated_at=response.updated_at, ) self.project_repository.add(project) self.project_repository.db.session.commit() return project def update_clip_project(self, project: OpusClipProject) -> None: created_at = project.created_at current_time = datetime.now() difference = current_time - created_at if difference.total_seconds() > 30: response = self.client.get_clips_by_project_id( project_id=project.external_id ) else: response = [] if response: clips = [] for clip in response: db_clip = OpusClipClip( id=str(uuid.uuid4()), external_id=clip.id, created_at=datetime.now(), title=clip.title, description=clip.description, s3_key=clip.uri_for_export, project_id=project.id, attributes=clip.model_dump(), ) clips.append(db_clip) project.status = ProjectStage.COMPLETE project.clips = clips else: project.status = ProjectStage.PENDING self.project_repository.add(project) self.project_repository.db.session.commit()