Zhofang commited on
Commit
0f559ef
·
verified ·
1 Parent(s): af19c28

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +119 -61
app.py CHANGED
@@ -6,79 +6,112 @@ import os
6
  from PIL import Image
7
  from deep_translator import GoogleTranslator
8
 
9
- # os.makedirs('assets', exist_ok=True)
10
  if not os.path.exists('icon.jpg'):
 
11
  os.system("wget -O icon.jpg https://i.pinimg.com/564x/64/49/88/644988c59447eb00286834c2e70fdd6b.jpg")
 
 
12
  API_URL_DEV = "https://lol-v2.mxflower.eu.org/api-inference.huggingface.co/models/black-forest-labs/FLUX.1-dev"
13
  API_URL = "https://lol-v2.mxflower.eu.org/api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell"
14
  timeout = 100
15
 
16
- def query(prompt, is_negative=False, steps=30, cfg_scale=7, sampler="DPM++ 2M Karras", seed=-1, strength=0.7, huggingface_api_key=None, use_dev=False):
17
  # Determine which API URL to use
18
  api_url = API_URL_DEV if use_dev else API_URL
19
 
20
- # Check if the request is an API call by checking for the presence of the huggingface_api_key
21
- is_api_call = huggingface_api_key is not None
22
-
23
- if is_api_call:
24
- # Use the environment variable for the API key in GUI mode
25
- API_TOKEN = os.getenv("HF_READ_TOKEN")
26
- headers = {"Authorization": f"Bearer {API_TOKEN}"}
27
  else:
28
- # Validate the API key if it's an API call
29
- if huggingface_api_key == "":
30
- raise gr.Error("API key is required for API calls.")
31
- headers = {"Authorization": f"Bearer {huggingface_api_key}"}
 
 
 
 
 
32
 
33
- if prompt == "" or prompt is None:
34
- return None
 
 
 
35
 
36
  key = random.randint(0, 999)
37
 
38
- prompt = GoogleTranslator(source='ru', target='en').translate(prompt)
39
- print(f'\033[1mGeneration {key} translation:\033[0m {prompt}')
 
 
 
 
 
 
40
 
41
- prompt = f"{prompt} | ultra detail, ultra elaboration, ultra quality, perfect."
42
- print(f'\033[1mGeneration {key}:\033[0m {prompt}')
 
43
 
44
- # If seed is -1, generate a random seed and use it
45
  if seed == -1:
46
  seed = random.randint(1, 1000000000)
47
 
48
  payload = {
49
- "inputs": prompt,
50
- "is_negative": is_negative,
51
  "steps": steps,
52
  "cfg_scale": cfg_scale,
53
  "seed": seed,
54
- "strength": strength
 
55
  }
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  response = requests.post(api_url, headers=headers, json=payload, timeout=timeout)
58
  if response.status_code != 200:
59
  print(f"Error: Failed to get image. Response status: {response.status_code}")
60
  print(f"Response content: {response.text}")
61
  if response.status_code == 503:
62
- raise gr.Error(f"{response.status_code} : The model is being loaded")
63
- raise gr.Error(f"{response.status_code}")
64
 
65
  try:
66
  image_bytes = response.content
67
  image = Image.open(io.BytesIO(image_bytes))
68
- print(f'\033[1mGeneration {key} completed!\033[0m ({prompt})')
69
 
70
- # Save the image to a file and return the file path and seed
71
- output_path = f"./output_{key}.png"
 
 
 
72
  image.save(output_path)
73
 
74
  return output_path, seed
75
  except Exception as e:
76
- print(f"Error when trying to open the image: {e}")
77
- return None, None
 
78
 
79
  css = """
80
  #app-container {
81
- max-width: 600px;
82
  margin-left: auto;
83
  margin-right: auto;
84
  }
@@ -86,51 +119,76 @@ css = """
86
  display: flex;
87
  align-items: center;
88
  justify-content: center;
 
89
  }
90
  #title-icon {
91
- width: 32px; /* Adjust the width of the icon as needed */
92
  height: auto;
93
- margin-right: 10px; /* Space between icon and title */
94
  }
95
  #title-text {
96
- font-size: 24px; /* Adjust font size as needed */
97
  font-weight: bold;
98
  }
 
 
 
99
  """
100
 
101
  with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css) as app:
102
  gr.HTML("""
