legco_ai_assistant/backend/app/routers/video.py

78 lines
2.4 KiB
Python

import logging
import uuid
from pathlib import Path
import aiofiles
from fastapi import APIRouter, UploadFile, File, HTTPException
from fastapi.responses import FileResponse
from app.models.video import VideoUploadResponse
from app.services.video_service import VideoService
logger = logging.getLogger(__name__)
router = APIRouter(tags=["video"])
def _get_video_service() -> VideoService:
from app.core.config import get_settings
s = get_settings()
return VideoService(
upload_dir=s.video_upload_dir,
max_size_mb=s.max_video_size_mb,
supported_formats=s.supported_video_formats,
)
@router.post("/video/upload", response_model=VideoUploadResponse)
async def upload_video(file: UploadFile = File(...)):
service = _get_video_service()
filename = file.filename or "unknown"
ext = Path(filename).suffix.lower()
total_size = 0
video_id = uuid.uuid4().hex[:12]
dest_path = service.upload_dir / f"{video_id}{ext}"
try:
async with aiofiles.open(dest_path, "wb") as out:
while chunk := await file.read(1024 * 1024):
total_size += len(chunk)
if total_size > service.max_size_bytes:
raise HTTPException(
status_code=413,
detail=f"File exceeds {service.max_size_bytes // 1024 // 1024}MB limit",
)
await out.write(chunk)
except HTTPException:
dest_path.unlink(missing_ok=True)
raise
except Exception:
dest_path.unlink(missing_ok=True)
raise HTTPException(status_code=500, detail="Upload failed")
service.validate_video(filename, file.content_type, total_size)
logger.info("Video uploaded: id=%s filename=%s size=%d", video_id, filename, total_size)
return VideoUploadResponse(
video_id=video_id,
filename=filename,
size_bytes=total_size,
url=f"/api/v1/video/{video_id}",
)
@router.get("/video/{video_id}")
async def serve_video(video_id: str):
service = _get_video_service()
video_path = service.get_video_path(video_id)
ext = video_path.suffix.lower()
media_types = {
".mp4": "video/mp4",
".webm": "video/webm",
".mov": "video/quicktime",
".avi": "video/x-msvideo",
".mkv": "video/x-matroska",
}
return FileResponse(str(video_path), media_type=media_types.get(ext, "application/octet-stream"))