Skip to content

Instantly share code, notes, and snippets.

@catboxanon
Last active July 28, 2023 22:33
Show Gist options
  • Save catboxanon/42ce1edae54748274b4616780bdbeb9d to your computer and use it in GitHub Desktop.
Save catboxanon/42ce1edae54748274b4616780bdbeb9d to your computer and use it in GitHub Desktop.
from pathlib import Path
from tqdm import tqdm
import argparse
def read_metadata_from_safetensors(filename):
import json
with open(filename, mode="rb") as file:
metadata_len = file.read(8)
metadata_len = int.from_bytes(metadata_len, "little")
json_start = file.read(2)
assert metadata_len > 2 and json_start in (b'{"', b"{'"), f"{filename} is not a safetensors file"
json_data = json_start + file.read(metadata_len-2)
json_obj = json.loads(json_data)
res = {}
for k, v in json_obj.get("__metadata__", {}).items():
res[k] = v
if isinstance(v, str) and v[0:1] == '{':
try:
res[k] = json.loads(v)
except Exception as e:
pass
return res
def human_size(bytes, units=[' bytes','KB','MB','GB','TB', 'PB', 'EB']):
return str(bytes) + units[0] if bytes < 1024 else human_size(bytes>>10, units[1:])
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("--src", type=str, required=True, default=None, metavar='PATH', help="Root directory where LoRAs models are stored.")
parser.add_argument("--dst", type=str, required=True, default=None, metavar='PATH', help="Destination directory to store LyCORIS models.")
args = parser.parse_args()
src = Path(args.src)
dst = Path(args.dst)
total = 0
to_move: list[Path] = []
extras: list[Path] = []
print('Scanning...')
for f in tqdm(src.rglob('*.safetensors')):
meta = read_metadata_from_safetensors(f)
if meta and 'ss_network_module' in meta and meta['ss_network_module'] not in ['sd_scripts.networks.lora', 'sd_scripts.networks.dylora', 'networks.lora', 'networks.dylora']:
to_move += list(Path(f.parent).glob(f'{f.stem}.*'))
total += 1
if (
Path(f.parent) not in extras
and len(list(Path(f.parent).glob('*.safetensors'))) < 10
and (
len(list(Path(f.parent).glob('*.txt'))) > 0
or len(list(Path(f.parent).glob('*.png')))
or len(list(Path(f.parent).glob('*.jpg')))
)
):
extras.append(Path(f.parent))
size = 0
for f in to_move:
size += f.stat().st_size
confirm = input(f'{len(to_move)} files consisting of {human_size(size)} will be moved. Continue? [Y/n]: ').lower().strip()
if confirm in ['no','n'] or confirm not in ['yes', 'y', '']:
print('Exiting')
exit(0)
print('Moving...')
for f in tqdm(to_move):
new_path = dst / f.relative_to(src)
new_path.parent.mkdir(parents=True, exist_ok=True)
f.rename(new_path)
continue
print('\nThe following paths may contain extra related files:')
for f in extras:
print(str(f))
if len(extras) > 0:
print('---\nPlease see the above for paths that may contain extra related files.\n---')
print('Done!')
@catboxanon
Copy link
Author

This should be considered deprecated now, as version 1.5.0 of the webui now supports all different LoRA types natively. https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases/tag/v1.5.0

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