HOPStudio commited on
Commit
5373ae2
·
verified ·
1 Parent(s): 790cdd9

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +407 -42
main.py CHANGED
@@ -6,6 +6,7 @@ import json
6
  import sys
7
  import time
8
  import zipfile
 
9
  import requests
10
  import gradio as gr
11
 
@@ -17,13 +18,17 @@ FRP_VERSION = "0.69.0"
17
  CURRENT_DIR = REPO_PATH
18
  LAST_OUTPUT = ""
19
 
20
- # ===== 新增:ModelScope 下载并启动 ComfyUI 的配置 =====
21
  MODELSCOPE_MODEL_ID = "HOPStudio/forgeui"
22
- MODELSCOPE_DOWNLOAD_DIR = os.path.join(REPO_PATH, "modelscope_download")
 
 
 
23
  OFFLINE_BUILD_DIR = os.path.join(REPO_PATH, "offline_build")
24
  COMFYUI_PORT = 8188
25
  COMFYUI_LOG_PATH = os.path.join(REPO_PATH, "comfyui.log")
26
  PROXY_URL = "http://103.71.69.203:17890"
 
27
 
28
  # 兼容可能的文件名拼写:用户当前指定 offlinbuild.zip,
29
  # 同时兼容 offlinebuild.zip / offline_build.zip,避免文件名略有差异时直接失败。
@@ -387,7 +392,7 @@ def start_jupyterlab_process():
387
 
388
 
389
 
390
- # ===== 新增:ModelScope 下载 offline_build 并启动 ComfyUI =====
391
  def get_proxy_env():
392
  env = os.environ.copy()
393
 
@@ -402,6 +407,43 @@ def get_proxy_env():
402
  return env
403
 
404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
405
  def configure_git_proxy():
406
  try:
