yeq6x commited on
Commit
b983cc6
·
1 Parent(s): a700acb

Refactor app.py to improve regex replacements and UI components

Browse files

Enhance the regex replacement logic in several functions to use lambda functions for better readability and maintainability. Update the UI to include a configuration-only generation button, allowing users to generate metadata without starting the training process. This improves user experience by providing clearer options and streamlining the configuration workflow.

Files changed (1) hide show
  1. app.py +53 -18
app.py CHANGED
@@ -12,7 +12,7 @@ import json
12
 
13
  import gradio as gr
14
  import importlib
15
- import spaces
16
 
17
  # Local modules
18
  from download_qwen_image_models import download_all_models, DEFAULT_MODELS_DIR
@@ -164,12 +164,14 @@ def _sync_dataset_config_jsonl(path: str, output_json: str) -> None:
164
  base = os.path.dirname(path)
165
  cache = os.path.join(base, "cache").replace("\\", "/")
166
 
167
- new = re.sub(r"(?m)^\s*image_jsonl_file\s*=.*$", f'image_jsonl_file = "{output_json}"', txt)
 
168
  if new == txt and "image_jsonl_file" not in txt:
169
  new = txt.rstrip("\n") + f'\nimage_jsonl_file = "{output_json}"\n'
170
 
171
  if re.search(r"(?m)^\s*cache_directory\s*=", new):
172
- new = re.sub(r"(?m)^\s*cache_directory\s*=.*$", f'cache_directory = "{cache}"', new)
 
173
  else:
174
  new = new.rstrip("\n") + f'\ncache_directory = "{cache}"\n'
175
 
@@ -414,7 +416,7 @@ def _prepare_script(
414
  )
415
 
416
  for pat, val in replacements.items():
417
- txt = re.sub(pat, val, txt, flags=re.MULTILINE)
418
 
419
  # Inject CONTROL_FOLDER_i if provided (uncomment/override or append)
420
  for i in range(8):
