greendra commited on
Commit
d6d5545
·
verified ·
1 Parent(s): 0075dfa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -43
app.py CHANGED
@@ -4,21 +4,23 @@ import io
4
  import random
5
  import os
6
  import time
7
- from PIL import Image, UnidentifiedImageError
8
  from deep_translator import GoogleTranslator
9
  import json
10
  import uuid
11
  from urllib.parse import quote
12
- import traceback
13
- from openai import OpenAI, RateLimitError, APIConnectionError, AuthenticationError
14
 
15
  # Project by Nymbo
16
 
17
  # --- Constants ---
18
- API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell"
19
  API_TOKEN = os.getenv("HF_READ_TOKEN")
20
  if not API_TOKEN:
21
  print("WARNING: HF_READ_TOKEN environment variable not set. API calls may fail.")
 
 
22
  headers = {"Authorization": f"Bearer {API_TOKEN}"} if API_TOKEN else {}
23
  timeout = 100 # seconds for API call timeout
24
 
@@ -40,20 +42,22 @@ absolute_image_dir = os.path.abspath(IMAGE_DIR)
40
  print(f"Absolute path for allowed_paths: {absolute_image_dir}")
41
 
42
  # --- OpenAI Client ---
 
43
  try:
 
44
  openai_api_key = os.getenv("OPENAI_API_KEY")
45
  if not openai_api_key:
46
  print("WARNING: OPENAI_API_KEY environment variable not set or empty. Moderation will be skipped.")
47
  openai_client = None
48
  else:
49
- openai_client = OpenAI()
50
  print("OpenAI client initialized successfully.")
51
  except Exception as e:
52
  print(f"ERROR: Failed to initialize OpenAI client: {e}. Moderation will be skipped.")
53
- openai_client = None
54
 
55
- # Function to query the API and return the generated image and download link
56
- def query(prompt, negative_prompt="", steps=4, cfg_scale=0, seed=-1, width=1024, height=1024):
57
  # Basic Input Validation
58
  if not prompt or not prompt.strip():
59
  print("WARNING: Empty prompt received.\n") # Add newline for separation
