Duskfallcrew commited on
Commit
47c5626
·
verified ·
1 Parent(s): cac7a2e

Upload 6 files

Browse files

This is the untested 0.4 branch with new code.

Files changed (6) hide show
  1. LICENSE +21 -0
  2. README.md +1 -6
  3. __init__.py +18 -0
  4. requirements.txt +2 -0
  5. scripts/hfbackup_script.py +187 -0
  6. scripts/ui-settings.py +37 -0
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2024 The Duskfall Portal Crew
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,8 +1,3 @@
1
- ---
2
- license: mit
3
- language:
4
- - en
5
- ---
6
  # Hugging Face Backup Extension for Stable Diffusion WebUI
7
 
8
  Welcome to our unique extension, designed to help you easily back up your valuable Stable Diffusion WebUI files to the Hugging Face Hub! This project is brought to you by the Duskfall Portal Crew, a diverse DID system passionate about creativity and AI.
@@ -96,4 +91,4 @@ We are the Duskfall Portal Crew, a DID system with over 300 alters, navigating l
96
 
97
  #### Community Groups
98
 
99
- * **Subreddit:** [Reddit](https://www.reddit.com/r/earthndusk/)
 
 
 
 
 
 
1
  # Hugging Face Backup Extension for Stable Diffusion WebUI
2
 
3
  Welcome to our unique extension, designed to help you easily back up your valuable Stable Diffusion WebUI files to the Hugging Face Hub! This project is brought to you by the Duskfall Portal Crew, a diverse DID system passionate about creativity and AI.
 
91
 
92
  #### Community Groups
93
 
94
+ * **Subreddit:** [Reddit](https://www.reddit.com/r/earthndusk/)
__init__.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from modules import scripts
2
+ from scripts import hfbackup_script
3
+
4
+ class Script(scripts.Script):
5
+ def title(self):
6
+ return "Huggingface Backup"
7
+
8
+ def show(self, is_img2img):
9
+ return scripts.AlwaysVisible
10
+
11
+ def ui(self, is_img2img):
12
+ return hfbackup_script.on_ui(self)
13
+
14
+ def run(self, p, *args):
15
+ return hfbackup_script.on_run(self, p, *args)
16
+
17
+ def on_script_load(self):
18
+ return hfbackup_script.on_script_load(self)
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ huggingface_hub==4.30.2
2
+ gitpython
scripts/hfbackup_script.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import datetime
4
+ import threading
5
+ import gradio as gr
6
+ import subprocess
7
+ import logging
8
+ from modules import script_callbacks, shared
9
+ from git import Repo
10
+ import shutil
11
+
12
+ # Constants
13
+ REPO_NAME = 'sd-webui-backups'
14
+ BACKUP_INTERVAL = 3600 # 1 hour in seconds
15
+ HF_TOKEN_KEY = 'hf_token'
16
+ BACKUP_PATHS_KEY = 'backup_paths'
17
+ SD_PATH_KEY = 'sd_path'
18
+ HF_USER_KEY = 'hf_user'
19
+ DEFAULT_BACKUP_PATHS = ['models/Stable-diffusion', 'models/VAE', 'embeddings', 'loras']
20
+
21
+ # --- Logging Setup ---
22
+ logging.basicConfig(level=logging.INFO,
23
+ format='%(asctime)s - %(levelname)s - %(message)s',
24
+ handlers=[
25
+ logging.StreamHandler()
26
+ ])
27
+ logger = logging.getLogger(__name__)
28
+
29
+ # --- Helper function for updating the status ---
30
+ def update_status(script, status, file=None):
31
+ if file:
32
+ script.status = f"{status}: {file}"
33
+ print(f"{status}: {file}") # For console logging.
34
+ else:
35
+ script.status = status
36
+ print(status) # For console logging
37
+
38
+ # --- Git Related Functions ---
39
+ def clone_or_create_repo(repo_url, repo_path, script):
40
+ update_status(script, "Checking/Cloning Repo...")
41
+ if os.path.exists(repo_path) and os.path.isdir(repo_path):
42
+ logger.info(f"Repository already exists at {repo_path}, updating...")
43
+ repo = Repo(repo_path)
44
+ if repo.is_dirty():
45
+ logger.warning("Local repo has uncommitted changes. Commit those before running to make sure nothing breaks.")
46
+ update_status(script, "Local repo has uncommitted changes")
47
+ else:
48
+ logger.info(f"Cloning repository from {repo_url} to {repo_path}")
49
+ update_status(script, "Cloning repository")
50
+ try:
51
+ use_git_credential_store = shared.opts.data.get("git_credential_store", True)
52
+ if use_git_credential_store:
53
+ repo = Repo.clone_from(repo_url, repo_path)
54
+ else:
55
+ if "HF_TOKEN" not in os.environ:
56
+ update_status(script, "HF_TOKEN environment variable not found")
57
+ raise Exception("HF_TOKEN environment variable not found")
58
+ env_token = os.environ["HF_TOKEN"]
59
+ repo = Repo.clone_from(repo_url.replace("https://", f"https://{script.hf_user}:{env_token}@"), repo_path)
60
+
61
+ except Exception as e:
62
+ logger.error(f"Error creating or cloning repo: {e}")
63
+ update_status(script, f"Error creating or cloning repo: {e}")
64
+ raise
65
+ update_status(script, "Repo ready")
66
+ return repo
67
+
68
+ def git_push_files(repo_path, commit_message, script):
69
+ update_status(script, "Pushing changes...")
70
+ try:
71
+ repo = Repo(repo_path)
72
+ repo.git.add(all=True)
73
+ repo.index.commit(commit_message)
74
+ origin = repo.remote(name='origin')
75
+ use_git_credential_store = shared.opts.data.get("git_credential_store", True)
76
+ if use_git_credential_store:
77
+ origin.push()
78
+ else:
79
+ if "HF_TOKEN" not in os.environ:
80
+ update_status(script, "HF_TOKEN environment variable not found")
81
+ raise Exception("HF_TOKEN environment variable not found")
82
+ env_token = os.environ["HF_TOKEN"]
83
+ origin.push(f"https://{script.hf_user}:{env_token}@huggingface.co/{script.hf_user}/{REPO_NAME}")
84
+
85
+ logger.info(f"Changes pushed successfully to remote repository.")
86
+ update_status(script, "Pushing Complete")
87
+ except Exception as e:
88
+ logger.error(f"Git push failed: {e}")
89
+ update_status(script, f"Git push failed: {e}")
90
+ raise
91
+
92
+ # --- Backup Logic ---
93
+ def backup_files(paths, hf_client, script):
94
+ logger.info("Starting backup...")
95
+ update_status(script, "Starting Backup...")
96
+ repo_id = script.hf_user + "/" + REPO_NAME
97
+ repo_path = os.path.join(script.basedir, 'backup')
98
+ sd_path = script.sd_path
99
+
100
+ try:
101
+ repo = clone_or_create_repo(f"https://huggingface.co/{repo_id}", repo_path, script)
102
+ except Exception as e:
103
+ logger.error("Error starting the backup, please see the traceback.")
104
+ return
105
+
106
+ for base_path in paths:
107
+ logger.info(f"Backing up: {base_path}")
108
+ for root, _, files in os.walk(os.path.join(sd_path, base_path)):
109
+ for file in files:
110
+ local_file_path = os.path.join(root, file)
111
+ repo_file_path = os.path.relpath(local_file_path, start=sd_path)
112
+ try:
113
+ os.makedirs(os.path.dirname(os.path.join(repo_path, repo_file_path)), exist_ok=True)
114
+ shutil.copy2(local_file_path, os.path.join(repo_path, repo_file_path))
115
+ logger.info(f"Copied: {repo_file_path}")
116
+ update_status(script, "Copied", repo_file_path)
117
+ except Exception as e:
118
+ logger.error(f"Error copying {repo_file_path}: {e}")
119
+ update_status(script, f"Error copying: {repo_file_path}: {e}")
120
+ return
121
+
122
+ try:
123
+ git_push_files(repo_path, f"Backup at {datetime.datetime.now()}", script)
124
+ logger.info("Backup complete")
125
+ update_status(script, "Backup Complete")
126
+ except Exception as e:
127
+ logger.error("Error pushing to the repo: ", e)
128
+ return
129
+
130
+ def start_backup_thread(script):
131
+ threading.Thread(target=backup_files, args=(script.backup_paths, None, script), daemon=True).start()
132
+
133
+ # Gradio UI Setup
134
+ def on_ui(script):
135
+ with gr.Column():
136
+ with gr.Row():
137
+ with gr.Column(scale=3):
138
+ hf_token_box = gr.Textbox(label="Huggingface Token", type='password', value=script.hf_token)
139
+ def on_token_change(token):
140
+ script.hf_token = token
141
+ script.save()
142
+ hf_token_box.change(on_token_change, inputs=[hf_token_box], outputs=None)
143
+ with gr.Column(scale=1):
144
+ status_box = gr.Textbox(label="Status", value=script.status)
145
+
146
+ def on_start_button():
147
+ start_backup_thread(script)
148
+ return "Starting Backup"
149
+
150
+ start_button = gr.Button(value="Start Backup")
151
+ start_button.click(on_start_button, inputs=None, outputs=[status_box])
152
+
153
+ with gr.Row():
154
+ with gr.Column():
155
+ sd_path_box = gr.Textbox(label="SD Webui Path", value=script.sd_path)
156
+ def on_sd_path_change(path):
157
+ script.sd_path = path
158
+ script.save()
159
+ sd_path_box.change(on_sd_path_change, inputs=[sd_path_box], outputs=None)
160
+ with gr.Column():
161
+ hf_user_box = gr.Textbox(label="Huggingface Username", value=script.hf_user)
162
+ def on_hf_user_change(user):
163
+ script.hf_user = user
164
+ script.save()
165
+ hf_user_box.change(on_hf_user_change, inputs=[hf_user_box], outputs=None)
166
+ with gr.Row():
167
+ backup_paths_box = gr.Textbox(label="Backup Paths (one path per line)", lines=4, value='\n'.join(script.backup_paths))
168
+ def on_backup_paths_change(paths):
169
+ paths_list = paths.split('\n')
170
+ paths_list = [p.strip() for p in paths_list if p.strip()]
171
+ script.backup_paths = paths_list
172
+ script.save()
173
+ backup_paths_box.change(on_backup_paths_change, inputs=[backup_paths_box], outputs=None)
174
+
175
+ def on_run(script, p, *args):
176
+ pass
177
+
178
+ def on_script_load(script):
179
+ script.hf_token = script.load().get(HF_TOKEN_KEY, '')
180
+ script.backup_paths = script.load().get(BACKUP_PATHS_KEY, DEFAULT_BACKUP_PATHS)
181
+ script.sd_path = script.load().get(SD_PATH_KEY, '')
182
+ script.hf_user = script.load().get(HF_USER_KEY, '')
183
+ script.status = "Not running"
184
+
185
+
186
+ script_callbacks.on_ui_tabs(on_ui)
187
+ script_callbacks.on_script_load(on_script_load)
scripts/ui-settings.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from modules import shared, script_callbacks
3
+
4
+ def on_ui_settings():
5
+ section = ('huggingface', "Hugging Face")
6
+ shared.opts.add_option(
7
+ "hf_write_key",
8
+ shared.OptionInfo(
9
+ "",
10
+ "Hugging Face Write API Key",
11
+ gr.Password,
12
+ {"interactive": True},
13
+ section=section
14
+ )
15
+ )
16
+ shared.opts.add_option(
17
+ "hf_read_key",
18
+ shared.OptionInfo(
19
+ "",
20
+ "Hugging Face Read API Key",
21
+ gr.Password,
22
+ {"interactive": True},
23
+ section=section
24
+ )
25
+ )
26
+ shared.opts.add_option(
27
+ "git_credential_store",
28
+ shared.OptionInfo(
29
+ True,
30
+ "Use Git Credential Store",
31
+ gr.Checkbox,
32
+ {"interactive": True},
33
+ section=section
34
+ )
35
+ )
36
+
37
+ script_callbacks.on_ui_settings(on_ui_settings)