Skip to content

Instantly share code, notes, and snippets.

@RupertAvery
Created May 2, 2025 22:37
Show Gist options
  • Save RupertAvery/2313682fecb430268cd0810f73a71556 to your computer and use it in GitHub Desktop.
Save RupertAvery/2313682fecb430268cd0810f73a71556 to your computer and use it in GitHub Desktop.
Script to download Checkpoint (model/LORA) metadata from CivitAI based on the models in your local machine
import os
import hashlib
import requests
import json
import argparse
# Config
BASE_URL = "https://civitai.com/api/v1"
EXTENSION = ".safetensors"
def get_sha256(file_path):
"""Compute the SHA-256 hash of a file."""
sha256_hash = hashlib.sha256()
with open(file_path, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
return sha256_hash.hexdigest()
def fetch_model_version_by_hash(file_hash):
"""Query Civitai for a model version using the file hash."""
url = f"{BASE_URL}/model-versions/by-hash/{file_hash}"
response = requests.get(url)
if response.status_code == 200:
return response.json()
else:
print(f"[ERROR] Failed to fetch model version for hash {file_hash} - {response.status_code}")
return None
def fetch_model_details(model_id):
"""Query Civitai for model details using the model ID."""
url = f"{BASE_URL}/models/{model_id}"
response = requests.get(url)
if response.status_code == 200:
return response.json()
else:
print(f"[ERROR] Failed to fetch model for ID {model_id} - {response.status_code}")
return None
def save_model_info(file_path, data):
"""Save JSON data next to the original file."""
json_path = os.path.splitext(file_path)[0] + ".json"
try:
with open(json_path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=4, ensure_ascii=False)
print(f"[INFO] Saved model info to {json_path}")
except Exception as e:
print(f"[ERROR] Failed to save JSON for {file_path} - {e}")
def main(search_dir):
for root, dirs, files in os.walk(search_dir):
for file in files:
if file.endswith(EXTENSION):
file_path = os.path.join(root, file)
print(f"\n[PROCESSING] {file_path}")
file_hash = get_sha256(file_path)
print(f"[HASH] {file_hash}")
model_version = fetch_model_version_by_hash(file_hash)
if not model_version:
continue
model_id = model_version.get("modelId")
model_info = {
"modelVersion": model_version
}
if model_id:
model_details = fetch_model_details(model_id)
if model_details:
model_info["model"] = model_details
save_model_info(file_path, model_info)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Scan .safetensors files and fetch Civitai metadata.")
parser.add_argument("search_dir", help="Path to directory containing .safetensors files")
args = parser.parse_args()
main(args.search_dir)
@RupertAvery
Copy link
Author

RupertAvery commented May 2, 2025

This will scan the models and calculate their SHA-256 to search in Civitai, then download the model information (trigger words, author comments) in json format, in the same folder as the model, using the name of the model with .json extension.

Usage:

python backup.py <path to models>

Disclaimer: This was 100% coded with ChatGPT (I could have done it, but ChatGPT is faster at typing)

@RupertAvery
Copy link
Author

Prompt 1:

Create a python script that will enumerate files with extension .safetensors from a location e.g. a network location "\192.168.1.71\ComfyUI\models\loras\Pony"

Then for each file, I want to calculate the SHA-256 of the file.

The, using the hash, I want to fetch from an api "{baseUrl}/model-versions/by-hash/{hash}" where baseUrl will be stored as https://civitai.com/api/v1 and hash is the hash of the file.

The result should return something that matches this class:

public class ModelVersion
{
    public int Id { get; set; }
    public int ModelId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime UpdatedAt { get; set; }
    public string DownloadUrl { get; set; }
    public List<string> TrainedWords { get; set; }
    public List<ModelFile> Files { get; set; }
    public List<ModelImage> Images { get; set; }
    public Stats Stats { get; set; }
    public string BaseModel { get; set; }

    // Additional properties
    //"trainingStatus": null,
    //"trainingDetails": null,
    //"baseModel": "SD 1.5",
    //"baseModelType": "Standard",
    //"earlyAccessTimeFrame": 0,
    //"description": null,
    //"vaeId": null,
}


/// <summary>
/// Used by model-versions api
/// </summary>
public class ModelVersion2 : ModelVersion
{
    public ModelVersionModel? Model { get; set; }
}



public class ModelVersionModel
{
    public string Name { get; set; }
    public ModelType Type { get; set; }
    public bool Nsfw { get; set; }
    public bool Poi { get; set; }
    public ModelMode? Mode { get; set; }
}

using that information, I want to fetch from the following url:

{baseUrl}/models/{modelVersion.ModelId}

Prompt 2:

I want to store it as json matching the input file

Prompt 3:

change SEARCH_DIR to be taken from the command line args

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment