john108stewart commited on
Commit
b22ab7a
·
verified ·
1 Parent(s): aaa6915

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. app.py +423 -0
  2. requirements.txt +6 -0
app.py ADDED
@@ -0,0 +1,423 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import random
4
+ import requests
5
+ from PIL import Image
6
+ import io
7
+ import time
8
+ import json
9
+ import os
10
+ from dotenv import load_dotenv
11
+
12
+ # Load environment variables
13
+ load_dotenv()
14
+
15
+ # Get API token from environment variable
16
+ api_token = os.getenv('HF_TOKEN')
17
+ print(f"Loaded API token: {api_token[:10]}...") # Only show first 10 chars for security
18
+
19
+ if not api_token:
20
+ raise ValueError("HF_TOKEN environment variable not found. Please check your .env file.")
21
+
22
+ MAX_SEED = np.iinfo(np.int32).max
23
+ MAX_IMAGE_SIZE = 2048
24
+
25
+ API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell"
26
+ headers = {"Authorization": f"Bearer {api_token}"}
27
+
28
+ def query(payload):
29
+ """Sendet eine Anfrage an die FLUX API mit Fehlerbehandlung und Rate-Limit-Checks"""
30
+ try:
31
+ print("\n=== Starting API Request ===")
32
+ print(f"Using API URL: {API_URL}")
33
+ print(f"Headers (auth truncated): {{'Authorization': 'Bearer ...'}}")
34
+ print(f"Payload: {payload}")
35
+
36
+ response = requests.post(API_URL, headers=headers, json=payload)
37
+ print(f"\n=== Response Details ===")
38
+ print(f"Status code: {response.status_code}")
39
+ print(f"Content type: {response.headers.get('content-type', 'unknown')}")
40
+ print(f"Response length: {len(response.content)} bytes")
41
+
42
+ if response.status_code != 200:
43
+ print(f"Error response text: {response.text}")
44
+
45
+ # Prüfe auf Rate Limit
46
+ if response.status_code == 429: # Too Many Requests
47
+ retry_after = int(response.headers.get('Retry-After', 20))
48
+ print(f"Rate limit erreicht. Warte {retry_after} Sekunden...")
49
+ time.sleep(retry_after)
50
+ # Versuche es noch einmal
51
+ print("\n=== Retrying Request ===")
52
+ response = requests.post(API_URL, headers=headers, json=payload)
53
+ print(f"Retry status code: {response.status_code}")
54
+
55
+ # Prüfe auf JSON-Antwort (könnte eine Fehlermeldung sein)
56
+ if response.headers.get('content-type', '').startswith('application/json'):
57
+ error_data = response.json()
58
+ print(f"\n=== JSON Response ===")
59
+ print(f"Response data: {error_data}")
60
+ if 'error' in error_data:
61
+ print(f"API Error: {error_data['error']}")
62
+ if "loading" in error_data.get('error', '').lower():
63
+ print("Model is loading, waiting 20 seconds...")
64
+ time.sleep(20)
65
+ return query(payload) # Rekursiver Aufruf
66
+ return None
67
+
68
+ response.raise_for_status()
69
+ print("\n=== Success ===")
70
+ print("Successfully received image data")
71
+ return response.content
72
+ except requests.exceptions.RequestException as e:
73
+ print(f"\n=== Request Exception ===")
74
+ print(f"Error type: {e.__class__.__name__}")
75
+ print(f"Error message: {str(e)}")
76
+ print(f"Full error details: {e}")
77
+ return None
78
+
79
+ def infer(prompt, seed=42, randomize_seed=False, width=1024, height=1024, num_inference_steps=4):
80
+ """Generiert ein Bild mit den gegebenen Parametern"""
81
+ try:
82
+ print("\n=== Starting Image Generation ===")
83
+ if randomize_seed:
84
+ seed = random.randint(0, MAX_SEED)
85
+ print(f"Using random seed: {seed}")
86
+ else:
87
+ print(f"Using fixed seed: {seed}")
88
+
89
+ # Parameter für die API-Anfrage
90
+ payload = {
91
+ "inputs": prompt,
92
+ "parameters": {
93
+ "width": width,
94
+ "height": height,
95
+ "num_inference_steps": num_inference_steps,
96
+ "seed": seed,
97
+ "guidance_scale": 0.0
98
+ }
99
+ }
100
+
101
+ print("Calling API...")
102
+ image_bytes = query(payload)
103
+ if image_bytes is None:
104
+ print("Failed to generate image - no image data received")
105
+ raise Exception("Failed to generate image")
106
+
107
+ print("Converting image bytes to PIL Image...")
108
+ image = Image.open(io.BytesIO(image_bytes))
109
+ print("Image generation completed successfully")
110
+ return image, seed
111
+ except Exception as e:
112
+ print(f"Error in infer function: {str(e)}")
113
+ print(f"Error type: {e.__class__.__name__}")
114
+ return None, seed
115
+
116
+ def generate_prompt(location, scene, lighting, mood, person, ethnicity, clothing, camera_perspective="", artistic_style=""):
117
+ """Generiert einen Prompt aus den Eingaben mit erweiterten FLUX.1-spezifischen Details"""
118
+ components = []
119
+
120
+ # Kamera und künstlerische Details (wenn angegeben)
121
+ if camera_perspective: components.append(camera_perspective)
122
+ if artistic_style: components.append(artistic_style)
123
+
124
+ # Hauptkomponenten
125
+ if location: components.append(location)
126
+ if scene: components.append(scene)
127
+
128
+ # Person und Attribute
129
+ person_desc = []
130
+ if person: person_desc.append(person)
131
+ if ethnicity: person_desc.append(ethnicity)
132
+ if clothing: person_desc.append(f"wearing {clothing}")
133
+ if person_desc:
134
+ components.append(", ".join(person_desc))
135
+
136
+ # Atmosphäre
137
+ atmosphere = []
138
+ if lighting: atmosphere.append(lighting)
139
+ if mood: atmosphere.append(mood)
140
+ if atmosphere:
141
+ components.append(", ".join(atmosphere))
142
+
143
+ # Standard-Stilelemente für bessere FLUX.1 Ergebnisse
144
+ components.append("professional photography")
145
+ components.append("highly detailed")
146
+ components.append("8k resolution")
147
+ components.append("ultra wide focus")
148
+
149
+ # Verbinde alles zu einem Prompt
150
+ final_prompt = ", ".join(filter(None, components))
151
+
152
+ return final_prompt
153
+
154
+ css = """
155
+ #col-container {
156
+ margin: 0 auto;
157
+ max-width: 720px;
158
+ }
159
+
160
+ .container {
161
+ margin-top: 1rem;
162
+ margin-bottom: 1rem;
163
+ padding: 1rem;
164
+ border-radius: 8px;
165
+ background-color: rgba(255, 255, 255, 0.05);
166
+ }
167
+
168
+ .generate-btn {
169
+ background-color: #2ecc71 !important;
170
+ }
171
+
172
+ .transfer-btn {
173
+ background-color: #3498db !important;
174
+ }
175
+ """
176
+
177
+ with gr.Blocks(css=css, title="FLUX Schnell") as demo:
178
+ # Geteilter Zustand für die Prompts
179
+ shared_prompt = gr.State("")
180
+
181
+ with gr.Tabs():
182
+ # Prompt Generator Tab
183
+ with gr.Tab("✨ Prompt Generator", elem_id="prompt_generator_tab"):
184
+ with gr.Column(elem_id="col-container"):
185
+ gr.Markdown("""## 🎨 Prompt Generator
186
+ Erstellen Sie detaillierte Prompts für die Bildgenerierung mit FLUX.1-spezifischen Optimierungen.""")
187
+
188
+ # Grundlegende Szeneninformationen
189
+ with gr.Group(elem_id="scene_info"):
190
+ gr.Markdown("### 📍 Grundlegende Szeneninformationen")
191
+ with gr.Row():
192
+ location = gr.Textbox(
193
+ label="Location",
194
+ placeholder="z.B. Rooftop, Nightclub, Street",
195
+ info="Der Hauptort der Szene",
196
+ elem_id="location_input"
197
+ )
198
+ scene = gr.Textbox(
199
+ label="Scene Description",
200
+ placeholder="z.B. bustling party, quiet alley",
201
+ info="Was passiert in der Szene?",
202
+ elem_id="scene_input"
203
+ )
204
+
205
+ # Kamera und Stil
206
+ with gr.Group(elem_id="camera_style"):
207
+ gr.Markdown("### 📸 Kamera & Stil")
208
+ camera_perspective = gr.Textbox(
209
+ label="Camera Perspective",
210
+ placeholder="z.B. close-up shot with 50mm lens, bird's eye view",
211
+ info="Spezifische Kameraeinstellungen und Perspektive",
212
+ elem_id="camera_input"
213
+ )
214
+ artistic_style = gr.Textbox(
215
+ label="Artistic Style",
216
+ placeholder="z.B. cinematic lighting, vintage film look",
217
+ info="Künstlerischer Stil und visuelle Ästhetik",
218
+ elem_id="style_input"
219
+ )
220
+
221
+ # Atmosphäre und Stimmung
222
+ with gr.Group(elem_id="mood_info"):
223
+ gr.Markdown("### 🎨 Atmosphäre und Stimmung")
224
+ with gr.Row():
225
+ lighting = gr.Textbox(
226
+ label="Lighting/Atmosphere",
227
+ placeholder="z.B. natural sunlight from left, soft diffused light",
228
+ info="Detaillierte Beleuchtungsbeschreibung",
229
+ elem_id="lighting_input"
230
+ )
231
+ mood = gr.Textbox(
232
+ label="Mood/Emotion",
233
+ placeholder="z.B. energetic, mysterious, serene",
234
+ info="Emotionale Stimmung der Szene",
235
+ elem_id="mood_input"
236
+ )
237
+
238
+ # Personenbeschreibung
239
+ with gr.Group(elem_id="person_info"):
240
+ gr.Markdown("### 👤 Personenbeschreibung")
241
+ with gr.Row():
242
+ person = gr.Textbox(
243
+ label="Person",
244
+ placeholder="z.B. young woman, old man",
245
+ info="Hauptperson in der Szene",
246
+ elem_id="person_input"
247
+ )
248
+ ethnicity = gr.Textbox(
249
+ label="Ethnicity",
250
+ placeholder="z.B. asian, african",
251
+ info="Ethnische Beschreibung",
252
+ elem_id="ethnicity_input"
253
+ )
254
+ clothing = gr.Textbox(
255
+ label="Clothing",
256
+ placeholder="z.B. elegant vintage dress, casual street wear",
257
+ info="Detaillierte Kleidungsbeschreibung",
258
+ elem_id="clothing_input"
259
+ )
260
+
261
+ # Generierter Prompt
262
+ with gr.Group(elem_id="generated_prompt_group"):
263
+ generated_prompt = gr.Textbox(
264
+ label="Generierter Prompt",
265
+ interactive=False,
266
+ lines=3,
267
+ elem_id="generated_prompt_output"
268
+ )
269
+ with gr.Row():
270
+ generate_button = gr.Button("🎨 Prompt Generieren", elem_classes="generate-btn", elem_id="generate_prompt_btn")
271
+ use_prompt_button = gr.Button("➡️ Im Bild-Generator verwenden", elem_classes="transfer-btn", elem_id="use_prompt_btn")
272
+
273
+ # Event Handler
274
+ generate_button.click(
275
+ generate_prompt,
276
+ inputs=[
277
+ location, scene, lighting, mood, person,
278
+ ethnicity, clothing, camera_perspective,
279
+ artistic_style
280
+ ],
281
+ outputs=[generated_prompt]
282
+ )
283
+
284
+ use_prompt_button.click(
285
+ lambda p: p,
286
+ inputs=[generated_prompt],
287
+ outputs=[shared_prompt]
288
+ )
289
+
290
+ # Bild Generator Tab
291
+ with gr.Tab("🖼️ Bild Generator", elem_id="image_generator_tab"):
292
+ with gr.Column(elem_id="col-container"):
293
+ gr.Markdown("""# FLUX.1 [schnell]
294
+ 12B param rectified flow transformer distilled from [FLUX.1 [pro]](https://blackforestlabs.ai/) for 4 step generation
295
+ [[blog](https://blackforestlabs.ai/announcing-black-forest-labs/)] [[model](https://huggingface.co/black-forest-labs/FLUX.1-schnell)]
296
+ """)
297
+
298
+ with gr.Group(elem_id="prompt_group"):
299
+ prompt_input = gr.Text(
300
+ label="Prompt",
301
+ show_label=False,
302
+ max_lines=1,
303
+ placeholder="Enter your prompt",
304
+ container=False,
305
+ )
306
+ run_button = gr.Button("Run", scale=0)
307
+
308
+ result = gr.Image(label="Result", show_label=False, elem_id="result_image")
309
+
310
+ with gr.Accordion("⚙️ Advanced Settings", open=False, elem_id="advanced_settings"):
311
+ seed = gr.Slider(
312
+ label="Seed",
313
+ minimum=0,
314
+ maximum=MAX_SEED,
315
+ step=1,
316
+ value=0,
317
+ elem_id="seed_slider"
318
+ )
319
+
320
+ randomize_seed = gr.Checkbox(
321
+ label="Randomize seed",
322
+ value=True,
323
+ elem_id="randomize_seed"
324
+ )
325
+
326
+ with gr.Row():
327
+ width = gr.Slider(
328
+ label="Width",
329
+ minimum=256,
330
+ maximum=MAX_IMAGE_SIZE,
331
+ step=32,
332
+ value=1024,
333
+ elem_id="width_slider"
334
+ )
335
+ height = gr.Slider(
336
+ label="Height",
337
+ minimum=256,
338
+ maximum=MAX_IMAGE_SIZE,
339
+ step=32,
340
+ value=1024,
341
+ elem_id="height_slider"
342
+ )
343
+
344
+ num_inference_steps = gr.Slider(
345
+ label="Inference Steps",
346
+ minimum=1,
347
+ maximum=50,
348
+ step=1,
349
+ value=4,
350
+ elem_id="steps_slider"
351
+ )
352
+
353
+ # Event Handler für die Bildgenerierung
354
+ def generate_image(prompt, seed, randomize, width, height, steps):
355
+ try:
356
+ gr.Info("🎨 Starte Bildgenerierung...")
357
+ print(f"\n=== Generate Image Called ===")
358
+ print(f"Prompt: {prompt}")
359
+ print(f"Settings: seed={seed}, randomize={randomize}, width={width}, height={height}, steps={steps}")
360
+
361
+ image, used_seed = infer(
362
+ prompt=prompt,
363
+ seed=seed,
364
+ randomize_seed=randomize,
365
+ width=width,
366
+ height=height,
367
+ num_inference_steps=steps
368
+ )
369
+
370
+ if image is None:
371
+ gr.Warning("⚠️ Bildgenerierung fehlgeschlagen. Bitte versuchen Sie es erneut.")
372
+ return None, used_seed
373
+
374
+ gr.Info("✅ Bild erfolgreich generiert!")
375
+ return image, used_seed
376
+ except Exception as e:
377
+ print(f"\n=== Generation Error ===")
378
+ print(f"Error type: {type(e).__name__}")
379
+ print(f"Error message: {str(e)}")
380
+ gr.Error(f"❌ Fehler bei der Bildgenerierung: {str(e)}")
381
+ return None, seed
382
+
383
+ # Event handlers
384
+ run_button.click(
385
+ fn=generate_image,
386
+ inputs=[
387
+ prompt_input,
388
+ seed,
389
+ randomize_seed,
390
+ width,
391
+ height,
392
+ num_inference_steps
393
+ ],
394
+ outputs=[
395
+ result,
396
+ seed
397
+ ]
398
+ )
399
+
400
+ prompt_input.submit(
401
+ fn=generate_image,
402
+ inputs=[
403
+ prompt_input,
404
+ seed,
405
+ randomize_seed,
406
+ width,
407
+ height,
408
+ num_inference_steps
409
+ ],
410
+ outputs=[
411
+ result,
412
+ seed
413
+ ]
414
+ )
415
+
416
+ # Event Handler für Prompt-Updates
417
+ demo.load(
418
+ fn=lambda: "",
419
+ outputs=[prompt_input]
420
+ )
421
+
422
+ if __name__ == "__main__":
423
+ demo.launch(share=True, server_port=7860)
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ gradio>=3.50.2
2
+ numpy>=1.24.3
3
+ requests>=2.31.0
4
+ Pillow>=10.0.0
5
+ torch>=2.0.1
6
+ python-dotenv>=1.0.0