mirror of
https://github.com/vladmandic/sdnext.git
synced 2026-01-27 15:02:48 +03:00
302 lines
13 KiB
Python
Executable File
302 lines
13 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# pylint: disable=no-member
|
|
import os
|
|
import re
|
|
import json
|
|
import time
|
|
import logging
|
|
import importlib
|
|
import asyncio
|
|
import argparse
|
|
from pathlib import Path
|
|
from util import Map, log
|
|
from sdapi import get, post, close
|
|
from generate import generate # pylint: disable=import-error
|
|
grid = importlib.import_module('image-grid').grid
|
|
|
|
|
|
options = Map({
|
|
# used by extra networks
|
|
'prompt': 'photo of <keyword> <embedding>, photograph, posing, pose, high detailed, intricate, elegant, sharp focus, skin texture, looking forward, facing camera, 135mm, shot on dslr, canon 5d, 4k, modelshoot style, cinematic lighting',
|
|
# used by models
|
|
'prompts': [
|
|
('photo citiscape', 'cityscape during night, photorealistic, high detailed, sharp focus, depth of field, 4k'),
|
|
('photo car', 'photo of a sports car, high detailed, sharp focus, dslr, cinematic lighting, realistic'),
|
|
('photo woman', 'portrait photo of beautiful woman, high detailed, dslr, 35mm'),
|
|
('photo naked', 'full body photo of beautiful sexy naked woman, high detailed, dslr, 35mm'),
|
|
|
|
('photo taylor', 'portrait photo of beautiful woman taylor swift, high detailed, sharp focus, depth of field, dslr, 35mm <lora:taylor-swift:1>'),
|
|
('photo ti-mia', 'portrait photo of beautiful woman "ti-mia", naked, high detailed, dslr, 35mm'),
|
|
('photo ti-vlado', 'portrait photo of man "ti-vlado", high detailed, dslr, 35mm'),
|
|
('photo lora-vlado', 'portrait photo of man vlado, high detailed, dslr, 35mm <lora:vlado-original:1>'),
|
|
|
|
('wlop', 'a stunning portrait of sexy teen girl in a wet t-shirt, vivid color palette, digital painting, octane render, highly detailed, particles, light effect, volumetric lighting, art by wlop'),
|
|
('greg rutkowski', 'beautiful woman, high detailed, sharp focus, depth of field, 4k, art by greg rutkowski'),
|
|
('carne griffiths', 'beautiful woman taylor swift, high detailed, sharp focus, depth of field, art by carne griffiths <lora:taylor-swift:1>'),
|
|
('carne griffiths', 'man vlado, high detailed, sharp focus, depth of field, art by carne griffiths <lora:vlado-full:1>'),
|
|
],
|
|
# save format
|
|
'format': '.jpg',
|
|
# used by generate script
|
|
'paths': {
|
|
"root": "/mnt/c/Users/mandi/OneDrive/Generative/Generate",
|
|
"generate": "image",
|
|
"upscale": "upscale",
|
|
"grid": "grid",
|
|
},
|
|
# generate params
|
|
'generate': {
|
|
'detailer': True,
|
|
'prompt': '',
|
|
'negative_prompt': 'foggy, blurry, blurred, duplicate, ugly, mutilated, mutation, mutated, out of frame, bad anatomy, disfigured, deformed, censored, low res, low resolution, watermark, text, poorly drawn face, poorly drawn hands, signature',
|
|
'steps': 20,
|
|
'batch_size': 2,
|
|
'n_iter': 1,
|
|
'seed': -1,
|
|
'sampler_name': 'UniPC',
|
|
'cfg_scale': 6,
|
|
'width': 512,
|
|
'height': 512,
|
|
},
|
|
'lora': {
|
|
'strength': 1.0,
|
|
},
|
|
})
|
|
|
|
|
|
def preview_exists(folder, model):
|
|
model = os.path.splitext(model)[0]
|
|
for suffix in ['', '.preview']:
|
|
for ext in ['.jpg', '.png', '.webp']:
|
|
fn = os.path.join(folder, f'{model}{suffix}{ext}')
|
|
if os.path.exists(fn):
|
|
return True
|
|
return False
|
|
|
|
|
|
async def preview_models(params):
|
|
data = await get('/sdapi/v1/sd-models')
|
|
allmodels = [m['title'] for m in data]
|
|
models = []
|
|
excluded = []
|
|
for m in allmodels: # loop through all registered models
|
|
ok = True
|
|
for e in params.exclude: # check if model is excluded
|
|
if e in m:
|
|
excluded.append(m)
|
|
ok = False
|
|
break
|
|
if ok:
|
|
short = m.split(' [')[0]
|
|
short = short.replace('.ckpt', '').replace('.safetensors', '')
|
|
models.append(short)
|
|
if len(params.input) > 0: # check if model is included in cmd line
|
|
filtered = []
|
|
for m in params.input:
|
|
if m in models:
|
|
filtered.append(m)
|
|
else:
|
|
log.error({ 'model not found': m })
|
|
return
|
|
models = filtered
|
|
log.info({ 'models preview' })
|
|
log.info({ 'models': len(models), 'excluded': len(excluded) })
|
|
opt = await get('/sdapi/v1/options')
|
|
log.info({ 'total jobs': len(models) * options.generate.batch_size, 'per-model': options.generate.batch_size })
|
|
log.info(json.dumps(options, indent=2))
|
|
for model in models:
|
|
if preview_exists(opt['ckpt_dir'], model) and len(params.input) == 0: # if model preview exists and not manually included
|
|
log.info({ 'model preview exists': model })
|
|
continue
|
|
fn = os.path.join(opt['ckpt_dir'], os.path.splitext(model)[0] + options.format)
|
|
log.info({ 'model load': model })
|
|
|
|
opt['sd_model_checkpoint'] = model
|
|
del opt['sd_lora']
|
|
del opt['sd_lyco']
|
|
await post('/sdapi/v1/options', opt)
|
|
opt = await get('/sdapi/v1/options')
|
|
images = []
|
|
labels = []
|
|
t0 = time.time()
|
|
for label, p in options.prompts:
|
|
options.generate.prompt = p
|
|
log.info({ 'model generating': model, 'label': label, 'prompt': options.generate.prompt })
|
|
data = await generate(options = options, quiet=True)
|
|
if 'image' in data:
|
|
for img in data['image']:
|
|
images.append(img)
|
|
labels.append(label)
|
|
else:
|
|
log.error({ 'model': model, 'error': data })
|
|
t1 = time.time()
|
|
if len(images) == 0:
|
|
log.error({ 'model': model, 'error': 'no images generated' })
|
|
continue
|
|
image = grid(images = images, labels = labels, border = 8)
|
|
log.info({ 'saving preview': fn, 'images': len(images), 'size': [image.width, image.height] })
|
|
image.save(fn)
|
|
t = t1 - t0
|
|
its = 1.0 * options.generate.steps * len(images) / t
|
|
log.info({ 'model preview created': model, 'image': fn, 'images': len(images), 'grid': [image.width, image.height], 'time': round(t, 2), 'its': round(its, 2) })
|
|
|
|
opt = await get('/sdapi/v1/options')
|
|
if opt['sd_model_checkpoint'] != params.model:
|
|
log.info({ 'model set default': params.model })
|
|
opt['sd_model_checkpoint'] = params.model
|
|
del opt['sd_lora']
|
|
del opt['sd_lyco']
|
|
await post('/sdapi/v1/options', opt)
|
|
|
|
|
|
async def lora(params):
|
|
opt = await get('/sdapi/v1/options')
|
|
folder = opt['lora_dir']
|
|
if not os.path.exists(folder):
|
|
log.error({ 'lora directory not found': folder })
|
|
return
|
|
models1 = list(Path(folder).glob('**/*.safetensors'))
|
|
models2 = list(Path(folder).glob('**/*.ckpt'))
|
|
models = [os.path.splitext(f)[0] for f in models1 + models2]
|
|
log.info({ 'loras': len(models) })
|
|
for model in models:
|
|
if preview_exists('', model) and len(params.input) == 0: # if model preview exists and not manually included
|
|
log.info({ 'lora preview exists': model })
|
|
continue
|
|
fn = model + options.format
|
|
model = os.path.basename(model)
|
|
images = []
|
|
labels = []
|
|
t0 = time.time()
|
|
keywords = re.sub(r'\d', '', model)
|
|
keywords = keywords.replace('-v', ' ').replace('-', ' ').strip().split(' ')
|
|
keyword = '\"' + '\" \"'.join(keywords) + '\"'
|
|
options.generate.prompt = options.prompt.replace('<keyword>', keyword)
|
|
options.generate.prompt = options.generate.prompt.replace('<embedding>', '')
|
|
options.generate.prompt += f' <lora:{model}:{options.lora.strength}>'
|
|
log.info({ 'lora generating': model, 'keyword': keyword, 'prompt': options.generate.prompt })
|
|
data = await generate(options = options, quiet=True)
|
|
if 'image' in data:
|
|
for img in data['image']:
|
|
images.append(img)
|
|
labels.append(keyword)
|
|
else:
|
|
log.error({ 'lora': model, 'keyword': keyword, 'error': data })
|
|
t1 = time.time()
|
|
if len(images) == 0:
|
|
log.error({ 'model': model, 'error': 'no images generated' })
|
|
continue
|
|
image = grid(images = images, labels = labels, border = 8)
|
|
log.info({ 'saving preview': fn, 'images': len(images), 'size': [image.width, image.height] })
|
|
image.save(fn)
|
|
t = t1 - t0
|
|
its = 1.0 * options.generate.steps * len(images) / t
|
|
log.info({ 'lora preview created': model, 'image': fn, 'images': len(images), 'grid': [image.width, image.height], 'time': round(t, 2), 'its': round(its, 2) })
|
|
|
|
|
|
async def lyco(params):
|
|
opt = await get('/sdapi/v1/options')
|
|
folder = opt['lyco_dir']
|
|
if not os.path.exists(folder):
|
|
log.error({ 'lyco directory not found': folder })
|
|
return
|
|
models1 = list(Path(folder).glob('**/*.safetensors'))
|
|
models2 = list(Path(folder).glob('**/*.ckpt'))
|
|
models = [os.path.splitext(f)[0] for f in models1 + models2]
|
|
log.info({ 'lycos': len(models) })
|
|
for model in models:
|
|
if preview_exists('', model) and len(params.input) == 0: # if model preview exists and not manually included
|
|
log.info({ 'lyco preview exists': model })
|
|
continue
|
|
fn = model + options.format
|
|
model = os.path.basename(model)
|
|
images = []
|
|
labels = []
|
|
t0 = time.time()
|
|
keywords = re.sub(r'\d', '', model)
|
|
keywords = keywords.replace('-v', ' ').replace('-', ' ').strip().split(' ')
|
|
keyword = '\"' + '\" \"'.join(keywords) + '\"'
|
|
options.generate.prompt = options.prompt.replace('<keyword>', keyword)
|
|
options.generate.prompt = options.generate.prompt.replace('<embedding>', '')
|
|
options.generate.prompt += f' <lyco:{model}:{options.lora.strength}>'
|
|
log.info({ 'lyco generating': model, 'keyword': keyword, 'prompt': options.generate.prompt })
|
|
data = await generate(options = options, quiet=True)
|
|
if 'image' in data:
|
|
for img in data['image']:
|
|
images.append(img)
|
|
labels.append(keyword)
|
|
else:
|
|
log.error({ 'lyco': model, 'keyword': keyword, 'error': data })
|
|
t1 = time.time()
|
|
if len(images) == 0:
|
|
log.error({ 'model': model, 'error': 'no images generated' })
|
|
continue
|
|
image = grid(images = images, labels = labels, border = 8)
|
|
log.info({ 'saving preview': fn, 'images': len(images), 'size': [image.width, image.height] })
|
|
image.save(fn)
|
|
t = t1 - t0
|
|
its = 1.0 * options.generate.steps * len(images) / t
|
|
log.info({ 'lyco preview created': model, 'image': fn, 'images': len(images), 'grid': [image.width, image.height], 'time': round(t, 2), 'its': round(its, 2) })
|
|
|
|
|
|
async def embedding(params):
|
|
opt = await get('/sdapi/v1/options')
|
|
folder = opt['embeddings_dir']
|
|
if not os.path.exists(folder):
|
|
log.error({ 'embeddings directory not found': folder })
|
|
return
|
|
models = [os.path.splitext(f)[0] for f in Path(folder).glob('**/*.pt')]
|
|
log.info({ 'embeddings': len(models) })
|
|
for model in models:
|
|
if preview_exists(folder, model) and len(params.input) == 0: # if model preview exists and not manually included
|
|
log.info({ 'embedding preview exists': model })
|
|
continue
|
|
fn = os.path.join(folder, model + '.preview' + options.format)
|
|
images = []
|
|
labels = []
|
|
t0 = time.time()
|
|
keyword = '\"' + re.sub(r'\d', '', model) + '\"'
|
|
options.generate.batch_size = 4
|
|
options.generate.prompt = options.prompt.replace('<keyword>', keyword)
|
|
options.generate.prompt = options.generate.prompt.replace('<embedding>', '')
|
|
log.info({ 'embedding generating': model, 'keyword': keyword, 'prompt': options.generate.prompt })
|
|
data = await generate(options = options, quiet=True)
|
|
if 'image' in data:
|
|
for img in data['image']:
|
|
images.append(img)
|
|
labels.append(keyword)
|
|
else:
|
|
log.error({ 'embeding': model, 'keyword': keyword, 'error': data })
|
|
t1 = time.time()
|
|
if len(images) == 0:
|
|
log.error({ 'model': model, 'error': 'no images generated' })
|
|
continue
|
|
image = grid(images = images, labels = labels, border = 8)
|
|
log.info({ 'saving preview': fn, 'images': len(images), 'size': [image.width, image.height] })
|
|
image.save(fn)
|
|
t = t1 - t0
|
|
its = 1.0 * options.generate.steps * len(images) / t
|
|
log.info({ 'embeding preview created': model, 'image': fn, 'images': len(images), 'grid': [image.width, image.height], 'time': round(t, 2), 'its': round(its, 2) })
|
|
|
|
|
|
async def create_previews(params):
|
|
await preview_models(params)
|
|
await lora(params)
|
|
await lyco(params)
|
|
await embedding(params)
|
|
await close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser(description = 'generate model previews')
|
|
parser.add_argument('--model', default='best/icbinp-icantbelieveIts-final.safetensors [73f48afbdc]', help="model used to create extra network previews")
|
|
parser.add_argument('--exclude', default=['sd-v20', 'sd-v21', 'inpainting', 'pix2pix'], help="exclude models with keywords")
|
|
parser.add_argument('--debug', default = False, action='store_true', help = 'print extra debug information')
|
|
parser.add_argument('input', type = str, nargs = '*')
|
|
args = parser.parse_args()
|
|
if args.debug:
|
|
log.setLevel(logging.DEBUG)
|
|
log.debug({ 'debug': True })
|
|
log.debug({ 'args': args.__dict__ })
|
|
asyncio.run(create_previews(args))
|