ttttdiva commited on
Commit
2dd9bb2
·
verified ·
1 Parent(s): e17e2d6

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +41 -29
main.py CHANGED
@@ -14,7 +14,6 @@ import requests
14
  from fastapi import FastAPI
15
  from huggingface_hub import HfApi, hf_hub_download, login
16
 
17
- # ロギングの設定
18
  logging.basicConfig(level=logging.INFO)
19
  logger = logging.getLogger(__name__)
20
 
@@ -48,6 +47,7 @@ class Config:
48
  # 暗号化されたファイルが出力されるローカルディレクトリ(cryptLocal: の実体)
49
  ENCRYPTED_DIR = "/home/user/app/encrypted"
50
 
 
51
  class CivitAICrawler:
52
  """CivitAIからモデルをダウンロードし、Hugging Faceにアップロードするクラス(フォルダ名も暗号化対応版)"""
53
 
@@ -58,7 +58,7 @@ class CivitAICrawler:
58
  self.repo_ids = self.config.REPO_IDS.copy()
59
  self.jst = self.config.JST
60
 
61
- # rclone のセットアップ(rclone.conf を環境変数から生成)
62
  self.setup_rclone_conf()
63
 
64
  self.setup_routes()
@@ -69,7 +69,7 @@ class CivitAICrawler:
69
  now = str(datetime.datetime.now(self.jst))
70
  description = f"""
71
  CivitAIを定期的に周回し新規モデルを {self.repo_ids['current']} にバックアップするSpaceです。
72
- 詳細は https://huggingface.co/{self.repo_ids['model_list']}/blob/main/model_list.log からどうぞ。
73
  Status: {now} + currently running :D
74
  """
75
  return description
@@ -97,8 +97,12 @@ class CivitAICrawler:
97
 
98
  def encrypt_with_rclone(self, local_path: str):
99
  """
100
- 指定ファイル or ディレクトリを cryptLocal: にコピーし、
101
- 暗号化された結果を self.config.ENCRYPTED_DIR に生成する。
 
 
 
 
102
  """
103
  if not os.path.exists(local_path):
104
  raise FileNotFoundError(f"[ERROR] Local path not found: {local_path}")
@@ -107,10 +111,17 @@ class CivitAICrawler:
107
  if os.path.isdir(self.config.ENCRYPTED_DIR):
108
  shutil.rmtree(self.config.ENCRYPTED_DIR, ignore_errors=True)
109
 
110
- cmd = ["rclone", "copy", local_path, "cryptLocal:", "-v"]
 
 
 
 
 
 
 
111
  logger.info(f"[INFO] Running: {' '.join(cmd)}")
112
  subprocess.run(cmd, check=True)
113
- logger.info(f"[OK] rclone copy => cryptLocal:")
114
 
115
  if not os.path.isdir(self.config.ENCRYPTED_DIR):
