Create monorepo from known-good production state

This commit is contained in:
makearmy 2026-07-09 21:07:34 -04:00
commit c034824338
651 changed files with 120469 additions and 0 deletions

70
bgbye/server/ormbg.py Normal file
View file

@ -0,0 +1,70 @@
# /app/server/ormbg.py
from __future__ import annotations
import io
import os
from typing import Optional, Union
from rembg import remove as rembg_remove, new_session
from PIL import Image
import onnxruntime as ort
# Choose GPU if available, else CPU
def _default_providers() -> list[str]:
providers = ort.get_available_providers()
return ["CUDAExecutionProvider", "CPUExecutionProvider"] if "CUDAExecutionProvider" in providers else ["CPUExecutionProvider"]
class ORMBGProcessor:
"""
Minimal adapter used by server.py.
Provides:
- .warmup()
- .process_bytes(input_bytes) -> bytes (PNG with alpha)
- .process_pil(img: PIL.Image.Image) -> PIL.Image.Image
- .close() (no-op; for API symmetry)
"""
def __init__(self, model_name: str = "isnet-general-use", providers: Optional[list[str]] = None):
# Some rembg internals pick providers automatically; onnxruntime-gpu presence
# will make CUDA provider available. We still compute a list so we can log/verify.
self.providers = providers or _default_providers()
# rembg's API chooses the best available EP under the hood if ORT-GPU is present.
# Just ensure the model name exists; common: isnet-general-use, u2net, u2netp, u2net_human_seg
self.model_name = model_name
self.session = new_session(self.model_name)
def warmup(self) -> None:
# Tiny 1x1 transparent PNG to trigger model load
img = Image.new("RGBA", (1, 1), (0, 0, 0, 0))
_ = self.process_pil(img)
def process_bytes(self, data: bytes, return_png: bool = True) -> bytes:
"""
Accept raw image bytes (jpg/png/etc), return PNG bytes with alpha.
"""
out = rembg_remove(data, session=self.session)
if return_png:
# rembg already returns PNG bytes by default; if it's bytes, just pass through
if isinstance(out, (bytes, bytearray)):
return bytes(out)
# if it's a PIL image, convert to PNG bytes
if isinstance(out, Image.Image):
buf = io.BytesIO()
out.save(buf, format="PNG")
return buf.getvalue()
# fallback: ensure bytes
if isinstance(out, Image.Image):
buf = io.BytesIO()
out.save(buf, format="PNG")
return buf.getvalue()
return bytes(out)
def process_pil(self, img: Image.Image) -> Image.Image:
out = rembg_remove(img, session=self.session)
if isinstance(out, Image.Image):
return out
# if rembg returned bytes, decode back to PIL
return Image.open(io.BytesIO(out)).convert("RGBA")
def close(self) -> None:
# Nothing to dispose explicitly; keep for API compatibility
pass