Files
label_ai_service/app/routers/video.py
wh 0274bb470a feat(US3+4): video frame extraction + video-to-text — POST /api/v1/video/*
- app/models/video_models.py: ExtractFramesRequest, VideoToTextRequest,
  FrameInfo, VideoJobCallback, VideoAcceptedResponse
- app/services/video_service.py: interval+keyframe frame extraction,
  uniform-sample video-to-text, HTTP callback, temp file cleanup
- app/routers/video.py: size check helper (_check_video_size via head_object),
  BackgroundTasks enqueue for both endpoints
- tests: 6 service + 4 router tests, 10/10 passing
2026-04-10 16:00:08 +08:00

70 lines
2.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import APIRouter, BackgroundTasks, Depends
from app.clients.llm.base import LLMClient
from app.clients.storage.base import StorageClient
from app.core.config import get_config
from app.core.dependencies import get_llm_client, get_storage_client
from app.core.exceptions import VideoTooLargeError
from app.models.video_models import (
ExtractFramesRequest,
VideoAcceptedResponse,
VideoToTextRequest,
)
from app.services import video_service
router = APIRouter(tags=["Video"])
async def _check_video_size(storage: StorageClient, bucket: str, file_path: str, max_mb: int) -> None:
size_bytes = await storage.get_object_size(bucket, file_path)
if size_bytes > max_mb * 1024 * 1024:
raise VideoTooLargeError(
f"视频文件大小超出限制(最大 {max_mb}MB当前 {size_bytes // 1024 // 1024}MB"
)
@router.post("/video/extract-frames", response_model=VideoAcceptedResponse, status_code=202)
async def extract_frames(
req: ExtractFramesRequest,
background_tasks: BackgroundTasks,
storage: StorageClient = Depends(get_storage_client),
) -> VideoAcceptedResponse:
cfg = get_config()
bucket = cfg["storage"]["buckets"]["source_data"]
max_mb = cfg["video"]["max_file_size_mb"]
callback_url = cfg.get("backend", {}).get("callback_url", "")
await _check_video_size(storage, bucket, req.file_path, max_mb)
background_tasks.add_task(
video_service.extract_frames_task,
req,
storage,
callback_url,
)
return VideoAcceptedResponse(message="任务已接受,后台处理中", job_id=req.job_id)
@router.post("/video/to-text", response_model=VideoAcceptedResponse, status_code=202)
async def video_to_text(
req: VideoToTextRequest,
background_tasks: BackgroundTasks,
storage: StorageClient = Depends(get_storage_client),
llm: LLMClient = Depends(get_llm_client),
) -> VideoAcceptedResponse:
cfg = get_config()
bucket = cfg["storage"]["buckets"]["source_data"]
max_mb = cfg["video"]["max_file_size_mb"]
callback_url = cfg.get("backend", {}).get("callback_url", "")
await _check_video_size(storage, bucket, req.file_path, max_mb)
background_tasks.add_task(
video_service.video_to_text_task,
req,
llm,
storage,
callback_url,
)
return VideoAcceptedResponse(message="任务已接受,后台处理中", job_id=req.job_id)