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

50
app/main.py Normal file
View File

@@ -0,0 +1,50 @@
import logging
import os
import sys
from contextlib import asynccontextmanager
from fastapi import FastAPI
# Ensure FaceFusion submodule is importable (must happen before any facefusion imports)
_project_root = os.path.dirname(os.path.dirname(__file__))
for _candidate in (os.path.join(_project_root, 'facefusion'), '/app/facefusion-src'):
if os.path.isdir(os.path.join(_candidate, 'facefusion')) and _candidate not in sys.path:
sys.path.insert(0, _candidate)
break
from app.routers import jobs, process, processors, system
from app.services import facefusion_bridge, file_manager
from app.services.worker import worker_queue
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s %(name)s: %(message)s',
)
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup
logger.info('Starting FaceFusion API...')
file_manager.ensure_directories()
facefusion_bridge.initialize()
worker_queue.start(facefusion_bridge.process_sync)
logger.info('FaceFusion API ready')
yield
# Shutdown
logger.info('Shutting down...')
worker_queue.stop()
app = FastAPI(
title='FaceFusion API',
version='1.0.0',
description='REST API for FaceFusion face processing',
lifespan=lifespan,
)
app.include_router(process.router)
app.include_router(jobs.router)
app.include_router(processors.router)
app.include_router(system.router)