mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 17:24:32 +02:00
fix metadata save and temp file handler
Signed-off-by: vladmandic <mandic00@live.com>
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
existing data files are auto-migrated on startup
|
||||
- further work on type consistency and type checking, thanks @awsr
|
||||
- log captured exceptions
|
||||
- improve temp folder handling and cleanup
|
||||
- add ui placeholders for future agent-scheduler work, thanks @ryanmeador
|
||||
- implement abort system on repeated errors, thanks @awsr
|
||||
currently used by lora and textual-inversion loaders
|
||||
@@ -46,6 +47,7 @@
|
||||
- ui css fixes for modernui
|
||||
- support lora inside prompt selector
|
||||
- framepack video save
|
||||
- metadata save for manual saves
|
||||
|
||||
## Update for 2026-01-22
|
||||
|
||||
|
||||
@@ -78,7 +78,8 @@ def image_from_url_text(filedata):
|
||||
filedata = filedata[len("data:image/jxl;base64,"):]
|
||||
filebytes = base64.decodebytes(filedata.encode('utf-8'))
|
||||
image = Image.open(io.BytesIO(filebytes))
|
||||
images.read_info_from_image(image)
|
||||
image.load()
|
||||
# images.read_info_from_image(image)
|
||||
return image
|
||||
|
||||
|
||||
|
||||
@@ -104,6 +104,9 @@ def on_tmpdir_changed():
|
||||
def cleanup_tmpdr():
|
||||
temp_dir = shared.opts.temp_dir
|
||||
if temp_dir == "" or not os.path.isdir(temp_dir):
|
||||
temp_dir = os.path.join(paths.temp_dir, "gradio")
|
||||
shared.log.debug(f'Temp folder: path="{temp_dir}"')
|
||||
if not os.path.isdir(temp_dir):
|
||||
return
|
||||
for root, _dirs, files in os.walk(temp_dir, topdown=False):
|
||||
for name in files:
|
||||
|
||||
+30
-16
@@ -10,7 +10,8 @@ from pathlib import Path
|
||||
from modules import shared, errors
|
||||
|
||||
|
||||
debug = errors.log.trace if os.environ.get('SD_NAMEGEN_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
debug= os.environ.get('SD_NAMEGEN_DEBUG', None) is not None
|
||||
debug_log = errors.log.trace if debug else lambda *args, **kwargs: None
|
||||
re_nonletters = re.compile(r'[\s' + string.punctuation + ']+')
|
||||
re_pattern = re.compile(r"(.*?)(?:\[([^\[\]]+)\]|$)")
|
||||
re_pattern_arg = re.compile(r"(.*)<([^>]*)>$")
|
||||
@@ -66,9 +67,9 @@ class FilenameGenerator:
|
||||
|
||||
def __init__(self, p, seed, prompt, image=None, grid=False, width=None, height=None):
|
||||
if p is None:
|
||||
debug('Filename generator init skip')
|
||||
debug_log('Filename generator init skip')
|
||||
else:
|
||||
debug(f'Filename generator init: seed={seed} prompt="{prompt}"')
|
||||
debug_log(f'Filename generator init: seed={seed} prompt="{prompt}"')
|
||||
self.p = p
|
||||
if seed is not None and int(seed) > 0:
|
||||
self.seed = seed
|
||||
@@ -163,7 +164,7 @@ class FilenameGenerator:
|
||||
def prompt_sanitize(self, prompt):
|
||||
invalid_chars = '#<>:\'"\\|?*\n\t\r'
|
||||
sanitized = prompt.translate({ ord(x): '_' for x in invalid_chars }).strip()
|
||||
debug(f'Prompt sanitize: input="{prompt}" output={sanitized}')
|
||||
debug_log(f'Prompt sanitize: input="{prompt}" output="{sanitized}"')
|
||||
return sanitized
|
||||
|
||||
def sanitize(self, filename):
|
||||
@@ -200,7 +201,7 @@ class FilenameGenerator:
|
||||
while len(os.path.abspath(fn)) > max_length:
|
||||
fn = fn[:-1]
|
||||
fn += ext
|
||||
debug(f'Filename sanitize: input="{filename}" parts={parts} output="{fn}" ext={ext} max={max_length} len={len(fn)}')
|
||||
debug_log(f'Filename sanitize: input="{filename}" parts={parts} output="{fn}" ext={ext} max={max_length} len={len(fn)}')
|
||||
return fn
|
||||
|
||||
def safe_int(self, s):
|
||||
@@ -234,25 +235,38 @@ class FilenameGenerator:
|
||||
|
||||
def apply(self, x):
|
||||
res = ''
|
||||
if debug:
|
||||
for k in self.replacements.keys():
|
||||
try:
|
||||
fn = self.replacements.get(k, None)
|
||||
debug_log(f'Namegen: key={k} value={fn(self)}')
|
||||
except Exception as e:
|
||||
shared.log.error(f'Namegen: key={k} {e}')
|
||||
errors.display(e, 'namegen')
|
||||
for m in re_pattern.finditer(x):
|
||||
text, pattern = m.groups()
|
||||
if pattern is None:
|
||||
res += text
|
||||
continue
|
||||
pattern_args = []
|
||||
while True:
|
||||
m = re_pattern_arg.match(pattern)
|
||||
if m is None:
|
||||
break
|
||||
pattern, arg = m.groups()
|
||||
pattern_args.insert(0, arg)
|
||||
debug_log(f'Filename apply: text="{text}" pattern="{pattern}"')
|
||||
if isinstance(pattern, list):
|
||||
pattern = ' '.join(pattern)
|
||||
if pattern is None or not isinstance(pattern, str) or pattern.strip() == '':
|
||||
debug_log(f'Filename skip: pattern="{pattern}"')
|
||||
res += text
|
||||
continue
|
||||
|
||||
_pattern = pattern
|
||||
pattern_args = []
|
||||
while True:
|
||||
m = re_pattern_arg.match(_pattern)
|
||||
if m is None:
|
||||
break
|
||||
_pattern, arg = m.groups()
|
||||
pattern_args.insert(0, arg)
|
||||
|
||||
fun = self.replacements.get(pattern.lower(), None)
|
||||
if fun is not None:
|
||||
try:
|
||||
debug(f'Filename apply: pattern={pattern.lower()} args={pattern_args}')
|
||||
replacement = fun(self, *pattern_args)
|
||||
debug_log(f'Filename apply: pattern="{pattern}" args={pattern_args} replacement="{replacement}"')
|
||||
except Exception as e:
|
||||
replacement = None
|
||||
errors.display(e, 'namegen')
|
||||
|
||||
@@ -4,6 +4,7 @@ import sys
|
||||
import json
|
||||
import shlex
|
||||
import argparse
|
||||
import tempfile
|
||||
from installer import log
|
||||
|
||||
|
||||
@@ -18,12 +19,16 @@ cli = parser.parse_known_args(argv)[0]
|
||||
parser.add_argument("--config", type=str, default=os.environ.get("SD_CONFIG", os.path.join(cli.data_dir, 'config.json')), help="Use specific server configuration file, default: %(default)s") # twice because we want data_dir
|
||||
cli = parser.parse_known_args(argv)[0]
|
||||
config_path = cli.config if os.path.isabs(cli.config) else os.path.join(cli.data_dir, cli.config)
|
||||
|
||||
try:
|
||||
with open(config_path, 'r', encoding='utf8') as f:
|
||||
config = json.load(f)
|
||||
except Exception:
|
||||
config = {}
|
||||
|
||||
temp_dir = config.get('temp_dir', '')
|
||||
if len(temp_dir) == 0:
|
||||
temp_dir = tempfile.gettempdir()
|
||||
reference_path = os.path.join('models', 'Reference')
|
||||
modules_path = os.path.dirname(os.path.realpath(__file__))
|
||||
script_path = os.path.dirname(modules_path)
|
||||
|
||||
+15
-13
@@ -5,8 +5,7 @@ import shutil
|
||||
import platform
|
||||
import subprocess
|
||||
import gradio as gr
|
||||
from modules import call_queue, shared, errors, ui_sections, ui_symbols, ui_components, generation_parameters_copypaste, images, scripts_manager, script_callbacks, infotext, processing
|
||||
from modules.paths import resolve_output_path
|
||||
from modules import paths, call_queue, shared, errors, ui_sections, ui_symbols, ui_components, generation_parameters_copypaste, images, scripts_manager, script_callbacks, infotext, processing
|
||||
|
||||
|
||||
folder_symbol = ui_symbols.folder
|
||||
@@ -106,7 +105,7 @@ def delete_files(js_data, files, all_files, index):
|
||||
|
||||
|
||||
def save_files(js_data, files, html_info, index):
|
||||
os.makedirs(resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save), exist_ok=True)
|
||||
os.makedirs(paths.resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save), exist_ok=True)
|
||||
|
||||
class PObject: # pylint: disable=too-few-public-methods
|
||||
def __init__(self, d=None):
|
||||
@@ -116,6 +115,7 @@ def save_files(js_data, files, html_info, index):
|
||||
self.prompt = getattr(self, 'prompt', None) or getattr(self, 'Prompt', None) or ''
|
||||
self.negative_prompt = getattr(self, 'negative_prompt', None) or getattr(self, 'Negative_prompt', None) or ''
|
||||
self.sampler = getattr(self, 'sampler', None) or getattr(self, 'Sampler', None) or ''
|
||||
self.sampler_name = self.sampler
|
||||
self.seed = getattr(self, 'seed', None) or getattr(self, 'Seed', None) or 0
|
||||
self.steps = getattr(self, 'steps', None) or getattr(self, 'Steps', None) or 0
|
||||
self.width = getattr(self, 'width', None) or getattr(self, 'Width', None) or getattr(self, 'Size-1', None) or 0
|
||||
@@ -128,13 +128,16 @@ def save_files(js_data, files, html_info, index):
|
||||
self.styles = getattr(self, 'styles', None) or getattr(self, 'Styles', None) or []
|
||||
self.styles = [s.strip() for s in self.styles.split(',')] if isinstance(self.styles, str) else self.styles
|
||||
|
||||
self.outpath_grids = resolve_output_path(shared.opts.outdir_grids, shared.opts.outdir_txt2img_grids)
|
||||
self.outpath_grids = paths.resolve_output_path(shared.opts.outdir_grids, shared.opts.outdir_txt2img_grids)
|
||||
self.infotexts = getattr(self, 'infotexts', [html_info])
|
||||
self.infotext = self.infotexts[0] if len(self.infotexts) > 0 else html_info
|
||||
self.all_negative_prompt = getattr(self, 'all_negative_prompts', [self.negative_prompt])
|
||||
self.all_prompts = getattr(self, 'all_prompts', [self.prompt])
|
||||
self.all_seeds = getattr(self, 'all_seeds', [self.seed])
|
||||
self.all_subseeds = getattr(self, 'all_subseeds', [self.subseed])
|
||||
|
||||
self.n_iter = 1
|
||||
self.batch_size = 1
|
||||
try:
|
||||
data = json.loads(js_data)
|
||||
except Exception:
|
||||
@@ -159,17 +162,17 @@ def save_files(js_data, files, html_info, index):
|
||||
p.all_prompts.append(p.prompt)
|
||||
while len(p.infotexts) <= i:
|
||||
p.infotexts.append(p.infotext)
|
||||
if 'name' in filedata and ('tmp' not in filedata['name']) and os.path.isfile(filedata['name']):
|
||||
if 'name' in filedata and (paths.temp_dir not in filedata['name']) and os.path.isfile(filedata['name']):
|
||||
fullfn = filedata['name']
|
||||
fullfns.append(fullfn)
|
||||
destination = resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save)
|
||||
destination = paths.resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save)
|
||||
namegen = images.FilenameGenerator(p, seed=p.all_seeds[i], prompt=p.all_prompts[i], image=None) # pylint: disable=no-member
|
||||
dirname = namegen.apply(shared.opts.directories_filename_pattern or "[prompt_words]").lstrip(' ').rstrip('\\ /')
|
||||
destination = os.path.join(destination, dirname)
|
||||
destination = namegen.sanitize(destination)
|
||||
os.makedirs(destination, exist_ok = True)
|
||||
tgt_filename = os.path.join(destination, os.path.basename(fullfn))
|
||||
relfn = os.path.relpath(tgt_filename, resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save))
|
||||
relfn = os.path.relpath(tgt_filename, paths.resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save))
|
||||
filenames.append(relfn)
|
||||
if not os.path.exists(tgt_filename):
|
||||
try:
|
||||
@@ -195,21 +198,20 @@ def save_files(js_data, files, html_info, index):
|
||||
if len(info) == 0:
|
||||
info = None
|
||||
if (js_data is None or len(js_data) == 0) and image is not None and image.info is not None:
|
||||
info = image.info.pop('parameters', None) or image.info.pop('UserComment', None)
|
||||
geninfo, _ = images.read_info_from_image(image)
|
||||
items = infotext.parse(geninfo)
|
||||
info, _items = images.read_info_from_image(image)
|
||||
items = infotext.parse(info)
|
||||
p = PObject(items)
|
||||
try:
|
||||
seed = p.all_seeds[i] if i < len(p.all_seeds) else p.seed
|
||||
prompt = p.all_prompts[i] if i < len(p.all_prompts) else p.prompt
|
||||
fullfn, txt_fullfn, _exif = images.save_image(image, resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save), "", seed=seed, prompt=prompt, info=info, extension=shared.opts.samples_format, grid=is_grid, p=p)
|
||||
fullfn, txt_fullfn, _exif = images.save_image(image, paths.resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save), "", seed=seed, prompt=prompt, info=info, extension=shared.opts.samples_format, grid=is_grid, p=p)
|
||||
except Exception as e:
|
||||
fullfn, txt_fullfn = None, None
|
||||
shared.log.error(f'Save: image={image} i={i} seeds={p.all_seeds} prompts={p.all_prompts}')
|
||||
errors.display(e, 'save')
|
||||
if fullfn is None:
|
||||
continue
|
||||
filename = os.path.relpath(fullfn, resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save))
|
||||
filename = os.path.relpath(fullfn, paths.resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save))
|
||||
filenames.append(filename)
|
||||
fullfns.append(fullfn)
|
||||
if txt_fullfn:
|
||||
@@ -217,7 +219,7 @@ def save_files(js_data, files, html_info, index):
|
||||
# fullfns.append(txt_fullfn)
|
||||
script_callbacks.image_save_btn_callback(filename)
|
||||
if shared.opts.samples_save_zip and len(fullfns) > 1:
|
||||
zip_filepath = os.path.join(resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save), "images.zip")
|
||||
zip_filepath = os.path.join(paths.resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save), "images.zip")
|
||||
from zipfile import ZipFile
|
||||
with ZipFile(zip_filepath, "w") as zip_file:
|
||||
for i in range(len(fullfns)):
|
||||
|
||||
+1
-1
Submodule wiki updated: 440b883838...a678731c5d
Reference in New Issue
Block a user