160 lines
5.9 KiB
Python
160 lines
5.9 KiB
Python
"""
|
|
Add Audio to Video endpoints.
|
|
"""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form, BackgroundTasks
|
|
from sqlalchemy.orm import Session
|
|
from typing import Optional, Dict, Any
|
|
import uuid
|
|
|
|
from ...database import get_db
|
|
from ...models.content_asset_models import AssetSource, AssetType
|
|
from ...services.video_studio.add_audio_to_video_service import AddAudioToVideoService
|
|
from ...services.asset_service import ContentAssetService
|
|
from ...utils.auth import get_current_user, require_authenticated_user
|
|
from ...utils.logger_utils import get_service_logger
|
|
|
|
logger = get_service_logger("video_studio.endpoints.add_audio_to_video")
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post("/add-audio-to-video")
|
|
async def add_audio_to_video(
|
|
background_tasks: BackgroundTasks,
|
|
video_file: UploadFile = File(..., description="Source video for audio addition"),
|
|
model: str = Form("hunyuan-video-foley", description="AI model to use: 'hunyuan-video-foley' or 'think-sound'"),
|
|
prompt: Optional[str] = Form(None, description="Optional text prompt describing desired sounds (Hunyuan Video Foley)"),
|
|
seed: Optional[int] = Form(None, description="Random seed for reproducibility (-1 for random)"),
|
|
current_user: Dict[str, Any] = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Add audio to video using AI models.
|
|
|
|
Supports:
|
|
1. Hunyuan Video Foley - Generate realistic Foley and ambient audio from video
|
|
- Optional text prompt to describe desired sounds
|
|
- Seed control for reproducibility
|
|
|
|
2. Think Sound - (To be added)
|
|
|
|
Args:
|
|
video_file: Source video file
|
|
model: AI model to use
|
|
prompt: Optional text prompt describing desired sounds
|
|
seed: Random seed for reproducibility
|
|
"""
|
|
try:
|
|
user_id = require_authenticated_user(current_user)
|
|
|
|
if not video_file.content_type.startswith('video/'):
|
|
raise HTTPException(status_code=400, detail="File must be a video")
|
|
|
|
# Initialize services
|
|
add_audio_service = AddAudioToVideoService()
|
|
asset_service = ContentAssetService(db)
|
|
|
|
logger.info(f"[AddAudioToVideo] Audio addition request: user={user_id}, model={model}, has_prompt={prompt is not None}")
|
|
|
|
# Read video file
|
|
video_data = await video_file.read()
|
|
|
|
# Add audio to video
|
|
result = await add_audio_service.add_audio(
|
|
video_data=video_data,
|
|
model=model,
|
|
prompt=prompt,
|
|
seed=seed,
|
|
user_id=user_id,
|
|
)
|
|
|
|
if not result.get("success"):
|
|
raise HTTPException(
|
|
status_code=500,
|
|
detail=f"Adding audio failed: {result.get('error', 'Unknown error')}"
|
|
)
|
|
|
|
# Store processed video in asset library
|
|
video_url = result.get("video_url")
|
|
if video_url:
|
|
asset_metadata = {
|
|
"original_file": video_file.filename,
|
|
"model": result.get("model_used", model),
|
|
"has_prompt": prompt is not None,
|
|
"prompt": prompt,
|
|
"generation_type": "add_audio",
|
|
}
|
|
|
|
asset_service.create_asset(
|
|
user_id=user_id,
|
|
filename=f"audio_added_{uuid.uuid4().hex[:8]}.mp4",
|
|
file_url=video_url,
|
|
asset_type=AssetType.VIDEO,
|
|
source_module=AssetSource.VIDEO_STUDIO,
|
|
asset_metadata=asset_metadata,
|
|
cost=result.get("cost", 0),
|
|
tags=["video_studio", "audio_addition", "ai-processed"]
|
|
)
|
|
|
|
logger.info(f"[AddAudioToVideo] Audio addition successful: user={user_id}, url={video_url}")
|
|
|
|
return {
|
|
"success": True,
|
|
"video_url": video_url,
|
|
"cost": result.get("cost", 0),
|
|
"model_used": result.get("model_used", model),
|
|
}
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"[AddAudioToVideo] Audio addition error: {e}", exc_info=True)
|
|
raise HTTPException(status_code=500, detail=f"Adding audio failed: {str(e)}")
|
|
|
|
|
|
@router.post("/add-audio-to-video/estimate-cost")
|
|
async def estimate_add_audio_cost(
|
|
model: str = Form("hunyuan-video-foley", description="AI model to use"),
|
|
estimated_duration: float = Form(10.0, description="Estimated video duration in seconds", ge=0.0),
|
|
current_user: Dict[str, Any] = Depends(get_current_user),
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Estimate cost for adding audio to video operation.
|
|
|
|
Returns estimated cost based on model and duration.
|
|
"""
|
|
try:
|
|
require_authenticated_user(current_user)
|
|
|
|
add_audio_service = AddAudioToVideoService()
|
|
estimated_cost = add_audio_service.calculate_cost(model, estimated_duration)
|
|
|
|
# Build response based on model pricing
|
|
if model == "think-sound":
|
|
return {
|
|
"estimated_cost": estimated_cost,
|
|
"model": model,
|
|
"estimated_duration": estimated_duration,
|
|
"pricing_model": "per_video",
|
|
"flat_rate": 0.05,
|
|
}
|
|
else:
|
|
# Hunyuan Video Foley (per-second pricing)
|
|
return {
|
|
"estimated_cost": estimated_cost,
|
|
"model": model,
|
|
"estimated_duration": estimated_duration,
|
|
"cost_per_second": 0.02, # Estimated pricing
|
|
"pricing_model": "per_second",
|
|
"min_duration": 5.0,
|
|
"max_duration": 600.0, # 10 minutes max
|
|
"min_charge": 0.02 * 5.0,
|
|
}
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"[AddAudioToVideo] Failed to estimate cost: {e}", exc_info=True)
|
|
raise HTTPException(status_code=500, detail=f"Failed to estimate cost: {str(e)}")
|