multimodalart HF Staff commited on
Commit
ed877b6
·
verified ·
1 Parent(s): c401704

Surface content-safety blocks: gr.Warning + stamped output image for generate and edit routes

Browse files
Files changed (1) hide show
  1. app.py +64 -1
app.py CHANGED
@@ -9,12 +9,15 @@ import os
9
  # Use flash_attention_2 for the HF text encoder (flash_attn is installed via wheel)
10
  os.environ.setdefault("VF_HF_ATTN_IMPL", "flash_attention_2")
11
 
 
 
12
  import spaces # MUST be first (after env setup)
13
  import torch
14
  import gradio as gr
15
- from PIL import Image
16
 
17
  from mage_flow.pipeline import MageFlowPipeline
 
18
 
19
  T2I_MODEL = "microsoft/Mage-Flow-Turbo"
20
  EDIT_MODEL = "microsoft/Mage-Flow-Edit-Turbo"
@@ -23,6 +26,48 @@ pipe_t2i = MageFlowPipeline.from_pretrained(T2I_MODEL, device="cuda")
23
  pipe_edit = MageFlowPipeline.from_pretrained(EDIT_MODEL, device="cuda")
24
 
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  @spaces.GPU(duration=60)
27
  def generate(
28
  prompt: str,
@@ -61,6 +106,16 @@ def generate(
61
  if isinstance(image, str):
62
  image = Image.open(image)
63
  refs = [image.convert("RGB")]
 
 
 
 
 
 
 
 
 
 
64
  out = pipe_edit.edit(
65
  [prompt],
66
  [refs],
@@ -73,6 +128,14 @@ def generate(
73
  return out
74
 
75
  # No image: route to the text-to-image model.
 
 
 
 
 
 
 
 
76
  img = pipe_t2i.generate(
77
  [prompt],
78
  neg_prompts=[negative_prompt or " "],
 
9
  # Use flash_attention_2 for the HF text encoder (flash_attn is installed via wheel)
10
  os.environ.setdefault("VF_HF_ATTN_IMPL", "flash_attention_2")
11
 
12
+ import textwrap
13
+
14
  import spaces # MUST be first (after env setup)
15
  import torch
16
  import gradio as gr
17
+ from PIL import Image, ImageDraw, ImageFont
18
 
19
  from mage_flow.pipeline import MageFlowPipeline
20
+ from mage_flow.models.modules.mage_text import CATEGORY_DISPLAY
21
 
22
  T2I_MODEL = "microsoft/Mage-Flow-Turbo"
23
  EDIT_MODEL = "microsoft/Mage-Flow-Edit-Turbo"
 
26
  pipe_edit = MageFlowPipeline.from_pretrained(EDIT_MODEL, device="cuda")
27
 
28
 
29
+ def _block_reason_text(verdict) -> str:
30
+ """Human-readable block reason: '<category> · <explanation>'."""
31
+ cat = ", ".join(
32
+ CATEGORY_DISPLAY.get(c, c) for c in verdict.categories
33
+ ) or "policy violation"
34
+ reason = (verdict.reason or "").strip()
35
+ return f"{cat} · {reason}" if reason else cat
36
+
37
+
38
+ def _blocked_image(reason_text: str, height: int = 1024, width: int = 1024) -> Image.Image:
39
+ """Neutral background image with the safety-filter message drawn on it."""
40
+ img = Image.new("RGB", (int(width), int(height)), color=(245, 245, 245))
41
+ draw = ImageDraw.Draw(img)
42
+ try:
43
+ font = ImageFont.load_default(size=28)
44
+ except TypeError: # older Pillow: load_default() takes no size
45
+ font = ImageFont.load_default()
46
+
47
+ message = (
48
+ "The safety classifiers included by default in the Microsoft Mage "
49
+ "Flow model flagged the following:\n\n" + reason_text
50
+ )
51
+
52
+ # Wrap each paragraph to a column width that fits the image.
53
+ max_chars = max(20, int(width / 16))
54
+ lines = []
55
+ for para in message.split("\n"):
56
+ if not para:
57
+ lines.append("")
58
+ continue
59
+ lines.extend(textwrap.wrap(para, width=max_chars))
60
+
61
+ # Vertically center the text block.
62
+ line_h = 38
63
+ total_h = line_h * len(lines)
64
+ y = max(20, (int(height) - total_h) // 2)
65
+ for line in lines:
66
+ draw.text((40, y), line, fill=(20, 20, 20), font=font)
67
+ y += line_h
68
+ return img
69
+
70
+
71
  @spaces.GPU(duration=60)
72
  def generate(
73
  prompt: str,
 
106
  if isinstance(image, str):
107
  image = Image.open(image)
108
  refs = [image.convert("RGB")]
109
+
110
+ # Content-safety gate: surface a block to the user instead of failing
111
+ # silently (gr.Warning toast + a stamped output image).
112
+ verdict = pipe_edit.model.txt_enc.screen_edit(prompt, refs)
113
+ if verdict.violates:
114
+ reason_text = _block_reason_text(verdict)
115
+ gr.Warning(reason_text)
116
+ w, h = refs[0].size
117
+ return _blocked_image(reason_text, height=h, width=w)
118
+
119
  out = pipe_edit.edit(
120
  [prompt],
121
  [refs],
 
128
  return out
129
 
130
  # No image: route to the text-to-image model.
131
+ # Content-safety gate: surface a block to the user instead of failing
132
+ # silently (gr.Warning toast + a stamped output image).
133
+ verdict = pipe_t2i.model.txt_enc.screen_text(prompt)
134
+ if verdict.violates:
135
+ reason_text = _block_reason_text(verdict)
136
+ gr.Warning(reason_text)
137
+ return _blocked_image(reason_text, height=int(height), width=int(width))
138
+
139
  img = pipe_t2i.generate(
140
  [prompt],
141
  neg_prompts=[negative_prompt or " "],