Spaces:
Runtime error
Runtime error
| 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) | |