File size: 7,842 Bytes
e547b24
 
 
 
25d39b9
764029a
e547b24
c64e303
e547b24
 
 
 
c64e303
974dc33
25d39b9
974dc33
dd21ab3
974dc33
dd21ab3
 
 
 
25d39b9
c64e303
25d39b9
c64e303
 
 
 
b5176b4
dd21ab3
c64e303
 
 
 
 
 
 
 
 
b5176b4
dd21ab3
c64e303
dd21ab3
c64e303
 
e547b24
c64e303
974dc33
c64e303
974dc33
c64e303
974dc33
e547b24
c64e303
 
764029a
 
 
 
 
 
 
 
 
c64e303
764029a
 
 
 
 
 
 
 
 
 
 
c64e303
 
764029a
 
 
c64e303
764029a
 
 
e547b24
c64e303
764029a
c64e303
764029a
c64e303
764029a
c64e303
 
 
 
06ff1bc
c64e303
e547b24
02f8cfa
c64e303
02f8cfa
 
73f7edc
e547b24
 
c64e303
 
 
 
 
4d6cbec
c64e303
02f8cfa
c64e303
25d39b9
c64e303
02f8cfa
c64e303
4d6cbec
c64e303
02f8cfa
c64e303
 
 
 
 
 
 
 
 
 
 
 
02f8cfa
c64e303
4d6cbec
c64e303
02f8cfa
c64e303
 
e547b24
c64e303
 
 
 
 
b5176b4
c64e303
 
b5176b4
 
c64e303
 
b5176b4
25d39b9
c64e303
b5176b4
c64e303
 
 
b5176b4
e547b24
c64e303
 
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
import gradio as gr
import random
import os
from PIL import Image
from typing import Optional
from huggingface_hub import InferenceClient

# Project by Nymbo

API_TOKEN = os.getenv("HF_READ_TOKEN")
timeout = 100

# Function to query the API and return the generated image
def flux_krea_generate(
    prompt: str, 
    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",
    steps: int = 35,
    cfg_scale: float = 7.0,
    sampler: str = "DPM++ 2M Karras",
    seed: int = -1,
    strength: float = 0.7,
    width: int = 1024,
    height: int = 1024
) -> Optional[Image.Image]:
    """
    Text-to-image generation with FLUX.1-Krea-dev (no input image required).

    This tool generates a single image from a text prompt using the
    black-forest-labs/FLUX.1-Krea-dev model on Hugging Face Inference.

    Args:
        prompt: Text description of the image to generate.
        negative_prompt: What should NOT appear in the image.
        steps: Number of denoising steps (1-100). Higher is slower but can improve quality.
        cfg_scale: Classifier-free guidance scale (1-20). Higher = follow the prompt more closely.
        sampler: Sampling method to use. One of: "DPM++ 2M Karras", "DPM++ SDE Karras", "Euler", "Euler a", "Heun", "DDIM".
        seed: Random seed for reproducible results. Use -1 for a random seed per call.
        strength: Generation strength (0-1). Kept for parity; not an input image strength.
        width: Output width in pixels (64-1216, multiple of 32 recommended).
        height: Output height in pixels (64-1216, multiple of 32 recommended).

    Returns:
        A PIL.Image of the generated result. No input image is expected or required.
    """
    if prompt == "" or prompt is None:
        return None

    key = random.randint(0, 999)
    
    # Add some extra flair to the prompt
    enhanced_prompt = f"{prompt} | ultra detail, ultra elaboration, ultra quality, perfect."
    print(f'\033[1mGeneration {key}:\033[0m {enhanced_prompt}')
    
    try:
        # Initialize the Hugging Face Inference Client
        # Try different providers in order of preference
        providers = ["auto", "replicate", "fal-ai"]
        
        for provider in providers:
            try:
                client = InferenceClient(
                    api_key=API_TOKEN,
                    provider=provider
                )
                
                # Generate the image using the proper client
                image = client.text_to_image(
                    prompt=enhanced_prompt,
                    negative_prompt=negative_prompt,
                    model="black-forest-labs/FLUX.1-Krea-dev",
                    width=width,
                    height=height,
                    num_inference_steps=steps,
                    guidance_scale=cfg_scale,
                    seed=seed if seed != -1 else random.randint(1, 1000000000)
                )
                
                print(f'\033[1mGeneration {key} completed with {provider}!\033[0m ({enhanced_prompt})')
                return image
                
            except Exception as provider_error:
                print(f"Provider {provider} failed: {provider_error}")
                if provider == providers[-1]:  # Last provider
                    raise provider_error
                continue
        
    except Exception as e:
        print(f"Error during image generation: {e}")
        if "404" in str(e):
            raise gr.Error("Model not found. Please ensure the FLUX.1-Krea-dev model is accessible with your API token.")
        elif "503" in str(e):
            raise gr.Error("The model is currently being loaded. Please try again in a moment.")
        elif "401" in str(e) or "403" in str(e):
            raise gr.Error("Authentication failed. Please check your HF_READ_TOKEN environment variable.")
        else:
            raise gr.Error(f"Image generation failed: {str(e)}")
        return None

