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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -51
app.py CHANGED
@@ -4,23 +4,21 @@ import io
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,22 +40,20 @@ absolute_image_dir = os.path.abspath(IMAGE_DIR)
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,7 +115,7 @@ def query(prompt, negative_prompt, steps=4, cfg_scale=0, seed=-1, width=1024, he
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,14 +125,20 @@ def query(prompt, negative_prompt, steps=4, cfg_scale=0, seed=-1, width=1024, he
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,7 +191,8 @@ def query(prompt, negative_prompt, steps=4, cfg_scale=0, seed=-1, width=1024, he
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,7 +205,7 @@ def query(prompt, negative_prompt, steps=4, cfg_scale=0, seed=-1, width=1024, he
202
  f'</div>'
203
  )
204
 
205
- # *** SUCCESS LOG ***
206
  print("SUCCESS:")
207
  print(f" Prompt: '{original_prompt}'")
208
  if translated_prompt != original_prompt:
@@ -219,7 +222,7 @@ def query(prompt, negative_prompt, steps=4, cfg_scale=0, seed=-1, width=1024, he
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,7 +233,7 @@ def query(prompt, negative_prompt, steps=4, cfg_scale=0, seed=-1, width=1024, he
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,15 +259,14 @@ def query(prompt, negative_prompt, steps=4, cfg_scale=0, seed=-1, width=1024, he
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,10 +277,10 @@ def query(prompt, negative_prompt, steps=4, cfg_scale=0, seed=-1, width=1024, he
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,34 +290,24 @@ css = """
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,28 +315,29 @@ with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css) as app:
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
 
330
  # --- Output Components ---
331
  with gr.Row():
332
- image_output = gr.Image(type="pil", label="Image Output", elem_id="gallery")
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
  )
 
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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
 
321
  # --- Output Components ---
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
  )