103
- <center>
104
- <div id="title-container">
105
- <img id="title-icon" src="icon.jpg" alt="Icon">
106
- <h1 id="title-text">FLUX Capacitor</h1>
107
- </div>
108
- </center>
109
- """)
110
 
111
  with gr.Column(elem_id="app-container"):
112
  with gr.Row():
113
- with gr.Column(elem_id="prompt-container"):
114
- with gr.Row():
115
- text_prompt = gr.Textbox(label="Prompt", placeholder="Enter a prompt here", lines=2, elem_id="prompt-text-input")
116
- with gr.Row():
117
- with gr.Accordion("Advanced Settings", open=False):
118
- 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")
119
- steps = gr.Slider(label="Sampling steps", value=35, minimum=1, maximum=100, step=1)
120
- cfg = gr.Slider(label="CFG Scale", value=7, minimum=1, maximum=20, step=1)
121
- method = gr.Radio(label="Sampling method", value="DPM++ 2M Karras", choices=["DPM++ 2M Karras", "DPM++ SDE Karras", "Euler", "Euler a", "Heun", "DDIM"])
122
- strength = gr.Slider(label="Strength", value=0.7, minimum=0, maximum=1, step=0.001)
123
- seed = gr.Slider(label="Seed", value=-1, minimum=-1, maximum=1000000000, step=1)
124
- huggingface_api_key = gr.Textbox(label="Hugging Face API Key (required for API calls)", placeholder="Enter your Hugging Face API Key here", type="password", elem_id="api-key")
125
- use_dev = gr.Checkbox(label="Use Dev API", value=False, elem_id="use-dev-checkbox")
 
 
 
126
 
127
  with gr.Row():
128
- text_button = gr.Button("Run", variant='primary', elem_id="gen-button")
 
129
  with gr.Row():
130
- image_output = gr.Image(type="pil", label="Image Output", elem_id="gallery")
131
- seed_output = gr.Textbox(label="Seed Used", elem_id="seed-output")
132
 
133
- # Adjust the click function to include the API key and use_dev as inputs
134
- text_button.click(query, inputs=[text_prompt, negative_prompt, steps, cfg, method, seed, strength, huggingface_api_key, use_dev], outputs=[image_output, seed_output])
135
-
136
- app.launch(show_api=True, share=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  from PIL import Image
7
  from deep_translator import GoogleTranslator
8
 
9
+ # os.makedirs('assets', exist_ok=True) # Tidak terlalu dibutuhkan jika icon.jpg ada di root
10
  if not os.path.exists('icon.jpg'):
11
+ print("Downloading icon.jpg...")
12
  os.system("wget -O icon.jpg https://i.pinimg.com/564x/64/49/88/644988c59447eb00286834c2e70fdd6b.jpg")
13
+ print("Icon downloaded.")
14
+
15
  API_URL_DEV = "https://lol-v2.mxflower.eu.org/api-inference.huggingface.co/models/black-forest-labs/FLUX.1-dev"
16
  API_URL = "https://lol-v2.mxflower.eu.org/api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell"
17
  timeout = 100
18
 
19
+ def query(prompt, negative_prompt_str, steps=30, cfg_scale=7, sampler="DPM++ 2M Karras", seed=-1, strength=0.7, huggingface_api_key_ui=None, use_dev=False):
20
  # Determine which API URL to use
21
  api_url = API_URL_DEV if use_dev else API_URL
22
 
23
+ # Determine the API token to use
24
+ api_token_to_use = None
25
+ if huggingface_api_key_ui and huggingface_api_key_ui.strip(): # Cek apakah UI key diisi dan bukan hanya spasi
26
+ api_token_to_use = huggingface_api_key_ui.strip()
27
+ print("Using API key from UI input.")
 
 
28
  else:
29
+ env_token = os.getenv("HF_READ_TOKEN")
30
+ if env_token and env_token.strip(): # Cek apakah environment variable ada dan bukan hanya spasi
31
+ api_token_to_use = env_token.strip()
32
+ print("Using API key from HF_READ_TOKEN environment variable.")
33
+
34
+ if not api_token_to_use:
35
+ raise gr.Error("Hugging Face API Key is required. Please provide it in the UI (Advanced Settings -> Hugging Face API Key) or set the HF_READ_TOKEN environment variable.")
36
+
37
+ headers = {"Authorization": f"Bearer {api_token_to_use}"}
38
 
39
+ if not prompt or prompt.strip() == "":
40
+ # Anda bisa mengembalikan gambar placeholder atau pesan error
41
+ # Untuk saat ini, kita kembalikan None, Gradio mungkin akan menampilkan error atau kosong
42
+ gr.Warning("Prompt cannot be empty.")
43
+ return None, seed # Atau raise gr.Error("Prompt cannot be empty.")
44
 
45
  key = random.randint(0, 999)
46
 
47
+ # Terjemahkan prompt
48
+ try:
49
+ translated_prompt = GoogleTranslator(source='auto', target='en').translate(prompt) # 'auto' lebih fleksibel
50
+ except Exception as e:
51
+ print(f"Error translating prompt: {e}. Using original prompt.")
52
+ translated_prompt = prompt # Fallback ke prompt asli jika translasi gagal
53
+
54
+ print(f'\033[1mGeneration {key} translation:\033[0m {translated_prompt}')
55
 
56
+ # Tambahkan detail ke prompt
57
+ final_prompt = f"{translated_prompt} | ultra detail, ultra elaboration, ultra quality, perfect."
58
+ print(f'\033[1mGeneration {key}:\033[0m {final_prompt}')
59
 
60
+ # Jika seed adalah -1, generate seed acak
61
  if seed == -1:
62
  seed = random.randint(1, 1000000000)
63
 
64
  payload = {
65
+ "inputs": final_prompt,
 
66
  "steps": steps,
67
  "cfg_scale": cfg_scale,
68
  "seed": seed,
69
+ "strength": strength,
70
+ "sampler": sampler # Menambahkan sampler ke payload
71
  }
72
 
73
+ # Logika untuk negative prompt:
74
+ # API Anda (lol-v2.mxflower.eu.org) sepertinya mengharapkan string negative prompt
75
+ # dikirim melalui field "is_negative" berdasarkan kode asli Anda.
76
+ # Jika API sebenarnya mengharapkan boolean untuk "is_negative" dan string di field lain (mis. "negative_prompt"),
77
+ # ini perlu disesuaikan.
78
+ # Untuk saat ini, saya mengikuti struktur asli dimana string negative_prompt_str dikirim sebagai "is_negative".
79
+ if negative_prompt_str and negative_prompt_str.strip():
80
+ payload["is_negative"] = negative_prompt_str.strip()
81
+ # Jika tidak, kita tidak mengirim field "is_negative" sama sekali jika API lebih suka begitu
82
+ # atau payload["is_negative"] = "" (tergantung preferensi API)
83
+
84
+ print(f"Payload to API: {payload}")
85
+
86
  response = requests.post(api_url, headers=headers, json=payload, timeout=timeout)
87
  if response.status_code != 200:
88
  print(f"Error: Failed to get image. Response status: {response.status_code}")
89
  print(f"Response content: {response.text}")
90
  if response.status_code == 503:
91
+ raise gr.Error(f"{response.status_code} : The model is being loaded or is unavailable. Details: {response.text[:500]}")
92
+ raise gr.Error(f"API Error {response.status_code}: {response.text[:500]}")
93
 
94
  try:
95
  image_bytes = response.content
96
  image = Image.open(io.BytesIO(image_bytes))
97
+ print(f'\033[1mGeneration {key} completed!\033[0m ({final_prompt})')
98
 
99
+ # Simpan gambar ke file dan kembalikan path file dan seed
100
+ # Pastikan direktori output ada jika Anda mau menyimpannya di subdirektori
101
+ # os.makedirs('outputs', exist_ok=True)
102
+ # output_path = f"./outputs/output_{key}.png"
103
+ output_path = f"./output_{key}.png" # Simpan di root untuk kesederhanaan
104
  image.save(output_path)
105
 
106
  return output_path, seed
107
  except Exception as e:
108
+ print(f"Error when trying to open or save the image: {e}")
109
+ print(f"Response content that caused error: {response.content[:200]}") # Tampilkan sebagian konten jika bukan gambar
110
+ raise gr.Error(f"Failed to process image from API response. {e}")
111
 
112
  css = """
