WIP checkpoint: US-1: Asset Import Pipeline — glTF upload endpoint with metadata extraction
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
"""Asset management router."""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
@@ -13,6 +14,7 @@ from app.database import get_db
|
||||
from app.dependencies import CurrentUser
|
||||
from app.models.asset import Asset, AssetType
|
||||
from app.models.world import World
|
||||
from app.services import gltf as gltf_service
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
router = APIRouter()
|
||||
@@ -64,6 +66,14 @@ def _sanitize_filename(filename: str) -> str:
|
||||
return safe or "file"
|
||||
|
||||
|
||||
def _detect_asset_type(filename: Optional[str], content: bytes) -> AssetType:
|
||||
"""Detect the asset type from filename and content."""
|
||||
if filename and gltf_service.looks_like_gltf(content, filename):
|
||||
return AssetType.MODEL_3D
|
||||
# Fallback: let the caller decide based on mime_type or default.
|
||||
return AssetType.OTHER
|
||||
|
||||
|
||||
# --- Endpoints ---
|
||||
|
||||
@router.post("/", response_model=AssetResponse, status_code=201)
|
||||
@@ -183,10 +193,16 @@ async def upload_asset_file(
|
||||
# Sanitize filename to prevent path traversal.
|
||||
safe_filename = _sanitize_filename(file.filename or f"asset_{asset_id}")
|
||||
|
||||
# Validate file size against configured maximum.
|
||||
max_bytes = settings.MAX_UPLOAD_SIZE_MB * 1024 * 1024
|
||||
# Read the file content.
|
||||
content = await file.read()
|
||||
file_size = len(content)
|
||||
|
||||
# Determine which size limit to apply.
|
||||
if gltf_service.looks_like_gltf(content, file.filename):
|
||||
max_bytes = settings.GLTF_MAX_FILE_SIZE_MB * 1024 * 1024
|
||||
else:
|
||||
max_bytes = settings.MAX_UPLOAD_SIZE_MB * 1024 * 1024
|
||||
|
||||
if file_size > max_bytes:
|
||||
raise HTTPException(
|
||||
status_code=413,
|
||||
@@ -200,10 +216,28 @@ async def upload_asset_file(
|
||||
file_path = upload_dir / stored_name
|
||||
file_path.write_bytes(content)
|
||||
|
||||
# Detect asset type from content/filename.
|
||||
detected_type = _detect_asset_type(file.filename, content)
|
||||
|
||||
# Update asset record.
|
||||
asset.file_path = str(file_path)
|
||||
asset.mime_type = file.content_type
|
||||
asset.file_size = file_size
|
||||
|
||||
# If this is a glTF file, extract and store metadata.
|
||||
if detected_type == AssetType.MODEL_3D:
|
||||
try:
|
||||
metadata = gltf_service.extract_gltf_metadata(content)
|
||||
asset.metadata_json = json.dumps(metadata)
|
||||
# Also set the asset type to model_3d if it was auto-detected.
|
||||
if asset.asset_type == AssetType.OTHER:
|
||||
asset.asset_type = AssetType.MODEL_3D
|
||||
except ValueError as exc:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Invalid glTF file: {exc}",
|
||||
)
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(asset)
|
||||
return asset
|
||||
|
||||
Reference in New Issue
Block a user