HOPStudio commited on
Commit
804bfe8
·
verified ·
1 Parent(s): bd993f3

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +104 -534
main.py CHANGED
@@ -3,10 +3,6 @@ import subprocess
3
  import threading
4
  import shutil
5
  import json
6
- import sys
7
- import time
8
- import zipfile
9
- import re
10
  import requests
11
  import gradio as gr
12
 
@@ -18,26 +14,6 @@ FRP_VERSION = "0.69.0"
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,避免文件名略有差异时直接失败。
35
- OFFLINE_BUILD_ZIP_CANDIDATES = [
36
- "offlinbuild.zip",
37
- "offlinebuild.zip",
38
- "offline_build.zip"
39
- ]
40
-
41
 
42
  def clone_repository():
43
  if os.path.exists(REPO_PATH):
@@ -391,8 +367,19 @@ def start_jupyterlab_process():
391
  print(f"启动 JupyterLab 失败: {e}")
392
 
393
 
 
 
 
 
 
 
 
 
 
 
 
 
394
 
395
- # ===== 新增:ModelScope 整库克隆/下载 offline_build 并启动 ComfyUI =====
396
  def get_proxy_env():
397
  env = os.environ.copy()
398
 
@@ -407,16 +394,11 @@ def get_proxy_env():
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",
@@ -437,9 +419,8 @@ def get_modelscope_download_env(use_proxy=False):
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
 
@@ -470,571 +451,158 @@ def is_valid_zip(path):
470
  return False
471
 
472
  try:
 
473
  if not zipfile.is_zipfile(path):
474
  return False
475
 
476
  with zipfile.ZipFile(path, "r") as zf:
477
- # 只读取目录,不做全量 testzip,避免大压缩包校验耗时过长。
478
  return len(zf.namelist()) > 0
479
  except Exception:
480
  return False
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):
488
- continue
489
-
490
- for zip_name in OFFLINE_BUILD_ZIP_CANDIDATES:
491
- zip_path = os.path.join(directory, zip_name)
492
- if is_valid_zip(zip_path):
493
- return zip_path
494
 
495
- for root, _, files in os.walk(directory):
496
- for filename in files:
497
- lower_name = filename.lower()
498
- if lower_name.endswith(".zip") and "offlin" in lower_name:
499
- zip_path = os.path.join(root, filename)
500
- if is_valid_zip(zip_path):
501
- return zip_path
502
 
503
- return None
504
-
505
-
506
- def install_modelscope_cli():
507
- if shutil.which("modelscope"):
508
- print("检测到 modelscope 命令。")
509
  return True
510
 
511
- print("未检测到 modelscope 命令,尝试安装 modelscope。")
512
-
513
- install_commands = [
514
- [
515
- sys.executable,
516
- "-m",
517
- "pip",
518
- "install",
519
- "-U",
520
- "modelscope",
521
- "-i",
522
- "https://pypi.tuna.tsinghua.edu.cn/simple"
523
- ],
524
- [
525
- sys.executable,
526
- "-m",
527
- "pip",
528
- "install",
529
- "-U",
530
- "modelscope"
531
- ]
532
- ]
533
 
534
- for command in install_commands:
 
535
  try:
536
- result = subprocess.run(
537
- command,
538
- stdout=subprocess.PIPE,
539
- stderr=subprocess.PIPE,
540
- text=True,
541
- timeout=300
542
- )
543
-
544
- if result.returncode == 0 and shutil.which("modelscope"):
545
- print("modelscope 安装成功。")
546
- return True
547
-
548
- print("modelscope 安装尝试失败。")
549
- if result.stdout.strip():
550
- print(result.stdout[-1000:])
551
- if result.stderr.strip():
552
- print(result.stderr[-1000:])
553
-
554
- except subprocess.TimeoutExpired:
555
- print("modelscope 安装超时。")
556
  except Exception as e:
557
- print(f"modelscope 安装异常: {e}")
558
-
559
- print("modelscope 不可用,无法继续下载 offline_build。")
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
-
958
- def locate_offline_build_dir():
959
- expected_main = os.path.join(OFFLINE_BUILD_DIR, "ComfyUI", "main.py")
960
- if os.path.exists(expected_main):
961
- return OFFLINE_BUILD_DIR
962
-
963
- for root, dirs, files in os.walk(REPO_PATH):
964
- if "main.py" in files and os.path.basename(root) == "ComfyUI":
965
- parent_dir = os.path.dirname(root)
966
- venv_activate = os.path.join(parent_dir, "venv", "bin", "activate")
967
- if os.path.exists(venv_activate):
968
- return parent_dir
969
 
970
- return None
971
 
 
 
 
 
972
 
973
- def extract_offline_build(zip_path):
974
- existing_dir = locate_offline_build_dir()
975
- if existing_dir:
976
- print(f"检测到已解压的 offline_build: {existing_dir}")
977
- return existing_dir
978
 
