Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,8 +1,6 @@
|
|
1 |
import os
|
2 |
-
os.system('pip install numpy pillow opencv-python fastapi starlette uvicorn requests')
|
3 |
import gradio as gr
|
4 |
import shutil
|
5 |
-
import cv2
|
6 |
import numpy as np
|
7 |
from PIL import Image
|
8 |
import asyncio
|
@@ -15,6 +13,14 @@ import uvicorn
|
|
15 |
import requests
|
16 |
from urllib.parse import quote
|
17 |
from unicodedata import normalize
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
root = os.path.dirname(os.path.abspath(__file__))
|
20 |
textures_folder = os.path.join(root, 'textures')
|
@@ -22,7 +28,6 @@ os.makedirs(textures_folder, exist_ok=True)
|
|
22 |
valid_extensions = ['.jpeg', '.jpg', '.png']
|
23 |
|
24 |
|
25 |
-
|
26 |
textures_repo = "https://huggingface.co/datasets/2ch/textures/resolve/main/"
|
27 |
textures_for_download = [
|
28 |
f"{textures_repo}гауссовский_шум_и_мелкое_зерно.png?download=true",
|
@@ -50,7 +55,7 @@ f"{textures_repo}шумная_матрица.png?download=true",
|
|
50 |
]
|
51 |
|
52 |
|
53 |
-
def dl_textures(texture_url):
|
54 |
texture_for_download = quote(normalize('NFD', texture_url), safe='/?:=')
|
55 |
filename = texture_url.split('/')[-1].split('?')[0]
|
56 |
file_path = os.path.join(textures_folder, filename)
|
@@ -61,7 +66,7 @@ def dl_textures(texture_url):
|
|
61 |
f.write(chunk)
|
62 |
|
63 |
|
64 |
-
def create_texture_preview(texture_folder, output_folder, size=(246, 246)):
|
65 |
os.makedirs(output_folder, exist_ok=True)
|
66 |
for texture in os.listdir(texture_folder):
|
67 |
img_path = os.path.join(texture_folder, texture)
|
@@ -72,21 +77,17 @@ def create_texture_preview(texture_folder, output_folder, size=(246, 246)):
|
|
72 |
cv2.imwrite(os.path.join(output_folder, texture), img)
|
73 |
|
74 |
|
75 |
-
def prepare_textures(texture_folder, output_folder):
|
76 |
with ThreadPoolExecutor(max_workers=len(textures_for_download)) as executor:
|
77 |
futures = [executor.submit(dl_textures, texture_for_download) for texture_for_download in
|
78 |
textures_for_download]
|
79 |
for future in as_completed(futures):
|
80 |
future.result()
|
81 |
-
|
82 |
create_texture_preview(texture_folder, output_folder, size=(246, 246))
|
83 |
|
84 |
|
85 |
-
prepare_textures(textures_folder, os.path.join(root, 'preview'))
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
preview_css = ""
|
|
|
90 |
for i, texture in enumerate(os.listdir(textures_folder), start=1):
|
91 |
if os.path.splitext(texture)[1].lower() in valid_extensions:
|
92 |
preview_css += f"""[data-testid="{i:02d}-radio-label"]::before {{
|
@@ -191,7 +192,8 @@ footer:after {
|
|
191 |
}
|
192 |
|
193 |
#textured_result-download-link,
|
194 |
-
#restored_image-download-link
|
|
|
195 |
position: absolute;
|
196 |
z-index: 9999;
|
197 |
padding: 2px 4px;
|
@@ -203,17 +205,21 @@ footer:after {
|
|
203 |
transition: 300ms
|
204 |
}
|
205 |
|
206 |
-
#download-link:hover
|
|
|
|
|
207 |
color: #99f7a8
|
208 |
}
|
209 |
|
210 |
-
#restored_images.disabled
|
|
|
211 |
height: 0px !important;
|
212 |
opacity: 0;
|
213 |
transition: 300ms
|
214 |
}
|
215 |
|
216 |
-
#restored_images.enabled
|
|
|
217 |
transition: 300ms
|
218 |
}
|
219 |
""" + preview_css
|
@@ -238,24 +244,28 @@ const PageLoadObserver = new MutationObserver((mutationsList, observer) => {
|
|
238 |
document.querySelector("label[data-testid='05-radio-label']").click()
|
239 |
}, 150);
|
240 |
})
|
241 |
-
|
242 |
-
|
243 |
-
const firstDiv = RestoredGallery.querySelector('div:first-child');
|
244 |
const hasChildElements = firstDiv && firstDiv.children.length > 0;
|
245 |
-
const hasImages =
|
246 |
if (hasChildElements || hasImages) {
|
247 |
-
|
248 |
-
|
249 |
} else {
|
250 |
-
|
251 |
-
|
252 |
}
|
253 |
}
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
|
|
|
|
|
|
|
|
|
|
259 |
function magnify(imgID, zoom) {
|
260 |
var img, glass, w, h, bw;
|
261 |
img = document.querySelector(imgID);
|
@@ -343,6 +353,12 @@ const PageLoadObserver = new MutationObserver((mutationsList, observer) => {
|
|
343 |
});
|
344 |
|
345 |
ImageRestoredObserver.observe(document, DownloadLinkObserverOptions);
|
|
|
|
|
|
|
|
|
|
|
|
|
346 |
|
347 |
}
|
348 |
}
|
@@ -352,7 +368,8 @@ const PageLoadObserver = new MutationObserver((mutationsList, observer) => {
|
|
352 |
PageLoadObserver.observe(document, { childList: true, subtree: true });
|
353 |
"""
|
354 |
|
355 |
-
|
|
|
356 |
if isinstance(predict_answer, (tuple, list)):
|
357 |
result = predict_answer[0]
|
358 |
shutil.rmtree(os.path.dirname(predict_answer[1]), ignore_errors=True)
|
@@ -386,7 +403,6 @@ def restore_face_codeformer(img_path: str) -> None:
|
|
386 |
restore_face_common(img_path, result, "codeformer")
|
387 |
|
388 |
|
389 |
-
|
390 |
async def restore_faces_one_image(img_path: str, func_list: list) -> bool:
|
391 |
def run_func(func) -> bool:
|
392 |
for _ in range(3):
|
@@ -435,7 +451,7 @@ def get_file_paths(input_path: str | list[str], extensions_list: list[str]) -> l
|
|
435 |
return files
|
436 |
|
437 |
|
438 |
-
async def restore_upscale(files, restore_method):
|
439 |
file_paths = [file.name for file in files]
|
440 |
if restore_method == 'codeformer':
|
441 |
func_list = [restore_face_codeformer]
|
@@ -446,10 +462,9 @@ async def restore_upscale(files, restore_method):
|
|
446 |
results = await restore_faces_batch(file_paths, func_list, batch_size=3)
|
447 |
if results:
|
448 |
file_paths = get_file_paths(file_paths, valid_extensions)
|
449 |
-
print(f"restore_upscale: get_file_paths: {file_paths}")
|
450 |
return file_paths
|
451 |
else:
|
452 |
-
return [
|
453 |
|
454 |
|
455 |
def image_noise_softlight_layer_mix(img, texture, output: str = None, opacity: float = 0.7):
|
@@ -488,17 +503,185 @@ def image_noise_softlight_layer_mix(img, texture, output: str = None, opacity: f
|
|
488 |
return np.array(image)
|
489 |
|
490 |
|
491 |
-
def apply_texture(input_image, textures_choice, opacity_slider):
|
492 |
result = image_noise_softlight_layer_mix(input_image, os.path.join(textures_folder, textures_choice), opacity=opacity_slider)
|
493 |
return [result]
|
494 |
|
495 |
|
496 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
497 |
with gr.Tab(label="восстановление лиц", id=1, elem_id="restore_tab"):
|
498 |
restore_method = gr.Radio(["codeformer", "gfpgan", "оба"], value="codeformer", label="", interactive=True)
|
499 |
restore_method.change(fn=lambda x: print(f"restore_method value = {x}"), inputs=restore_method, api_name="show_selected_method")
|
500 |
file_output = gr.Gallery(label="", container=True, object_fit="cover", columns=4, rows=4, allow_preview=True, preview=True, show_share_button=False, show_download_button=False, elem_id="restored_images")
|
501 |
-
upload_button = gr.UploadButton("выбор изображений для обработки", file_types=["image"], file_count="multiple", variant="primary")
|
502 |
upload_button.upload(fn=restore_upscale, inputs=[upload_button, restore_method], outputs=file_output, api_name="face_restore")
|
503 |
with gr.Tab(label="наложение зернистости пленки и шума", id=2, elem_id="textures_tab"):
|
504 |
with gr.Row(variant="compact", elem_id="textures_tab_images"):
|
|
|
1 |
import os
|
|
|
2 |
import gradio as gr
|
3 |
import shutil
|
|
|
4 |
import numpy as np
|
5 |
from PIL import Image
|
6 |
import asyncio
|
|
|
13 |
import requests
|
14 |
from urllib.parse import quote
|
15 |
from unicodedata import normalize
|
16 |
+
import json
|
17 |
+
import time
|
18 |
+
from html.parser import HTMLParser
|
19 |
+
try:
|
20 |
+
import cv2
|
21 |
+
except ImportError:
|
22 |
+
os.system('pip install opencv-python')
|
23 |
+
import cv2
|
24 |
|
25 |
root = os.path.dirname(os.path.abspath(__file__))
|
26 |
textures_folder = os.path.join(root, 'textures')
|
|
|
28 |
valid_extensions = ['.jpeg', '.jpg', '.png']
|
29 |
|
30 |
|
|
|
31 |
textures_repo = "https://huggingface.co/datasets/2ch/textures/resolve/main/"
|
32 |
textures_for_download = [
|
33 |
f"{textures_repo}гауссовский_шум_и_мелкое_зерно.png?download=true",
|
|
|
55 |
]
|
56 |
|
57 |
|
58 |
+
def dl_textures(texture_url: str) -> None:
|
59 |
texture_for_download = quote(normalize('NFD', texture_url), safe='/?:=')
|
60 |
filename = texture_url.split('/')[-1].split('?')[0]
|
61 |
file_path = os.path.join(textures_folder, filename)
|
|
|
66 |
f.write(chunk)
|
67 |
|
68 |
|
69 |
+
def create_texture_preview(texture_folder: str, output_folder: str, size: tuple[int] = (246, 246)) -> None:
|
70 |
os.makedirs(output_folder, exist_ok=True)
|
71 |
for texture in os.listdir(texture_folder):
|
72 |
img_path = os.path.join(texture_folder, texture)
|
|
|
77 |
cv2.imwrite(os.path.join(output_folder, texture), img)
|
78 |
|
79 |
|
80 |
+
def prepare_textures(texture_folder: str, output_folder: str) -> None:
|
81 |
with ThreadPoolExecutor(max_workers=len(textures_for_download)) as executor:
|
82 |
futures = [executor.submit(dl_textures, texture_for_download) for texture_for_download in
|
83 |
textures_for_download]
|
84 |
for future in as_completed(futures):
|
85 |
future.result()
|
|
|
86 |
create_texture_preview(texture_folder, output_folder, size=(246, 246))
|
87 |
|
88 |
|
|
|
|
|
|
|
|
|
89 |
preview_css = ""
|
90 |
+
prepare_textures(textures_folder, os.path.join(root, 'preview'))
|
91 |
for i, texture in enumerate(os.listdir(textures_folder), start=1):
|
92 |
if os.path.splitext(texture)[1].lower() in valid_extensions:
|
93 |
preview_css += f"""[data-testid="{i:02d}-radio-label"]::before {{
|
|
|
192 |
}
|
193 |
|
194 |
#textured_result-download-link,
|
195 |
+
#restored_image-download-link,
|
196 |
+
#upscaled_image-download-link {
|
197 |
position: absolute;
|
198 |
z-index: 9999;
|
199 |
padding: 2px 4px;
|
|
|
205 |
transition: 300ms
|
206 |
}
|
207 |
|
208 |
+
#textured_result-download-link:hover,
|
209 |
+
#restored_image-download-link:hover,
|
210 |
+
#upscaled_image-download-link:hover {
|
211 |
color: #99f7a8
|
212 |
}
|
213 |
|
214 |
+
#restored_images.disabled,
|
215 |
+
#upscaled_images.disabled {
|
216 |
height: 0px !important;
|
217 |
opacity: 0;
|
218 |
transition: 300ms
|
219 |
}
|
220 |
|
221 |
+
#restored_images.enabled,
|
222 |
+
#upscaled_images.enabled {
|
223 |
transition: 300ms
|
224 |
}
|
225 |
""" + preview_css
|
|
|
244 |
document.querySelector("label[data-testid='05-radio-label']").click()
|
245 |
}, 150);
|
246 |
})
|
247 |
+
function checkImagesAndSetClass(galleryElement) {
|
248 |
+
const firstDiv = galleryElement.querySelector('div:first-child');
|
|
|
249 |
const hasChildElements = firstDiv && firstDiv.children.length > 0;
|
250 |
+
const hasImages = galleryElement.querySelectorAll('img').length > 0;
|
251 |
if (hasChildElements || hasImages) {
|
252 |
+
galleryElement.classList.add('enabled');
|
253 |
+
galleryElement.classList.remove('disabled');
|
254 |
} else {
|
255 |
+
galleryElement.classList.add('disabled');
|
256 |
+
galleryElement.classList.remove('enabled');
|
257 |
}
|
258 |
}
|
259 |
+
function setupGalleryObserver(galleryId) {
|
260 |
+
let gallery = document.getElementById(galleryId);
|
261 |
+
const observer = new MutationObserver(() => {
|
262 |
+
checkImagesAndSetClass(gallery);
|
263 |
+
});
|
264 |
+
observer.observe(gallery, { childList: true, subtree: true });
|
265 |
+
checkImagesAndSetClass(gallery);
|
266 |
+
}
|
267 |
+
setupGalleryObserver('restored_images');
|
268 |
+
setupGalleryObserver('upscaled_images');
|
269 |
function magnify(imgID, zoom) {
|
270 |
var img, glass, w, h, bw;
|
271 |
img = document.querySelector(imgID);
|
|
|
353 |
});
|
354 |
|
355 |
ImageRestoredObserver.observe(document, DownloadLinkObserverOptions);
|
356 |
+
|
357 |
+
const ImageUpscaledObserver = new MutationObserver((mutationsList, observer) => {
|
358 |
+
DownloadLinkObserverCallback(mutationsList, observer, '#upscaled_images img[data-testid="detailed-image"]', '#upscaled_image-download-link', 'upscaled_image-download-link');
|
359 |
+
});
|
360 |
+
|
361 |
+
ImageUpscaledObserver.observe(document, DownloadLinkObserverOptions);
|
362 |
|
363 |
}
|
364 |
}
|
|
|
368 |
PageLoadObserver.observe(document, { childList: true, subtree: true });
|
369 |
"""
|
370 |
|
371 |
+
|
372 |
+
def extract_path_from_result(predict_answer: str | list[str] | tuple[str]) -> str:
|
373 |
if isinstance(predict_answer, (tuple, list)):
|
374 |
result = predict_answer[0]
|
375 |
shutil.rmtree(os.path.dirname(predict_answer[1]), ignore_errors=True)
|
|
|
403 |
restore_face_common(img_path, result, "codeformer")
|
404 |
|
405 |
|
|
|
406 |
async def restore_faces_one_image(img_path: str, func_list: list) -> bool:
|
407 |
def run_func(func) -> bool:
|
408 |
for _ in range(3):
|
|
|
451 |
return files
|
452 |
|
453 |
|
454 |
+
async def restore_upscale(files: tuple, restore_method: str) -> list[str]:
|
455 |
file_paths = [file.name for file in files]
|
456 |
if restore_method == 'codeformer':
|
457 |
func_list = [restore_face_codeformer]
|
|
|
462 |
results = await restore_faces_batch(file_paths, func_list, batch_size=3)
|
463 |
if results:
|
464 |
file_paths = get_file_paths(file_paths, valid_extensions)
|
|
|
465 |
return file_paths
|
466 |
else:
|
467 |
+
return ['https://iili.io/JzrxjDP.png']
|
468 |
|
469 |
|
470 |
def image_noise_softlight_layer_mix(img, texture, output: str = None, opacity: float = 0.7):
|
|
|
503 |
return np.array(image)
|
504 |
|
505 |
|
506 |
+
def apply_texture(input_image, textures_choice: str, opacity_slider: float):
|
507 |
result = image_noise_softlight_layer_mix(input_image, os.path.join(textures_folder, textures_choice), opacity=opacity_slider)
|
508 |
return [result]
|
509 |
|
510 |
|
511 |
+
def temp_upload_file(file_path: str) -> str | None:
|
512 |
+
servers = [
|
513 |
+
('https://transfer.sh/', 'fileToUpload'),
|
514 |
+
('https://x0.at/', 'file'),
|
515 |
+
('https://tmpfiles.org/api/v1/upload', 'file'),
|
516 |
+
('https://uguu.se/upload.php', 'files[]')
|
517 |
+
]
|
518 |
+
for i in range(3):
|
519 |
+
for server, file_key in servers:
|
520 |
+
try:
|
521 |
+
with open(file_path, 'rb') as f:
|
522 |
+
files = {file_key: f}
|
523 |
+
response = requests.post(server, files=files)
|
524 |
+
if response.status_code == 200:
|
525 |
+
if server == 'https://transfer.sh/':
|
526 |
+
return response.text.replace("https://transfer.sh/","https://transfer.sh/get/").replace("\n","")
|
527 |
+
elif server == 'https://tmpfiles.org/api/v1/upload':
|
528 |
+
response_json = response.json()
|
529 |
+
if response_json['status'] == 'success':
|
530 |
+
return response_json['data']['url'].replace("https://tmpfiles.org/", "https://tmpfiles.org/dl/")
|
531 |
+
elif server == 'https://uguu.se/upload.php':
|
532 |
+
response_json = response.json()
|
533 |
+
if response_json['success']:
|
534 |
+
return response_json['files'][0]['url']
|
535 |
+
else:
|
536 |
+
return response.text
|
537 |
+
except Exception as e:
|
538 |
+
print(f'{server}: {e}')
|
539 |
+
return None
|
540 |
+
|
541 |
+
|
542 |
+
def upload_image(image_path: str) -> str | None:
|
543 |
+
files = {'source': open(image_path, "rb")}
|
544 |
+
data = {'key': '6d207e02198a847aa98d0a2a901485a5', 'action': 'upload', 'format': 'json'}
|
545 |
+
response = requests.post('https://freeimage.host/api/1/upload', files=files, data=data)
|
546 |
+
if response.json()["status_code"] == 200:
|
547 |
+
return response.json()["image"]["url"]
|
548 |
+
else:
|
549 |
+
return temp_upload_file(image_path)
|
550 |
+
|
551 |
+
|
552 |
+
def get_headers(url: str) -> dict:
|
553 |
+
session = requests.Session()
|
554 |
+
anon_auth = session.get(url)
|
555 |
+
cookies = session.cookies.get_dict()
|
556 |
+
return {
|
557 |
+
'content-type': 'application/json',
|
558 |
+
'cookie': f'csrftoken={cookies["csrftoken"]}; replicate_anonymous_id={cookies["replicate_anonymous_id"]};',
|
559 |
+
'origin': 'https://replicate.com',
|
560 |
+
'x-csrftoken': cookies['csrftoken'],
|
561 |
+
'authority': 'replicate.com',
|
562 |
+
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
563 |
+
'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
|
564 |
+
'cache-control': 'no-cache',
|
565 |
+
'dnt': '1',
|
566 |
+
'pragma': 'no-cache',
|
567 |
+
'referer': f'{url}?input=http',
|
568 |
+
'sec-ch-ua': '"Chromium";v="117", "Not;A=Brand";v="8"',
|
569 |
+
'sec-ch-ua-mobile': '?0',
|
570 |
+
'sec-ch-ua-platform': '"Windows"',
|
571 |
+
'sec-fetch-dest': 'document',
|
572 |
+
'sec-fetch-mode': 'navigate',
|
573 |
+
'sec-fetch-site': 'same-origin',
|
574 |
+
'sec-fetch-user': '?1',
|
575 |
+
'upgrade-insecure-requests': '1',
|
576 |
+
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'
|
577 |
+
}
|
578 |
+
|
579 |
+
|
580 |
+
def get_version(url: str) -> str:
|
581 |
+
url = url.rstrip('/') + '/versions'
|
582 |
+
response = requests.get(url)
|
583 |
+
|
584 |
+
class Version(HTMLParser):
|
585 |
+
def __init__(self):
|
586 |
+
super().__init__()
|
587 |
+
self.recording = 0
|
588 |
+
self.data = ''
|
589 |
+
|
590 |
+
def handle_starttag(self, tag, attrs):
|
591 |
+
if tag == 'a':
|
592 |
+
for name, value in attrs:
|
593 |
+
if name == 'href' and '/versions/' in value:
|
594 |
+
self.recording = 1
|
595 |
+
|
596 |
+
def handle_endtag(self, tag):
|
597 |
+
if tag == 'a' and self.recording:
|
598 |
+
self.recording -= 1
|
599 |
+
|
600 |
+
def handle_data(self, data):
|
601 |
+
if self.recording:
|
602 |
+
self.data = data
|
603 |
+
|
604 |
+
parser = Version()
|
605 |
+
parser.feed(response.text)
|
606 |
+
return parser.data.strip()
|
607 |
+
|
608 |
+
|
609 |
+
def replicate_upscale(url: str, image_url: str, upscale: int = 2) -> str:
|
610 |
+
version = get_version(url)
|
611 |
+
headers = get_headers(url)
|
612 |
+
session = requests.Session()
|
613 |
+
anon_auth = session.get(url, headers=headers)
|
614 |
+
data = {
|
615 |
+
"version": version,
|
616 |
+
"input": {
|
617 |
+
"img": image_url,
|
618 |
+
"image": image_url,
|
619 |
+
"upscale": upscale,
|
620 |
+
"scale": upscale,
|
621 |
+
"version": "General - RealESRGANplus",
|
622 |
+
},
|
623 |
+
"face_enhance": False,
|
624 |
+
"is_training": False,
|
625 |
+
"stream": False
|
626 |
+
}
|
627 |
+
response = session.post('https://replicate.com/api/predictions', headers=headers, data=json.dumps(data))
|
628 |
+
prediction_id = response.json()['id']
|
629 |
+
while True:
|
630 |
+
response = session.get(f'https://replicate.com/api/predictions/{prediction_id}', headers=headers)
|
631 |
+
if 'status' in response.json():
|
632 |
+
status = response.json()['status']
|
633 |
+
else:
|
634 |
+
status = 'processing'
|
635 |
+
if status == 'succeeded':
|
636 |
+
break
|
637 |
+
time.sleep(1)
|
638 |
+
session.close()
|
639 |
+
return response.json()['output']
|
640 |
+
|
641 |
+
|
642 |
+
def upscaler(img_url: str) -> list[str] | None:
|
643 |
+
def run(url):
|
644 |
+
try:
|
645 |
+
return replicate_upscale(url, img_url)
|
646 |
+
except Exception as e:
|
647 |
+
print(e)
|
648 |
+
return None
|
649 |
+
|
650 |
+
urls = [
|
651 |
+
'https://replicate.com/cjwbw/real-esrgan',
|
652 |
+
'https://replicate.com/daanelson/real-esrgan-a100',
|
653 |
+
'https://replicate.com/xinntao/realesrgan',
|
654 |
+
]
|
655 |
+
with ThreadPoolExecutor() as executor:
|
656 |
+
futures = {executor.submit(run, url) for url in urls}
|
657 |
+
for future in as_completed(futures):
|
658 |
+
result = future.result()
|
659 |
+
if result is not None:
|
660 |
+
break
|
661 |
+
return [result]
|
662 |
+
|
663 |
+
|
664 |
+
def check_upscale_result(image: str) -> list[str]:
|
665 |
+
attempt = 0
|
666 |
+
response = None
|
667 |
+
while attempt < 3:
|
668 |
+
response = upscaler(upload_image(image))
|
669 |
+
if response:
|
670 |
+
return response
|
671 |
+
attempt += 1
|
672 |
+
return ['https://iili.io/JzrxjDP.png']
|
673 |
+
|
674 |
+
|
675 |
+
with gr.Blocks(analytics_enabled=False, css=radio_css, theme='Taithrah/Minimal', title='апскейл') as demo:
|
676 |
+
with gr.Tab(label="апскейл", elem_id="upscale_tab"):
|
677 |
+
file_output = gr.Gallery(label="", container=True, object_fit="cover", columns=4, rows=4, allow_preview=True, preview=True, show_share_button=False, show_download_button=False, elem_id="upscaled_images")
|
678 |
+
upload_button = gr.UploadButton("выбор одного изображения для обработки", file_types=["image"], file_count="single", variant="primary")
|
679 |
+
upload_button.upload(fn=check_upscale_result, inputs=[upload_button], outputs=file_output, api_name="upscale")
|
680 |
with gr.Tab(label="восстановление лиц", id=1, elem_id="restore_tab"):
|
681 |
restore_method = gr.Radio(["codeformer", "gfpgan", "оба"], value="codeformer", label="", interactive=True)
|
682 |
restore_method.change(fn=lambda x: print(f"restore_method value = {x}"), inputs=restore_method, api_name="show_selected_method")
|
683 |
file_output = gr.Gallery(label="", container=True, object_fit="cover", columns=4, rows=4, allow_preview=True, preview=True, show_share_button=False, show_download_button=False, elem_id="restored_images")
|
684 |
+
upload_button = gr.UploadButton("выбор нескольких изображений для обработки", file_types=["image"], file_count="multiple", variant="primary")
|
685 |
upload_button.upload(fn=restore_upscale, inputs=[upload_button, restore_method], outputs=file_output, api_name="face_restore")
|
686 |
with gr.Tab(label="наложение зернистости пленки и шума", id=2, elem_id="textures_tab"):
|
687 |
with gr.Row(variant="compact", elem_id="textures_tab_images"):
|