Nymbo commited on
Commit
1ecadaa
·
verified ·
1 Parent(s): 26a3d7f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -95
app.py CHANGED
@@ -5,19 +5,12 @@ import spaces
5
  import torch
6
  from PIL import Image
7
  from typing import Annotated, Iterator, Tuple
8
- from diffusers import DiffusionPipeline, FlowMatchEulerDiscreteScheduler, AutoencoderKL
9
- from transformers import CLIPTextModel, CLIPTokenizer, T5EncoderModel, T5TokenizerFast
10
  from live_preview_helpers import calculate_shift, retrieve_timesteps, flux_pipe_call_that_returns_an_iterable_of_images
11
 
12
  dtype = torch.bfloat16
13
  device = "cuda" if torch.cuda.is_available() else "cpu"
14
 
15
- TOOL_SUMMARY = (
16
- "Generate an image from a text prompt via an uncensored model; "
17
- "tunable model/steps/guidance/size, supports negative prompt and seed; returns a PIL.Image. "
18
- "Return the generated media to the user in this format `![Alt text](URL)`."
19
- )
20
-
21
  good_vae = AutoencoderKL.from_pretrained("black-forest-labs/FLUX.1-dev", subfolder="vae", torch_dtype=dtype).to(device)
22
  pipe = DiffusionPipeline.from_pretrained("black-forest-labs/FLUX.1-dev", torch_dtype=dtype, vae=good_vae).to(device)
23
  pipe.load_lora_weights("enhanceaiteam/Flux-Uncensored-V2")
@@ -29,7 +22,7 @@ MAX_IMAGE_SIZE = 2048
29
  pipe.flux_pipe_call_that_returns_an_iterable_of_images = flux_pipe_call_that_returns_an_iterable_of_images.__get__(pipe)
30
 
31
  @spaces.GPU(duration=25)
