DageBjorne
Expand style transfer catalog with PyTorch backends and richer keywords.
fd8b97e
Raw
History Blame Contribute Delete
6.6 kB
import os
# HF Spaces often set HTTP_PROXY; without NO_PROXY, Gradio's localhost health check fails.
os.environ.setdefault("NO_PROXY", "localhost,127.0.0.1,::1")
os.environ.setdefault("no_proxy", "localhost,127.0.0.1,::1")
import gradio as gr
from PIL import Image
from pipeline import run_pipeline
from pipeline.background_replace import warmup as warmup_rembg
from pipeline.planner import warmup
from pipeline.text_regions import warmup as warmup_ocr
_warmed_up = False
def _ensure_warmup():
global _warmed_up
if _warmed_up:
return
print("Loading embedding planner, RapidOCR, and rembg...")
try:
warmup()
warmup_ocr()
warmup_rembg()
print("Models loaded.")
except Exception as exc:
print(f"Warmup failed (will retry on next request): {exc}")
return
_warmed_up = True
EXAMPLE_PROMPTS = [
["rotate randomly"],
["rotate left"],
["rotate right"],
["flip upside down"],
["rotate 180 degrees"],
["gamma brighten"],
["make it brighter"],
["more contrast"],
["vintage warm look"],
["replace background"],
["replace background with beach sunset"],
["replace background with snowy mountains"],
["replace background with anything"],
["replace background with neon city at night and rotate"],
["cover a piece but not text"],
["just cover"],
["cover and add cutout"],
["cover and several cutouts avoid text"],
["add cutout avoid text"],
["add cutout"],
["transparent cutout"],
["perspective transform"],
["cartoon style"],
["anime style"],
["starry night style"],
["pencil sketch"],
["stylize"],
["mosaic painting"],
["impressionist look"],
["flip horizontally"],
["blur everything softly"],
]
SUPPORTED_EXAMPLES = "\n".join(f"- `{row[0]}`" for row in EXAMPLE_PROMPTS)
def _format_spatial(applied_spatial: list[dict]) -> str:
if not applied_spatial:
return ""
lines = []
for item in applied_spatial:
op = item.get("op", "")
if op == "replace_background":
q = item.get("query") or "(random)"
src = item.get("source", "?")
lines.append(f"- replace_background: \"{q}\" via {src}")
continue
if op in ("cover_and_cutout", "cover_and_cutout_avoid_text"):
covers = item.get("cover_rects", [])
cutouts = item.get("cutouts", [])
fallback = " (fallback position)" if item.get("used_fallback") else ""
lines.append(
f"- {op}: {len(covers)} cover(s){fallback}, {len(cutouts)} cutout(s)"
)
for idx, rect in enumerate(covers, 1):
lines.append(f" - cover {idx} at {rect}")
for idx, detail in enumerate(cutouts, 1):
shape = detail.get("shape", "?")
style = detail.get("style", "?")
lines.append(f" - cutout {idx} ({shape}, {style}) at {detail.get('rect')}")
continue
if op in ("add_cutout", "cutout") and item.get("cutouts"):
cutouts = item.get("cutouts", [])
lines.append(f"- {op}: {len(cutouts)} cutout(s)")
for idx, detail in enumerate(cutouts, 1):
shape = detail.get("shape", "?")
style = detail.get("style", "?")
lines.append(f" - cutout {idx} ({shape}, {style}) at {detail.get('rect')}")
continue
rect = item.get("rect", ())
style = item.get("cutout_style")
shape = item.get("shape")
style_note = f", {style}" if style else ""
shape_note = f", {shape}" if shape else ""
fallback = " (fallback position)" if item.get("used_fallback") else ""
lines.append(f"- {op}{style_note}{shape_note} at {rect}{fallback}")
return "\n".join(lines)
def process(image, instruction, strength):
if image is None:
return None, None, "Please upload an image."
_ensure_warmup()
result = run_pipeline(image, instruction, strength=strength)
if not result["supported"]:
return (
image,
image,
f"**Not supported**\n\n{result['reason']}\n\n**Try these prompts:**\n{SUPPORTED_EXAMPLES}",
)
tags = ", ".join(result["applied_tags"]) or "(none)"
spatial_info = _format_spatial(result.get("applied_spatial", []))
scores = result.get("planned_scores", [])
score_info = ", ".join(f"{name} ({score:.2f})" for name, score in scores) if scores else "(none)"
info = (
f"**Instruction:** {result['instruction']}\n\n"
f"**Matched keywords:** {score_info}\n\n"
f"**Applied transforms:** {tags}\n\n"
)
if spatial_info:
info += f"**Spatial ops:**\n{spatial_info}\n\n"
if result.get("text_regions_found", 0) > 0:
info += f"**Text regions detected:** {result['text_regions_found']}\n"
return image, result["image"], info
with gr.Blocks(title="Text-Driven Image Augmentation") as demo:
gr.Markdown(
"# Text-Driven Image Augmentation\n"
"Upload an image and describe what you want. Transforms are chosen by **semantic similarity** "
"to augmentation keywords (1–5 matches above a similarity threshold). "
"Background replacement uses CC-licensed photos from Openverse "
"(web only — describe any scene, e.g. `replace background with sunset over Paris`)."
)
with gr.Row():
input_image = gr.Image(type="pil", label="Input image")
instruction = gr.Textbox(
label="Instruction",
placeholder='e.g. "vintage warm look", "replace background with snowy mountains", "blur softly"',
lines=2,
)
strength = gr.Slider(
minimum=0.5,
maximum=1.5,
value=1.0,
step=0.1,
label="Augmentation strength",
)
gr.Examples(
examples=EXAMPLE_PROMPTS,
inputs=[instruction],
label="Example prompts (click to use)",
)
run_btn = gr.Button("Augment", variant="primary")
with gr.Row():
original_out = gr.Image(label="Original", interactive=False)
augmented_out = gr.Image(label="Augmented", interactive=False)
info_out = gr.Markdown()
run_btn.click(
fn=process,
inputs=[input_image, instruction, strength],
outputs=[original_out, augmented_out, info_out],
)
if __name__ == "__main__":
demo.queue().launch(
server_name="0.0.0.0",
server_port=int(os.environ.get("PORT", 7860)),
share=False,
)