Nymbo commited on
Commit
25d39b9
·
verified ·
1 Parent(s): 06ff1bc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +249 -196
app.py CHANGED
@@ -2,16 +2,20 @@ import gradio as gr
2
  import random
3
  import os
4
  from PIL import Image
5
- from typing import Optional, Dict, Tuple
6
  from huggingface_hub import InferenceClient
 
 
 
7
 
8
- # Project by Nymbo
9
 
 
10
  API_TOKEN = os.getenv("HF_READ_TOKEN")
11
  timeout = 100
12
 
13
  def flux_krea_generate(
14
- prompt: str,
15
  negative_prompt: str = "(deformed, distorted, disfigured), poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, (mutated hands and fingers), disconnected limbs, mutation, mutated, ugly, disgusting, blurry, amputation, misspellings, typos",
16
  steps: int = 35,
17
  cfg_scale: float = 7.0,
@@ -19,41 +23,45 @@ def flux_krea_generate(
19
  seed: int = -1,
20
  strength: float = 0.7,
21
  width: int = 1024,
22
- height: int = 1024,
23
- ) -> Optional[Image.Image]:
24
- """Generate a single image from a text prompt using FLUX.1-Krea-dev.
25
-
26
- Contract (for UI):
27
- - Inputs: prompt (required), optional tuning params below. No input image used.
28
- - Output: a PIL.Image for Gradio image component wiring.
29
- - Errors: raises gr.Error on auth/model/service issues.
 
30
 
31
  Args:
32
- prompt: Required. Describes what to create. Keep it specific and concise.
33
- negative_prompt: Phrases/objects to avoid in the output.
34
- steps: Number of diffusion steps (1-100). Higher may improve detail but is slower.
35
- cfg_scale: Classifier-free guidance scale (1-20). Higher forces closer adherence to prompt.
36
- sampler: Sampler algorithm label (UI only; provider may ignore or auto-select).
37
- seed: Set a deterministic seed (>=0). Use -1 to randomize per call.
38
- strength: Kept for parity; has no effect without an input image (0-1).
39
- width: Output width in pixels (64-1216). Prefer multiples of 32.
40
- height: Output height in pixels (64-1216). Prefer multiples of 32.
41
 
42
  Returns:
43
- PIL.Image or None if prompt is empty.
44
  """
45
- if prompt == "" or prompt is None:
46
- return None
 
 
 
 
47
 
48
- key = random.randint(0, 999)
49
 
50
- # Add some extra flair to the prompt
51
  enhanced_prompt = f"{prompt} | ultra detail, ultra elaboration, ultra quality, perfect."
52
- print(f'\033[1mGeneration {key}:\033[0m {enhanced_prompt}')
53
 
54
  try:
55
- # Initialize the Hugging Face Inference Client
56
- # Try different providers in order of preference
57
  providers = ["auto", "replicate", "fal-ai"]
58
 
59
  for provider in providers:
@@ -63,7 +71,7 @@ def flux_krea_generate(
63
  provider=provider
64
  )
65
 
66
- # Generate the image using the proper client
67
  image = client.text_to_image(
68
  prompt=enhanced_prompt,
69
  negative_prompt=negative_prompt,
@@ -75,207 +83,252 @@ def flux_krea_generate(
75
  seed=seed if seed != -1 else random.randint(1, 1000000000)
76
  )
77
 
78
- print(f'\033[1mGeneration {key} completed with {provider}!\033[0m ({enhanced_prompt})')
79
- return image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
  except Exception as provider_error:
82
  print(f"Provider {provider} failed: {provider_error}")
83
- if provider == providers[-1]: # Last provider
84
  raise provider_error
85
  continue
86
 
87
  except Exception as e:
88
- print(f"Error during image generation: {e}")
 
 
89
  if "404" in str(e):
90
- raise gr.Error("Model not found. Please ensure the FLUX.1-Krea-dev model is accessible with your API token.")
91
  elif "503" in str(e):
92
- raise gr.Error("The model is currently being loaded. Please try again in a moment.")
93
  elif "401" in str(e) or "403" in str(e):
94
- raise gr.Error("Authentication failed. Please check your HF_READ_TOKEN environment variable.")
95
- else:
96
- raise gr.Error(f"Image generation failed: {str(e)}")
97
- return None
98
-
99
-
100
- def _space_base_url() -> Optional[str]:
101
- """Return the public base URL of this Space if available.
102
-
103
- Looks up SPACE_ID (e.g. "username/space-name") and converts it to
104
- the public subdomain "https://username-space-name.hf.space".
105
- If SPACE_ID is not set, optionally respects HF_SPACE_BASE_URL.
106
- """
107
- # Explicit override if provided
108
- explicit = os.getenv("HF_SPACE_BASE_URL")
109
- if explicit:
110
- return explicit.rstrip("/")
111
-
112
- space_id = os.getenv("SPACE_ID")
113
- if not space_id:
114
- return None
115
- sub = space_id.replace("/", "-")
116
- return f"https://{sub}.hf.space"
117
-
118
-
119
- def _save_image_and_url(image: Image.Image, key: int) -> Tuple[str, Optional[str]]:
120
- """Save the image to a temporary path and construct a public URL if running on Spaces.
121
-
122
- Returns (local_path, public_url_or_None).
123
- """
124
- # Ensure POSIX-like temp dir (Spaces is Linux). Still works locally.
125
- out_dir = os.path.join("/tmp", "flux-krea-outputs")
126
- os.makedirs(out_dir, exist_ok=True)
127
- file_path = os.path.join(out_dir, f"flux_{key}.png")
128
- image.save(file_path)
129
-
130
- base_url = _space_base_url()
131
- public_url = None
132
- if base_url:
133
- # Gradio serves local files via /file=<absolute-path>
134
- # Normalize backslashes to forward slashes in case of local dev on Windows
135
- posix_path = file_path.replace("\\", "/")
136
- public_url = f"{base_url}/file={posix_path}"
137
-
138
- return file_path, public_url
139
-
140
-
141
- def flux_krea_generate_mcp(
142
- prompt: str,
143
- negative_prompt: str = "(deformed, distorted, disfigured), poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, (mutated hands and fingers), disconnected limbs, mutation, mutated, ugly, disgusting, blurry, amputation, misspellings, typos",
144
- steps: int = 35,
145
- cfg_scale: float = 7,
146
- sampler: str = "DPM++ 2M Karras",
147
- seed: int = -1,
148
- strength: float = 0.7,
149
- width: int = 1024,
150
- height: int = 1024,
151
- ) -> Dict[str, object]:
152
- """Generate an image (MCP tool) and return a JSON payload with a public URL.
153
-
154
- This endpoint is tailored for Model Context Protocol (MCP) clients per the
155
- latest Hugging Face MCP Space guidance (see hf-docs-search: "Spaces as MCP servers").
156
-
157
- Inputs:
158
- - prompt (str, required): Description of the desired image.
159
- - negative_prompt (str): Items to avoid in the generation.
160
- - steps (int, 1-100): Denoising steps. Higher is slower and may add detail.
161
- - cfg_scale (float, 1-20): Guidance strength. Higher adheres more to the prompt.
162
- - sampler (str): Sampler label (informational; provider may auto-select).
163
- - seed (int): -1 for random per call; otherwise a deterministic seed >= 0.
164
- - strength (float, 0-1): No-op in pure text-to-image; kept for cross-app parity.
165
- - width (int, 64-1216): Output width (prefer multiples of 32).
166
- - height (int, 64-1216): Output height (prefer multiples of 32).
167
-
168
- Returns (JSON):
169
- - image_path (str): Absolute path to the saved image on the Space VM.
170
- - image_url (str|None): Publicly accessible URL to the image on the Space
171
- (present when running on Spaces; None when running locally).
172
- - seed (int): The seed used for this run (randomized if input was -1).
173
- - width (int), height (int): Echo of output dimensions.
174
- - sampler (str): Echo of requested sampler.
175
-
176
- Error Modes:
177
- - Raises a Gradio-friendly error with a concise message for common HTTP
178
- failure codes (401/403 auth; 404 model; 503 warmup).
179
- """
180
- if not prompt:
181
- raise gr.Error("'prompt' is required and cannot be empty.")
182
-
183
- # Reuse core generator for image creation
184
- image = flux_krea_generate(
185
- prompt=prompt,
186
- negative_prompt=negative_prompt,
187
- steps=steps,
188
- cfg_scale=cfg_scale,
189
- sampler=sampler,
190
- seed=seed,
191
- strength=strength,
192
- width=width,
193
- height=height,
194
- )
195
-
196
- if image is None:
197
- raise gr.Error("No image generated.")
198
-
199
- # Save and build URLs
200
- key = random.randint(0, 999)
201
- file_path, public_url = _save_image_and_url(image, key)
202
 
203
- # Expose URL explicitly for MCP clients (LLMs need a resolvable URL)
204
- return {
205
- "image_path": file_path,
206
- "image_url": public_url,
207
- "seed": seed,
208
- "width": width,
209
- "height": height,
210
- "sampler": sampler,
211
- }
 
 
212
 
213
- # CSS to style the app
214
  css = """
215
  #app-container {
216
- max-width: 800px;
217
  margin-left: auto;
218
  margin-right: auto;
219
  }
 
 
 
 
 
 
 
 
220
  """
221
 
222
- # Build the Gradio UI with Blocks
223
- with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css) as app:
224
- # Add a title to the app
225
- gr.HTML("<center><h1>FLUX.1-Krea-dev</h1></center>")
226
- gr.HTML("<center><p>High-quality image generation via Model Context Protocol</p></center>")
 
 
 
 
 
227
 
228
- # Container for all the UI elements
229
  with gr.Column(elem_id="app-container"):
230
- # Add a text input for the main prompt
231
  with gr.Row():
232
- with gr.Column(elem_id="prompt-container"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  with gr.Row():
234
- text_prompt = gr.Textbox(label="Prompt", placeholder="Enter a prompt here", lines=2, elem_id="prompt-text-input")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
- # Accordion for advanced settings
237
  with gr.Row():
238
- with gr.Accordion("Advanced Settings", open=False):
239
- negative_prompt = gr.Textbox(label="Negative Prompt", placeholder="What should not be in the image", value="(deformed, distorted, disfigured), poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, (mutated hands and fingers), disconnected limbs, mutation, mutated, ugly, disgusting, blurry, amputation, misspellings, typos", lines=3, elem_id="negative-prompt-text-input")
240
- with gr.Row():
241
- width = gr.Slider(label="Width", value=1024, minimum=64, maximum=1216, step=32)
242
- height = gr.Slider(label="Height", value=1024, minimum=64, maximum=1216, step=32)
243
- steps = gr.Slider(label="Sampling steps", value=35, minimum=1, maximum=100, step=1)
244
- cfg = gr.Slider(label="CFG Scale", value=7, minimum=1, maximum=20, step=1)
245
- strength = gr.Slider(label="Strength", value=0.7, minimum=0, maximum=1, step=0.001)
246
- seed = gr.Slider(label="Seed", value=-1, minimum=-1, maximum=1000000000, step=1) # Setting the seed to -1 will make it random
247
- method = gr.Radio(label="Sampling method", value="DPM++ 2M Karras", choices=["DPM++ 2M Karras", "DPM++ SDE Karras", "Euler", "Euler a", "Heun", "DDIM"])
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
- # Add a button to trigger the image generation
250
  with gr.Row():
251
- text_button = gr.Button("Run", variant='primary', elem_id="gen-button")
252
 
253
- # Image output area to display the generated image
254
  with gr.Row():
255
- # Output component only; no input image is required by the tool
256
- image_output = gr.Image(label="Image Output", elem_id="gallery")
 
 
 
 
257
 
258
- # Bind the button to the flux_krea_generate function for the UI only
259
- # Hide this event as an MCP tool to avoid schema confusion (UI wires image output)
260
- text_button.click(
261
- flux_krea_generate,
262
- inputs=[text_prompt, negative_prompt, steps, cfg, method, seed, strength, width, height],
 
 
 
 
 
 
 
 
 
 
263
  outputs=image_output,
264
- show_api=False,
265
- api_description=False,
266
  )
267
 
268
- # Expose a dedicated MCP/API endpoint with a clear schema (text-to-image only)
269
- # This wrapper returns both a local file path and a fully-qualified public URL
270
- # when running on Spaces so LLMs can access the finished image.
271
  gr.api(
272
- flux_krea_generate_mcp,
273
- api_name="generate_image",
274
  api_description=(
275
- "Generate an image from a text prompt using FLUX.1-Krea-dev. "
276
- "Returns JSON with image_path and image_url (public URL when on Spaces)."
277
- ),
 
278
  )
279
 
280
- # Launch the Gradio app with MCP server enabled
281
- app.launch(show_api=True, share=False, mcp_server=True)
 
 
 
 
 
 
 
 
 
 
2
  import random
3
  import os
4
  from PIL import Image
5
+ from typing import Optional
6
  from huggingface_hub import InferenceClient
7
+ import tempfile
8
+ import json
9
+ import uuid
10
 
11
+ # Project by Nymbo - Converted to MCP Server
12
 
13
+ # Configuration
14
  API_TOKEN = os.getenv("HF_READ_TOKEN")
15
  timeout = 100
16
 
17
  def flux_krea_generate(
18
+ prompt: str,
19
  negative_prompt: str = "(deformed, distorted, disfigured), poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, (mutated hands and fingers), disconnected limbs, mutation, mutated, ugly, disgusting, blurry, amputation, misspellings, typos",
20
  steps: int = 35,
21
  cfg_scale: float = 7.0,
 
23
  seed: int = -1,
24
  strength: float = 0.7,
25
  width: int = 1024,
26
+ height: int = 1024
27
+ ) -> str:
28
+ """
29
+ Generate high-quality professional images using FLUX.1-Krea-dev via HuggingFace Serverless Inference.
30
+
31
+ This MCP tool creates realistic, professional-quality images from text prompts using the
32
+ FLUX.1-Krea-dev model through HuggingFace's serverless inference infrastructure. The model
33
+ excels at generating natural-looking images without typical AI artifacts, making it ideal
34
+ for product photography, e-commerce visuals, concept art, fashion photography, and stock images.
35
 
36
  Args:
37
+ prompt: Detailed text description of the image to generate. Best results with approximately 60-70 words max. Include technical photography terms, specific lighting, and material textures for photorealistic results.
38
+ negative_prompt: Elements to avoid in the generated image (deformities, poor anatomy, etc.).
39
+ steps: Number of denoising steps (1-100). Higher values generally improve quality but increase generation time.
40
+ cfg_scale: Classifier-free guidance scale (1-20). Higher values make the model follow the prompt more closely but may reduce creativity.
41
+ sampler: Sampling method for diffusion process. Options: "DPM++ 2M Karras", "DPM++ SDE Karras", "Euler", "Euler a", "Heun", "DDIM".
42
+ seed: Random seed for reproducible results. Use -1 for random generation each time.
43
+ strength: Generation strength parameter (0-1). Controls the influence of the generation process.
44
+ width: Output image width in pixels (64-1216). Recommend multiples of 32 for best results.
45
+ height: Output image height in pixels (64-1216). Recommend multiples of 32 for best results.
46
 
47
  Returns:
48
+ JSON string containing the image URL and generation metadata that can be accessed by LLMs and MCP clients.
49
  """
50
+ if not prompt or prompt.strip() == "":
51
+ return json.dumps({
52
+ "success": False,
53
+ "error": "Prompt is required and cannot be empty",
54
+ "image_url": None
55
+ })
56
 
57
+ generation_id = random.randint(0, 999)
58
 
59
+ # Enhance prompt for better quality
60
  enhanced_prompt = f"{prompt} | ultra detail, ultra elaboration, ultra quality, perfect."
61
+ print(f'\033[1mMCP Generation {generation_id}:\033[0m {enhanced_prompt}')
62
 
63
  try:
64
+ # Initialize the Hugging Face Inference Client with fallback providers
 
65
  providers = ["auto", "replicate", "fal-ai"]
66
 
67
  for provider in providers:
 
71
  provider=provider
72
  )
73
 
74
+ # Generate the image using serverless inference
75
  image = client.text_to_image(
76
  prompt=enhanced_prompt,
77
  negative_prompt=negative_prompt,
 
83
  seed=seed if seed != -1 else random.randint(1, 1000000000)
84
  )
85
 
86
+ # Save the image to a temporary file that Gradio can serve
87
+ # This creates a local file that Gradio can serve with a public URL
88
+ if image:
89
+ # Generate a unique filename
90
+ unique_id = str(uuid.uuid4())[:8]
91
+ temp_filename = f"flux_krea_{generation_id}_{unique_id}.png"
92
+
93
+ # Save to temp directory
94
+ temp_file = tempfile.NamedTemporaryFile(
95
+ delete=False,
96
+ suffix=".png",
97
+ prefix=f"flux_krea_{generation_id}_"
98
+ )
99
+ image.save(temp_file.name)
100
+ temp_file.close()
101
+
102
+ # For MCP clients, we need to provide a URL that they can access
103
+ # Gradio will serve temp files via the /file/ endpoint
104
+ file_url = temp_file.name
105
+
106
+ print(f'\033[1mMCP Generation {generation_id} completed with {provider}!\033[0m')
107
+
108
+ # Return JSON with both file path and success metadata
109
+ result = {
110
+ "success": True,
111
+ "image_url": file_url,
112
+ "image_path": file_url,
113
+ "generation_id": generation_id,
114
+ "provider": provider,
115
+ "model": "black-forest-labs/FLUX.1-Krea-dev",
116
+ "prompt": enhanced_prompt,
117
+ "parameters": {
118
+ "width": width,
119
+ "height": height,
120
+ "steps": steps,
121
+ "cfg_scale": cfg_scale,
122
+ "seed": seed if seed != -1 else "random",
123
+ "sampler": sampler
124
+ },
125
+ "metadata": {
126
+ "tool": "flux_krea_generate",
127
+ "timestamp": str(generation_id),
128
+ "mcp_compatible": True
129
+ }
130
+ }
131
+
132
+ return json.dumps(result)
133
 
134
  except Exception as provider_error:
135
  print(f"Provider {provider} failed: {provider_error}")
136
+ if provider == providers[-1]: # Last provider failed
137
  raise provider_error
138
  continue
139
 
140
  except Exception as e:
141
+ print(f"Error during MCP image generation: {e}")
142
+ error_message = "Image generation failed due to an unknown error."
143
+
144
  if "404" in str(e):
145
+ error_message = "Model not found. Please ensure the FLUX.1-Krea-dev model is accessible with your API token."
146
  elif "503" in str(e):
147
+ error_message = "The model is currently being loaded. Please try again in a moment."
148
  elif "401" in str(e) or "403" in str(e):
149
+ error_message = "Authentication failed. Please check your HF_READ_TOKEN environment variable."
150
+
151
+ return json.dumps({
152
+ "success": False,
153
+ "error": error_message,
154
+ "image_url": None,
155
+ "generation_id": generation_id
156
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
+ # For UI compatibility - this function returns a PIL Image for the Gradio interface
159
+ def flux_krea_generate_ui(*args) -> Optional[Image.Image]:
160
+ """UI wrapper that returns PIL Image for Gradio interface"""
161
+ result_json = flux_krea_generate(*args)
162
+ try:
163
+ result = json.loads(result_json)
164
+ if result.get("success") and result.get("image_path"):
165
+ return Image.open(result["image_path"])
166
+ except:
167
+ pass
168
+ return None
169
 
170
+ # CSS for improved styling
171
  css = """
172
  #app-container {
173
+ max-width: 900px;
174
  margin-left: auto;
175
  margin-right: auto;
176
  }
177
+ .mcp-badge {
178
+ background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
179
+ color: white;
180
+ padding: 5px 10px;
181
+ border-radius: 15px;
182
+ font-size: 12px;
183
+ font-weight: bold;
184
+ }
185
  """
186
 
187
+ # Build the Gradio app
188
+ with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css, title="FLUX.1-Krea MCP Server") as app:
189
+ # Header
190
+ gr.HTML("""
191
+ <center>
192
+ <h1>🚀 FLUX.1-Krea-dev <span class="mcp-badge">MCP SERVER</span></h1>
193
+ <p>High-quality serverless image generation via Model Context Protocol</p>
194
+ <p><em>Professional-grade images • No AI artifacts • MCP-compatible</em></p>
195
+ </center>
196
+ """)
197
 
198
+ # Main interface
199
  with gr.Column(elem_id="app-container"):
200
+ # Prompt input
201
  with gr.Row():
202
+ text_prompt = gr.Textbox(
203
+ label="Image Prompt",
204
+ placeholder="Describe the image you want to generate (60-70 words recommended)",
205
+ lines=3,
206
+ elem_id="prompt-text-input"
207
+ )
208
+
209
+ # Advanced settings accordion
210
+ with gr.Row():
211
+ with gr.Accordion("🔧 Advanced Generation Settings", open=False):
212
+ negative_prompt = gr.Textbox(
213
+ label="Negative Prompt",
214
+ placeholder="What should NOT be in the image",
215
+ value="(deformed, distorted, disfigured), poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, (mutated hands and fingers), disconnected limbs, mutation, mutated, ugly, disgusting, blurry, amputation, misspellings, typos",
216
+ lines=3,
217
+ elem_id="negative-prompt-text-input"
218
+ )
219
+
220
+ with gr.Row():
221
+ width = gr.Slider(
222
+ label="Width",
223
+ value=1024,
224
+ minimum=64,
225
+ maximum=1216,
226
+ step=32,
227
+ info="Output width in pixels"
228
+ )
229
+ height = gr.Slider(
230
+ label="Height",
231
+ value=1024,
232
+ minimum=64,
233
+ maximum=1216,
234
+ step=32,
235
+ info="Output height in pixels"
236
+ )
237
+
238
  with gr.Row():
239
+ steps = gr.Slider(
240
+ label="Sampling Steps",
241
+ value=35,
242
+ minimum=1,
243
+ maximum=100,
244
+ step=1,
245
+ info="More steps = higher quality, longer generation time"
246
+ )
247
+ cfg = gr.Slider(
248
+ label="CFG Scale",
249
+ value=7,
250
+ minimum=1,
251
+ maximum=20,
252
+ step=1,
253
+ info="How closely to follow the prompt"
254
+ )
255
 
 
256
  with gr.Row():
257
+ strength = gr.Slider(
258
+ label="Strength",
259
+ value=0.7,
260
+ minimum=0,
261
+ maximum=1,
262
+ step=0.01,
263
+ info="Generation strength parameter"
264
+ )
265
+ seed = gr.Slider(
266
+ label="Seed",
267
+ value=-1,
268
+ minimum=-1,
269
+ maximum=1000000000,
270
+ step=1,
271
+ info="Use -1 for random seed"
272
+ )
273
+
274
+ sampler = gr.Radio(
275
+ label="Sampling Method",
276
+ value="DPM++ 2M Karras",
277
+ choices=["DPM++ 2M Karras", "DPM++ SDE Karras", "Euler", "Euler a", "Heun", "DDIM"],
278
+ info="Algorithm used for image generation"
279
+ )
280
 
281
+ # Generation button
282
  with gr.Row():
283
+ generate_button = gr.Button("🎨 Generate Image", variant='primary', elem_id="gen-button", scale=1)
284
 
285
+ # Output area
286
  with gr.Row():
287
+ image_output = gr.Image(
288
+ label="Generated Image",
289
+ elem_id="gallery",
290
+ show_share_button=True,
291
+ show_download_button=True
292
+ )
293
 
294
+ # MCP Information
295
+ with gr.Row():
296
+ gr.HTML("""
297
+ <div style="background: #f0f0f0; padding: 15px; border-radius: 10px; margin-top: 20px;">
298
+ <h3>📡 MCP Server Information</h3>
299
+ <p><strong>Server Endpoint:</strong> <code>/gradio_api/mcp/sse</code></p>
300
+ <p><strong>Tool Name:</strong> <code>flux_krea_generate</code></p>
301
+ <p>This server exposes the image generation function as an MCP tool that returns JSON with image URLs for LLM integration.</p>
302
+ </div>
303
+ """)
304
+
305
+ # Wire up the UI event (this is separate from the MCP tool)
306
+ generate_button.click(
307
+ flux_krea_generate_ui,
308
+ inputs=[text_prompt, negative_prompt, steps, cfg, sampler, seed, strength, width, height],
309
  outputs=image_output,
310
+ show_api=False # Hide from API docs since we have dedicated MCP tool
 
311
  )
312
 
313
+ # Expose the MCP tool with clear API documentation
 
 
314
  gr.api(
315
+ flux_krea_generate,
316
+ api_name="flux_krea_generate",
317
  api_description=(
318
+ "MCP Tool: Generate professional-quality images using FLUX.1-Krea-dev via serverless inference. "
319
+ "Returns JSON with image URL and metadata for MCP clients and LLMs. "
320
+ "Optimized for natural, realistic images without AI artifacts."
321
+ )
322
  )
323
 
324
+ # Launch with MCP server enabled
325
+ if __name__ == "__main__":
326
+ # Enable MCP server functionality
327
+ app.launch(
328
+ mcp_server=True,
329
+ show_api=True,
330
+ share=False,
331
+ server_name="0.0.0.0",
332
+ server_port=7860,
333
+ show_error=True
334
+ )