116
  raise FileNotFoundError(
@@ -119,23 +130,25 @@ class CivitAICrawler:
119
 
120
  def upload_encrypted_files(self, repo_id: str, base_path_in_repo: str = ""):
121
  """
122
- self.config.ENCRYPTED_DIR にある暗号化後のファイル/フォルダ構造をそっくりそのまま
123
- Hugging Faceにアップロードする。フォルダ名・ファイル名はrcloneの設定によって暗号化されている。
 
 
 
 
 
 
124
  """
125
  max_retries = 5
126
 
127
- # 再帰的に暗号化フォルダを探索
128
  for root, dirs, files in os.walk(self.config.ENCRYPTED_DIR):
129
  for fn in files:
130
  encrypted_file_path = os.path.join(root, fn)
131
  if not os.path.isfile(encrypted_file_path):
132
  continue
133
 
134
- # self.config.ENCRYPTED_DIR からの相対パスを算出
135
  relative_path = os.path.relpath(encrypted_file_path, self.config.ENCRYPTED_DIR)
136
- # Hugging Face上にアップロードする際のディレクトリパス
137
- # ここ��は base_path_in_repo + relative_path にしているが、
138
- # base_path_in_repo が空("")なら、rclone で暗号化されたディレクトリ名をそのまま使う
139
  upload_path_in_repo = os.path.join(base_path_in_repo, relative_path)
140
 
141
  attempt = 0
@@ -162,7 +175,7 @@ class CivitAICrawler:
162
  elif "you can retry this action in about 1 hour" in error_message:
163
  logger.warning("Encountered 'retry in 1 hour' error. Waiting 1 hour before retrying...")
164
  time.sleep(3600)
165
- attempt -= 1 # この場合はリトライ回数をカウントしない
166
  else:
167
  if attempt < max_retries:
168
  logger.warning(
@@ -347,38 +360,37 @@ class CivitAICrawler:
347
  with open(os.path.join(folder, "model_info.json"), "w") as file:
348
  json.dump(model_info, file, indent=2)
349
 
 
 
 
350
  @staticmethod
351
  def increment_repo_name(repo_id: str) -> str:
352
- """リポジトリ名の末尾の数字をインクリメントする。"""
353
  match = re.search(r'(\d+)$', repo_id)
354
  if match:
355
  number = int(match.group(1)) + 1
356
- new_repo_id = re.sub(r'\d+$', str(number), repo_id)
357
  else:
358
- new_repo_id = f"{repo_id}1"
359
- return new_repo_id
360
 
361
  # =============================================================================
362
- # 既存のファイル/フォルダアップロードを「フォルダ名も暗号化」するよう変更
363
  # =============================================================================
364
  def upload_file(self, file_path: str):
365
  """
366
- 1) rcloneで file_path を暗号化
367
- 2) 暗号化された単一ファイル(またはフォルダ構造)をそのままHugging Faceへアップロード
368
- (ファイル名もフォルダ名も暗号化される)
369
  """
370
- # rcloneで暗号化
371
- self.encrypt_with_rclone(file_path)
372
- # 暗号化フォルダ全体をアップロード (フォルダ名も暗号化される)
373
  self.upload_encrypted_files(repo_id=self.repo_ids['current'], base_path_in_repo="")
374
- # 後始末
375
  if os.path.isdir(self.config.ENCRYPTED_DIR):
376
  shutil.rmtree(self.config.ENCRYPTED_DIR, ignore_errors=True)
377
 
378
  def upload_folder(self, folder_path: str):
379
  """
380
- 1) rcloneでフォルダ全体を暗号化 (フォルダ名含むディレクトリ構造が暗号化)
381
- 2) 暗号化済みディレクトリ構造をHugging Faceにアップロード
 
 
382
  """
383
  self.encrypt_with_rclone(folder_path)
384
  self.upload_encrypted_files(repo_id=self.repo_ids['current'], base_path_in_repo="")
 
14
  from fastapi import FastAPI
15
  from huggingface_hub import HfApi, hf_hub_download, login
16
 
 
17
  logging.basicConfig(level=logging.INFO)
18
  logger = logging.getLogger(__name__)
19
 
 
47
  # 暗号化されたファイルが出力されるローカルディレクトリ(cryptLocal: の実体)
48
  ENCRYPTED_DIR = "/home/user/app/encrypted"
49
 
50
+
51
  class CivitAICrawler:
52
  """CivitAIからモデルをダウンロードし、Hugging Faceにアップロードするクラス(フォルダ名も暗号化対応版)"""
53
 
 
58
  self.repo_ids = self.config.REPO_IDS.copy()
59
  self.jst = self.config.JST
60
 
61
+ # rclone のセットアップ
62
  self.setup_rclone_conf()
63
 
64
  self.setup_routes()
 
69
  now = str(datetime.datetime.now(self.jst))
70
  description = f"""
71
  CivitAIを定期的に周回し新規モデルを {self.repo_ids['current']} にバックアップするSpaceです。
72
+ モデル名とバックアップURLの紐づきは: https://huggingface.co/{self.repo_ids['model_list']}/blob/main/model_list.log
73
  Status: {now} + currently running :D
74
  """
75
  return description
 
97
 
98
  def encrypt_with_rclone(self, local_path: str):
99
  """
100
+ 指定ファイル or ディレクトリを cryptLocal:にコピー。
101
+ このとき「トップレベルのフォルダ名」も暗号化して保持するため、
102
+ cryptLocal:{os.path.basename(local_path)} の形でコピーする。
103
+
104
+ ※ rclone の crypt設定が filename_encryption = standard 等なら、
105
+ フォルダ名やファイル名も丸ごと暗号化される
106
  """
107
  if not os.path.exists(local_path):
108
  raise FileNotFoundError(f"[ERROR] Local path not found: {local_path}")
 
111
  if os.path.isdir(self.config.ENCRYPTED_DIR):
112
  shutil.rmtree(self.config.ENCRYPTED_DIR, ignore_errors=True)
113
 
114
+ # コピー先を cryptLocal:xxx に指定することで、xxx というフォルダ単位で
115
+ # 暗号化されたディレクトリを作成できるようにする。
116
+ top_level_name = os.path.basename(local_path.rstrip("/"))
117
+ if not top_level_name:
118
+ top_level_name = "unknown"
119
+
120
+ # rclone copy local_path -> cryptLocal:top_level_name
121
+ cmd = ["rclone", "copy", local_path, f"cryptLocal:{top_level_name}", "-v"]
122
  logger.info(f"[INFO] Running: {' '.join(cmd)}")
123
  subprocess.run(cmd, check=True)
124
+ logger.info(f"[OK] rclone copy => cryptLocal:{top_level_name}")
125
 
126
  if not os.path.isdir(self.config.ENCRYPTED_DIR):
127
  raise FileNotFoundError(
 
130
 
131
  def upload_encrypted_files(self, repo_id: str, base_path_in_repo: str = ""):
132
  """
133
+ self.config.ENCRYPTED_DIR にある暗号化後のファイル/フォルダ構造を
134
+ そのまま Hugging Face にアップロードする。
135
+
136
+ rclone で filename_encryption=standard が有効な場合:
137
+ - 元フォルダ名/ファイル名は完全に暗号化され、HF上では判読不能な名称になる。
138
+
139
+ base_path_in_repo が空("")の場合は、
140
+ `/home/user/app/encrypted` の構造が HF リポジトリの直下に展開される。
141
  """
142
  max_retries = 5
143
 
 
144
  for root, dirs, files in os.walk(self.config.ENCRYPTED_DIR):
145
  for fn in files:
146
  encrypted_file_path = os.path.join(root, fn)
147
  if not os.path.isfile(encrypted_file_path):
148
  continue
149
 
150
+ # self.config.ENCRYPTED_DIR からの相対パス(暗号化後のフォルダ名・ファイル名)
151
  relative_path = os.path.relpath(encrypted_file_path, self.config.ENCRYPTED_DIR)
 
 
 
152
  upload_path_in_repo = os.path.join(base_path_in_repo, relative_path)
153
 
154
  attempt = 0
 
175
  elif "you can retry this action in about 1 hour" in error_message:
176
  logger.warning("Encountered 'retry in 1 hour' error. Waiting 1 hour before retrying...")
177
  time.sleep(3600)
178
+ attempt -= 1
179
  else:
180
  if attempt < max_retries:
181
  logger.warning(
 
360
  with open(os.path.join(folder, "model_info.json"), "w") as file:
361
  json.dump(model_info, file, indent=2)
362
 
363
+ # =============================================================================
364
+ # 以下はダウンロードやモデル情報処理の部分(元コードと同等)
365
+ # =============================================================================
366
  @staticmethod
367
  def increment_repo_name(repo_id: str) -> str:
 
368
  match = re.search(r'(\d+)$', repo_id)
369
  if match:
370
  number = int(match.group(1)) + 1
371
+ return re.sub(r'\d+$', str(number), repo_id)
372
  else:
373
+ return f"{repo_id}1"
 
374
 
375
  # =============================================================================
376
+ # フォルダアップロード
377
  # =============================================================================
378
  def upload_file(self, file_path: str):
379
  """
380
+ 単一ファイルを暗号化 暗号化後のものをHugging Faceへアップロード。
381
+ rcloneでフォルダを作って暗号化するため、フォルダ構造としてアップされる。
 
382
  """
383
+ self.encrypt_with_rclone(file_path) # 1) ローカルを -> cryptLocal:basename(…)
 
 
384
  self.upload_encrypted_files(repo_id=self.repo_ids['current'], base_path_in_repo="")
 
385
  if os.path.isdir(self.config.ENCRYPTED_DIR):
386
  shutil.rmtree(self.config.ENCRYPTED_DIR, ignore_errors=True)
387
 
388
  def upload_folder(self, folder_path: str):
389
  """
390
+ フォルダを暗号化 フォルダ名ごとアップロード。
391
+ rclone copy folder_path => cryptLocal:folder_pathのbasename
392
+ すると {ENCRYPTED_DIR}/{暗号化後のトップレベルフォルダ} が生成されるため、
393
+ それを再帰的にHugging Faceへアップロードする。
394
  """
395
  self.encrypt_with_rclone(folder_path)
396
  self.upload_encrypted_files(repo_id=self.repo_ids['current'], base_path_in_repo="")