@@ -442,9 +444,10 @@ def _prepare_script(
442
 
443
  # Point model paths to the selected models_root
444
  def _replace_model_path(txt: str, key: str, rel: str) -> str:
 
445
  return re.sub(
446
  rf"--{key} \"[^\"]+\"",
447
- f"--{key} \"{models_root.rstrip('/')}/{rel}\"",
448
  txt,
449
  )
450
 
@@ -455,9 +458,19 @@ def _prepare_script(
455
  txt = _replace_model_path(txt, "dit", f"dit/{dit_filename}")
456
 
457
  # Replace working dir for metadata generation to runtime /auto
458
- txt = re.sub(r"^cd\s+/workspace/auto\s*$", f"cd {AUTO_DIR_RUNTIME}", txt, flags=re.MULTILINE)
 
 
 
 
 
459
  # Ensure musubi-tuner path matches runtime location
460
- txt = re.sub(r"^cd\s+/musubi-tuner\s*$", f"cd {re.escape(MUSUBI_TUNER_DIR_RUNTIME)}", txt, flags=re.MULTILINE)
 
 
 
 
 
461
 
462
  # ZeroGPU compatibility: avoid spawning via 'accelerate launch'.
463
  # Run the training module directly in-process so GPU stays attached
@@ -477,7 +490,8 @@ def _prepare_script(
477
  txt = re.sub(r"--save_every_n_epochs\s+\d+",
478
  f"--save_every_n_epochs {override_save_every}", txt)
479
  if override_run_name:
480
- txt = re.sub(r"^RUN_NAME=.*$", f"RUN_NAME={_bash_quote(override_run_name)}", txt, flags=re.MULTILINE)
 
481
 
482
  # Inject prefix/suffix flags for metadata creation
483
  extra_lines: List[str] = []
@@ -526,7 +540,7 @@ def _prepare_script(
526
  pattern = rf"(?m)^\s*{name}\s*=.*$"
527
  replacement = f'{name}="{value}"' if not str(value).isdigit() else f'{name}={value}'
528
  if re.search(pattern, txt):
529
- txt = re.sub(pattern, replacement, txt)
530
  else:
531
  txt = f"{replacement}\n" + txt
532
 
@@ -655,7 +669,7 @@ def _startup_install_musubi_deps() -> None:
655
  print("[QIE] WARN: musubi-tuner installation failed. Continuing.")
656
 
657
 
658
- @spaces.GPU
659
  def run_training(
660
  output_name: str,
661
  caption: str,
@@ -723,8 +737,8 @@ def run_training(
723
  # Auto-generate dataset directory name
724
  import time
725
  ds_name = f"dataset_{int(time.time())}"
726
- ds_dir = os.path.join(DATA_ROOT_RUNTIME, ds_name)
727
- run_out_dir = os.path.join(ds_dir, output_name.strip())
728
  img_folder_name = DEFAULT_IMAGE_FOLDER
729
  img_dir = os.path.join(ds_dir, img_folder_name)
730
  os.makedirs(img_dir, exist_ok=True)
@@ -1013,8 +1027,6 @@ def build_ui() -> gr.Blocks:
1013
  cr_w = gr.Number(label="Control resolution W", value=1024, precision=0)
1014
  cr_h = gr.Number(label="Control resolution H", value=1024, precision=0)
1015
  te_bs = gr.Number(label="TE cache batch size", value=16, precision=0)
1016
- with gr.Row():
1017
- config_only = gr.Checkbox(label="設定のみ生成 (学習しない)", value=False)
1018
 
1019
  with gr.Accordion("Target Image", elem_classes=["pad-section_0"]):
1020
  with gr.Group():
@@ -1112,11 +1124,13 @@ def build_ui() -> gr.Blocks:
1112
 
1113
  # Models root / OUTPUT_DIR_BASE / DATASET_CONFIG are auto-resolved at runtime; no user input needed.
1114
 
1115
- run_btn = gr.Button("Start Training", variant="primary")
1116
- run_out_dir_box = gr.Textbox(label="今回の出力フォルダ", lines=1, interactive=False)
 
 
1117
  scripts_files = gr.Files(label="Scripts & Config (live)", interactive=False)
1118
- logs = gr.Textbox(label="Logs", lines=20)
1119
  ckpt_files = gr.Files(label="Checkpoints (live)", interactive=False)
 
1120
  with gr.Row():
1121
  refresh_scripts_btn = gr.Button("ファイルを再取得", variant="secondary")
1122
 
@@ -1133,6 +1147,9 @@ def build_ui() -> gr.Blocks:
1133
  ctrl6_files.change(fn=_files_to_gallery, inputs=ctrl6_files, outputs=ctrl6_gallery)
1134
  ctrl7_files.change(fn=_files_to_gallery, inputs=ctrl7_files, outputs=ctrl7_gallery)
1135
 
 
 
 
1136
  run_btn.click(
1137
  fn=run_training,
1138
  inputs=[
@@ -1147,7 +1164,25 @@ def build_ui() -> gr.Blocks:
1147
  ctrl7_files, ctrl7_prefix, ctrl7_suffix,
1148
  lr_input, dim_input,
1149
  tr_w, tr_h, train_bs, cr_w, cr_h, te_bs,
1150
- seed_input, max_epochs, save_every, config_only,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1151
  ],
1152
  outputs=[logs, ckpt_files, scripts_files, run_out_dir_box],
1153
  )
 
12
 
13
  import gradio as gr
14
  import importlib
15
+ # import spaces
16
 
17
  # Local modules
18
  from download_qwen_image_models import download_all_models, DEFAULT_MODELS_DIR
 
164
  base = os.path.dirname(path)
165
  cache = os.path.join(base, "cache").replace("\\", "/")
166
 
167
+ image_line = f'image_jsonl_file = "{output_json}"'
168
+ new = re.sub(r"(?m)^\s*image_jsonl_file\s*=.*$", lambda _m, r=image_line: r, txt)
169
  if new == txt and "image_jsonl_file" not in txt:
170
  new = txt.rstrip("\n") + f'\nimage_jsonl_file = "{output_json}"\n'
171
 
172
  if re.search(r"(?m)^\s*cache_directory\s*=", new):
173
+ cache_line = f'cache_directory = "{cache}"'
174
+ new = re.sub(r"(?m)^\s*cache_directory\s*=.*$", lambda _m, r=cache_line: r, new)
175
  else:
176
  new = new.rstrip("\n") + f'\ncache_directory = "{cache}"\n'
177
 
 
416
  )
417
 
418
  for pat, val in replacements.items():
419
+ txt = re.sub(pat, lambda _m, v=val: v, txt, flags=re.MULTILINE)
420
 
421
  # Inject CONTROL_FOLDER_i if provided (uncomment/override or append)
422
  for i in range(8):
 
444
 
445
  # Point model paths to the selected models_root
446
  def _replace_model_path(txt: str, key: str, rel: str) -> str:
447
+ repl = f"--{key} \"{models_root.rstrip('/')}/{rel}\""
448
  return re.sub(
449
  rf"--{key} \"[^\"]+\"",
450
+ lambda _m, r=repl: r,
451
  txt,
452
  )
453
 
 
458
  txt = _replace_model_path(txt, "dit", f"dit/{dit_filename}")
459
 
460
  # Replace working dir for metadata generation to runtime /auto
461
+ txt = re.sub(
462
+ r"^cd\s+/workspace/auto\s*$",
463
+ lambda _m: f"cd {AUTO_DIR_RUNTIME}",
464
+ txt,
465
+ flags=re.MULTILINE,
466
+ )
467
  # Ensure musubi-tuner path matches runtime location
468
+ txt = re.sub(
469
+ r"^cd\s+/musubi-tuner\s*$",
470
+ lambda _m: f"cd {MUSUBI_TUNER_DIR_RUNTIME}",
471
+ txt,
472
+ flags=re.MULTILINE,
473
+ )
474
 
475
  # ZeroGPU compatibility: avoid spawning via 'accelerate launch'.
476
  # Run the training module directly in-process so GPU stays attached
 
490
  txt = re.sub(r"--save_every_n_epochs\s+\d+",
491
  f"--save_every_n_epochs {override_save_every}", txt)
492
  if override_run_name:
493
+ repl = f"RUN_NAME={_bash_quote(override_run_name)}"
494
+ txt = re.sub(r"^RUN_NAME=.*$", lambda _m, r=repl: r, txt, flags=re.MULTILINE)
495
 
496
  # Inject prefix/suffix flags for metadata creation
497
  extra_lines: List[str] = []
 
540
  pattern = rf"(?m)^\s*{name}\s*=.*$"
541
  replacement = f'{name}="{value}"' if not str(value).isdigit() else f'{name}={value}'
542
  if re.search(pattern, txt):
543
+ txt = re.sub(pattern, lambda _m, r=replacement: r, txt)
544
  else:
545
  txt = f"{replacement}\n" + txt
546
 
 
669
  print("[QIE] WARN: musubi-tuner installation failed. Continuing.")
670
 
671
 
672
+ # @spaces.GPU
673
  def run_training(
674
  output_name: str,
675
  caption: str,
 
737
  # Auto-generate dataset directory name
738
  import time
739
  ds_name = f"dataset_{int(time.time())}"
740
+ ds_dir = os.path.abspath(os.path.join(DATA_ROOT_RUNTIME, ds_name))
741
+ run_out_dir = os.path.abspath(os.path.join(ds_dir, output_name.strip()))
742
  img_folder_name = DEFAULT_IMAGE_FOLDER
743
  img_dir = os.path.join(ds_dir, img_folder_name)
744
  os.makedirs(img_dir, exist_ok=True)
 
1027
  cr_w = gr.Number(label="Control resolution W", value=1024, precision=0)
1028
  cr_h = gr.Number(label="Control resolution H", value=1024, precision=0)
1029
  te_bs = gr.Number(label="TE cache batch size", value=16, precision=0)
 
 
1030
 
1031
  with gr.Accordion("Target Image", elem_classes=["pad-section_0"]):
1032
  with gr.Group():
 
1124
 
1125
  # Models root / OUTPUT_DIR_BASE / DATASET_CONFIG are auto-resolved at runtime; no user input needed.
1126
 
1127
+ with gr.Row():
1128
+ run_btn = gr.Button("Start Training", variant="primary")
1129
+ config_btn = gr.Button("設定のみ生成", variant="secondary")
1130
+ run_out_dir_box = gr.Textbox(label="出力フォルダ", lines=1, interactive=False)
1131
  scripts_files = gr.Files(label="Scripts & Config (live)", interactive=False)
 
1132
  ckpt_files = gr.Files(label="Checkpoints (live)", interactive=False)
1133
+ logs = gr.Textbox(label="Logs", lines=20)
1134
  with gr.Row():
1135
  refresh_scripts_btn = gr.Button("ファイルを再取得", variant="secondary")
1136
 
 
1147
  ctrl6_files.change(fn=_files_to_gallery, inputs=ctrl6_files, outputs=ctrl6_gallery)
1148
  ctrl7_files.change(fn=_files_to_gallery, inputs=ctrl7_files, outputs=ctrl7_gallery)
1149
 
1150
+ config_only_off = gr.State(False)
1151
+ config_only_on = gr.State(True)
1152
+
1153
  run_btn.click(
1154
  fn=run_training,
1155
  inputs=[
 
1164
  ctrl7_files, ctrl7_prefix, ctrl7_suffix,
1165
  lr_input, dim_input,
1166
  tr_w, tr_h, train_bs, cr_w, cr_h, te_bs,
1167
+ seed_input, max_epochs, save_every, config_only_off,
1168
+ ],
1169
+ outputs=[logs, ckpt_files, scripts_files, run_out_dir_box],
1170
+ )
1171
+ config_btn.click(
1172
+ fn=run_training,
1173
+ inputs=[
1174
+ output_name, caption, images_input, main_prefix, main_suffix,
1175
+ ctrl0_files, ctrl0_prefix, ctrl0_suffix,
1176
+ ctrl1_files, ctrl1_prefix, ctrl1_suffix,
1177
+ ctrl2_files, ctrl2_prefix, ctrl2_suffix,
1178
+ ctrl3_files, ctrl3_prefix, ctrl3_suffix,
1179
+ ctrl4_files, ctrl4_prefix, ctrl4_suffix,
1180
+ ctrl5_files, ctrl5_prefix, ctrl5_suffix,
1181
+ ctrl6_files, ctrl6_prefix, ctrl6_suffix,
1182
+ ctrl7_files, ctrl7_prefix, ctrl7_suffix,
1183
+ lr_input, dim_input,
1184
+ tr_w, tr_h, train_bs, cr_w, cr_h, te_bs,
1185
+ seed_input, max_epochs, save_every, config_only_on,
1186
  ],
1187
  outputs=[logs, ckpt_files, scripts_files, run_out_dir_box],
1188
  )