Spaces:
Running
on
Zero
Running
on
Zero
File size: 9,837 Bytes
61c16d1 5b8270b 4accd7e 8c1d120 5b8270b 4accd7e 5b8270b 4accd7e 8c1d120 5b8270b 4accd7e 5b8270b 4accd7e b07f8ef 5b8270b b07f8ef 4b3f2a2 5b8270b 4accd7e 31d44d6 3421bda 31d44d6 4accd7e 31d44d6 4accd7e 3421bda 4accd7e a2a7641 4accd7e f00ffec 5b8270b 30b2327 f30cd13 30b2327 85d98b6 5b8270b d4cae39 b07f8ef d4cae39 b07f8ef d4cae39 5b8270b f00ffec 5b8270b b07f8ef d4cae39 5b8270b b07f8ef |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# PyTorch 2.8 (temporary hack)
import os
os.system('pip install --upgrade --pre --extra-index-url https://download.pytorch.org/whl/nightly/cu126 "torch<2.9" spaces')
# Actual demo code
import gradio as gr
import numpy as np
import spaces
import torch
import random
from PIL import Image
import logging
from diffusers import FluxKontextPipeline
from diffusers.utils import load_image
# Enhanced logging configuration
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)
MAX_SEED = np.iinfo(np.int32).max
class GenerationError(Exception):
"""Custom exception for generation errors"""
pass
pipe = FluxKontextPipeline.from_pretrained("black-forest-labs/FLUX.1-Kontext-dev", torch_dtype=torch.bfloat16).to("cuda")
# -------------------- NSFW 检测模型加载 --------------------
try:
logger.info("Loading NSFW detector...")
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
from transformers import AutoProcessor, AutoModelForImageClassification
nsfw_processor = AutoProcessor.from_pretrained("Falconsai/nsfw_image_detection")
nsfw_model = AutoModelForImageClassification.from_pretrained(
"Falconsai/nsfw_image_detection"
).to(device)
logger.info("NSFW detector loaded successfully.")
except Exception as e:
logger.error(f"Failed to load NSFW detector: {e}")
nsfw_model = None
nsfw_processor = None
def detect_nsfw(image: Image.Image, threshold: float = 0.5) -> bool:
"""Returns True if image is NSFW"""
inputs = nsfw_processor(images=image, return_tensors="pt").to(device)
with torch.no_grad():
outputs = nsfw_model(**inputs)
probs = torch.nn.functional.softmax(outputs.logits, dim=-1)
nsfw_score = probs[0][1].item() # label 1 = NSFW
return nsfw_score > threshold
@spaces.GPU
def _infer(input_image, prompt, seed=42, randomize_seed=False, guidance_scale=2.5, steps=28, progress=gr.Progress()):
"""
Perform image editing using the FLUX.1 Kontext pipeline.
This function takes an input image and a text prompt to generate a modified version
of the image based on the provided instructions. It uses the FLUX.1 Kontext model
for contextual image editing tasks.
Args:
input_image (PIL.Image.Image): The input image to be edited. Will be converted
to RGB format if not already in that format.
prompt (str): Text description of the desired edit to apply to the image.
Examples: "Remove glasses", "Add a hat", "Change background to beach".
seed (int, optional): Random seed for reproducible generation. Defaults to 42.
Must be between 0 and MAX_SEED (2^31 - 1).
randomize_seed (bool, optional): If True, generates a random seed instead of
using the provided seed value. Defaults to False.
guidance_scale (float, optional): Controls how closely the model follows the
prompt. Higher values mean stronger adherence to the prompt but may reduce
image quality. Range: 1.0-10.0. Defaults to 2.5.
steps (int, optional): Controls how many steps to run the diffusion model for.
Range: 1-30. Defaults to 28.
progress (gr.Progress, optional): Gradio progress tracker for monitoring
generation progress. Defaults to gr.Progress(track_tqdm=True).
Returns:
tuple: A 3-tuple containing:
- PIL.Image.Image: The generated/edited image
- int: The seed value used for generation (useful when randomize_seed=True)
- gr.update: Gradio update object to make the reuse button visible
Example:
>>> edited_image, used_seed, button_update = infer(
... input_image=my_image,
... prompt="Add sunglasses",
... seed=123,
... randomize_seed=False,
... guidance_scale=2.5
... )
"""
progress(0,desc="Starting")
def callback_fn(pipe, step, timestep, callback_kwargs):
print(f"[Step {step}] Timestep: {timestep}")
progress_value = (step+1.0)/steps
progress(progress_value, desc=f"Image generating, {step + 1}/{steps} steps")
return callback_kwargs
if randomize_seed:
seed = random.randint(0, MAX_SEED)
try:
if input_image:
input_image = input_image.convert("RGB")
# NSFW 检测
if nsfw_model and nsfw_processor:
if detect_nsfw(input_image):
msg = "The input image contains NSFW content and cannot be generated. Please modify the input image or prompt and try again."
raise Exception(msg)
image = pipe(
image=input_image,
prompt=prompt,
guidance_scale=guidance_scale,
width = input_image.size[0],
height = input_image.size[1],
num_inference_steps=steps,
callback_on_step_end=callback_fn,
generator=torch.Generator().manual_seed(seed),
).images[0]
else:
image = pipe(
prompt=prompt,
guidance_scale=guidance_scale,
num_inference_steps=steps,
callback_on_step_end=callback_fn,
generator=torch.Generator().manual_seed(seed),
).images[0]
# NSFW 检测
if nsfw_model and nsfw_processor:
if detect_nsfw(image):
msg = "Generated image contains NSFW content and cannot be displayed. Please modify the input image or prompt and try again."
raise Exception(msg)
progress(1, desc="Complete")
info = {
"status": "success"
}
return image, info, seed, gr.Button(visible=True)
except GenerationError as e:
error_info = {
"error": str(e),
"status": "failed",
}
return None, error_info, None, None
except Exception as e:
error_info = {
"error": str(e),
"status": "failed",
}
return None, error_info, None, None
def infer(input_image, prompt, seed=42, randomize_seed=False, guidance_scale=2.5, steps=28, progress=gr.Progress()):
# 调用 GPU 函数
image, info, seed, reuse_button = _infer(input_image, prompt,seed,randomize_seed,guidance_scale,steps,progress)
# 如果出错,抛出异常
if info["status"] == "failed":
raise gr.Error(info["error"])
# 返回图片
return image, seed, reuse_button
@spaces.GPU
def infer_example(input_image, prompt):
image, seed, _ = infer(input_image, prompt)
return image, seed
title = "# Image to Image AI Editor"
description = "Your Image-to-Image AI editor. Just describe changes (‘brighter, remove object, cartoon style’) and let the AI handle the rest—no Photoshop skills needed. Try the stable version at [Image to Image AI Generator](https://www.image2image.ai)."
with gr.Blocks() as demo:
gr.Markdown(title)
gr.Markdown(description)
with gr.Column():
with gr.Row():
with gr.Column():
input_image = gr.Image(label="Upload the image for editing", type="pil")
with gr.Row():
prompt = gr.Text(
label="Prompt",
show_label=False,
max_lines=1,
placeholder="Enter your prompt for editing (e.g., 'Remove glasses', 'Add a hat')",
container=False,
)
run_button = gr.Button("Run", scale=0)
with gr.Accordion("Advanced Settings", open=False):
seed = gr.Slider(
label="Seed",
minimum=0,
maximum=MAX_SEED,
step=1,
value=0,
)
randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
guidance_scale = gr.Slider(
label="Guidance Scale",
minimum=1,
maximum=10,
step=0.1,
value=2.5,
)
steps = gr.Slider(
label="Steps",
minimum=1,
maximum=30,
value=28,
step=1
)
with gr.Column():
result = gr.Image(label="Result", show_label=False, interactive=False)
reuse_button = gr.Button("Reuse this image", visible=False)
examples = gr.Examples(
examples=[
["flowers.png", "turn the flowers into sunflowers"],
["monster.png", "make this monster ride a skateboard on the beach"],
["cat.png", "make this cat happy"]
],
inputs=[input_image, prompt],
outputs=[result, seed],
fn=infer_example,
cache_examples="lazy"
)
gr.on(
triggers=[run_button.click, prompt.submit],
fn = infer,
inputs = [input_image, prompt, seed, randomize_seed, guidance_scale, steps],
outputs = [result, seed, reuse_button]
)
reuse_button.click(
fn = lambda image: image,
inputs = [result],
outputs = [input_image]
)
demo.launch(mcp_server=True) |