113
  #app-container {
114
+ max-width: 700px; /* Sedikit lebih lebar untuk kenyamanan */
115
  margin-left: auto;
116
  margin-right: auto;
117
  }
 
119
  display: flex;
120
  align-items: center;
121
  justify-content: center;
122
+ margin-bottom: 15px; /* Tambah margin bawah */
123
  }
124
  #title-icon {
125
+ width: 40px; /* Sedikit lebih besar */
126
  height: auto;
127
+ margin-right: 10px;
128
  }
129
  #title-text {
130
+ font-size: 28px; /* Sedikit lebih besar */
131
  font-weight: bold;
132
  }
133
+ #gen-button {
134
+ margin-top: 10px;
135
+ }
136
  """
137
 
138
  with gr.Blocks(theme='Nymbo/Nymbo_Theme', css=css) as app:
139
  gr.HTML("""
140
+ <div id="title-container">
141
+ <img id="title-icon" src="file/icon.jpg" alt="Icon"> <!-- Perbaiki path jika icon.jpg di root -->
142
+ <h1 id="title-text">FLUX Capacitor</h1>
143
+ </div>
144
+ """) # Menggunakan </center> tidak standar, div dengan margin auto lebih baik untuk centering global
 
 
145
 
146
  with gr.Column(elem_id="app-container"):
147
  with gr.Row():
148
+ text_prompt = gr.Textbox(label="Prompt", placeholder="Enter a prompt here", lines=3, elem_id="prompt-text-input")
149
+
150
+ with gr.Accordion("Advanced Settings", open=False):
151
+ negative_prompt_ui = 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")
152
+ steps_ui = gr.Slider(label="Sampling steps", value=35, minimum=1, maximum=100, step=1)
153
+ cfg_ui = gr.Slider(label="CFG Scale", value=7, minimum=1, maximum=20, step=1)
154
+ method_ui = gr.Radio(label="Sampling method", value="DPM++ 2M Karras", choices=["DPM++ 2M Karras", "DPM++ SDE Karras", "Euler", "Euler a", "Heun", "DDIM"])
155
+ strength_ui = gr.Slider(label="Strength (for Img2Img/SDEdit, might not apply here)", value=0.7, minimum=0, maximum=1, step=0.001)
156
+ seed_ui = gr.Slider(label="Seed (-1 for random)", value=-1, minimum=-1, maximum=1000000000, step=1)
157
+ huggingface_api_key_ui_input = gr.Textbox(
158
+ label="Hugging Face API Key (optional, uses HF_READ_TOKEN if empty)",
159
+ placeholder="Enter your Hugging Face API Key (e.g., hf_xxxx)",
160
+ type="password",
161
+ elem_id="api-key"
162
+ )
163
+ use_dev_ui = gr.Checkbox(label="Use Dev API (potentially unstable)", value=False, elem_id="use-dev-checkbox")
164
 
165
  with gr.Row():
166
+ text_button = gr.Button("Generate Image", variant='primary', elem_id="gen-button", scale=3) # scale untuk mengambil lebih banyak ruang jika diinginkan
167
+
168
  with gr.Row():
169
+ image_output = gr.Image(type="filepath", label="Generated Image", elem_id="gallery") # type="filepath" lebih baik untuk output path
170
+ seed_output = gr.Textbox(label="Seed Used", elem_id="seed-output", interactive=False)
171
 
172
+ # Sesuaikan fungsi click untuk menyertakan input API key dan use_dev
173
+ # Pastikan urutan input di sini sesuai dengan urutan argumen di fungsi query
174
+ text_button.click(
175
+ query,
176
+ inputs=[
177
+ text_prompt,
178
+ negative_prompt_ui,
179
+ steps_ui,
180
+ cfg_ui,
181
+ method_ui,
182
+ seed_ui,
183
+ strength_ui,
184
+ huggingface_api_key_ui_input,
185
+ use_dev_ui
186
+ ],
187
+ outputs=[image_output, seed_output]
188
+ )
189
+
190
+ # Jika Anda menjalankan di environment seperti Hugging Face Spaces, share=True biasanya diperlukan atau default.
191
+ # TypeError: argument of type 'bool' is not iterable (dari log Anda) sering terkait dengan show_api=True
192
+ # pada versi Gradio tertentu. Memperbarui Gradio atau menyetel show_api=False dapat membantu.
193
+ # Untuk tujuan demo ini, show_api=False bisa lebih stabil jika Anda masih menghadapi error tersebut.
194
+ app.launch(show_api=False, share=True) # show_api=False untuk menghindari potensi error schema, share=True untuk aksesibilitas