32
- def infer(
33
  prompt: Annotated[str, "Text description of the image to generate."],
34
  seed: Annotated[int, "Random seed for reproducibility. Use 0 for a random seed per call."] = 42,
35
  randomize_seed: Annotated[bool, "If true, pick a new random seed for every call (overrides seed)."] = True,
@@ -40,88 +33,52 @@ def infer(
40
  progress: gr.Progress = gr.Progress(track_tqdm=True),
41
  ) -> Iterator[Tuple[Image.Image, int]]:
42
  """
43
- Generate professional-quality images with Flux.1 dev paired with the Flux-Uncensored-V2 LoRA.
44
-
45
- Streams intermediate frames so MCP clients can preview progress. Optimized for product photography,
46
- fashion, concept art, and stock-style imagery where lighting and material realism matter.
47
-
48
- Args:
49
- prompt (str): Text description of the desired image.
50
- seed (int): Random seed for reproducibility. Use 0 to randomize per call.
51
- randomize_seed (bool): If true, ignore seed and pick a new random value per call.
52
- width (int): Image width in pixels. Upper bound enforced by MAX_IMAGE_SIZE.
53
- height (int): Image height in pixels. Upper bound enforced by MAX_IMAGE_SIZE.
54
- guidance_scale (float): Classifier-free guidance strength.
55
- num_inference_steps (int): Number of denoising iterations to perform.
56
- progress (gr.Progress): Managed by Gradio to surface progress updates.
57
-
58
- Yields:
59
- tuple[Image.Image, int]: Intermediate or final image paired with the seed used.
60
-
61
- Raises:
62
- gr.Error: If the prompt is empty or the requested dimensions exceed MAX_IMAGE_SIZE.
63
- """
64
- if not prompt or not prompt.strip():
65
- raise gr.Error("Please provide a non-empty prompt.")
66
- if width > MAX_IMAGE_SIZE or height > MAX_IMAGE_SIZE:
67
- raise gr.Error(f"Width and height must be <= {MAX_IMAGE_SIZE}.")
68
-
69
- if randomize_seed or seed == 0:
70
- seed = random.randint(0, MAX_SEED)
71
- generator = torch.Generator().manual_seed(seed)
72
-
73
- for img in pipe.flux_pipe_call_that_returns_an_iterable_of_images(
74
- prompt=prompt,
75
- guidance_scale=guidance_scale,
76
- num_inference_steps=num_inference_steps,
77
- width=width,
78
- height=height,
79
- generator=generator,
80
- output_type="pil",
81
- good_vae=good_vae,
82
- ):
83
- yield img, seed
84
-
85
-
86
- @spaces.GPU(duration=25)
87
- def infer_mcp(
88
- prompt: Annotated[str, "Text description of the desired image."],
89
- seed: Annotated[int, "Random seed for reproducibility. Use 0 to randomize per call."] = 42,
90
- randomize_seed: Annotated[bool, "If true, ignore seed and pick a new random value per call."] = True,
91
- width: Annotated[int, "Image width in pixels. Upper bound enforced by MAX_IMAGE_SIZE."] = 768,
92
- height: Annotated[int, "Image height in pixels. Upper bound enforced by MAX_IMAGE_SIZE."] = 768,
93
- guidance_scale: Annotated[float, "Classifier-free guidance strength."] = 4.5,
94
- num_inference_steps: Annotated[int, "Number of denoising iterations to perform."] = 24,
95
- ) -> Tuple[Image.Image, int]:
96
- """
97
- Generate an image from a text prompt via an uncensored model.
98
 
99
- Returns the generated image and the seed used. Return the generated media
100
- to the user in this format: `![Alt text](URL)`.
101
  """
102
  if not prompt or not prompt.strip():
103
- raise gr.Error("Please provide a non-empty prompt.")
 
 
 
104
  if width > MAX_IMAGE_SIZE or height > MAX_IMAGE_SIZE:
105
- raise gr.Error(f"Width and height must be <= {MAX_IMAGE_SIZE}.")
 
 
 
 
 
 
 
 
106
 
107
  if randomize_seed or seed == 0:
108
  seed = random.randint(0, MAX_SEED)
109
  generator = torch.Generator().manual_seed(seed)
110
 
111
- final_img = None
112
- for img in pipe.flux_pipe_call_that_returns_an_iterable_of_images(
113
- prompt=prompt,
114
- guidance_scale=guidance_scale,
115
- num_inference_steps=num_inference_steps,
116
- width=width,
117
- height=height,
118
- generator=generator,
119
- output_type="pil",
120
- good_vae=good_vae,
121
- ):
122
- final_img = img
123
-
124
- return final_img, seed
 
 
 
 
 
 
 
 
125
 
126
  css="""
127
  #col-container {
@@ -200,23 +157,14 @@ with gr.Blocks() as demo:
200
  value=24,
201
  )
202
 
203
- # UI event: uses the generator for live preview (api_name=False = not exposed to MCP)
204
  gr.on(
205
  triggers=[run_button.click, prompt.submit],
206
- fn = infer,
207
- inputs = [prompt, seed, randomize_seed, width, height, guidance_scale, num_inference_steps],
208
- outputs = [result, seed],
209
- api_name=False,
210
- )
211
-
212
- # MCP tool: uses non-generator function to avoid middleware issues
213
- mcp_button = gr.Button("Generate (MCP)", visible=False)
214
- mcp_button.click(
215
- fn=infer_mcp,
216
  inputs=[prompt, seed, randomize_seed, width, height, guidance_scale, num_inference_steps],
217
  outputs=[result, seed],
218
- api_name="Fun_Img_infer",
219
  )
220
 
221
  if __name__ == "__main__":
222
- demo.launch(mcp_server=True, theme="Nymbo/Nymbo_Theme", css=css)
 
5
  import torch
6
  from PIL import Image
7
  from typing import Annotated, Iterator, Tuple
8
+ from diffusers import DiffusionPipeline, AutoencoderKL
 
9
  from live_preview_helpers import calculate_shift, retrieve_timesteps, flux_pipe_call_that_returns_an_iterable_of_images
10
 
11
  dtype = torch.bfloat16
12
  device = "cuda" if torch.cuda.is_available() else "cpu"
13
 
 
 
 
 
 
 
14
  good_vae = AutoencoderKL.from_pretrained("black-forest-labs/FLUX.1-dev", subfolder="vae", torch_dtype=dtype).to(device)
15
  pipe = DiffusionPipeline.from_pretrained("black-forest-labs/FLUX.1-dev", torch_dtype=dtype, vae=good_vae).to(device)
16
  pipe.load_lora_weights("enhanceaiteam/Flux-Uncensored-V2")
 
22
  pipe.flux_pipe_call_that_returns_an_iterable_of_images = flux_pipe_call_that_returns_an_iterable_of_images.__get__(pipe)
23
 
24
  @spaces.GPU(duration=25)
25
+ def Generate_Image(
26
  prompt: Annotated[str, "Text description of the image to generate."],
27
  seed: Annotated[int, "Random seed for reproducibility. Use 0 for a random seed per call."] = 42,
28
  randomize_seed: Annotated[bool, "If true, pick a new random seed for every call (overrides seed)."] = True,
 
33
  progress: gr.Progress = gr.Progress(track_tqdm=True),
34
  ) -> Iterator[Tuple[Image.Image, int]]:
35
  """
36
+ Generate an image from a text prompt using Flux.1 dev with LoRA.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
+ Return the generated media to the user in this format: `![Alt text](URL)`.
 
39
  """
40
  if not prompt or not prompt.strip():
41
+ raise gr.Error(
42
+ "Empty prompt provided. Please describe what you want to generate, "
43
+ "e.g. 'a sunset over mountains' or 'portrait of a cat in watercolor style'."
44
+ )
45
  if width > MAX_IMAGE_SIZE or height > MAX_IMAGE_SIZE:
46
+ raise gr.Error(
47
+ f"Image dimensions too large. Maximum allowed is {MAX_IMAGE_SIZE}x{MAX_IMAGE_SIZE} pixels. "
48
+ f"You requested {width}x{height}. Please reduce width and/or height."
49
+ )
50
+ if width < 256 or height < 256:
51
+ raise gr.Error(
52
+ f"Image dimensions too small. Minimum allowed is 256x256 pixels. "
53
+ f"You requested {width}x{height}. Please increase width and/or height."
54
+ )
55
 
56
  if randomize_seed or seed == 0:
57
  seed = random.randint(0, MAX_SEED)
58
  generator = torch.Generator().manual_seed(seed)
59
 
60
+ try:
61
+ for img in pipe.flux_pipe_call_that_returns_an_iterable_of_images(
62
+ prompt=prompt,
63
+ guidance_scale=guidance_scale,
64
+ num_inference_steps=num_inference_steps,
65
+ width=width,
66
+ height=height,
67
+ generator=generator,
68
+ output_type="pil",
69
+ good_vae=good_vae,
70
+ ):
71
+ yield img, seed
72
+ except torch.cuda.OutOfMemoryError:
73
+ raise gr.Error(
74
+ "GPU ran out of memory. Try reducing image dimensions (e.g., 512x512) "
75
+ "or reducing the number of inference steps."
76
+ )
77
+ except Exception as exc:
78
+ raise gr.Error(
79
+ f"Image generation failed: {exc}. "
80
+ "Please try again or adjust your parameters."
81
+ )
82
 
83
  css="""
84
  #col-container {
 
157
  value=24,
158
  )
159
 
160
+ # UI event and MCP tool
161
  gr.on(
162
  triggers=[run_button.click, prompt.submit],
163
+ fn=Generate_Image,
 
 
 
 
 
 
 
 
 
164
  inputs=[prompt, seed, randomize_seed, width, height, guidance_scale, num_inference_steps],
165
  outputs=[result, seed],
166
+ api_name="Generate_Image",
167
  )
168
 
169
  if __name__ == "__main__":
170
+ demo.launch(mcp_server=True, ssr_mode=False, theme="Nymbo/Nymbo_Theme", css=css)