PhotoEdit / app.py
Rooni's picture
Update app.py
7cc13a5 verified
import os
import random
import gradio as gr
from gradio_client import Client, handle_file
from PIL import Image
from deep_translator import GoogleTranslator
from langdetect import detect
import requests
def get_random_api_key():
keys = os.getenv("KEYS", "").split(",")
if keys and keys[0]: # Check if KEYS is set and not empty
return random.choice(keys).strip()
else:
raise ValueError("API keys not found. Please set the KEYS environment variable.")
# Константа
NSFW_THRESHOLD = 0.85
# Ссылка на файл CSS
css_url = "https://neurixyufi-aihub.static.hf.space/style.css"
# Получение CSS по ссылке
try:
response = requests.get(css_url)
response.raise_for_status() # Поднимаем исключение, если статус ответа не 200
css = response.text + " h1{text-align:center}"
except requests.exceptions.RequestException as e:
print(f"Ошибка при загрузке CSS: {e}")
css = " h1{text-align:center}" # Используем базовый стиль, если загрузка CSS не удалась
def create_demo(args, model_name: str, device: str = "cpu", offload: bool = False):
with gr.Blocks(css=css) as demo:
def generate_image(
prompt,
id_image,
start_step,
guidance,
seed,
true_cfg,
width=896,
height=1152,
num_steps=20,
id_weight=1.0,
neg_prompt="плохое качество, очень плохое качество, текст, подпись, водяной знак, лишние конечности",
timestep_to_start_cfg=1,
max_sequence_length=128,
):
client = Client("yanze/PuLID-FLUX", hf_token=get_random_api_key())
if seed == -1:
seed = None
else:
seed = int(seed)
language = detect(prompt)
if language != 'en':
prompt = GoogleTranslator(source=language, target='en').translate(prompt)
languagen = detect(neg_prompt)
if languagen != 'en':
neg_prompt = GoogleTranslator(source=languagen, target='en').translate(neg_prompt)
try:
if id_image is not None:
# Сохраняем изображение во временный файл
temp_file_path = "/tmp/id_image.png"
Image.fromarray(id_image).save(temp_file_path)
id_image_for_api = handle_file(temp_file_path)
else:
id_image_for_api = None
result = client.predict(
prompt,
id_image_for_api,
start_step,
guidance,
str(seed), # Преобразуем seed в строку
true_cfg,
width,
height,
num_steps,
id_weight,
neg_prompt,
timestep_to_start_cfg,
max_sequence_length,
api_name="/generate_image"
)
generated_image, used_seed, debug_images = result
if generated_image is None:
return None, used_seed, debug_images # Возвращаем сообщение об ошибке из API
else:
pil_image = Image.open(generated_image)
return pil_image, used_seed, debug_images
except Exception as e:
return None, f"Ошибка при генерации: {e}", []
gr.Markdown("# Редактор фото")
with gr.Row():
with gr.Column():
prompt = gr.Textbox(label="Описание", placeholder="портрет, цветное, кинематографическое")
id_image = gr.Image(label="Изображение")
id_weight = gr.Slider(0.0, 3.0, 1, step=0.05, label="Идентичность")
width = gr.Slider(256, 1536, 896, step=16, label="Ширина")
height = gr.Slider(256, 1536, 1152, step=16, label="Высота")
num_steps = gr.Slider(1, 20, 20, step=1, label="Количество шагов обработки")
start_step = gr.Slider(0, 10, 0, step=1, label="Шаг начала внедрения оригинала")
guidance = gr.Slider(1.0, 10.0, 4, step=0.1, label="Совпадение с описанием")
seed = gr.Textbox(-1, label="Сид (-1 для случайного)")
max_sequence_length = gr.Slider(128, 512, 128, step=128, label="Максимальная длина последовательности для описания (T5), меньше будет быстрее")
with gr.Accordion("Дополнительные опции", open=False):
neg_prompt = gr.Textbox(
label="Отрицательное описание",
value="плохое качество, очень плохое качество, текст, подпись, водяной знак, лишние конечности")
true_cfg = gr.Slider(1.0, 10.0, 1, step=0.1, label="Масштаб true CFG")
timestep_to_start_cfg = gr.Slider(0, 20, 1, step=1, label="Шаг начала CFG", visible=args.dev)
generate_btn = gr.Button("Изменить")
with gr.Column():
output_image = gr.Image(label="Сгенерированное изображение", format='png')
seed_output = gr.Textbox(label="Использованный сид")
intermediate_output = gr.Gallery(label='Промежуточные изображения', elem_id="gallery", visible=args.dev)
with gr.Row(), gr.Column():
gr.Markdown("## Примеры")
example_inps = [
[
'женщина с табличкой с зелёным текстом "Im Human"',
'https://huggingface.co/spaces/yanze/PuLID-FLUX/resolve/main/example_inputs/liuyifei.png',
4, 4, 2680261499100305976, 1
],
[
'портрет, боковое видение',
'https://huggingface.co/spaces/yanze/PuLID-FLUX/resolve/main/example_inputs/liuyifei.png',
4, 4, 180825677246321775, 1
],
[
'блондинка с технологией VR, революционный магнум с деталями',
'https://huggingface.co/spaces/yanze/PuLID-FLUX/resolve/main/example_inputs/liuyifei.png',
4, 4, 16942328329935464989, 1
],
[
'малыш ест мороженое',
'https://huggingface.co/spaces/yanze/PuLID-FLUX/resolve/main/example_inputs/liuyifei.png',
4, 4, 4527590969012358757, 1
],
[
'мужчина с табличкой с текстом "Im Human", зима, снегопад, вершина горы',
'https://huggingface.co/spaces/yanze/PuLID-FLUX/resolve/main/example_inputs/pengwei.jpg',
4, 4, 6273700647573240909, 1
],
[
'портрет, свет свечей',
'https://huggingface.co/spaces/yanze/PuLID-FLUX/resolve/main/example_inputs/pengwei.jpg',
4, 4, 17522759474323955700, 1
],
[
'кадр с тёмным фото 25-летнего мужчины с дымом изо рта, снимок в обратном освещении, естественное лицо, естественные брови, естественная текстура кожи, наградное фото, деталированное лицо, атмосферное освещение, зернистость, монохромное',
'https://huggingface.co/spaces/yanze/PuLID-FLUX/resolve/main/example_inputs/pengwei.jpg',
4, 4, 17733156847328193625, 1
],
[
'американская комикса, мальчик',
'https://huggingface.co/spaces/yanze/PuLID-FLUX/resolve/main/example_inputs/pengwei.jpg',
1, 4, 13223174453874179686, 1
],
[
'портрет, стилизация Pixar',
'https://huggingface.co/spaces/yanze/PuLID-FLUX/resolve/main/example_inputs/pengwei.jpg',
1, 4, 9445036702517583939, 1
],
]
gr.Examples(examples=example_inps, inputs=[prompt, id_image, start_step, guidance, seed, true_cfg],
label='Использование fake CFG', cache_examples='lazy', outputs=[output_image, seed_output],
fn=generate_image)
example_inps = [
[
'портрет, сделанный из льда',
'example_inputs/lecun.jpg',
1, 1, 7717391560531186077, 5
],
]
gr.Examples(examples=example_inps, inputs=[prompt, id_image, start_step, guidance, seed, true_cfg],
label='Использование true CFG', cache_examples='lazy', outputs=[output_image, seed_output],
fn=generate_image)
generate_btn.click(
fn=generate_image,
inputs=[prompt, id_image, start_step, guidance, seed, true_cfg, width, height, num_steps, id_weight,
neg_prompt, timestep_to_start_cfg, max_sequence_length],
outputs=[output_image, seed_output, intermediate_output],
)
return demo
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="PuLID для FLUX")
parser.add_argument("--name", type=str, default="flux-dev", choices=["flux-dev"],
help="в настоящее время поддерживается только flux-dev")
parser.add_argument("--device", type=str, default="cpu",
help="Устройство для использования")
parser.add_argument("--offload", action="store_true", help="Выгрузка модели на CPU при неприменении")
parser.add_argument("--port", type=int, default=8080, help="Порт для использования")
parser.add_argument("--dev", action='store_true', help="Режим разработки")
parser.add_argument("--pretrained_model", type=str, help='для разработки')
args = parser.parse_args()
demo = create_demo(args, args.name, args.device, args.offload)
demo.launch(server_port=7860)