GarmentCode / app.py
qbhf2's picture
modified: app.py
e8212a9
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)