room-visualizer-api / backend /app /providers /replicate_provider.py
Johnntirs's picture
Room Visualizer backend (Docker)
0cdb4e8
Raw
History Blame Contribute Delete
2.84 kB
"""Default real provider — Replicate (SDXL inpainting + IP-Adapter).
Sends the room image, the inpaint mask, the catalog reference image, optional
depth conditioning, and a prompt to a Replicate model that supports image-
conditioned inpainting, then returns the generated image.
Credentials and the model id come from the environment only (see config.py).
Input field names are configurable so different compatible models can be used
without code changes.
"""
from __future__ import annotations
import io
import requests
from PIL import Image
from ..config import settings
from .base import ImageGenProvider
def _to_png_file(img: Image.Image, name: str) -> io.BytesIO:
buf = io.BytesIO()
img.save(buf, format="PNG")
buf.seek(0)
buf.name = name # helps the client infer the content type
return buf
def _output_to_image(output) -> Image.Image:
"""Replicate may return a URL, a list of URLs, or FileOutput objects."""
item = output[0] if isinstance(output, (list, tuple)) else output
if hasattr(item, "read"): # FileOutput (newer client)
return Image.open(io.BytesIO(item.read())).convert("RGB")
resp = requests.get(str(item), timeout=180)
resp.raise_for_status()
return Image.open(io.BytesIO(resp.content)).convert("RGB")
class ReplicateImageGenProvider(ImageGenProvider):
name = "replicate"
def __init__(self) -> None:
if not settings.REPLICATE_API_TOKEN:
raise RuntimeError("REPLICATE_API_TOKEN is not set")
if not settings.REPLICATE_MODEL:
raise RuntimeError("REPLICATE_MODEL is not set")
import replicate # imported lazily so mock mode needs no creds
self._client = replicate.Client(api_token=settings.REPLICATE_API_TOKEN)
def generate(
self,
room_image: Image.Image,
mask: Image.Image,
reference_image: Image.Image,
depth_map: Image.Image | None = None,
prompt: str = "",
**kwargs,
) -> Image.Image:
inputs = {
settings.REPLICATE_INPUT_IMAGE_KEY: _to_png_file(room_image.convert("RGB"), "room.png"),
settings.REPLICATE_INPUT_MASK_KEY: _to_png_file(mask.convert("L"), "mask.png"),
settings.REPLICATE_INPUT_REFERENCE_KEY: _to_png_file(
reference_image.convert("RGB"), "reference.png"
),
settings.REPLICATE_INPUT_PROMPT_KEY: prompt,
}
if depth_map is not None and kwargs.get("send_depth", True):
inputs.setdefault("depth_image", _to_png_file(depth_map.convert("RGB"), "depth.png"))
# Allow callers/models to inject any additional inputs verbatim.
inputs.update(kwargs.get("extra_inputs") or {})
output = self._client.run(settings.REPLICATE_MODEL, input=inputs)
return _output_to_image(output)