979
- if not zip_path or not is_valid_zip(zip_path):
980
- print(f"offline_build缩包无效: {zip_path}")
981
- return None
 
 
 
 
982
 
983
  try:
984
- print(f"正在解压 offline_build: {zip_path}")
985
 
986
- with zipfile.ZipFile(zip_path, "r") as zf:
987
- zf.extractall(REPO_PATH)
 
988
 
989
- extracted_dir = locate_offline_build_dir()
990
- if extracted_dir:
991
- print(f"offline_build 解压完成: {extracted_dir}")
992
- return extracted_dir
993
 
994
- print("解压完成,但未找到 offline_build/ComfyUI/main.py。")
995
- return None
996
 
997
  except Exception as e:
998
- print(f"解压 offline_build 失败: {e}")
999
- return None
1000
 
1001
 
1002
- def prepare_offline_build():
1003
- existing_dir = locate_offline_build_dir()
1004
- if existing_dir:
1005
- print(f"offline_build 已存在,跳过下载解压: {existing_dir}")
1006
- return existing_dir
1007
 
1008
- zip_path = download_offline_build_from_modelscope()
1009
- if not zip_path:
1010
- return None
1011
 
1012
- return extract_offline_build(zip_path)
1013
 
1014
 
1015
  def start_comfyui_process():
1016
- offline_build_dir = prepare_offline_build()
1017
-
1018
- if not offline_build_dir:
1019
- print("offline_build 准备失败,跳过 ComfyUI 启动。")
1020
  return
1021
 
1022
- venv_activate = os.path.join(offline_build_dir, "venv", "bin", "activate")
1023
- comfyui_main = os.path.join(offline_build_dir, "ComfyUI", "main.py")
1024
-
1025
- if not os.path.exists(venv_activate):
1026
- print(f"未找到虚拟环境激活脚本: {venv_activate}")
1027
  return
1028
 
1029
- if not os.path.exists(comfyui_main):
1030
- print(f"未找到 ComfyUI main.py: {comfyui_main}")
1031
  return
1032
 
1033
  configure_git_proxy()
1034
 
1035
- command = f'''
 
 
 
1036
  set -e
1037
- source "{venv_activate}"
1038
  export http_proxy={PROXY_URL}
1039
  export https_proxy={PROXY_URL}
1040
  export HTTP_PROXY={PROXY_URL}
@@ -1044,9 +612,9 @@ export no_proxy=localhost,127.0.0.1
1044
  export NO_PROXY=localhost,127.0.0.1
1045
  git config --global http.proxy {PROXY_URL}
1046
  git config --global https.proxy {PROXY_URL}
1047
- cd "{os.path.join(offline_build_dir, "ComfyUI")}"
1048
- python main.py --listen 0.0.0.0 --port {COMFYUI_PORT}
1049
- '''
1050
 
1051
  try:
1052
  os.makedirs(REPO_PATH, exist_ok=True)
@@ -1054,12 +622,13 @@ python main.py --listen 0.0.0.0 --port {COMFYUI_PORT}
1054
 
1055
  process = subprocess.Popen(
1056
  ["bash", "-lc", command],
1057
- cwd=offline_build_dir,
1058
  env=get_proxy_env(),
1059
  stdout=log_file,
1060
  stderr=subprocess.STDOUT
1061
  )
1062
 
 
1063
  time.sleep(3)
1064
 
1065
  if process.poll() is None:
@@ -1070,6 +639,7 @@ python main.py --listen 0.0.0.0 --port {COMFYUI_PORT}
1070
  except Exception as e:
1071
  print(f"启动 ComfyUI 失败: {e}")
1072
 
 
1073
  def start_gradio():
1074
  with gr.Blocks() as demo:
1075
  gr.Markdown("# InternLM 控制台")
 
3
  import threading
4
  import shutil
5
  import json
 
 
 
 
6
  import requests
7
  import gradio as gr
8
 
 
14
  CURRENT_DIR = REPO_PATH
15
  LAST_OUTPUT = ""
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  def clone_repository():
19
  if os.path.exists(REPO_PATH):
 
367
  print(f"启动 JupyterLab 失败: {e}")
368
 
369
 
