""" API endpoints for background task submission. """ from __future__ import annotations import uuid from typing import cast from fastapi import APIRouter, Depends, HTTPException, Request, status from sqlalchemy.ext.asyncio import AsyncSession from cpv3.db.session import get_db from cpv3.infrastructure.auth import get_current_user from cpv3.modules.jobs.service import JobService from cpv3.modules.tasks.schemas import ( CaptionsGenerateRequest, MediaConvertRequest, MediaProbeRequest, SilenceRemoveRequest, TaskStatusEnum, TaskStatusResponse, TaskSubmitResponse, TaskTypeEnum, TranscriptionGenerateRequest, ) from cpv3.modules.tasks.service import TaskService from cpv3.modules.users.models import User router = APIRouter(prefix="/api/tasks", tags=["tasks"]) @router.post( "/media-probe/", response_model=TaskSubmitResponse, status_code=status.HTTP_202_ACCEPTED, ) async def submit_media_probe( body: MediaProbeRequest, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> TaskSubmitResponse: """Submit a background task to probe media file metadata.""" service = TaskService(db) return await service.submit_media_probe(requester=current_user, request=body) @router.post( "/silence-remove/", response_model=TaskSubmitResponse, status_code=status.HTTP_202_ACCEPTED, ) async def submit_silence_remove( body: SilenceRemoveRequest, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> TaskSubmitResponse: """Submit a background task to remove silence from media file.""" service = TaskService(db) return await service.submit_silence_remove(requester=current_user, request=body) @router.post( "/media-convert/", response_model=TaskSubmitResponse, status_code=status.HTTP_202_ACCEPTED, ) async def submit_media_convert( body: MediaConvertRequest, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> TaskSubmitResponse: """Submit a background task to convert media file format.""" service = TaskService(db) return await service.submit_media_convert(requester=current_user, request=body) @router.post( "/transcription-generate/", response_model=TaskSubmitResponse, status_code=status.HTTP_202_ACCEPTED, ) async def submit_transcription_generate( body: TranscriptionGenerateRequest, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> TaskSubmitResponse: """Submit a background task to generate transcription from audio/video.""" service = TaskService(db) return await service.submit_transcription_generate( requester=current_user, request=body ) @router.post( "/captions-generate/", response_model=TaskSubmitResponse, status_code=status.HTTP_202_ACCEPTED, ) async def submit_captions_generate( body: CaptionsGenerateRequest, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> TaskSubmitResponse: """Submit a background task to generate captions on video.""" service = TaskService(db) try: return await service.submit_captions_generate( requester=current_user, request=body ) except ValueError as e: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e)) @router.get("/status/{job_id}/", response_model=TaskStatusResponse) async def get_task_status( job_id: uuid.UUID, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> TaskStatusResponse: """Get the status of a background task.""" job_service = JobService(db) job = await job_service.get_job(job_id) if job is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Job not found" ) if not current_user.is_staff and job.user_id != current_user.id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Forbidden") return TaskStatusResponse( job_id=job.id, status=cast(TaskStatusEnum, job.status), job_type=cast(TaskTypeEnum, job.job_type), progress_pct=job.project_pct, current_message=job.current_message, error_message=job.error_message, output_data=job.output_data, started_at=job.started_at, finished_at=job.finished_at, ) @router.post("/webhook/{job_id}/", include_in_schema=False) async def task_webhook_callback( job_id: uuid.UUID, request: Request, db: AsyncSession = Depends(get_db), ) -> dict[str, str]: """Internal webhook endpoint for task status updates.""" try: await request.json() except Exception: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid JSON payload" ) job_service = JobService(db) job = await job_service.get_job(job_id) if job is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Job not found" ) return {"status": "received", "job_id": str(job_id)}