# CSS to style the app
css = """
#app-container {
    max-width: 800px;
    margin-left: auto;
    margin-right: auto;
}
"""

# Build the Gradio UI with Blocks
with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css) as app:
    # Add a title to the app
    gr.HTML("<center><h1>FLUX.1-Krea-dev</h1></center>")
    gr.HTML("<center><p>High-quality image generation via Model Context Protocol</p></center>")
    
    # Container for all the UI elements
    with gr.Column(elem_id="app-container"):
        # Add a text input for the main prompt
        with gr.Row():
            with gr.Column(elem_id="prompt-container"):
                with gr.Row():
                    text_prompt = gr.Textbox(label="Prompt", placeholder="Enter a prompt here", lines=2, elem_id="prompt-text-input")
                
                # Accordion for advanced settings
                with gr.Row():
                    with gr.Accordion("Advanced Settings", open=False):
                        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")
                        with gr.Row():
                            width = gr.Slider(label="Width", value=1024, minimum=64, maximum=1216, step=32)
                            height = gr.Slider(label="Height", value=1024, minimum=64, maximum=1216, step=32)
                        steps = gr.Slider(label="Sampling steps", value=35, minimum=1, maximum=100, step=1)
                        cfg = gr.Slider(label="CFG Scale", value=7, minimum=1, maximum=20, step=1)
                        strength = gr.Slider(label="Strength", value=0.7, minimum=0, maximum=1, step=0.001)
                        seed = gr.Slider(label="Seed", value=-1, minimum=-1, maximum=1000000000, step=1) # Setting the seed to -1 will make it random
                        method = gr.Radio(label="Sampling method", value="DPM++ 2M Karras", choices=["DPM++ 2M Karras", "DPM++ SDE Karras", "Euler", "Euler a", "Heun", "DDIM"])

        # Add a button to trigger the image generation
        with gr.Row():
            text_button = gr.Button("Run", variant='primary', elem_id="gen-button")
        
        # Image output area to display the generated image
        with gr.Row():
            # Output component only; no input image is required by the tool
            image_output = gr.Image(label="Image Output", elem_id="gallery")
        
        # Bind the button to the flux_krea_generate function for the UI only
        # Hide this event as an MCP tool to avoid schema confusion (UI wires image output)
        text_button.click(
            flux_krea_generate,
            inputs=[text_prompt, negative_prompt, steps, cfg, method, seed, strength, width, height],
            outputs=image_output,
            show_api=False,
            api_description=False,
        )

    # Expose a dedicated MCP/API endpoint with a clear schema (text-to-image only)
    # This avoids clients misinterpreting the UI event as requiring an input image.
    gr.api(
        flux_krea_generate,
        api_name="generate_image",
        api_description=(
            "Generate an image from a text prompt using FLUX.1-Krea-dev. "
            "Inputs are text and numeric parameters only; no input image is required."
        ),
    )

# Launch the Gradio app with MCP server enabled
app.launch(show_api=True, share=False, mcp_server=True)