407
  subprocess.run(
@@ -439,7 +481,7 @@ def is_valid_zip(path):
439
 
440
 
441
  def find_existing_offline_zip():
442
- search_dirs = [MODELSCOPE_DOWNLOAD_DIR, REPO_PATH]
443
 
444
  for directory in search_dirs:
445
  if not os.path.isdir(directory):
@@ -518,75 +560,398 @@ def install_modelscope_cli():
518
  return False
519
 
520
 
521
- def download_offline_build_from_modelscope():
522
- os.makedirs(MODELSCOPE_DOWNLOAD_DIR, exist_ok=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
523
 
524
  existing_zip = find_existing_offline_zip()
525
  if existing_zip:
526
  print(f"检测到已有 offline_build 压缩包: {existing_zip}")
527
  return existing_zip
528
 
529
- if not install_modelscope_cli():
 
530
  return None
531
 
532
- print(f"开始从 ModelScope 下载 {MODELSCOPE_MODEL_ID} 的 offline_build 压缩包。")
 
 
 
 
 
533
 
534
- env = get_proxy_env()
535
- download_commands = []
 
 
 
 
 
 
 
 
 
 
 
536
 
537
- # 优先按指定文件下载,避免把整个仓库全部拉下来。
538
- for zip_name in OFFLINE_BUILD_ZIP_CANDIDATES:
539
- download_commands.append([
540
- "modelscope",
541
- "download",
542
- "--model",
543
- MODELSCOPE_MODEL_ID,
544
- zip_name,
545
- "--local_dir",
546
- MODELSCOPE_DOWNLOAD_DIR
547
- ])
548
-
549
- # 如果指定文件名不匹配���则退回下载整个模型仓库。
550
- download_commands.append([
551
- "modelscope",
552
- "download",
553
- "--model",
554
- MODELSCOPE_MODEL_ID,
555
- "--local_dir",
556
- MODELSCOPE_DOWNLOAD_DIR
557
- ])
558
-
559
- for command in download_commands:
560
  try:
561
- print("执行下载命令: " + " ".join(command))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
562
 
563
  result = subprocess.run(
564
  command,
565
- env=env,
566
  stdout=subprocess.PIPE,
567
  stderr=subprocess.PIPE,
568
  text=True,
569
- timeout=3600
570
  )
571
 
 
572
  if result.stdout.strip():
 
573
  print(result.stdout[-2000:])
574
  if result.stderr.strip():
575
- print(result.stderr[-2000:])
 
576
 
577
  zip_path = find_existing_offline_zip()
578
  if result.returncode == 0 and zip_path:
579
- print(f"offline_build 压缩包下载成功: {zip_path}")
580
  return zip_path
581
 
582
- print("本次下载未找到有效 offline_build 压缩包继续尝试下一个命令")
 
 
 
 
 
 
583
 
584
  except subprocess.TimeoutExpired:
585
- print("ModelScope 下载超时,继续尝试下一个命令。")
586
  except Exception as e:
587
- print(f"ModelScope 下载异常: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
588
 
589
- print("ModelScope 下载失败,未找到有效 offline_build 压缩包。")
590
  return None
591
 
592
 
 
6
  import sys
7
  import time
8
  import zipfile
9
+ import re
10
  import requests
11
  import gradio as gr
12
 
 
18
  CURRENT_DIR = REPO_PATH
19
  LAST_OUTPUT = ""
20
 
21
+ # ===== 新增:ModelScope 整库克隆/下载并启动 ComfyUI 的配置 =====
22
  MODELSCOPE_MODEL_ID = "HOPStudio/forgeui"
23
+ # forgeui 整库和 offline_build 下载包都很大,不放在 REPO_PATH 里,避免 clone_repository() 删除 /root/modelscope 时把断点文件删掉。
24
+ OFFLINE_BUILD_CACHE_DIR = "/root/offline_build_cache"
25
+ MODELSCOPE_DOWNLOAD_DIR = os.path.join(OFFLINE_BUILD_CACHE_DIR, "modelscope_download")
26
+ MODELSCOPE_CACHE_DIR = os.path.join(OFFLINE_BUILD_CACHE_DIR, "modelscope_cache")
27
  OFFLINE_BUILD_DIR = os.path.join(REPO_PATH, "offline_build")
28
  COMFYUI_PORT = 8188
29
  COMFYUI_LOG_PATH = os.path.join(REPO_PATH, "comfyui.log")
30
  PROXY_URL = "http://103.71.69.203:17890"
31
+ MODELSCOPE_DOWNLOAD_TIMEOUT = 21600
32
 
33
  # 兼容可能的文件名拼写:用户当前指定 offlinbuild.zip,
34
  # 同时兼容 offlinebuild.zip / offline_build.zip,避免文件名略有差异时直接失败。
 
392
 
393
 
394
 
395
+ # ===== 新增:ModelScope 整库克隆/下载 offline_build 并启动 ComfyUI =====
396
  def get_proxy_env():
397
  env = os.environ.copy()
398
 
 
407
  return env
408
 
409
 
410
+ def get_modelscope_download_env(use_proxy=False):
411
+ env = os.environ.copy()
412
+
413
+ # 固定 ModelScope 缓存目录,避免默认缓存散落到 ~/.cache,且方便断点续传。
414
+ os.makedirs(MODELSCOPE_CACHE_DIR, exist_ok=True)
415
+ env["MODELSCOPE_CACHE"] = MODELSCOPE_CACHE_DIR
416
+ env["MODELSCOPE_ENDPOINT"] = "https://www.modelscope.cn"
417
+ env["MODELSCOPE_SDK_ENDPOINT"] = "https://www.modelscope.cn"
418
+
419
+ # ModelScope 下载大文件时会跳到阿里云 OSS。这里默认直连,避免代理把 OSS 内网地址转坏。
420
+ proxy_keys = [
421
+ "http_proxy",
422
+ "https_proxy",
423
+ "HTTP_PROXY",
424
+ "HTTPS_PROXY",
425
+ "ALL_PROXY",
426
+ "all_proxy"
427
+ ]
428
+
429
+ if use_proxy:
430
+ env["http_proxy"] = PROXY_URL
431
+ env["https_proxy"] = PROXY_URL
432
+ env["HTTP_PROXY"] = PROXY_URL
433
+ env["HTTPS_PROXY"] = PROXY_URL
434
+ env["ALL_PROXY"] = PROXY_URL
435
+ env["all_proxy"] = PROXY_URL
436
+ else:
437
+ for key in proxy_keys:
438
+ env.pop(key, None)
439
+
440
+ no_proxy_value = "localhost,127.0.0.1,modelscope.cn,www.modelscope.cn,.modelscope.cn,aliyuncs.com,.aliyuncs.com"
441
+ env["no_proxy"] = no_proxy_value
442
+ env["NO_PROXY"] = no_proxy_value
443
+
444
+ return env
445
+
446
+
447
  def configure_git_proxy():
448
  try:
449
  subprocess.run(
 
481
 
482
 
483
  def find_existing_offline_zip():
484
+ search_dirs = [MODELSCOPE_DOWNLOAD_DIR, OFFLINE_BUILD_CACHE_DIR, REPO_PATH]
485
 
486
  for directory in search_dirs:
487
  if not os.path.isdir(directory):
 
560
  return False
561
 
562
 
563
+ def extract_urls_from_text(text):
564
+ if not text:
565
+ return []
566
+
567
+ urls = re.findall(r"https?://[^\s'\")<>]+", text)
568
+ cleaned_urls = []
569
+
570
+ for url in urls:
571
+ cleaned_urls.append(url.rstrip(".,;"))
572
+
573
+ return cleaned_urls
574
+
575
+
576
+ def convert_internal_oss_url_to_public(url):
577
+ if not url:
578
+ return None
579
+
580
+ public_url = url.replace("-internal.aliyuncs.com", ".aliyuncs.com")
581
+ public_url = public_url.replace("http://", "https://", 1)
582
+
583
+ if public_url == url:
584
+ return None
585
+
586
+ return public_url
587
+
588
+
589
+ def download_url_to_file(url, output_path, use_proxy=False):
590
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
591
+
592
+ env = get_modelscope_download_env(use_proxy=use_proxy)
593
+
594
+ if shutil.which("aria2c"):
595
+ command = [
596
+ "aria2c",
597
+ "--continue=true",
598
+ "--max-connection-per-server=8",
599
+ "--split=8",
600
+ "--min-split-size=16M",
601
+ "--check-certificate=false",
602
+ "--summary-interval=30",
603
+ "--timeout=30",
604
+ "--retry-wait=10",
605
+ "--max-tries=20",
606
+ "--dir",
607
+ os.path.dirname(output_path),
608
+ "--out",
609
+ os.path.basename(output_path),
610
+ url
611
+ ]
612
+ else:
613
+ command = [
614
+ "wget",
615
+ "--continue",
616
+ "--timeout=30",
617
+ "--tries=20",
618
+ "--no-check-certificate",
619
+ "--output-document",
620
+ output_path,
621
+ url
622
+ ]
623
+
624
+ try:
625
+ print("执行直链下载命令: " + " ".join(command[:1]) + " ...")
626
+
627
+ result = subprocess.run(
628
+ command,
629
+ env=env,
630
+ stdout=subprocess.PIPE,
631
+ stderr=subprocess.PIPE,
632
+ text=True,
633
+ timeout=MODELSCOPE_DOWNLOAD_TIMEOUT
634
+ )
635
+
636
+ if result.stdout.strip():
637
+ print(result.stdout[-2000:])
638
+ if result.stderr.strip():
639
+ print(result.stderr[-2000:])
640
+
641
+ if result.returncode == 0 and is_valid_zip(output_path):
642
+ print(f"直链下载成功: {output_path}")
643
+ return True
644
+
645
+ print(f"直链下载失败或压缩包无效: {output_path}")
646
+ return False
647
+
648
+ except subprocess.TimeoutExpired:
649
+ print("直链下载超时。")
650
+ return False
651
+ except Exception as e:
652
+ print(f"直链下载异常: {e}")
653
+ return False
654
+
655
+
656
+ def try_public_oss_fallback(download_output, zip_name):
657
+ urls = extract_urls_from_text(download_output)
658
+
659
+ for url in urls:
660
+ public_url = convert_internal_oss_url_to_public(url)
661
+ if not public_url:
662
+ continue
663
+
664
+ print("检测到 ModelScope 返回 OSS 内网地址,尝试改用公网 OSS 地址继续下载。")
665
+ target_path = os.path.join(MODELSCOPE_DOWNLOAD_DIR, zip_name)
666
+
667
+ # 先直连公网 OSS;失败后才走代理。直连更适合国内服务器访问阿里云 OSS。
668
+ if download_url_to_file(public_url, target_path, use_proxy=False):
669
+ return target_path
670
+
671
+ if download_url_to_file(public_url, target_path, use_proxy=True):
672
+ return target_path
673
+
674
+ return None
675
+
676
+
677
+ def ensure_git_lfs_available():
678
+ try:
679
+ result = subprocess.run(
680
+ ["git", "lfs", "version"],
681
+ stdout=subprocess.PIPE,
682
+ stderr=subprocess.PIPE,
683
+ text=True,
684
+ timeout=20
685
+ )
686
+ if result.returncode == 0:
687
+ print("检测到 git-lfs。")
688
+ return True
689
+ except Exception:
690
+ pass
691
+
692
+ print("未检测到 git-lfs,尝试安装 git-lfs。")
693
+
694
+ install_commands = []
695
+ if shutil.which("apt-get"):
696
+ install_commands.append(["bash", "-lc", "apt-get update && apt-get install -y git-lfs"])
697
+ if shutil.which("yum"):
698
+ install_commands.append(["bash", "-lc", "yum install -y git-lfs"])
699
+
700
+ for command in install_commands:
701
+ try:
702
+ result = subprocess.run(
703
+ command,
704
+ stdout=subprocess.PIPE,
705
+ stderr=subprocess.PIPE,
706
+ text=True,
707
+ timeout=600
708
+ )
709
+ if result.stdout.strip():
710
+ print(result.stdout[-2000:])
711
+ if result.stderr.strip():
712
+ print(result.stderr[-2000:])
713
+
714
+ check = subprocess.run(
715
+ ["git", "lfs", "version"],
716
+ stdout=subprocess.PIPE,
717
+ stderr=subprocess.PIPE,
718
+ text=True,
719
+ timeout=20
720
+ )
721
+ if check.returncode == 0:
722
+ print("git-lfs 安装成功。")
723
+ return True
724
+
725
+ except subprocess.TimeoutExpired:
726
+ print("git-lfs 安装超时。")
727
+ except Exception as e:
728
+ print(f"git-lfs 安装异常: {e}")
729
+
730
+ print("git-lfs 不可用,后续 git clone 可能只能拿到 LFS 指针文件。")
731
+ return False
732
+
733
+
734
+ def clone_whole_forgeui_repo_with_git():
735
+ os.makedirs(OFFLINE_BUILD_CACHE_DIR, exist_ok=True)
736
 
737
  existing_zip = find_existing_offline_zip()
738
  if existing_zip:
739
  print(f"检测到已有 offline_build 压缩包: {existing_zip}")
740
  return existing_zip
741
 
742
+ if not shutil.which("git"):
743
+ print("未检测到 git,跳过 git 整库克隆。")
744
  return None
745
 
746
+ ensure_git_lfs_available()
747
+
748
+ repo_urls = [
749
+ "https://www.modelscope.cn/HOPStudio/forgeui.git",
750
+ "https://modelscope.cn/HOPStudio/forgeui.git"
751
+ ]
752
 
753
+ if os.path.isdir(os.path.join(MODELSCOPE_DOWNLOAD_DIR, ".git")):
754
+ print(f"检测到已存在 ModelScope 整库仓库: {MODELSCOPE_DOWNLOAD_DIR}")
755
+ try:
756
+ subprocess.run(
757
+ ["git", "-C", MODELSCOPE_DOWNLOAD_DIR, "lfs", "pull"],
758
+ env=get_modelscope_download_env(use_proxy=False),
759
+ stdout=subprocess.PIPE,
760
+ stderr=subprocess.PIPE,
761
+ text=True,
762
+ timeout=MODELSCOPE_DOWNLOAD_TIMEOUT
763
+ )
764
+ except Exception as e:
765
+ print(f"git lfs pull 执行异常: {e}")
766
 
767
+ existing_zip = find_existing_offline_zip()
768
+ if existing_zip:
769
+ print(f"在已克隆仓库中找到 offline_build 压缩包: {existing_zip}")
770
+ return existing_zip
771
+
772
+ elif os.path.exists(MODELSCOPE_DOWNLOAD_DIR):
773
+ # 这里是旧版 modelscope download 留下的目录。整库 git clone 需要空目录,
774
+ # 因此先改名备份,不直接删除,避免误删已有断点文件。
775
+ backup_dir = MODELSCOPE_DOWNLOAD_DIR + f".bak_{int(time.time())}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
776
  try:
777
+ shutil.move(MODELSCOPE_DOWNLOAD_DIR, backup_dir)
778
+ print(f"检测到非 git 下载目录,已备份为: {backup_dir}")
779
+ except Exception as e:
780
+ print(f"备份旧下载目录失败: {e}")
781
+ return None
782
+
783
+ for repo_url in repo_urls:
784
+ for use_proxy, mode_name in [(False, "直连"), (True, "代理")]:
785
+ if os.path.exists(MODELSCOPE_DOWNLOAD_DIR):
786
+ shutil.rmtree(MODELSCOPE_DOWNLOAD_DIR, ignore_errors=True)
787
+
788
+ env = get_modelscope_download_env(use_proxy=use_proxy)
789
+ command = [
790
+ "git",
791
+ "clone",
792
+ "--depth",
793
+ "1",
794
+ repo_url,
795
+ MODELSCOPE_DOWNLOAD_DIR
796
+ ]
797
+
798
+ try:
799
+ print(f"执行 ModelScope 整库 git clone [{mode_name}]: " + " ".join(command))
800
+
801
+ result = subprocess.run(
802
+ command,
803
+ env=env,
804
+ stdout=subprocess.PIPE,
805
+ stderr=subprocess.PIPE,
806
+ text=True,
807
+ timeout=MODELSCOPE_DOWNLOAD_TIMEOUT
808
+ )
809
+
810
+ if result.stdout.strip():
811
+ print(result.stdout[-2000:])
812
+ if result.stderr.strip():
813
+ print(result.stderr[-4000:])
814
+
815
+ if result.returncode != 0:
816
+ print("本次 git clone 失败,继续尝试下一个方式。")
817
+ continue
818
+
819
+ try:
820
+ subprocess.run(
821
+ ["git", "-C", MODELSCOPE_DOWNLOAD_DIR, "lfs", "pull"],
822
+ env=env,
823
+ stdout=subprocess.PIPE,
824
+ stderr=subprocess.PIPE,
825
+ text=True,
826
+ timeout=MODELSCOPE_DOWNLOAD_TIMEOUT
827
+ )
828
+ except Exception as e:
829
+ print(f"git lfs pull 执行异常: {e}")
830
+
831
+ zip_path = find_existing_offline_zip()
832
+ if zip_path:
833
+ print(f"ModelScope 整库克隆完成,找到 offline_build 压缩包: {zip_path}")
834
+ return zip_path
835
+
836
+ print("整库 git clone 完成,但未找到有效 offline_build 压缩包。")
837
+
838
+ except subprocess.TimeoutExpired:
839
+ print("ModelScope 整库 git clone 超时,继续尝试下一个方式。")
840
+ except Exception as e:
841
+ print(f"ModelScope 整库 git clone 异常: {e}")
842
+
843
+ return None
844
+
845
+
846
+ def download_whole_forgeui_repo_with_modelscope_cli():
847
+ if not install_modelscope_cli():
848
+ return None
849
+
850
+ commands = [
851
+ (
852
+ [
853
+ "modelscope",
854
+ "download",
855
+ "--model",
856
+ MODELSCOPE_MODEL_ID,
857
+ "--local_dir",
858
+ MODELSCOPE_DOWNLOAD_DIR
859
+ ],
860
+ False,
861
+ "整库直连"
862
+ ),
863
+ (
864
+ [
865
+ "modelscope",
866
+ "download",
867
+ "--model",
868
+ MODELSCOPE_MODEL_ID,
869
+ "--local_dir",
870
+ MODELSCOPE_DOWNLOAD_DIR,
871
+ "--endpoint",
872
+ "https://www.modelscope.cn"
873
+ ],
874
+ False,
875
+ "整库直连+显式 endpoint"
876
+ ),
877
+ (
878
+ [
879
+ "modelscope",
880
+ "download",
881
+ "--model",
882
+ MODELSCOPE_MODEL_ID,
883
+ "--local_dir",
884
+ MODELSCOPE_DOWNLOAD_DIR
885
+ ],
886
+ True,
887
+ "整库代理"
888
+ )
889
+ ]
890
+
891
+ for command, use_proxy, mode_name in commands:
892
+ try:
893
+ print(f"执行 ModelScope CLI 整库下载 [{mode_name}]: " + " ".join(command))
894
 
895
  result = subprocess.run(
896
  command,
897
+ env=get_modelscope_download_env(use_proxy=use_proxy),
898
  stdout=subprocess.PIPE,
899
  stderr=subprocess.PIPE,
900
  text=True,
901
+ timeout=MODELSCOPE_DOWNLOAD_TIMEOUT
902
  )
903
 
904
+ output_text = ""
905
  if result.stdout.strip():
906
+ output_text += result.stdout + "\n"
907
  print(result.stdout[-2000:])
908
  if result.stderr.strip():
909
+ output_text += result.stderr + "\n"
910
+ print(result.stderr[-4000:])
911
 
912
  zip_path = find_existing_offline_zip()
913
  if result.returncode == 0 and zip_path:
914
+ print(f"ModelScope CLI 整库下载完成,找到 offline_build 压缩包: {zip_path}")
915
  return zip_path
916
 
917
+ # 这里不再按文件名调用 modelscope download只在 CLI 日志暴露 OSS 直链时做公网地址回退
918
+ fallback_zip = try_public_oss_fallback(output_text, "offlinbuild.zip")
919
+ if fallback_zip and is_valid_zip(fallback_zip):
920
+ print(f"offline_build 压缩包通过公网 OSS 回退下载成功: {fallback_zip}")
921
+ return fallback_zip
922
+
923
+ print("本次整库下载未找到有效 offline_build 压缩包,继续尝试下一个命令。")
924
 
925
  except subprocess.TimeoutExpired:
926
+ print("ModelScope CLI 整库下载超时,继续尝试下一个命令。")
927
  except Exception as e:
928
+ print(f"ModelScope CLI 整库下载异常: {e}")
929
+
930
+ return None
931
+
932
+
933
+ def download_offline_build_from_modelscope():
934
+ os.makedirs(MODELSCOPE_DOWNLOAD_DIR, exist_ok=True)
935
+ os.makedirs(MODELSCOPE_CACHE_DIR, exist_ok=True)
936
+
937
+ existing_zip = find_existing_offline_zip()
938
+ if existing_zip:
939
+ print(f"检测到已有 offline_build 压缩包: {existing_zip}")
940
+ return existing_zip
941
+
942
+ print(f"开始从 ModelScope 整库克隆/下载 {MODELSCOPE_MODEL_ID}。")
943
+
944
+ zip_path = clone_whole_forgeui_repo_with_git()
945
+ if zip_path:
946
+ return zip_path
947
+
948
+ print("git 整库克隆未成功,改用 ModelScope CLI 整库下载。")
949
+
950
+ zip_path = download_whole_forgeui_repo_with_modelscope_cli()
951
+ if zip_path:
952
+ return zip_path
953
 
954
+ print("ModelScope 整库克隆/下载失败,未找到有效 offline_build 压缩包。")
955
  return None
956
 
957