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:
0
app/schemas/__init__.py
Normal file
0
app/schemas/__init__.py
Normal file
31
app/schemas/jobs.py
Normal file
31
app/schemas/jobs.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class JobStatus(str, Enum):
|
||||
pending = 'pending'
|
||||
processing = 'processing'
|
||||
completed = 'completed'
|
||||
failed = 'failed'
|
||||
cancelled = 'cancelled'
|
||||
|
||||
|
||||
class JobCreateResponse(BaseModel):
|
||||
job_id: str
|
||||
status: JobStatus
|
||||
|
||||
|
||||
class JobStatusResponse(BaseModel):
|
||||
job_id: str
|
||||
status: JobStatus
|
||||
created_at: datetime
|
||||
updated_at: Optional[datetime] = None
|
||||
error: Optional[str] = None
|
||||
|
||||
|
||||
class JobDeleteResponse(BaseModel):
|
||||
job_id: str
|
||||
deleted: bool
|
||||
114
app/schemas/process.py
Normal file
114
app/schemas/process.py
Normal file
@@ -0,0 +1,114 @@
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class FaceSwapperOptions(BaseModel):
|
||||
model: str = 'hyperswap_1a_256'
|
||||
pixel_boost: Optional[str] = None
|
||||
weight: float = 0.5
|
||||
|
||||
|
||||
class FaceEnhancerOptions(BaseModel):
|
||||
model: str = 'gfpgan_1.4'
|
||||
blend: int = 80
|
||||
weight: float = 0.5
|
||||
|
||||
|
||||
class FaceEditorOptions(BaseModel):
|
||||
model: str = 'live_portrait'
|
||||
eyebrow_direction: Optional[float] = None
|
||||
eye_gaze_horizontal: Optional[float] = None
|
||||
eye_gaze_vertical: Optional[float] = None
|
||||
eye_open_ratio: Optional[float] = None
|
||||
lip_open_ratio: Optional[float] = None
|
||||
mouth_grim: Optional[float] = None
|
||||
mouth_pout: Optional[float] = None
|
||||
mouth_purse: Optional[float] = None
|
||||
mouth_smile: Optional[float] = None
|
||||
mouth_position_horizontal: Optional[float] = None
|
||||
mouth_position_vertical: Optional[float] = None
|
||||
head_pitch: Optional[float] = None
|
||||
head_yaw: Optional[float] = None
|
||||
head_roll: Optional[float] = None
|
||||
|
||||
|
||||
class LipSyncerOptions(BaseModel):
|
||||
model: str = 'wav2lip_96'
|
||||
|
||||
|
||||
class AgeModifierOptions(BaseModel):
|
||||
model: str = 'styleganex_age'
|
||||
direction: int = 0
|
||||
|
||||
|
||||
class ExpressionRestorerOptions(BaseModel):
|
||||
model: str = 'live_portrait'
|
||||
factor: int = 80
|
||||
|
||||
|
||||
class FrameEnhancerOptions(BaseModel):
|
||||
model: str = 'span_kendata_1x'
|
||||
blend: int = 80
|
||||
|
||||
|
||||
class FrameColorizerOptions(BaseModel):
|
||||
model: str = 'ddcolor'
|
||||
blend: int = 80
|
||||
size: str = '256x256'
|
||||
|
||||
|
||||
class BackgroundRemoverOptions(BaseModel):
|
||||
model: str = 'isnet_general_use'
|
||||
|
||||
|
||||
class FaceDetectorOptions(BaseModel):
|
||||
model: str = 'yolo_face'
|
||||
size: str = '640x640'
|
||||
score: float = 0.5
|
||||
|
||||
|
||||
class FaceSelectorOptions(BaseModel):
|
||||
mode: str = 'reference'
|
||||
order: str = 'large-small'
|
||||
gender: Optional[str] = None
|
||||
race: Optional[str] = None
|
||||
age_start: Optional[int] = None
|
||||
age_end: Optional[int] = None
|
||||
|
||||
|
||||
class OutputOptions(BaseModel):
|
||||
image_quality: int = 80
|
||||
image_scale: float = 1.0
|
||||
video_encoder: Optional[str] = None
|
||||
video_preset: str = 'veryfast'
|
||||
video_quality: int = 80
|
||||
video_scale: float = 1.0
|
||||
video_fps: Optional[float] = None
|
||||
audio_encoder: Optional[str] = None
|
||||
audio_quality: int = 80
|
||||
audio_volume: int = 100
|
||||
|
||||
|
||||
class ProcessingOptions(BaseModel):
|
||||
processors: List[str] = Field(default_factory=lambda: ['face_swapper'])
|
||||
face_swapper: Optional[FaceSwapperOptions] = None
|
||||
face_enhancer: Optional[FaceEnhancerOptions] = None
|
||||
face_editor: Optional[FaceEditorOptions] = None
|
||||
lip_syncer: Optional[LipSyncerOptions] = None
|
||||
age_modifier: Optional[AgeModifierOptions] = None
|
||||
expression_restorer: Optional[ExpressionRestorerOptions] = None
|
||||
frame_enhancer: Optional[FrameEnhancerOptions] = None
|
||||
frame_colorizer: Optional[FrameColorizerOptions] = None
|
||||
background_remover: Optional[BackgroundRemoverOptions] = None
|
||||
face_detector: Optional[FaceDetectorOptions] = None
|
||||
face_selector: Optional[FaceSelectorOptions] = None
|
||||
output: Optional[OutputOptions] = None
|
||||
execution_providers: Optional[List[str]] = None
|
||||
execution_thread_count: Optional[int] = None
|
||||
video_memory_strategy: Optional[str] = None
|
||||
|
||||
|
||||
class ProcessingResponse(BaseModel):
|
||||
output_path: str
|
||||
processing_time: float
|
||||
33
app/schemas/system.py
Normal file
33
app/schemas/system.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class HealthResponse(BaseModel):
|
||||
status: str = 'ok'
|
||||
|
||||
|
||||
class GpuDevice(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
memory_total: Optional[int] = None
|
||||
memory_used: Optional[int] = None
|
||||
|
||||
|
||||
class SystemInfoResponse(BaseModel):
|
||||
execution_providers: List[str]
|
||||
gpu_devices: List[GpuDevice]
|
||||
cpu_count: Optional[int] = None
|
||||
memory_total: Optional[int] = None
|
||||
memory_available: Optional[int] = None
|
||||
|
||||
|
||||
class ProcessorInfo(BaseModel):
|
||||
name: str
|
||||
models: List[str]
|
||||
|
||||
|
||||
class ModelInfo(BaseModel):
|
||||
name: str
|
||||
path: str
|
||||
size_bytes: int
|
||||
Reference in New Issue
Block a user