Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import asyncio | |
| import os | |
| import subprocess | |
| import shutil | |
| import logging | |
| import json | |
| from pathlib import Path | |
| import yaml | |
| import coloredlogs | |
| import re | |
| from custom_utils.setup_env import run_setup_script | |
| logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") | |
| coloredlogs.install(level='INFO', fmt='%(levelname)s: %(message)s', | |
| level_styles={'info': {'color': 'green'}, | |
| 'error':{'color':'red'} | |
| } | |
| ) | |
| # === Загрузка конфига === | |
| with open("GarmentCode/gradio_config.yml", "r") as f: | |
| config = yaml.safe_load(f) | |
| # === Вспомогательные функции === | |
| def organize_images_into_structure(source_folder, new_folder): | |
| os.makedirs(new_folder, exist_ok=True) | |
| for file_name in os.listdir(source_folder): | |
| source_file = os.path.join(source_folder, file_name) | |
| if os.path.isfile(source_file) and file_name.lower().endswith(('.png', '.jpg', '.jpeg')): | |
| folder_name = os.path.splitext(file_name)[0] | |
| subfolder_path = os.path.join(new_folder, folder_name, "outputs") | |
| os.makedirs(subfolder_path, exist_ok=True) | |
| destination_file = os.path.join(subfolder_path, file_name) | |
| shutil.copy(source_file, destination_file) | |
| def update_body_model(selected_key): | |
| return config['body_model_files'].get(selected_key, config['defaults']['body_config']) | |
| def get_design_choices(): | |
| design_dir = config['assets_paths']['design_params'] # "assets/design_params/" | |
| design_choices = [] | |
| for fname in os.listdir(design_dir): | |
| if fname.endswith(".yaml"): | |
| design_choices.append(os.path.splitext(fname)[0]) | |
| return design_choices | |
| def get_sim_props_choices(): | |
| sim_props_dir=config['assets_paths']['sim_props'] | |
| sim_props_choices_yaml, sim_props_choices_json=[],[] | |
| for fname in os.listdir(sim_props_dir): | |
| if fname.endswith(".yaml"): | |
| sim_props_choices_yaml.append(os.path.splitext(fname)[0]) | |
| elif fname.endswith(".json"): | |
| sim_props_choices_json.append(os.path.splitext(fname)[0]) | |
| return sim_props_choices_yaml, sim_props_choices_json | |
| def extract_dataset_path(stdout: str) -> str: | |
| # Ищем строку с "Result saved to:" | |
| match = re.search(r"Result saved to: (.+)", stdout) | |
| if match: | |
| path = match.group(1).strip() | |
| # Убираем подкаталог default_body, если он есть в конце пути | |
| if path.endswith('/default_body') or path.endswith('\\default_body'): | |
| path = os.path.dirname(path) | |
| return path | |
| return None | |
| def get_png_path(folder: str): | |
| basename = os.path.basename(folder) | |
| png_path = os.path.join(folder, f"{basename}_pattern.png") | |
| if os.path.isfile(png_path): | |
| logging.info(f"PNG FILE LOCATED AT {png_path}") | |
| return png_path | |
| return None | |
| def zip_folder(folder_path: str) -> str: | |
| folder_path_obj = Path(folder_path) | |
| zip_path = str(folder_path_obj) + '.zip' | |
| shutil.make_archive(str(folder_path_obj), 'zip', folder_path) | |
| return zip_path | |
| def show_button_if_both_uploaded(front_img, back_img): | |
| return gr.update(visible=front_img is not None and back_img is not None) | |
| def update_submenu(clothing_type): | |
| if clothing_type == "Top": | |
| return ( | |
| gr.Dropdown(visible=True, label="Front Collar", | |
| choices=["CircleNeckHalf", "CurvyNeckHalf", "VNeckHalf", "SquareNeckHalf", | |
| "TrapezoidNeckHalf", "CircleArcNeckHalf", "Bezier2NeckHalf"], | |
| interactive=True), | |
| gr.Dropdown(visible=True, label="Back Collar", | |
| choices=["CircleNeckHalf", "CurvyNeckHalf", "VNeckHalf", "SquareNeckHalf", | |
| "TrapezoidNeckHalf", "CircleArcNeckHalf", "Bezier2NeckHalf"], | |
| interactive=True) | |
| ) | |
| elif clothing_type == "Down": | |
| return ( | |
| gr.Dropdown(visible=True, label="Waist Style", | |
| choices=["High Waist", "Low Waist", "Medium Waist"], | |
| interactive=True), | |
| gr.Dropdown(visible=False, interactive=True) | |
| ) | |
| elif clothing_type == "Full body": | |
| return ( | |
| gr.Dropdown(visible=True, label="Overall Style", | |
| choices=["Slim Fit", "Loose Fit", "Regular Fit"], | |
| interactive=True), | |
| gr.Dropdown(visible=False, interactive=True) | |
| ) | |
| else: | |
| return ( | |
| gr.Dropdown(visible=False, interactive=True), | |
| gr.Dropdown(visible=False, interactive=True) | |
| ) | |
| # === Симуляция/сэмплирование === | |
| # TODO: recreate fitting. Is it strictly necessary? | |
| async def run_dataset_fitting(design_file: str, size: int, name: str, replicate: bool) -> str: | |
| return | |
| async def run_pattern_sampler(size: int, dataset_name: str, replicate: bool, pattern_config_name: str, body_file:str): | |
| pattern_config_path = f"assets/design_params/{pattern_config_name}.yaml" | |
| body_path = getattr(body_file, 'name', body_file) if body_file else "mean_female" | |
| cmd = [ | |
| "python3", "GarmentCode/pattern_sampler.py", | |
| "-s", str(size), | |
| "--name", dataset_name, | |
| "--pattern-config", pattern_config_path, | |
| "--body", body_path | |
| ] | |
| if replicate: | |
| cmd.append("--replicate") | |
| proc = await asyncio.create_subprocess_exec( | |
| *cmd, | |
| stdout=asyncio.subprocess.PIPE, | |
| stderr=asyncio.subprocess.PIPE | |
| ) | |
| stdout, stderr = await proc.communicate() | |
| logging.info(stdout.decode()) | |
| log = stdout.decode() | |
| if proc.returncode != 0: | |
| logging.error(f"Ошибка при генерации датасета:{stderr.decode()}") | |
| return f"Ошибка при генерации датасета:\n{stderr.decode()}", gr.update(visible=False), None | |
| dataset_path = (extract_dataset_path(log)) | |
| zip_folder_path = f"{zip_folder(dataset_path)}" | |
| return stdout.decode(), gr.update(visible=True), dataset_path, zip_folder_path | |
| async def run_pattern_data_sim(dataset_path: str, clothing_spec: str, default_body: bool = False): | |
| dataset_path = dataset_path.replace("datasets/", "", 1) | |
| clothing_spec=clothing_spec+".yaml" | |
| cmd = [ | |
| "python3", "GarmentCode/pattern_data_sim.py", | |
| "--data", dataset_path, | |
| "-c", clothing_spec | |
| ] | |
| # Добавляем флаг только если default_body=True | |
| if default_body: | |
| cmd.append("--default_body") | |
| proc = await asyncio.create_subprocess_exec( | |
| *cmd, | |
| stdout=asyncio.subprocess.PIPE, | |
| stderr=asyncio.subprocess.PIPE | |
| ) | |
| stdout, stderr = await proc.communicate() | |
| if proc.returncode != 0: | |
| logging.error(f"Ошибка при симуляции: {stderr.decode()}") | |
| return f"Ошибка при симуляции:\n{stderr.decode()}" | |
| dataset_sim_path = "datasets_sim/" + dataset_path | |
| zip_file_path = f"{zip_folder(dataset_sim_path)}" | |
| return zip_file_path | |
| async def simulation(pattern_spec_path:str, sim_props_path:str): | |
| cmd = [ | |
| "python3", "GarmentCode/test_garment_sim.py", | |
| "-p", pattern_spec_path, | |
| "-s", sim_props_path, | |
| ] | |
| async def create_pattern( | |
| body_config_file, # gr.File или None | |
| design_config_file, # gr.File или None | |
| body_to_use=None, # str или None | |
| design_to_use=None # str или None | |
| ): | |
| # Если файл не выбран - используем дефолт из конфига | |
| body_config_path = getattr(body_config_file, 'name', body_config_file) if body_config_file else config['defaults'][ | |
| 'body_config'] | |
| design_config_path = getattr(design_config_file, 'name', design_config_file) if design_config_file else \ | |
| config['defaults']['design_config'] | |
| logging.info("CREATION OF PATTERN FILES...") | |
| cmd = [ | |
| "python3", "test_garmentcode.py", | |
| "--body-config", body_config_path, | |
| "--design-config", design_config_path, | |
| ] | |
| if body_to_use: | |
| cmd += ["--body-to-use", body_to_use] | |
| if design_to_use: | |
| cmd += ["--design-to-use", design_to_use] | |
| proc = await asyncio.create_subprocess_exec( | |
| *cmd, | |
| stdout=asyncio.subprocess.PIPE, | |
| stderr=asyncio.subprocess.PIPE | |
| ) | |
| stdout, stderr = await proc.communicate() | |
| if proc.returncode != 0: | |
| logging.error(f"Pattern creation failed:\n{stderr.decode()}") | |
| return f"Pattern creation failed:\n{stderr.decode()}" | |
| result_str = stdout.decode() | |
| folder = None | |
| for line in result_str.splitlines(): | |
| if "saved to" in line: | |
| folder = line.split("saved to")[-1].strip() | |
| break | |
| if not folder or not os.path.isdir(folder): | |
| logging.error("Ошибка: не удалось найти папку с результатом.") | |
| return "Ошибка: не удалось найти папку с результатом.", None, None | |
| png_file = get_png_path(folder) | |
| if not png_file: | |
| logging.error("Ошибка: PNG-файл не найден.") | |
| return "Ошибка: PNG-файл не найден.", None, None | |
| zip_path = zip_folder(folder) | |
| logging.info("PATTERN CREATION ENDED SUCCESSFULLY") | |
| return result_str, zip_path, png_file | |
| with gr.Blocks(title="3D Garment Generator", theme=gr.themes.Default(text_size="sm")) as demo: | |
| with gr.Tabs(): | |
| with gr.Tab("Генератор одежды"): | |
| front_collar = gr.State() | |
| back_collar = gr.State() | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| with gr.Accordion("Инференс",open=False): | |
| front_img = gr.Image(label="Добавьте фотографию впереди") | |
| back_img = gr.Image(label="Добавьте фотографию сзади") | |
| create_pattern_btn = gr.Button("Создать паттерн", visible=False) | |
| with gr.Accordion("1. Пресеты", open=False): | |
| gr.Markdown("### Параметры генерации") | |
| with gr.Accordion("Загрузить файлы", open=False): | |
| body_config_file = gr.File(label="Body config (YAML)") | |
| design_config_file = gr.File(label="Design config (YAML)") | |
| system_config_file = gr.File(label="System config (JSON)") | |
| body_to_use_dropdown = gr.Dropdown( | |
| choices=list(config['body_model_files'].keys()), | |
| label="Body key", value="mean_female") | |
| design_to_use_dropdown = gr.Dropdown( | |
| choices=["t-shirt"], label="Design key", value="t-shirt") | |
| create_pattern_btn = gr.Button("Создать паттерн") | |
| result_box = gr.Textbox(label="Результат") | |
| image_result = gr.Image(label="Результат PNG") | |
| with gr.Accordion("2. Параметры генерации", open=True): | |
| clothing_type_dropdown = gr.Dropdown( | |
| label="Тип одежды", | |
| choices=["Top", "Down", "Full body"], | |
| value="Top", | |
| interactive=True | |
| ) | |
| front_dropdown = gr.Dropdown( | |
| visible=False, | |
| label="Front Collar", | |
| choices=[], | |
| interactive=True | |
| ) | |
| back_dropdown = gr.Dropdown( | |
| visible=False, | |
| label="Back Collar", | |
| choices=[], | |
| interactive=True | |
| ) | |
| overall_length = gr.Slider( | |
| 1, 50, value=25, label="Длина одежды", | |
| info="Выберите значение от 1 до 50", | |
| interactive=True | |
| ) | |
| clothing_type_dropdown.change( | |
| fn=update_submenu, | |
| inputs=clothing_type_dropdown, | |
| outputs=[front_dropdown, back_dropdown] | |
| ) | |
| with gr.Accordion("3. Дополнительные инструменты", open=False): | |
| with gr.Accordion("Генерация датасета", open=False): | |
| dataset_size = gr.Slider(1, 5000, value=1, label="Размер датасета", | |
| info="Выберите значение от 1 до 5000", interactive=True) | |
| replicate_checkbox = gr.Checkbox(label="Репликация", value=False) | |
| dataset_name_box = gr.Textbox(label="Название датасета", max_lines=1) | |
| pattern_config_choices = get_design_choices() | |
| pattern_config_file = gr.Radio( | |
| label="Config", | |
| choices=pattern_config_choices, | |
| value=pattern_config_choices[0] if pattern_config_choices else None | |
| ) | |
| body_file = gr.File(label="Body config (YAML)") | |
| pattern_sampler_run_button = gr.Button("Сгенерировать паттерны", size="sm") | |
| pattern_result_box = gr.Textbox(label="Лог генерации") | |
| # sim_props_gen_choices_yaml = gr.Radio(label="Properties config", | |
| # choices=get_sim_props_choices()[0], | |
| # interactive=True, | |
| # value=pattern_config_choices[ | |
| # 0] if pattern_config_choices else None | |
| # | |
| # ) | |
| sim_props_gen_choices_json = gr.Radio(label="Clothing config", | |
| choices=get_sim_props_choices()[0], | |
| interactive=True, | |
| value=pattern_config_choices[ | |
| 0] if pattern_config_choices else None | |
| ) | |
| dataset_path_box = gr.Textbox(visible=False) | |
| default_body_checkbox = gr.Checkbox(label="default body",value=False) | |
| dataset_gen_button = gr.Button("Генерация датасета", | |
| variant="primary", visible=False) | |
| ## Button callbacks ## | |
| with gr.Column(scale=3): | |
| viewer = gr.Model3D( | |
| config['body_model_files']['custom_female'], | |
| display_mode="solid", label="3D Рендер", | |
| height=500, container=True, camera_position=(90, None, None), | |
| interactive=False, clear_color=(0.85, 0.85, 0.85, 1) | |
| ) | |
| fit_button = gr.Button("Запустить симуляцию", variant="primary", size="sm") | |
| with gr.Row(): | |
| save_render_btn = gr.Button("Сохранить рендер") | |
| save_obj_btn = gr.Button("Сохранить OBJ") | |
| clear_button = gr.Button("Очистить") | |
| zip_file = gr.File(label="Download Zip File", file_count="multiple", | |
| file_types=[".zip"], height=50, interactive=False) | |
| create_pattern_btn.click( | |
| fn=create_pattern, | |
| inputs=[body_config_file, design_config_file, body_to_use_dropdown, design_to_use_dropdown], | |
| outputs=[result_box, zip_file, image_result] | |
| ) | |
| body_to_use_dropdown.change( | |
| fn=update_body_model, | |
| inputs=body_to_use_dropdown, | |
| outputs=viewer | |
| ) | |
| pattern_sampler_run_button.click( | |
| fn=run_pattern_sampler, | |
| inputs=[dataset_size, dataset_name_box, replicate_checkbox, pattern_config_file, | |
| body_file], | |
| outputs=[pattern_result_box, dataset_gen_button, dataset_path_box, zip_file] | |
| ) | |
| dataset_gen_button.click( | |
| fn=run_pattern_data_sim, | |
| inputs=[dataset_path_box, sim_props_gen_choices_json, default_body_checkbox], | |
| outputs=[zip_file], | |
| ) | |
| front_img.change( | |
| fn=show_button_if_both_uploaded, | |
| inputs=[front_img, back_img], | |
| outputs=create_pattern_btn | |
| ) | |
| back_img.change( | |
| fn=show_button_if_both_uploaded, | |
| inputs=[front_img, back_img], | |
| outputs=create_pattern_btn | |
| ) | |
| with gr.Tab("SewFormer"): | |
| gr.Markdown("Photo to pattern") | |
| with gr.Tab("Image to Pattern"): | |
| gr.Markdown("JPG to PBR") | |
| if __name__ == "__main__": | |
| run_setup_script() | |
| demo.launch(server_port=7860) | |