370
+ # ===== 新增:ModelScope 下载 comfy_portable.zip,解压后使用自带 Python 启动 ComfyUI =====
371
+ MODELSCOPE_MODEL_ID = "HOPStudio/forgeui"
372
+ COMFY_PORTABLE_ZIP_NAME = "comfy_portable.zip"
373
+ COMFY_PORTABLE_ZIP_PATH = os.path.join("/root", COMFY_PORTABLE_ZIP_NAME)
374
+ COMFY_PORTABLE_DIR = "/root/comfy_portable"
375
+ COMFY_PORTABLE_PYTHON = os.path.join(COMFY_PORTABLE_DIR, "python", "bin", "python")
376
+ COMFYUI_MAIN = os.path.join(COMFY_PORTABLE_DIR, "ComfyUI", "main.py")
377
+ COMFYUI_PORT = 8188
378
+ COMFYUI_LOG_PATH = os.path.join(REPO_PATH, "comfyui.log")
379
+ PROXY_URL = "http://103.71.69.203:17890"
380
+ MODELSCOPE_DOWNLOAD_TIMEOUT = 21600
381
+
382
 
 
383
  def get_proxy_env():
384
  env = os.environ.copy()
385
 
 
394
  return env
395
 
396
 
397
+ def get_modelscope_env(use_proxy=False):
398
  env = os.environ.copy()
 
 
 
 
399
  env["MODELSCOPE_ENDPOINT"] = "https://www.modelscope.cn"
400
  env["MODELSCOPE_SDK_ENDPOINT"] = "https://www.modelscope.cn"
