Spaces:
Running
Running
Update app.py
Browse files
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
|
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 |
-
) ->
|
24 |
-
"""
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
-
|
29 |
-
-
|
|
|
30 |
|
31 |
Args:
|
32 |
-
prompt:
|
33 |
-
negative_prompt:
|
34 |
-
steps: Number of
|
35 |
-
cfg_scale: Classifier-free guidance scale (1-20). Higher
|
36 |
-
sampler:
|
37 |
-
seed:
|
38 |
-
strength:
|
39 |
-
width: Output width in pixels (64-1216).
|
40 |
-
height: Output height in pixels (64-1216).
|
41 |
|
42 |
Returns:
|
43 |
-
|
44 |
"""
|
45 |
-
if prompt
|
46 |
-
return
|
|
|
|
|
|
|
|
|
47 |
|
48 |
-
|
49 |
|
50 |
-
#
|
51 |
enhanced_prompt = f"{prompt} | ultra detail, ultra elaboration, ultra quality, perfect."
|
52 |
-
print(f'\033[
|
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
|
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 |
-
|
79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
91 |
elif "503" in str(e):
|
92 |
-
|
93 |
elif "401" in str(e) or "403" in str(e):
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
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 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
"
|
210 |
-
|
211 |
-
|
|
|
|
|
212 |
|
213 |
-
# CSS
|
214 |
css = """
|
215 |
#app-container {
|
216 |
-
max-width:
|
217 |
margin-left: auto;
|
218 |
margin-right: auto;
|
219 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
"""
|
221 |
|
222 |
-
# Build the Gradio
|
223 |
-
with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css) as app:
|
224 |
-
#
|
225 |
-
gr.HTML("
|
226 |
-
|
|
|
|
|
|
|
|
|
|
|
227 |
|
228 |
-
#
|
229 |
with gr.Column(elem_id="app-container"):
|
230 |
-
#
|
231 |
with gr.Row():
|
232 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
with gr.Row():
|
234 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
|
236 |
-
# Accordion for advanced settings
|
237 |
with gr.Row():
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
|
249 |
-
#
|
250 |
with gr.Row():
|
251 |
-
|
252 |
|
253 |
-
#
|
254 |
with gr.Row():
|
255 |
-
|
256 |
-
|
|
|
|
|
|
|
|
|
257 |
|
258 |
-
#
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
outputs=image_output,
|
264 |
-
show_api=False
|
265 |
-
api_description=False,
|
266 |
)
|
267 |
|
268 |
-
# Expose
|
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 |
-
|
273 |
-
api_name="
|
274 |
api_description=(
|
275 |
-
"
|
276 |
-
"Returns JSON with
|
277 |
-
|
|
|
278 |
)
|
279 |
|
280 |
-
# Launch
|
281 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
)
|