Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -15,7 +15,25 @@ API_URL = "black-forest-labs/FLUX.1-schnell"
|
|
15 |
|
16 |
mod_list = {
|
17 |
"FLUX.1 Schnell": API_URL,
|
18 |
-
"FLUX.1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
}
|
20 |
API_TOKEN = os.getenv("HF_READ_TOKEN")
|
21 |
headers = {"Authorization": f"Bearer {API_TOKEN}"}
|
@@ -28,9 +46,16 @@ def add_noise(image, intensity=25):
|
|
28 |
:param intensity: Интенсивность шума (от 0 до 255)
|
29 |
:return: Изображение с шумом (PIL.Image)
|
30 |
"""
|
|
|
31 |
img_array = np.array(image)
|
|
|
|
|
32 |
noise = np.random.randint(-intensity, intensity, img_array.shape, dtype=np.int32)
|
|
|
|
|
33 |
noisy_array = np.clip(img_array + noise, 0, 255).astype(np.uint8)
|
|
|
|
|
34 |
noisy_image = Image.fromarray(noisy_array)
|
35 |
return noisy_image
|
36 |
|
@@ -38,12 +63,19 @@ def resize_and_crop(image, target_width=768, target_height=1024):
|
|
38 |
"""
|
39 |
Подгоняет изображение под размер target_width x target_height с сохранением пропорций.
|
40 |
Если изображение не соответствует соотношению сторон, обрезает его по бокам.
|
|
|
|
|
|
|
|
|
41 |
"""
|
|
|
42 |
original_width, original_height = image.size
|
43 |
target_ratio = target_width / target_height
|
44 |
original_ratio = original_width / original_height
|
45 |
|
|
|
46 |
if original_ratio > target_ratio:
|
|
|
47 |
new_height = target_height
|
48 |
new_width = int(original_width * (target_height / original_height))
|
49 |
resized_image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
@@ -52,6 +84,7 @@ def resize_and_crop(image, target_width=768, target_height=1024):
|
|
52 |
right = (new_width + target_width) / 2
|
53 |
bottom = target_height
|
54 |
else:
|
|
|
55 |
new_width = target_width
|
56 |
new_height = int(original_height * (target_width / original_width))
|
57 |
resized_image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
@@ -60,74 +93,82 @@ def resize_and_crop(image, target_width=768, target_height=1024):
|
|
60 |
right = target_width
|
61 |
bottom = (new_height + target_height) / 2
|
62 |
|
|
|
63 |
cropped_image = resized_image.crop((left, top, right, bottom))
|
64 |
return cropped_image
|
65 |
|
66 |
def compress_image(image, quality=50):
|
67 |
"""
|
68 |
Сжимает изображение и понижает его качество в формате JPEG.
|
|
|
|
|
|
|
69 |
"""
|
|
|
70 |
buffer = io.BytesIO()
|
71 |
image.save(buffer, format="JPEG", quality=quality)
|
72 |
buffer.seek(0)
|
|
|
|
|
73 |
compressed_image = Image.open(buffer)
|
74 |
return compressed_image
|
75 |
|
76 |
-
def query(prompt, is_realistic, num_inference_steps, width, height, mod=None):
|
77 |
-
if
|
78 |
return None
|
79 |
|
80 |
key = random.randint(0, 999)
|
81 |
-
|
|
|
82 |
headers = {"Authorization": f"Bearer {API_TOKEN}"}
|
83 |
|
84 |
payload = {
|
85 |
"inputs": prompt,
|
86 |
"seed": random.randint(1, 1000000000),
|
87 |
-
"parameters": {
|
88 |
-
"num_inference_steps": num_inference_steps,
|
89 |
-
"width": 1024,
|
90 |
-
"height": 1024
|
91 |
-
}
|
92 |
}
|
93 |
|
94 |
model = API_URL
|
95 |
-
|
96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
98 |
try:
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
json=payload,
|
103 |
-
timeout=timeout
|
104 |
-
)
|
105 |
-
response.raise_for_status()
|
106 |
-
|
107 |
-
image = Image.open(io.BytesIO(response.content))
|
108 |
image = resize_and_crop(image, width, height)
|
109 |
|
110 |
-
if is_realistic:
|
111 |
-
image = add_noise(image, intensity=randint(50, 100) / 10)
|
112 |
image = compress_image(image, randint(80, 90))
|
113 |
-
|
114 |
enhancer = ImageEnhance.Contrast(image)
|
115 |
-
image = enhancer.enhance(randint(75,
|
116 |
|
|
|
117 |
enhancer = ImageEnhance.Color(image)
|
118 |
-
image = enhancer.enhance(randint(80,
|
119 |
-
|
|
|
120 |
enhancer = ImageEnhance.Brightness(image)
|
121 |
-
image = enhancer.enhance(randint(70,
|
122 |
|
|
|
123 |
print(f'\033[1mGeneration {key} completed!\033[0m ({prompt})')
|
124 |
return image
|
125 |
-
|
126 |
-
except requests.exceptions.RequestException as e:
|
127 |
-
print(f"Request error: {e}")
|
128 |
-
raise gr.Error(f"API Error: {str(e)}")
|
129 |
except Exception as e:
|
130 |
-
print(f"
|
131 |
return None
|
132 |
|
133 |
css = """
|
@@ -139,59 +180,27 @@ css = """
|
|
139 |
"""
|
140 |
|
141 |
test_prompt = """[amateur perspective of a house],
|
142 |
-
[on this house staying white russian female with white t-shirt, black jeans, lime sneakers and looks aside]
|
143 |
[night melancholic lighting]"""
|
144 |
|
145 |
with gr.Blocks(theme='gstaff/xkcd', css=css) as app:
|
146 |
-
gr.
|
147 |
with gr.Column(elem_id="app-container"):
|
148 |
with gr.Row():
|
149 |
with gr.Column(elem_id="prompt-container"):
|
150 |
-
text_prompt = gr.Textbox(
|
151 |
-
label="Prompt",
|
152 |
-
placeholder="Enter a prompt here",
|
153 |
-
lines=2,
|
154 |
-
value=test_prompt
|
155 |
-
)
|
156 |
is_realistic = gr.Checkbox(label="Realistic filter", value=True)
|
157 |
-
num_inference_steps = gr.Slider(
|
158 |
-
label="Number of inference steps",
|
159 |
-
minimum=1,
|
160 |
-
maximum=50,
|
161 |
-
step=1,
|
162 |
-
value=4
|
163 |
-
)
|
164 |
with gr.Row():
|
165 |
-
width = gr.Slider(
|
166 |
-
|
167 |
-
|
168 |
-
maximum=1024,
|
169 |
-
step=32,
|
170 |
-
value=480
|
171 |
-
)
|
172 |
-
height = gr.Slider(
|
173 |
-
label="Height",
|
174 |
-
minimum=128,
|
175 |
-
maximum=1024,
|
176 |
-
step=32,
|
177 |
-
value=640
|
178 |
-
)
|
179 |
-
mod_choice = gr.Dropdown(
|
180 |
-
list(mod_list.keys()),
|
181 |
-
label="Model",
|
182 |
-
value="FLUX.1 Schnell"
|
183 |
-
)
|
184 |
|
185 |
with gr.Row():
|
186 |
-
text_button = gr.Button("
|
187 |
with gr.Row():
|
188 |
-
image_output = gr.Image(type="pil", label="
|
189 |
-
|
190 |
-
|
191 |
-
fn=query,
|
192 |
-
inputs=[text_prompt, is_realistic, num_inference_steps, width, height, mod_choice],
|
193 |
-
outputs=image_output
|
194 |
-
)
|
195 |
|
196 |
-
|
197 |
-
app.launch(show_api=True, share=False)
|
|
|
15 |
|
16 |
mod_list = {
|
17 |
"FLUX.1 Schnell": API_URL,
|
18 |
+
"FLUX.1 Schnell | Face Realism": "prithivMLmods/Canopus-LoRA-Flux-FaceRealism",
|
19 |
+
"FLUX.1 Schnell | Midjourney": "Jovie/Midjourney_Schnell",
|
20 |
+
"FLUX.1 Dev": "black-forest-labs/FLUX.1-dev",
|
21 |
+
"FLUX.1 Schnell | realism": "hugovntr/flux-schnell-realism",
|
22 |
+
"FLUX.1 Schnell | MJ v6": "strangerzonehf/Flux-Midjourney-Mix2-LoRA",
|
23 |
+
"FLUX.1 Dev | Flux Realism": "XLabs-AI/flux-RealismLora",
|
24 |
+
"FLUX.1 Redux": "black-forest-labs/FLUX.1-Redux-dev",
|
25 |
+
"FLUX.1 Dev | UltraRealism 2.0": "prithivMLmods/Canopus-LoRA-Flux-UltraRealism-2.0",
|
26 |
+
"Lumina Image 2.0": "Alpha-VLLM/Lumina-Image-2.0",
|
27 |
+
"FLUX.1 Dev | Vector Journey": "Shakker-Labs/FLUX.1-dev-LoRA-Vector-Journey",
|
28 |
+
"FLUX.1 Dev | Deep Blue": "fffiloni/deep-blue-v2",
|
29 |
+
"Realism Engine v1.0": "digiplay/RealismEngine_v1",
|
30 |
+
"Absolute Reality v1.8.1": "digiplay/AbsoluteReality_v1.8.1",
|
31 |
+
"FLUX.1 Dev | Midjourney Anime": "brushpenbob/flux-midjourney-anime",
|
32 |
+
"FLUX.1 Dev | Pencil v2": "brushpenbob/flux-pencil-v2",
|
33 |
+
"FLUX.1 Dev | Add Details": "Shakker-Labs/FLUX.1-dev-LoRA-add-details",
|
34 |
+
"FLUX.1 Dev | Pastel Anime": "Raelina/Flux-Pastel-Anime",
|
35 |
+
"FLUX.1 Dev | CartoonStyle": "Norod78/CartoonStyle-flux-lora",
|
36 |
+
"Kwai Kolors": "Kwai-Kolors/Kolors"
|
37 |
}
|
38 |
API_TOKEN = os.getenv("HF_READ_TOKEN")
|
39 |
headers = {"Authorization": f"Bearer {API_TOKEN}"}
|
|
|
46 |
:param intensity: Интенсивность шума (от 0 до 255)
|
47 |
:return: Изображение с шумом (PIL.Image)
|
48 |
"""
|
49 |
+
# Преобразуем изображение в массив NumPy
|
50 |
img_array = np.array(image)
|
51 |
+
|
52 |
+
# Генерируем шум
|
53 |
noise = np.random.randint(-intensity, intensity, img_array.shape, dtype=np.int32)
|
54 |
+
|
55 |
+
# Добавляем шум к изображению
|
56 |
noisy_array = np.clip(img_array + noise, 0, 255).astype(np.uint8)
|
57 |
+
|
58 |
+
# Преобразуем массив обратно в изображение
|
59 |
noisy_image = Image.fromarray(noisy_array)
|
60 |
return noisy_image
|
61 |
|
|
|
63 |
"""
|
64 |
Подгоняет изображение под размер target_width x target_height с сохранением пропорций.
|
65 |
Если изображение не соответствует соотношению сторон, обрезает его по бокам.
|
66 |
+
:param image: Изображение (PIL.Image)
|
67 |
+
:param target_width: Целевая ширина
|
68 |
+
:param target_height: Целевая высота
|
69 |
+
:return: Изображение с измененным размером (PIL.Image)
|
70 |
"""
|
71 |
+
# Сохраняем исходные пропорции
|
72 |
original_width, original_height = image.size
|
73 |
target_ratio = target_width / target_height
|
74 |
original_ratio = original_width / original_height
|
75 |
|
76 |
+
# Масштабируем изображение с сохранением пропорций
|
77 |
if original_ratio > target_ratio:
|
78 |
+
# Если изображение шире, чем нужно, обрезаем по бокам
|
79 |
new_height = target_height
|
80 |
new_width = int(original_width * (target_height / original_height))
|
81 |
resized_image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
|
|
84 |
right = (new_width + target_width) / 2
|
85 |
bottom = target_height
|
86 |
else:
|
87 |
+
# Если изображение уже, чем нужно, обрезаем сверху и снизу
|
88 |
new_width = target_width
|
89 |
new_height = int(original_height * (target_width / original_width))
|
90 |
resized_image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
|
|
93 |
right = target_width
|
94 |
bottom = (new_height + target_height) / 2
|
95 |
|
96 |
+
# Обрезаем изображение до целевого размера
|
97 |
cropped_image = resized_image.crop((left, top, right, bottom))
|
98 |
return cropped_image
|
99 |
|
100 |
def compress_image(image, quality=50):
|
101 |
"""
|
102 |
Сжимает изображение и понижает его качество в формате JPEG.
|
103 |
+
:param image: Изображение (PIL.Image)
|
104 |
+
:param quality: Качество JPEG (от 1 до 100)
|
105 |
+
:return: Сжатое изображение (PIL.Image)
|
106 |
"""
|
107 |
+
# Сохраняем изображение в буфер с пониженным качеством
|
108 |
buffer = io.BytesIO()
|
109 |
image.save(buffer, format="JPEG", quality=quality)
|
110 |
buffer.seek(0)
|
111 |
+
|
112 |
+
# Загружаем изображение обратно из буфера
|
113 |
compressed_image = Image.open(buffer)
|
114 |
return compressed_image
|
115 |
|
116 |
+
def query(prompt, is_realistic, num_inference_steps, width, height, mod = None):
|
117 |
+
if prompt == "" or prompt == None:
|
118 |
return None
|
119 |
|
120 |
key = random.randint(0, 999)
|
121 |
+
|
122 |
+
API_TOKEN = random.choice([os.getenv("HF_READ_TOKEN")])
|
123 |
headers = {"Authorization": f"Bearer {API_TOKEN}"}
|
124 |
|
125 |
payload = {
|
126 |
"inputs": prompt,
|
127 |
"seed": random.randint(1, 1000000000),
|
128 |
+
"parameters": {"num_inference_steps": num_inference_steps, "width": 1024, "height": 1024}
|
|
|
|
|
|
|
|
|
129 |
}
|
130 |
|
131 |
model = API_URL
|
132 |
+
for mod_name, mod_link in mod_list.items():
|
133 |
+
if (mod == mod_name):
|
134 |
+
model = mod_link
|
135 |
+
|
136 |
+
model = "https://api-inference.huggingface.co/models/" + model;
|
137 |
+
|
138 |
+
response = requests.post(model, headers=headers, json=payload, timeout=timeout)
|
139 |
+
if response.status_code != 200:
|
140 |
+
print(f"Error: Failed to get image. Response status: {response.status_code}")
|
141 |
+
print(f"Response content: {response.text}")
|
142 |
+
if response.status_code == 503:
|
143 |
+
raise gr.Error(f"{response.status_code} : The model is being loaded")
|
144 |
+
raise gr.Error(f"{response.status_code}")
|
145 |
|
146 |
try:
|
147 |
+
image_bytes = response.content
|
148 |
+
image = Image.open(io.BytesIO(image_bytes))
|
149 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
image = resize_and_crop(image, width, height)
|
151 |
|
152 |
+
if (is_realistic == True):
|
153 |
+
image = add_noise(image, intensity = randint(50, 100) / 10)
|
154 |
image = compress_image(image, randint(80, 90))
|
155 |
+
|
156 |
enhancer = ImageEnhance.Contrast(image)
|
157 |
+
image = enhancer.enhance(randint(75,80) / 100)
|
158 |
|
159 |
+
# Изменение насыщенности
|
160 |
enhancer = ImageEnhance.Color(image)
|
161 |
+
image = enhancer.enhance(randint(80,90) / 100)
|
162 |
+
|
163 |
+
# Изменение экспозиции (яркости)
|
164 |
enhancer = ImageEnhance.Brightness(image)
|
165 |
+
image = enhancer.enhance(randint(70,100) / 100)
|
166 |
|
167 |
+
|
168 |
print(f'\033[1mGeneration {key} completed!\033[0m ({prompt})')
|
169 |
return image
|
|
|
|
|
|
|
|
|
170 |
except Exception as e:
|
171 |
+
print(f"Error when trying to open the image: {e}")
|
172 |
return None
|
173 |
|
174 |
css = """
|
|
|
180 |
"""
|
181 |
|
182 |
test_prompt = """[amateur perspective of a house],
|
183 |
+
[on this house staying white russian female (if you can see it) with white t-shirt (if you can see it) on her body, with black jeans (if you can see it) on her legs, with lime sneakers (if you can see it) on her feet and looks aside (if you can see it)]
|
184 |
[night melancholic lighting]"""
|
185 |
|
186 |
with gr.Blocks(theme='gstaff/xkcd', css=css) as app:
|
187 |
+
gr.HTML("<center><h1>FLUX.1-Schnell</h1></center>")
|
188 |
with gr.Column(elem_id="app-container"):
|
189 |
with gr.Row():
|
190 |
with gr.Column(elem_id="prompt-container"):
|
191 |
+
text_prompt = gr.Textbox(label="Prompt", placeholder="Enter a prompt here", lines=2, elem_id="prompt-text-input", value=test_prompt)
|
|
|
|
|
|
|
|
|
|
|
192 |
is_realistic = gr.Checkbox(label="Realistic filter", value=True)
|
193 |
+
num_inference_steps = gr.Slider(label="Number of inference steps", minimum=1, maximum=50, step=1, value=4)
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
with gr.Row():
|
195 |
+
width = gr.Slider(label="Width", minimum = 128, maximum = 1024, step = 32, value = 480)
|
196 |
+
height = gr.Slider(label="Height", minimum = 128, maximum = 1024, step = 32, value = 640)
|
197 |
+
mod_choice = gr.Dropdown(list(mod_list.keys()), label="Mod")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
|
199 |
with gr.Row():
|
200 |
+
text_button = gr.Button("Run", variant='primary', elem_id="gen-button")
|
201 |
with gr.Row():
|
202 |
+
image_output = gr.Image(type="pil", label="Image Output", elem_id="gallery")
|
203 |
+
|
204 |
+
text_button.click(query, inputs=[text_prompt, is_realistic, num_inference_steps, width, height, mod_choice], outputs=image_output)
|
|
|
|
|
|
|
|
|
205 |
|
206 |
+
app.launch(show_api=True, share=True)
|
|