401
 
 
402
  proxy_keys = [
403
  "http_proxy",
404
  "https_proxy",
 
419
  for key in proxy_keys:
420
  env.pop(key, None)
421
 
422
+ env["no_proxy"] = "localhost,127.0.0.1"
423
+ env["NO_PROXY"] = "localhost,127.0.0.1"
 
424
 
425
  return env
426
 
 
451
  return False
452
 
453
  try:
454
+ import zipfile
455
  if not zipfile.is_zipfile(path):
456
  return False
457
 
458
  with zipfile.ZipFile(path, "r") as zf:
 
459
  return len(zf.namelist()) > 0
460
  except Exception:
461
  return False
462
 
463
 
464
+ def is_comfy_portable_ready():
465
+ return os.path.exists(COMFY_PORTABLE_PYTHON) and os.path.exists(COMFYUI_MAIN)
 
 
 
 
 
 
 
 
 
466
 
 
 
 
 
 
 
 
467
 
468
+ def download_comfy_portable_from_modelscope():
469
+ if is_comfy_portable_ready():
470
+ print(f"检测到已解压的 comfy_portable: {COMFY_PORTABLE_DIR}")
 
 
 
471
  return True
472
 
473
+ if is_valid_zip(COMFY_PORTABLE_ZIP_PATH):
474
+ print(f"检测到已有 comfy_portable 压缩包: {COMFY_PORTABLE_ZIP_PATH}")
475
+ return True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
476
 
477
+ if os.path.exists(COMFY_PORTABLE_ZIP_PATH):
478
+ print(f"检测到无效 comfy_portable 压缩包,正在删除: {COMFY_PORTABLE_ZIP_PATH}")
479
  try:
480
+ os.remove(COMFY_PORTABLE_ZIP_PATH)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
  except Exception as e:
482
+ print(f"删除无效压缩包失败: {e}")
483
+ return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
 
485
+ if not shutil.which("modelscope"):
486
+ print("未检测到 modelscope 命令为避免改动系统 Python 依赖,本脚本不会自动安装 modelscope。")
487
+ print("请先在外部环境安装好 modelscope CLI,或手动把 comfy_portable.zip 放到 /root/comfy_portable.zip。")
 
 
488
  return False
489
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  commands = [
491
+ (False, "直连"),
492
+ (True, "代理")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  ]
494
 
495
+ for use_proxy, mode_name in commands:
496
+ command = [
497
+ "modelscope",
498
+ "download",
499
+ "--model",
500
+ MODELSCOPE_MODEL_ID,
501
+ COMFY_PORTABLE_ZIP_NAME,
502
+ "--local_dir",
503
+ "/root"
504
+ ]
505
+
506
  try:
507
+ print(f"执行 ModelScope 下载 comfy_portable.zip [{mode_name}]: " + " ".join(command))
508
 
509
  result = subprocess.run(
510
  command,
511
+ env=get_modelscope_env(use_proxy=use_proxy),
512
  stdout=subprocess.PIPE,
513
  stderr=subprocess.PIPE,
514
  text=True,
515
  timeout=MODELSCOPE_DOWNLOAD_TIMEOUT
516
  )
517
 
 
518
  if result.stdout.strip():
 
519
  print(result.stdout[-2000:])
520
  if result.stderr.strip():
 
521
  print(result.stderr[-4000:])
522
 
523
+ if result.returncode == 0 and is_valid_zip(COMFY_PORTABLE_ZIP_PATH):
524
+ print(f"comfy_portable.zip 下载完成: {COMFY_PORTABLE_ZIP_PATH}")
525
+ return True
 
 
 
 
 
 
 
526
 
527
+ print("本次 ModelScope 下载失败或压缩包无效,继续尝试下一个方式。")
528
 
529
  except subprocess.TimeoutExpired:
530
+ print("ModelScope 下载 comfy_portable.zip 超时,继续尝试下一个方式。")
531
  except Exception as e:
532
+ print(f"ModelScope 下载 comfy_portable.zip 异常: {e}")
 
 
 
 
 
 
 
533
 
534
+ print("ModelScope 下载 comfy_portable.zip 失败。")
535
+ return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
 
 
537
 
538
+ def extract_comfy_portable():
539
+ if is_comfy_portable_ready():
540
+ print(f"comfy_portable 已存在,跳过解压: {COMFY_PORTABLE_DIR}")
541
+ return True
542
 
543
+ if not is_valid_zip(COMFY_PORTABLE_ZIP_PATH):
544
+ print(f"comfy_portable.zip 不存在或无效: {COMFY_PORTABLE_ZIP_PATH}")
545
+ return False
 
 
546
 
547
+ if os.path.exists(COMFY_PORTABLE_DIR):
548
+ print(f"检测到不完整的 comfy_portable 目录,正在删除后重新解压: {COMFY_PORTABLE_DIR}")
549
+ try:
550
+ shutil.rmtree(COMFY_PORTABLE_DIR)
551
+ except Exception as e:
552
+ print(f"删除不完整 comfy_portable 目录失败: {e}")
553
+ return False
554
 
555
  try:
556
+ print(f"正在解压 comfy_portable.zip 到 /root: {COMFY_PORTABLE_ZIP_PATH}")
557
 
558
+ import zipfile
559
+ with zipfile.ZipFile(COMFY_PORTABLE_ZIP_PATH, "r") as zf:
560
+ zf.extractall("/root")
561
 
562
+ if is_comfy_portable_ready():
563
+ print(f"comfy_portable 解压完成: {COMFY_PORTABLE_DIR}")
564
+ return True
 
565
 
566
+ print("解压完成,但未找到 /root/comfy_portable/python/bin/python 或 /root/comfy_portable/ComfyUI/main.py。")
567
+ return False
568
 
569
  except Exception as e:
570
+ print(f"解压 comfy_portable.zip 失败: {e}")
571
+ return False
572
 
573
 
574
+ def prepare_comfy_portable():
575
+ if is_comfy_portable_ready():
576
+ print(f"comfy_portable 已准备完成: {COMFY_PORTABLE_DIR}")
577
+ return True
 
578
 
579
+ if not download_comfy_portable_from_modelscope():
580
+ return False
 
581
 
582
+ return extract_comfy_portable()
583
 
584
 
585
  def start_comfyui_process():
586
+ if not prepare_comfy_portable():
587
+ print("comfy_portable 准备失败,跳过 ComfyUI 启动。")
 
 
588
  return
589
 
590
+ if not os.path.exists(COMFY_PORTABLE_PYTHON):
591
+ print(f"未找到便携 Python: {COMFY_PORTABLE_PYTHON}")
 
 
 
592
  return
593
 
594
+ if not os.path.exists(COMFYUI_MAIN):
595
+ print(f"未找到 ComfyUI main.py: {COMFYUI_MAIN}")
596
  return
597
 
598
  configure_git_proxy()
599
 
600
+ python_lib_dir = os.path.join(COMFY_PORTABLE_DIR, "python", "lib")
601
+ comfyui_dir = os.path.join(COMFY_PORTABLE_DIR, "ComfyUI")
602
+
603
+ command = f"""
604
  set -e
605
+ export LD_LIBRARY_PATH=\"{python_lib_dir}:${{LD_LIBRARY_PATH:-}}\"
606
  export http_proxy={PROXY_URL}
607
  export https_proxy={PROXY_URL}
608
  export HTTP_PROXY={PROXY_URL}
 
612
  export NO_PROXY=localhost,127.0.0.1
613
  git config --global http.proxy {PROXY_URL}
614
  git config --global https.proxy {PROXY_URL}
615
+ cd \"{comfyui_dir}\"
616
+ \"{COMFY_PORTABLE_PYTHON}\" main.py --listen 0.0.0.0 --port {COMFYUI_PORT}
617
+ """
618
 
619
  try:
620
  os.makedirs(REPO_PATH, exist_ok=True)
 
622
 
623
  process = subprocess.Popen(
624
  ["bash", "-lc", command],
625
+ cwd=COMFY_PORTABLE_DIR,
626
  env=get_proxy_env(),
627
  stdout=log_file,
628
  stderr=subprocess.STDOUT
629
  )
630
 
631
+ import time
632
  time.sleep(3)
633
 
634
  if process.poll() is None:
 
639
  except Exception as e:
640
  print(f"启动 ComfyUI 失败: {e}")
641
 
642
+
643
  def start_gradio():
644
  with gr.Blocks() as demo:
645
  gr.Markdown("# InternLM 控制台")