civitaiarchive commited on
Commit
e9c50ee
·
1 Parent(s): 4185d56

Add civitai-to-hf-uploader

Browse files
Files changed (2) hide show
  1. README.md +7 -0
  2. main.py +217 -0
README.md CHANGED
@@ -7,6 +7,13 @@ sdk: gradio
7
  sdk_version: 5.27.0
8
  app_file: app.py
9
  pinned: false
 
 
 
 
 
 
 
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
7
  sdk_version: 5.27.0
8
  app_file: app.py
9
  pinned: false
10
+ license: mit
11
+ hf_oauth: true
12
+ hf_oauth_expiration_minutes: 43200
13
+ hf_oauth_scopes:
14
+ - read-repos
15
+ - write-repos
16
+ - manage-repos
17
  ---
18
 
19
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
main.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import os
3
+ import gradio as gr
4
+ from huggingface_hub import update_repo_visibility, whoami, upload_folder, create_repo, upload_file, update_repo_visibility
5
+
6
+ import gradio as gr
7
+ import re
8
+ import uuid
9
+ from typing import Optional
10
+ import json
11
+ def download_file(url, file_path, folder):
12
+ headers = {}
13
+ gr.Info("Downloading file from "+ url + " to "+ file_path)
14
+ try:
15
+ response = requests.get(url, headers=headers)
16
+ response.raise_for_status()
17
+ except requests.exceptions.HTTPError as e:
18
+ print(e)
19
+ if response.status_code == 401:
20
+ headers['Authorization'] = f'Bearer {os.environ["CIVITAI_API_KEY"]}'
21
+ try:
22
+ response = requests.get(url, headers=headers)
23
+ response.raise_for_status()
24
+ except requests.exceptions.RequestException as e:
25
+ raise gr.Error(f"Error downloading file: {e}")
26
+ else:
27
+ raise gr.Error(f"Error downloading file: {e}")
28
+ except requests.exceptions.RequestException as e:
29
+ raise gr.Error(f"Error downloading file: {e}")
30
+
31
+ os.makedirs(os.path.join(folder, os.path.dirname(file_path)), exist_ok=True)
32
+
33
+ with open(os.path.join(folder, file_path), 'wb') as f:
34
+ f.write(response.content)
35
+
36
+ gr.Info("Downloaded "+ file_path)
37
+
38
+ def get_files_by_username(username):
39
+ url = f"https://civitai.com/api/v1/models?username={username}&limit=100"
40
+ output = {}
41
+
42
+ while url:
43
+ response = requests.get(url)
44
+ data = response.json()
45
+ # Add current page items to the list
46
+ for model in data['items']:
47
+ for version in model['modelVersions']:
48
+ for file in version['files']:
49
+ output[str(model['id']) + '/' + str(version['id']) + '/' + file['name']] = file['downloadUrl']
50
+ return output
51
+
52
+ def get_files_by_model_id(model_id):
53
+ api_url = f"https://civitai.com/api/v1/models/{model_id}"
54
+ try:
55
+ response = requests.get(api_url)
56
+ response.raise_for_status()
57
+ model = response.json()
58
+
59
+ output = {}
60
+ for version in model['modelVersions']:
61
+ for file in version['files']:
62
+ output[str(model['id']) + '/' + str(version['id']) + '/' + file['name']] = file['downloadUrl']
63
+ return output
64
+
65
+ except requests.exceptions.RequestException as e:
66
+ raise gr.Error("Something went wrong in fetching CivitAI API")
67
+
68
+ def process_url(url, profile, do_download=True, folder="."):
69
+ if url.startswith("https://civitai.com/models/"):
70
+ model_id = url.split('/')[4]
71
+ files = get_files_by_model_id(model_id)
72
+ elif url.startswith("https://civitai.com/user/"):
73
+ username = url.split('/')[4]
74
+ files = get_files_by_username(username)
75
+ else:
76
+ raise gr.Error("Unknown CivitAI URL format, please provide model URL or user profile URL")
77
+
78
+ if do_download:
79
+ downloaded_files = {}
80
+ for dl_path, download_url in files.items():
81
+ try:
82
+ download_file(download_url, dl_path, folder)
83
+ downloaded_files[dl_path] = download_url
84
+ except Exception as e:
85
+ gr.Warning(f"Failed to download {dl_path}: {str(e)}")
86
+ return downloaded_files
87
+ return files
88
+
89
+
90
+
91
+ def add_mirror(repo_id):
92
+ response = requests.post("https://civitaiarchive.com/api/mirrors",
93
+ headers={
94
+ "Authorization": f"Bearer {os.environ['CIVITAIARCHIVE_API_KEY']}",
95
+ "Content-Type": "application/json"
96
+ },
97
+ json={
98
+ "type": "huggingface",
99
+ "url": repo_id
100
+ })
101
+ if response.status_code == 200:
102
+ gr.Info("Added mirror to CivitaiArchive.com")
103
+ else:
104
+ gr.Error("Failed to add mirror to CivitaiArchive.com")
105
+
106
+
107
+
108
+ def upload_civit_to_hf(profile: Optional[gr.OAuthProfile], oauth_token: gr.OAuthToken, url, destination_repo):
109
+ if not profile.name:
110
+ return gr.Error("Are you sure you are logged in?")
111
+
112
+ if not destination_repo:
113
+ return gr.Error("Please provide a destination repository name")
114
+
115
+ # validate destination repo is alphanumeric
116
+ if not re.match(r'^[a-zA-Z0-9_-]+$', destination_repo):
117
+ return gr.Error("Destination repository name must contain only alphanumeric characters, underscores, and hyphens")
118
+
119
+ folder = str(uuid.uuid4())
120
+ os.makedirs(folder, exist_ok=False)
121
+ gr.Info(f"Starting download from {url}")
122
+
123
+ try:
124
+ files = process_url(url, profile, folder=folder)
125
+ if not files or len(files.keys()) == 0:
126
+ return gr.Error("No files were downloaded. Please check the URL and try again.")
127
+
128
+ results = []
129
+
130
+ user_repo_id = f"{profile.username}/{destination_repo}"
131
+
132
+ # Try to create repo only if it doesn't exist
133
+ try:
134
+ create_repo(repo_id=user_repo_id, private=True, exist_ok=False, token=oauth_token.token)
135
+ gr.Info(f"Created new repository {user_repo_id}")
136
+ except Exception as e:
137
+ gr.Info(f"Repository {user_repo_id} already exists, will update it:"+ str(e))
138
+
139
+ gr.Info(f"Uploading models to {user_repo_id}...")
140
+
141
+ # Upload the model and card
142
+ upload_folder(
143
+ folder_path=folder,
144
+ repo_id=user_repo_id,
145
+ repo_type="model",
146
+ token=oauth_token.token
147
+ )
148
+ update_repo_visibility(repo_id=user_repo_id, private=False, token=oauth_token.token)
149
+ results.append(f"## [{user_repo_id}](https://huggingface.co/{user_repo_id})")
150
+
151
+ if not results:
152
+ return gr.Error("Failed to upload any models. Please check the logs for details.")
153
+
154
+ add_mirror(user_repo_id)
155
+
156
+ return "# Models uploaded to 🤗!\n" + "\n".join(results)
157
+
158
+ except Exception as e:
159
+ print(e)
160
+ raise gr.Error(f"Error during upload process: {str(e)}")
161
+ finally:
162
+ # Cleanup
163
+ if os.path.exists(folder):
164
+ import shutil
165
+ shutil.rmtree(folder)
166
+
167
+ css = '''
168
+ #login {
169
+ width: 100% !important;
170
+ margin: 0 auto;
171
+ }
172
+ #disabled_upload{
173
+ opacity: 0.5;
174
+ pointer-events:none;
175
+ }
176
+ '''
177
+
178
+ with gr.Blocks(css=css) as demo:
179
+ gr.Markdown('''# Upload CivitAI models to HuggingFace
180
+
181
+ You can upload either:
182
+ - A single model by providing a CivitAI model URL (e.g., https://civitai.com/models/144684)
183
+ - All models from a user by providing their profile URL (e.g., https://civitai.com/user/username)
184
+
185
+ This will create a new HuggingFace repository under your username if it doesn't exist.
186
+ Once uploaded, it will add this repository to CivitaiArchive.com as a mirror.
187
+ ''')
188
+
189
+ gr.LoginButton(elem_id="login")
190
+
191
+
192
+ with gr.Column() :
193
+ submit_source_civit = gr.Textbox(
194
+ placeholder="https://civitai.com/models/144684 or https://civitai.com/user/username",
195
+ label="CivitAI URL",
196
+ info="Enter either a model URL or user profile URL",
197
+ )
198
+ destination_repo = gr.Textbox(
199
+ placeholder="my-awesome-model",
200
+ label="HF Repo Name",
201
+ info="Name for the HuggingFace repository (a new one will be created if it doesn't exist)",
202
+ )
203
+
204
+ instructions = gr.HTML("")
205
+ submit_button_civit = gr.Button("Upload to Hugging Face", interactive=True)
206
+ output = gr.Markdown(label="Upload Progress")
207
+
208
+
209
+
210
+ submit_button_civit.click(
211
+ fn=upload_civit_to_hf,
212
+ inputs=[submit_source_civit, destination_repo],
213
+ outputs=[output]
214
+ )
215
+
216
+ demo.queue(default_concurrency_limit=50)
217
+ demo.launch()