PixelForge / imageforge /backend /app /api /schemas.py
Gregorfun's picture
Initial commit
32c5da4
from __future__ import annotations
from datetime import datetime
from enum import Enum
from typing import Literal
from pydantic import BaseModel, Field, field_validator
class JobStatus(str, Enum):
QUEUED = "queued"
RUNNING = "running"
DONE = "done"
ERROR = "error"
CANCELLED = "cancelled"
class GenerateRequest(BaseModel):
prompt: str = Field(min_length=1, max_length=2000)
negative_prompt: str = Field(default="", max_length=2000)
model: str = Field(default="localai") # Changed from "dummy" to "localai"
size: Literal["512x512", "768x768", "1024x1024", "1024x1536", "1536x1024"] = "512x512"
count: int = Field(default=1, ge=1, le=4)
seed: int | None = Field(default=None, ge=0)
random_seed: bool = True
steps: int = Field(default=30, ge=1, le=100)
guidance: float = Field(default=6.5, ge=1.0, le=20.0)
image_type: Literal[
"general",
"photo",
"portrait",
"landscape",
"architecture",
"product",
"logo",
"icon",
"poster",
"illustration",
"anime",
"pixel_art",
"sketch",
"painting",
"3d",
] = "general"
style_preset: Literal[
"auto",
"photorealistic",
"cinematic",
"minimal",
"vibrant",
"monochrome",
"watercolor",
"oil",
"noir",
"fantasy",
] = "auto"
style_strength: int = Field(default=60, ge=0, le=100)
admin_override: bool = False
init_image_path: str | None = None
img2img_strength: float = Field(default=0.45, ge=0.0, le=1.0)
model_variant: str | None = Field(default=None, max_length=200)
@field_validator("prompt")
@classmethod
def validate_prompt(cls, value: str) -> str:
value = value.strip()
if not value:
raise ValueError("Prompt must not be empty")
return value
class GenerateResponse(BaseModel):
job_id: str
class RetryResponse(BaseModel):
old_job_id: str
new_job_id: str
class JobInfoResponse(BaseModel):
job_id: str
status: JobStatus
progress: int
message: str
created_at: datetime
updated_at: datetime
image_paths: list[str] = Field(default_factory=list)
output_dir: str | None = None
error: str | None = None
class CancelResponse(BaseModel):
success: bool
class ModelInfo(BaseModel):
id: str
name: str
available: bool
description: str
class HistoryItem(BaseModel):
prompt: str
negative_prompt: str
timestamp: datetime
class HealthResponse(BaseModel):
status: str
timestamp: datetime
class PresetPayload(BaseModel):
name: str = Field(min_length=1, max_length=80)
prompt: str = ""
negative_prompt: str = ""
model: str = "dummy"
size: Literal["512x512", "768x768", "1024x1024", "1024x1536", "1536x1024"] = "512x512"
count: int = Field(default=1, ge=1, le=4)
steps: int = Field(default=30, ge=1, le=100)
guidance: float = Field(default=6.5, ge=1.0, le=20.0)
image_type: str = "general"
style_preset: str = "auto"
style_strength: int = Field(default=60, ge=0, le=100)
class PresetResponse(PresetPayload):
updated_at: datetime
class DashboardStats(BaseModel):
queued: int
running: int
done: int
error: int
cancelled: int
total: int
last_24h: int
class ExportRequest(BaseModel):
source_path: str
format: Literal["png", "jpg", "webp"] = "png"
quality: int = Field(default=92, ge=1, le=100)
max_width: int | None = Field(default=None, ge=64, le=8192)
max_height: int | None = Field(default=None, ge=64, le=8192)
class ExportResponse(BaseModel):
output_path: str
class AdminSettings(BaseModel):
content_profile: str
rate_limit_per_minute: int
output_retention_days: int
adult_enabled: bool = False
class MetricsResponse(BaseModel):
metrics: dict[str, float | int]