uzairbinasif commited on
Commit
d682210
·
verified ·
1 Parent(s): 782c478

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +105 -7
  2. app.py +332 -0
  3. requirements.txt +3 -0
README.md CHANGED
@@ -1,13 +1,111 @@
1
  ---
2
- title: Text To Image Pro
3
- emoji: 📈
4
- colorFrom: red
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 6.12.0
8
  app_file: app.py
9
  pinned: false
10
- license: mit
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: FLUX.1-schnell Image Generator
3
+ emoji: ⚡
4
+ colorFrom: indigo
5
+ colorTo: purple
6
  sdk: gradio
7
+ sdk_version: "6.0.0"
8
  app_file: app.py
9
  pinned: false
10
+ license: apache-2.0
11
  ---
12
 
13
+ # ⚡ FLUX.1-schnell Text-to-Image Generator
14
+
15
+ A production-ready Gradio application that generates stunning AI images from text prompts using [`black-forest-labs/FLUX.1-schnell`](https://huggingface.co/black-forest-labs/FLUX.1-schnell) — one of the fastest and highest-quality open-source text-to-image models available.
16
+
17
+ ---
18
+
19
+ ## ✨ Features
20
+
21
+ - 🎨 **9 built-in styles** — Realistic, Spirited Away, Cyberpunk, Oil Painting, Anime, Watercolor, Fantasy Epic, Minimalist, and None
22
+ - ⚙️ **Advanced controls** — Guidance scale, custom width & height (512–1344px)
23
+ - 💡 **Example prompts** — One-click examples to get started instantly
24
+ - 🔄 **Retry logic** — Automatically retries on timeouts or model-loading delays
25
+ - 🛡️ **Robust error handling** — Clear messages for 403 (gated model), 429 (rate limit), 503 (model loading), and timeouts
26
+
27
+ ---
28
+
29
+ ## 🚀 Deployment on Hugging Face Spaces
30
+
31
+ ### 1. Fork or Create a Space
32
+
33
+ Go to [huggingface.co/new-space](https://huggingface.co/new-space) and:
34
+ - Select **Gradio** as the SDK
35
+ - Choose **CPU Basic** (free tier is sufficient — inference runs on HF servers)
36
+
37
+ ### 2. Upload Files
38
+
39
+ Add these files to your Space repository:
40
+ ```
41
+ app.py
42
+ requirements.txt
43
+ README.md
44
+ ```
45
+
46
+ ### 3. Set the Secret Token
47
+
48
+ > ⚠️ This is required — the app will not work without it.
49
+
50
+ 1. Go to your Space → **Settings** → **Variables and Secrets**
51
+ 2. Click **New Secret**
52
+ 3. Name: `HF_TOKEN`
53
+ 4. Value: Your Hugging Face access token from [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens)
54
+
55
+ ### 4. Accept the Model License
56
+
57
+ Visit [black-forest-labs/FLUX.1-schnell](https://huggingface.co/black-forest-labs/FLUX.1-schnell) and click **Agree and access repository** while logged into the HF account whose token you are using.
58
+
59
+ ### 5. Deploy
60
+
61
+ Push your files — the Space will build automatically and be live in ~1 minute.
62
+
63
+ ---
64
+
65
+ ## 🗂️ Project Structure
66
+
67
+ ```
68
+ ├── app.py # Main Gradio application
69
+ ├── requirements.txt # Python dependencies
70
+ └── README.md # This file (also configures the HF Space)
71
+ ```
72
+
73
+ ---
74
+
75
+ ## 🔧 Key Functions
76
+
77
+ | Function | Purpose |
78
+ |---|---|
79
+ | `authenticate_client()` | Loads `HF_TOKEN` from env and returns an `InferenceClient` |
80
+ | `apply_style_to_prompt()` | Merges user prompt with style-specific keywords |
81
+ | `generate_image()` | Calls FLUX API with retry logic and full error handling |
82
+ | `build_interface()` | Constructs the Gradio Blocks UI |
83
+
84
+ ---
85
+
86
+ ## ⚠️ Common Errors & Fixes
87
+
88
+ | Error | Cause | Fix |
89
+ |---|---|---|
90
+ | `🔑 Authentication Error` | `HF_TOKEN` secret not set | Add it in Space Settings → Secrets |
91
+ | `🚫 Access Denied (403)` | Model license not accepted | Visit the model page and accept the license |
92
+ | `🚦 Rate limit (429)` | HF Inference API quota exceeded | Upgrade HF plan or wait for quota reset |
93
+ | `⏳ Model loading (503)` | Cold start | App retries automatically — wait a moment |
94
+ | `⏱️ Timeout` | Slow network or overloaded API | App retries automatically |
95
+
96
+ ---
97
+
98
+ ## 📦 Dependencies
99
+
100
+ | Package | Purpose |
101
+ |---|---|
102
+ | `gradio` | Web UI framework |
103
+ | `huggingface_hub` | HF Inference API client |
104
+ | `Pillow` | Image processing |
105
+
106
+ ---
107
+
108
+ ## 📄 License
109
+
110
+ This Space is released under the **Apache 2.0** license.
111
+ The underlying model (`FLUX.1-schnell`) is licensed under its own terms — see the [model card](https://huggingface.co/black-forest-labs/FLUX.1-schnell) for details.
app.py ADDED
@@ -0,0 +1,332 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ FHDR pro Text-to-Image Generator
3
+ Production-ready Gradio application using black-forest-labs/FLUX.1-schnell
4
+ via the Hugging Face Inference API.
5
+ """
6
+
7
+ import os
8
+ import io
9
+ import logging
10
+ import time
11
+ from typing import Optional
12
+
13
+ import gradio as gr
14
+ from huggingface_hub import InferenceClient
15
+ from huggingface_hub.utils import HfHubHTTPError
16
+ from PIL import Image
17
+
18
+ # ── Logging ────────────────────────────────────────────────────────────────────
19
+ logging.basicConfig(
20
+ level=logging.INFO,
21
+ format="%(asctime)s [%(levelname)s] %(message)s",
22
+ )
23
+ logger = logging.getLogger(__name__)
24
+
25
+ # ── Constants ──────────────────────────────────────────────────────────────────
26
+ MODEL_ID = "kpsss34/FHDR_Uncensored"
27
+ MAX_RETRIES = 3
28
+ RETRY_DELAY = 5 # seconds between retries
29
+
30
+ STYLES: dict[str, str] = {
31
+ "None": "",
32
+ "Realistic": (
33
+ "photorealistic, ultra-detailed, 8K resolution, RAW photo, "
34
+ "sharp focus, natural lighting, Canon EOS R5"
35
+ ),
36
+ "Spirited Away": (
37
+ "Studio Ghibli style, Hayao Miyazaki, hand-drawn animation, "
38
+ "soft watercolor palette, whimsical, magical, fantastical landscape"
39
+ ),
40
+ "Cyberpunk": (
41
+ "cyberpunk, neon-lit, dystopian cityscape, rain-slicked streets, "
42
+ "holographic signs, dark atmosphere, Blade Runner aesthetic, 4K"
43
+ ),
44
+ "Oil Painting": (
45
+ "oil painting, impasto technique, rich brushstrokes, museum-quality, "
46
+ "Renaissance lighting, chiaroscuro, canvas texture"
47
+ ),
48
+ "Anime": (
49
+ "anime style, vibrant colors, cel-shaded, dynamic composition, "
50
+ "detailed linework, Makoto Shinkai inspired"
51
+ ),
52
+ "Watercolor": (
53
+ "soft watercolor painting, delicate washes, paper texture, "
54
+ "loose brushwork, pastel tones, dreamy atmosphere"
55
+ ),
56
+ "Fantasy Epic": (
57
+ "epic fantasy, dramatic lighting, highly detailed, "
58
+ "cinematic composition, concept art, ArtStation trending"
59
+ ),
60
+ "Minimalist": (
61
+ "minimalist, clean lines, flat design, limited color palette, "
62
+ "geometric shapes, negative space, modern aesthetic"
63
+ ),
64
+ }
65
+
66
+ EXAMPLE_PROMPTS = [
67
+ ["A dragon soaring over a misty mountain range at dawn", "Fantasy Epic", 7.5, 1024, 1024],
68
+ ["A lone samurai standing in a bamboo forest during rainfall", "Anime", 7.0, 1024, 1024],
69
+ ["A futuristic Tokyo street market at night", "Cyberpunk", 8.0, 1024, 1024],
70
+ ["A young girl riding a giant cat bus through the clouds", "Spirited Away", 7.0, 1024, 1024],
71
+ ["Portrait of an astronaut on Mars, golden hour", "Realistic", 7.5, 1024, 1024],
72
+ ["A cozy bookshop in autumn rain, warm light inside", "Oil Painting", 7.0, 1024, 1024],
73
+ ]
74
+
75
+
76
+ # ── Core Functions ─────────────────────────────────────────────────────────────
77
+
78
+ def authenticate_client() -> InferenceClient:
79
+ """
80
+ Load the Hugging Face token from environment variables and
81
+ return an authenticated InferenceClient.
82
+
83
+ Raises:
84
+ EnvironmentError: If HF_TOKEN is not set.
85
+ """
86
+ token = os.environ.get("HF_TOKEN")
87
+ if not token:
88
+ raise EnvironmentError(
89
+ "HF_TOKEN environment variable is not set. "
90
+ "Please add your Hugging Face token to the Space secrets."
91
+ )
92
+ logger.info("HF_TOKEN loaded successfully. Authenticating client...")
93
+ return InferenceClient(token=token)
94
+
95
+
96
+ def apply_style_to_prompt(user_prompt: str, style_name: str) -> str:
97
+ """
98
+ Combine the user's prompt with pre-defined style keywords.
99
+
100
+ Args:
101
+ user_prompt: The raw text prompt from the user.
102
+ style_name: The name of the style to apply (must be a key in STYLES).
103
+
104
+ Returns:
105
+ A fully composed prompt string ready for the model.
106
+ """
107
+ style_keywords = STYLES.get(style_name, "")
108
+ if style_keywords:
109
+ composed = f"{user_prompt.strip()}, {style_keywords}"
110
+ else:
111
+ composed = user_prompt.strip()
112
+
113
+ logger.info("Composed prompt: %s", composed)
114
+ return composed
115
+
116
+
117
+ def generate_image(
118
+ user_prompt: str,
119
+ style_name: str,
120
+ guidance_scale: float,
121
+ width: int,
122
+ height: int,
123
+ progress: gr.Progress = gr.Progress(),
124
+ ) -> tuple[Optional[Image.Image], str]:
125
+ """
126
+ Generate an image from a text prompt using FHDR-schnell.
127
+
128
+ Args:
129
+ user_prompt: The raw user prompt.
130
+ style_name: Style to blend into the prompt.
131
+ guidance_scale: How closely the model follows the prompt (1.0–10.0).
132
+ width: Output image width in pixels.
133
+ height: Output image height in pixels.
134
+ progress: Gradio progress tracker.
135
+
136
+ Returns:
137
+ A tuple of (PIL Image or None, status message string).
138
+ """
139
+ # ── Input validation ───────────────────────────────────────────────────────
140
+ if not user_prompt or not user_prompt.strip():
141
+ return None, "⚠️ Please enter a prompt before generating."
142
+
143
+ # ── Authenticate ───────────────────────────────────────────────────────────
144
+ try:
145
+ client = authenticate_client()
146
+ except EnvironmentError as e:
147
+ logger.error("Authentication failed: %s", e)
148
+ return None, f"🔑 Authentication Error: {e}"
149
+
150
+ # ── Build prompt ───────────────────────────────────────────────────────────
151
+ final_prompt = apply_style_to_prompt(user_prompt, style_name)
152
+
153
+ # ── Generate with retry logic ──────────────────────────────────────────────
154
+ for attempt in range(1, MAX_RETRIES + 1):
155
+ try:
156
+ progress(0.1 * attempt, desc=f"Sending request to FLUX (attempt {attempt}/{MAX_RETRIES})...")
157
+ logger.info("Generation attempt %d/%d", attempt, MAX_RETRIES)
158
+
159
+ image_bytes: bytes = client.text_to_image(
160
+ prompt=final_prompt,
161
+ model=MODEL_ID,
162
+ guidance_scale=guidance_scale,
163
+ width=width,
164
+ height=height,
165
+ )
166
+
167
+ progress(0.9, desc="Processing image...")
168
+ image = Image.open(io.BytesIO(image_bytes)) if isinstance(image_bytes, bytes) else image_bytes
169
+ progress(1.0, desc="Done!")
170
+ logger.info("Image generated successfully on attempt %d.", attempt)
171
+ return image, f"✅ Image generated successfully with style: **{style_name}**"
172
+
173
+ except HfHubHTTPError as e:
174
+ status_code = getattr(e.response, "status_code", None)
175
+
176
+ if status_code == 403:
177
+ msg = (
178
+ "🚫 Access Denied (403): The model is gated. "
179
+ "Please visit https://huggingface.co/black-forest-labs/FHDR-schnell "
180
+ "and accept the license agreement with your HF account."
181
+ )
182
+ logger.error(msg)
183
+ return None, msg
184
+
185
+ elif status_code == 503:
186
+ msg = f"⏳ Model is loading (503). Retrying in {RETRY_DELAY}s... (attempt {attempt}/{MAX_RETRIES})"
187
+ logger.warning(msg)
188
+ if attempt < MAX_RETRIES:
189
+ time.sleep(RETRY_DELAY)
190
+ continue
191
+ return None, "❌ Model failed to load after multiple retries. Please try again later."
192
+
193
+ elif status_code == 429:
194
+ msg = (
195
+ "🚦 Rate limit exceeded (429). "
196
+ "You have exceeded your Inference API quota. "
197
+ "Please check your HF plan at https://huggingface.co/settings/billing"
198
+ )
199
+ logger.error(msg)
200
+ return None, msg
201
+
202
+ else:
203
+ logger.error("HfHubHTTPError: %s", e)
204
+ if attempt < MAX_RETRIES:
205
+ time.sleep(RETRY_DELAY)
206
+ continue
207
+ return None, f"❌ API Error: {e}"
208
+
209
+ except TimeoutError:
210
+ logger.warning("Request timed out on attempt %d.", attempt)
211
+ if attempt < MAX_RETRIES:
212
+ time.sleep(RETRY_DELAY)
213
+ continue
214
+ return None, "⏱️ Request timed out after multiple attempts. Please try again."
215
+
216
+ except Exception as e:
217
+ logger.error("Unexpected error: %s", e, exc_info=True)
218
+ return None, f"❌ Unexpected error: {str(e)}"
219
+
220
+ return None, "❌ Generation failed after all retries. Please try again later."
221
+
222
+
223
+ # ── Gradio Interface ───────────────────────────────────────────────────────────
224
+
225
+ def build_interface() -> gr.Blocks:
226
+ """Construct and return the Gradio Blocks interface."""
227
+
228
+ with gr.Blocks(title="FLUX.1 Image Generator") as demo:
229
+
230
+ # Header
231
+ gr.HTML("""
232
+ <div style="text-align:center; padding: 24px 0 8px;">
233
+ <h1 style="font-size:2.2rem; font-weight:800; margin:0;">
234
+ ⚡ FLUX.1-schnell Image Generator
235
+ </h1>
236
+ <p style="color:#6b7280; margin-top:8px; font-size:1rem;">
237
+ Generate stunning AI images from text using
238
+ <a href="https://huggingface.co/black-forest-labs/FLUX.1-schnell"
239
+ target="_blank" style="color:#2563eb;">
240
+ black-forest-labs/FLUX.1-schnell
241
+ </a>
242
+ — one of the fastest open-source text-to-image models.
243
+ </p>
244
+ </div>
245
+ """)
246
+
247
+ with gr.Row():
248
+ # ── Left column: Inputs ────────────────────────────────────────────
249
+ with gr.Column(scale=1):
250
+ prompt_input = gr.Textbox(
251
+ label="📝 Your Prompt",
252
+ placeholder="Describe the image you want to generate...",
253
+ lines=4,
254
+ max_lines=8,
255
+ )
256
+ style_input = gr.Dropdown(
257
+ label="🎨 Style",
258
+ choices=list(STYLES.keys()),
259
+ value="None",
260
+ info="Blend a pre-defined aesthetic into your prompt.",
261
+ )
262
+ with gr.Accordion("⚙️ Advanced Settings", open=False):
263
+ guidance_input = gr.Slider(
264
+ label="Guidance Scale",
265
+ minimum=1.0,
266
+ maximum=10.0,
267
+ value=7.5,
268
+ step=0.5,
269
+ info="Higher = follows prompt more strictly.",
270
+ )
271
+ with gr.Row():
272
+ width_input = gr.Slider(
273
+ label="Width (px)",
274
+ minimum=512,
275
+ maximum=1344,
276
+ value=1024,
277
+ step=64,
278
+ )
279
+ height_input = gr.Slider(
280
+ label="Height (px)",
281
+ minimum=512,
282
+ maximum=1344,
283
+ value=1024,
284
+ step=64,
285
+ )
286
+
287
+ generate_btn = gr.Button(
288
+ "🚀 Generate Image", variant="primary", size="lg"
289
+ )
290
+ status_output = gr.Markdown(value="")
291
+
292
+ # ── Right column: Output ───────────────────────────────────────────
293
+ with gr.Column(scale=1):
294
+ image_output = gr.Image(
295
+ label="🖼️ Generated Image",
296
+ type="pil",
297
+ height=520,
298
+ )
299
+
300
+ # Examples
301
+ gr.Examples(
302
+ examples=EXAMPLE_PROMPTS,
303
+ inputs=[prompt_input, style_input, guidance_input, width_input, height_input],
304
+ outputs=[image_output, status_output],
305
+ fn=generate_image,
306
+ cache_examples=False,
307
+ label="💡 Example Prompts — click any to try",
308
+ )
309
+
310
+ # Footer
311
+ gr.HTML("""
312
+ <div style="text-align:center; color:#9ca3af; font-size:0.8rem; margin-top:20px; border-top:1px solid #e5e7eb; padding-top:12px;">
313
+ Built with 🤗 Gradio &amp; Hugging Face Inference API ·
314
+ Model: <code>black-forest-labs/FLUX.1-schnell</code>
315
+ </div>
316
+ """)
317
+
318
+ # Wire up
319
+ generate_btn.click(
320
+ fn=generate_image,
321
+ inputs=[prompt_input, style_input, guidance_input, width_input, height_input],
322
+ outputs=[image_output, status_output],
323
+ )
324
+
325
+ return demo
326
+
327
+
328
+ # ── Entry Point ────────────────────────────────────────────────────────────────
329
+
330
+ if __name__ == "__main__":
331
+ demo = build_interface()
332
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio>=6.0.0
2
+ huggingface_hub>=0.24.0
3
+ Pillow>=10.0.0