Initial commit: FaceFusion REST API

FastAPI wrapper around FaceFusion v3.5.3 submodule with:
- Sync and async (job-based) processing endpoints
- FaceFusion bridge with manual key registration and Lock-serialized processing
- Multi-target Dockerfile (CPU + CUDA GPU)
- Docker Compose configs for dev, prod-cpu, and prod-gpu
- Gitea CI/CD workflow with dual image builds
- All 11 FaceFusion processors supported via options API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 12:58:33 +01:00
commit 800edc08ea
31 changed files with 1784 additions and 0 deletions

47
app/routers/processors.py Normal file
View File

@@ -0,0 +1,47 @@
import logging
from typing import List
from fastapi import APIRouter, HTTPException
from app.schemas.system import ModelInfo, ProcessorInfo
from app.services import facefusion_bridge, file_manager
logger = logging.getLogger(__name__)
router = APIRouter(prefix='/api/v1', tags=['processors'])
@router.get('/processors', response_model=List[ProcessorInfo])
async def list_processors():
"""List available processors and their models."""
try:
processor_names = facefusion_bridge.get_available_processors()
result = []
for name in processor_names:
result.append(ProcessorInfo(name=name, models=[]))
return result
except Exception as e:
logger.error(f'Failed to list processors: {e}')
raise HTTPException(status_code=500, detail=str(e))
@router.get('/models', response_model=List[ModelInfo])
async def list_models():
"""List downloaded model files."""
models = file_manager.list_model_files()
return [ModelInfo(name=name, path=path, size_bytes=size) for name, path, size in models]
@router.post('/models/download')
async def download_models(processors: List[str] = None):
"""Trigger model download for specified processors."""
try:
success = facefusion_bridge.force_download_models(processors)
if success:
return {'status': 'ok', 'message': 'Models downloaded successfully'}
raise HTTPException(status_code=500, detail='Some models failed to download')
except HTTPException:
raise
except Exception as e:
logger.error(f'Model download failed: {e}')
raise HTTPException(status_code=500, detail=str(e))