Claude 5e2094f2ad
feat(media): local inference sidecar for Media Studio
FastAPI service in infra/media-worker implementing every
MediaInferenceProvider operation behind HTTP API v1, plus capabilities.
Bearer auth, MEDIA_ROOT realpath enforcement, strict request schemas,
cancellation on disconnect, GPU/CPU gates with 503 overflow, input
size/duration limits, lazy SHA256-pinned model downloads, fail-closed
redaction with atomic output, offline pytest suite with fake backends,
CPU/CUDA/ROCm Dockerfile and a license review of every model.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138YqDj3ttfayRwuMKKrqVj
2026-10-03 18:19:47 +00:00

81 lines
3.0 KiB
Python

"""Sidecar settings, read once from the environment."""
from __future__ import annotations
import os
from dataclasses import dataclass, field
MIN_TOKEN_LENGTH = 32
GIB = 1024**3
class ConfigError(Exception):
pass
def _int(env: dict[str, str], name: str, default: int, minimum: int = 0) -> int:
raw = env.get(name, "").strip()
if not raw:
return default
try:
value = int(raw)
except ValueError as error:
raise ConfigError(f"{name} must be an integer") from error
if value < minimum:
raise ConfigError(f"{name} must be >= {minimum}")
return value
@dataclass(frozen=True)
class Settings:
token: str
media_root: str
models_dir: str
host: str = "127.0.0.1"
port: int = 8790
accelerator: str = "cpu"
gpu_concurrency: int = 1
cpu_concurrency: int = 2
queue_size: int = 8
max_input_bytes: int = 20 * GIB
max_seconds: int = 4 * 3600
allow_model_download: bool = True
# Backends that are not licensed for commercial use stay off unless named here.
optional_backends: frozenset[str] = field(default_factory=frozenset)
insecure_dev: bool = False
@staticmethod
def from_env(env: dict[str, str] | None = None) -> Settings:
env = dict(os.environ if env is None else env)
insecure = env.get("MEDIA_WORKER_INSECURE_DEV", "") == "1"
token = env.get("MEDIA_WORKER_TOKEN", "")
if len(token) < MIN_TOKEN_LENGTH and not insecure:
raise ConfigError(f"MEDIA_WORKER_TOKEN must be at least {MIN_TOKEN_LENGTH} characters")
media_root = env.get("MEDIA_ROOT", "").strip()
if not media_root or not os.path.isabs(media_root):
raise ConfigError("MEDIA_ROOT must be an absolute path")
if not os.path.isdir(media_root):
raise ConfigError("MEDIA_ROOT does not exist")
accelerator = env.get("MEDIA_ACCELERATOR", "cpu").strip() or "cpu"
if accelerator not in ("cpu", "cuda", "rocm"):
raise ConfigError("MEDIA_ACCELERATOR must be cpu, cuda or rocm")
optional = frozenset(
item.strip() for item in env.get("MEDIA_OPTIONAL_BACKENDS", "").split(",") if item.strip()
)
return Settings(
token=token,
media_root=media_root,
models_dir=env.get("MEDIA_MODELS_DIR", "/models").strip() or "/models",
host=env.get("MEDIA_WORKER_HOST", "127.0.0.1").strip() or "127.0.0.1",
port=_int(env, "MEDIA_WORKER_PORT", 8790, 1),
accelerator=accelerator,
gpu_concurrency=_int(env, "MEDIA_GPU_CONCURRENCY", 1, 1),
cpu_concurrency=_int(env, "MEDIA_CPU_CONCURRENCY", 2, 1),
queue_size=_int(env, "MEDIA_QUEUE_SIZE", 8, 0),
max_input_bytes=_int(env, "MEDIA_MAX_INPUT_BYTES", 20 * GIB, 1),
max_seconds=_int(env, "MEDIA_MAX_SECONDS", 4 * 3600, 1),
allow_model_download=env.get("MEDIA_MODEL_DOWNLOAD", "1") != "0",
optional_backends=optional,
insecure_dev=insecure,
)