
Features: - JWT authentication with user registration and login - Video upload to Amazon S3 with file validation (200MB limit) - Audio transcription using OpenAI Whisper API - Text translation using GPT-4 API - Voice cloning and audio synthesis using ElevenLabs API - Video processing with ffmpeg for audio replacement - Complete SQLite database with proper models and migrations - Background task processing for long-running operations - Health endpoint and comprehensive API documentation Tech stack: - FastAPI with SQLAlchemy ORM - SQLite database with Alembic migrations - Amazon S3 for file storage - OpenAI APIs for transcription and translation - ElevenLabs API for voice cloning - ffmpeg for video processing - JWT authentication with bcrypt password hashing
137 lines
3.8 KiB
Python
137 lines
3.8 KiB
Python
import uuid
|
|
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form, BackgroundTasks
|
|
from sqlalchemy.orm import Session
|
|
from pydantic import BaseModel
|
|
from typing import List
|
|
from app.db.session import get_db
|
|
from app.models.user import User
|
|
from app.models.video import Video
|
|
from app.utils.auth import get_current_user
|
|
from app.services.s3_service import upload_file_to_s3
|
|
|
|
router = APIRouter()
|
|
|
|
ALLOWED_VIDEO_TYPES = ["video/mp4", "video/quicktime"]
|
|
MAX_FILE_SIZE = 200 * 1024 * 1024 # 200MB
|
|
|
|
|
|
class VideoResponse(BaseModel):
|
|
id: int
|
|
user_id: int
|
|
original_s3_url: str
|
|
language_from: str
|
|
language_to: str
|
|
status: str
|
|
created_at: str
|
|
|
|
class Config:
|
|
orm_mode = True
|
|
|
|
|
|
class VideoUploadResponse(BaseModel):
|
|
video_id: int
|
|
message: str
|
|
s3_url: str
|
|
|
|
|
|
@router.post("/upload", response_model=VideoUploadResponse)
|
|
async def upload_video(
|
|
background_tasks: BackgroundTasks,
|
|
video: UploadFile = File(...),
|
|
language_from: str = Form(...),
|
|
language_to: str = Form(...),
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
# Validate file type
|
|
if video.content_type not in ALLOWED_VIDEO_TYPES:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Invalid file type. Only MP4 and MOV files are allowed."
|
|
)
|
|
|
|
# Read file content
|
|
file_content = await video.read()
|
|
|
|
# Validate file size
|
|
if len(file_content) > MAX_FILE_SIZE:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="File too large. Maximum size is 200MB."
|
|
)
|
|
|
|
# Generate unique filename
|
|
file_extension = video.filename.split('.')[-1] if video.filename else 'mp4'
|
|
unique_filename = f"videos/{uuid.uuid4()}.{file_extension}"
|
|
|
|
# Upload to S3
|
|
s3_url = await upload_file_to_s3(file_content, unique_filename, video.content_type)
|
|
|
|
if not s3_url:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail="Failed to upload video to S3"
|
|
)
|
|
|
|
# Save video metadata to database
|
|
db_video = Video(
|
|
user_id=current_user.id,
|
|
original_s3_url=s3_url,
|
|
language_from=language_from,
|
|
language_to=language_to,
|
|
status="uploaded"
|
|
)
|
|
db.add(db_video)
|
|
db.commit()
|
|
db.refresh(db_video)
|
|
|
|
return VideoUploadResponse(
|
|
video_id=db_video.id,
|
|
message="Video uploaded successfully",
|
|
s3_url=s3_url
|
|
)
|
|
|
|
|
|
@router.get("/", response_model=List[VideoResponse])
|
|
async def get_user_videos(
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
videos = db.query(Video).filter(Video.user_id == current_user.id).all()
|
|
return [VideoResponse(
|
|
id=video.id,
|
|
user_id=video.user_id,
|
|
original_s3_url=video.original_s3_url,
|
|
language_from=video.language_from,
|
|
language_to=video.language_to,
|
|
status=video.status,
|
|
created_at=str(video.created_at)
|
|
) for video in videos]
|
|
|
|
|
|
@router.get("/{video_id}", response_model=VideoResponse)
|
|
async def get_video(
|
|
video_id: int,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
video = db.query(Video).filter(
|
|
Video.id == video_id,
|
|
Video.user_id == current_user.id
|
|
).first()
|
|
|
|
if not video:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Video not found"
|
|
)
|
|
|
|
return VideoResponse(
|
|
id=video.id,
|
|
user_id=video.user_id,
|
|
original_s3_url=video.original_s3_url,
|
|
language_from=video.language_from,
|
|
language_to=video.language_to,
|
|
status=video.status,
|
|
created_at=str(video.created_at)
|
|
) |