@@ -115,7 +119,7 @@ def query(prompt, negative_prompt="", steps=4, cfg_scale=0, seed=-1, width=1024,
115
  if translated_prompt != original_prompt:
116
  print(f" Translated: '{translated_prompt}'")
117
  print(f" Error: {e}\n") # Add newline
118
- traceback.print_exc()
119
  return None, "<p style='color: red; text-align: center;'>An unexpected error occurred during safety check. Generation blocked.</p>"
120
  else:
121
  print(f"WARNING: OpenAI client not available. Skipping moderation.")
@@ -125,20 +129,14 @@ def query(prompt, negative_prompt="", steps=4, cfg_scale=0, seed=-1, width=1024,
125
  print("") # Add newline
126
 
127
  # --- Proceed with Generation ---
128
- # Add suffix (Ensure consistency with gradio1.py if desired, or keep model-specific suffixes)
129
  final_prompt = f"{translated_prompt} | ultra detail, ultra elaboration, ultra quality, perfect."
130
 
131
- # Prepare payload (Adjust parameters based on FLUX.1-schnell API requirements if different)
132
  payload = {
133
  "inputs": final_prompt,
134
  "parameters": {
135
- "negative_prompt": negative_prompt,
136
- "num_inference_steps": steps,
137
- "guidance_scale": cfg_scale,
138
  "seed": seed if seed != -1 else random.randint(1, 1000000000),
139
- "width": width,
140
- "height": height,
141
- # Add any other specific parameters for FLUX.1-schnell if needed
142
  }
143
  }
144
 
@@ -191,8 +189,7 @@ def query(prompt, negative_prompt="", steps=4, cfg_scale=0, seed=-1, width=1024,
191
  print(f" Path: '{save_path}'\n") # Add newline
192
  return image, "<p style='color: red; text-align: center;'>Internal Error: Failed to confirm image file save.</p>"
193
 
194
- # Use the correct space name for this Gradio app
195
- space_name = "greendra-flux-1-schnell-serverless" # Updated space_name
196
  relative_file_url = f"gradio_api/file={save_path}"
197
  encoded_file_url = quote(relative_file_url)
198
  arinteli_url = f"{ARINTELI_REDIRECT_BASE}?download_url={encoded_file_url}&space_name={space_name}"
@@ -205,7 +202,7 @@ def query(prompt, negative_prompt="", steps=4, cfg_scale=0, seed=-1, width=1024,
205
  f'</div>'
206
  )
207
 
208
- # *** SUCCESS LOG *** (Updated format)
209
  print("SUCCESS:")
210
  print(f" Prompt: '{original_prompt}'")
211
  if translated_prompt != original_prompt:
@@ -222,7 +219,7 @@ def query(prompt, negative_prompt="", steps=4, cfg_scale=0, seed=-1, width=1024,
222
  print(f" Path: '{save_path}'")
223
  print(f" Error: {save_err}\n") # Add newline
224
  traceback.print_exc()
225
- return image, f"<p style='color: red; text-align: center;'>Internal Error: Failed to save image file. Details: {save_err}</p>"
226
  except Exception as e:
227
  print("FAILED:")
228
  print(f" Reason: Link Creation/Save Unexpected Error")
@@ -233,7 +230,7 @@ def query(prompt, negative_prompt="", steps=4, cfg_scale=0, seed=-1, width=1024,
233
  traceback.print_exc()
234
  return image, "<p style='color: red; text-align: center;'>Internal Error creating download link.</p>"
235
 
236
- # --- Exception Handling for API Call --- (Updated format)
237
  except requests.exceptions.Timeout:
238
  print("FAILED:")
239
  print(f" Reason: HF API Timeout")
@@ -259,14 +256,15 @@ def query(prompt, negative_prompt="", steps=4, cfg_scale=0, seed=-1, width=1024,
259
  print(f" Translated: '{translated_prompt}'")
260
  print(f" Details: '{error_text[:200]}'\n") # Add newline
261
 
262
- # User-facing messages (Keep consistent with previous version of this file)
263
  if status_code == 503:
264
  estimated_time = error_data.get("estimated_time") if isinstance(error_data, dict) else None
265
  error_message = f"Model is loading (503), please wait." + (f" Est. time: {estimated_time:.1f}s." if estimated_time else "") + " Try again."
266
- elif status_code == 400: error_message = f"Bad Request (400): Check parameters. API Error: {error_text}"
267
- elif status_code == 422: error_message = f"Validation Error (422): Input invalid. API Error: {error_text}"
268
- elif status_code == 401 or status_code == 403: error_message = f"Authorization Error ({status_code}): Check your API Token (HF_READ_TOKEN)."
269
- else: error_message = f"API Error: {status_code}. Details: {error_text}" # Adjusted generic message slightly
 
270
 
271
  return None, f"<p style='color: red; text-align: center;'>{error_message}</p>"
272
  except Exception as e:
@@ -277,10 +275,10 @@ def query(prompt, negative_prompt="", steps=4, cfg_scale=0, seed=-1, width=1024,
277
  print(f" Translated: '{translated_prompt}'")
278
  print(f" Error: {e}\n") # Add newline
279
  traceback.print_exc()
280
- return None, f"<p style='color: red; text-align: center;'>An unexpected error occurred: {e}</p>" # Keep specific error for user
281
 
282
 
283
- # CSS to style the app
284
  css = """
285
  #app-container {
286
  max-width: 800px;
@@ -290,24 +288,34 @@ css = """
290
  textarea:focus {
291
  background: #0d1117 !important;
292
  }
293
- #download-link-container p {
294
- margin-top: 10px;
295
- font-size: 0.9em;
296
  }
297
  """
298
 
299
- # Build the Gradio UI with Blocks
300
  with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css) as app:
301
-
302
  with gr.Column(elem_id="app-container"):
 
303
  with gr.Row():
304
  with gr.Column(elem_id="prompt-container"):
305
  with gr.Row():
306
- text_prompt = gr.Textbox(label="Prompt", placeholder="Enter a prompt here", lines=2, elem_id="prompt-text-input")
307
-
 
 
 
 
308
  with gr.Row():
309
  with gr.Accordion("Advanced Settings", open=False):
310
- 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")
 
 
 
 
 
 
311
  with gr.Row():
312
  width = gr.Slider(label="Width", value=1024, minimum=64, maximum=1216, step=32)
313
  height = gr.Slider(label="Height", value=1024, minimum=64, maximum=1216, step=32)
@@ -315,6 +323,7 @@ with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css) as app:
315
  cfg = gr.Slider(label="CFG Scale (guidance_scale)", value=0, minimum=0, maximum=10, step=1)
316
  seed = gr.Slider(label="Seed", value=-1, minimum=-1, maximum=1000000000, step=1, info="Set to -1 for random seed")
317
 
 
318
  with gr.Row():
319
  text_button = gr.Button("Run", variant='primary', elem_id="gen-button")
320
 
@@ -322,22 +331,20 @@ with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css) as app:
322
  with gr.Row():
323
  image_output = gr.Image(type="pil", label="Image Output", elem_id="gallery", show_label=False, show_download_button=False, show_share_button=False, show_fullscreen_button=False)
324
  with gr.Row():
325
- # HTML component to display status messages or the download link
326
  download_link_display = gr.HTML(elem_id="download-link-container")
327
 
328
- # Bind the button to the query function
329
  text_button.click(
330
  query,
331
- # Ensure inputs match the query function definition
332
  inputs=[text_prompt, negative_prompt, steps, cfg, seed, width, height],
333
- # Outputs go to the image and HTML components
334
  outputs=[image_output, download_link_display]
335
  )
336
 
337
- # Launch the Gradio app with allowed_paths
338
  print("Starting Gradio app...")
339
  app.launch(
340
  show_api=False,
341
  share=False,
342
- allowed_paths=[absolute_image_dir] # Added allowed_paths
 
343
  )
 
4
  import random
5
  import os
6
  import time
7
+ from PIL import Image, UnidentifiedImageError # Added UnidentifiedImageError
8
  from deep_translator import GoogleTranslator
9
  import json
10
  import uuid
11
  from urllib.parse import quote
12
+ import traceback # For detailed error logging
13
+ from openai import OpenAI, RateLimitError, APIConnectionError, AuthenticationError # Added OpenAI errors
14
 
15
  # Project by Nymbo
16
 
17
  # --- Constants ---
18
+ API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-3.5-large-turbo"
19
  API_TOKEN = os.getenv("HF_READ_TOKEN")
20
  if not API_TOKEN:
21
  print("WARNING: HF_READ_TOKEN environment variable not set. API calls may fail.")
22
+ # Optionally, raise an error or exit if the token is essential
23
+ # raise ValueError("Missing required environment variable: HF_READ_TOKEN")
24
  headers = {"Authorization": f"Bearer {API_TOKEN}"} if API_TOKEN else {}
25
  timeout = 100 # seconds for API call timeout
26
 
 
42
  print(f"Absolute path for allowed_paths: {absolute_image_dir}")
43
 
44
  # --- OpenAI Client ---
45
+ # Initialize OpenAI client (it will automatically look for the OPENAI_API_KEY env var)
46
  try:
47
+ # Check if the environment variable exists and is not empty
48
  openai_api_key = os.getenv("OPENAI_API_KEY")
49
  if not openai_api_key:
50
  print("WARNING: OPENAI_API_KEY environment variable not set or empty. Moderation will be skipped.")
51
  openai_client = None
52
  else:
53
+ openai_client = OpenAI() # Key is implicitly used by the library
54
  print("OpenAI client initialized successfully.")
55
  except Exception as e:
56
  print(f"ERROR: Failed to initialize OpenAI client: {e}. Moderation will be skipped.")
57
+ openai_client = None # Set to None so we can check later
58
 
59
+ # --- Function to query the API and return the generated image and download link ---
60
+ def query(prompt, negative_prompt, steps=4, cfg_scale=0, seed=-1, width=1024, height=1024):
61
  # Basic Input Validation
62
  if not prompt or not prompt.strip():
63
  print("WARNING: Empty prompt received.\n") # Add newline for separation
 
119
  if translated_prompt != original_prompt:
120
  print(f" Translated: '{translated_prompt}'")
121
  print(f" Error: {e}\n") # Add newline
122
+ traceback.print_exc() # Keep traceback for unexpected errors
123
  return None, "<p style='color: red; text-align: center;'>An unexpected error occurred during safety check. Generation blocked.</p>"
124
  else:
125
  print(f"WARNING: OpenAI client not available. Skipping moderation.")
 
129
  print("") # Add newline
130
 
131
  # --- Proceed with Generation ---
 
132
  final_prompt = f"{translated_prompt} | ultra detail, ultra elaboration, ultra quality, perfect."
133
 
 
134
  payload = {
135
  "inputs": final_prompt,
136
  "parameters": {
137
+ "width": width, "height": height, "num_inference_steps": steps,
138
+ "negative_prompt": negative_prompt, "guidance_scale": cfg_scale,
 
139
  "seed": seed if seed != -1 else random.randint(1, 1000000000),
 
 
 
140
  }
141
  }
142
 
 
189
  print(f" Path: '{save_path}'\n") # Add newline
190
  return image, "<p style='color: red; text-align: center;'>Internal Error: Failed to confirm image file save.</p>"
191
 
192
+ space_name = "greendra-stable-diffusion-3-5-large-serverless"
 
193
  relative_file_url = f"gradio_api/file={save_path}"
194
  encoded_file_url = quote(relative_file_url)
195
  arinteli_url = f"{ARINTELI_REDIRECT_BASE}?download_url={encoded_file_url}&space_name={space_name}"
 
202
  f'</div>'
203
  )
204
 
205
+ # *** SUCCESS LOG ***
206
  print("SUCCESS:")
207
  print(f" Prompt: '{original_prompt}'")
208
  if translated_prompt != original_prompt:
 
219
  print(f" Path: '{save_path}'")
220
  print(f" Error: {save_err}\n") # Add newline
221
  traceback.print_exc()
222
+ return image, f"<p style='color: red; text-align: center;'>Internal Error: Failed to save image file.</p>"
223
  except Exception as e:
224
  print("FAILED:")
225
  print(f" Reason: Link Creation/Save Unexpected Error")
 
230
  traceback.print_exc()
231
  return image, "<p style='color: red; text-align: center;'>Internal Error creating download link.</p>"
232
 
233
+ # --- Exception Handling for API Call ---
234
  except requests.exceptions.Timeout:
235
  print("FAILED:")
236
  print(f" Reason: HF API Timeout")
 
256
  print(f" Translated: '{translated_prompt}'")
257
  print(f" Details: '{error_text[:200]}'\n") # Add newline
258
 
259
+ # User-facing messages remain the same
260
  if status_code == 503:
261
  estimated_time = error_data.get("estimated_time") if isinstance(error_data, dict) else None
262
  error_message = f"Model is loading (503), please wait." + (f" Est. time: {estimated_time:.1f}s." if estimated_time else "") + " Try again."
263
+ elif status_code == 400: error_message = f"Bad Request (400): Check parameters."
264
+ elif status_code == 422: error_message = f"Validation Error (422): Input invalid."
265
+ elif status_code == 401 or status_code == 403: error_message = f"Authorization Error ({status_code}): Check API Token."
266
+ elif status_code == 429: error_message = f"Rate Limit Error (429): Too many requests. Try again later."
267
+ else: error_message = f"API Error ({status_code}). Please try again."
268
 
269
  return None, f"<p style='color: red; text-align: center;'>{error_message}</p>"
270
  except Exception as e:
 
275
  print(f" Translated: '{translated_prompt}'")
276
  print(f" Error: {e}\n") # Add newline
277
  traceback.print_exc()
278
+ return None, f"<p style='color: red; text-align: center;'>An unexpected error occurred. Please check logs.</p>"
279
 
280
 
281
+ # --- CSS Styling ---
282
  css = """
283
  #app-container {
284
  max-width: 800px;
 
288
  textarea:focus {
289
  background: #0d1117 !important;
290
  }
291
+ #download-link-container p { /* Style the link container */
292
+ margin-top: 10px; /* Add some space above the link */
293
+ font-size: 0.9em; /* Slightly smaller text for the link message */
294
  }
295
  """
296
 
297
+ # --- Build the Gradio UI with Blocks ---
298
  with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css) as app:
 
299
  with gr.Column(elem_id="app-container"):
300
+ # --- Input Components ---
301
  with gr.Row():
302
  with gr.Column(elem_id="prompt-container"):
303
  with gr.Row():
304
+ text_prompt = gr.Textbox(
305
+ label="Prompt",
306
+ placeholder="Enter a prompt here",
307
+ lines=2,
308
+ elem_id="prompt-text-input"
309
+ )
310
  with gr.Row():
311
  with gr.Accordion("Advanced Settings", open=False):
312
+ negative_prompt = gr.Textbox(
313
+ label="Negative Prompt",
314
+ placeholder="What should not be in the image",
315
+ 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",
316
+ lines=3,
317
+ elem_id="negative-prompt-text-input"
318
+ )
319
  with gr.Row():
320
  width = gr.Slider(label="Width", value=1024, minimum=64, maximum=1216, step=32)
321
  height = gr.Slider(label="Height", value=1024, minimum=64, maximum=1216, step=32)
 
323
  cfg = gr.Slider(label="CFG Scale (guidance_scale)", value=0, minimum=0, maximum=10, step=1)
324
  seed = gr.Slider(label="Seed", value=-1, minimum=-1, maximum=1000000000, step=1, info="Set to -1 for random seed")
325
 
326
+ # --- Action Button ---
327
  with gr.Row():
328
  text_button = gr.Button("Run", variant='primary', elem_id="gen-button")
329
 
 
331
  with gr.Row():
332
  image_output = gr.Image(type="pil", label="Image Output", elem_id="gallery", show_label=False, show_download_button=False, show_share_button=False, show_fullscreen_button=False)
333
  with gr.Row():
 
334
  download_link_display = gr.HTML(elem_id="download-link-container")
335
 
336
+ # --- Event Listener ---
337
  text_button.click(
338
  query,
 
339
  inputs=[text_prompt, negative_prompt, steps, cfg, seed, width, height],
 
340
  outputs=[image_output, download_link_display]
341
  )
342
 
343
+ # --- Launch the Gradio app ---
344
  print("Starting Gradio app...")
345
  app.launch(
346
  show_api=False,
347
  share=False,
348
+ allowed_paths=[absolute_image_dir],
349
+ # server_name="0.0.0.0"
350
  )