Skip to content

Commit 2ee23df

Browse files
committed
feature: adds --format flag for cli of imagine, upscale, and edit.
1 parent 374f608 commit 2ee23df

File tree

9 files changed

+322
-48
lines changed

9 files changed

+322
-48
lines changed

imaginairy/api/generate.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
import logging
44
import os
5+
from datetime import datetime, timezone
56
from typing import TYPE_CHECKING, Callable
67

8+
from imaginairy.config import DEFAULT_SHARED_FILE_FORMAT_TEMPLATE, DEFAULT_SHARED_OUTDIR
9+
710
if TYPE_CHECKING:
811
from imaginairy.schema import ImaginePrompt
912

@@ -24,10 +27,10 @@
2427

2528
def imagine_image_files(
2629
prompts: "list[ImaginePrompt] | ImaginePrompt",
27-
outdir: str,
30+
outdir: str = DEFAULT_SHARED_OUTDIR,
31+
format_template: str = DEFAULT_SHARED_FILE_FORMAT_TEMPLATE,
2832
precision: str = "autocast",
2933
record_step_images: bool = False,
30-
output_file_extension: str = "jpg",
3134
print_caption: bool = False,
3235
make_gif: bool = False,
3336
make_compare_gif: bool = False,
@@ -60,14 +63,18 @@ def imagine_image_files(
6063
from imaginairy.api.video_sample import generate_video
6164
from imaginairy.utils import get_next_filenumber, prompt_normalized
6265
from imaginairy.utils.animations import make_bounce_animation
66+
from imaginairy.utils.format_file_name import format_filename
6367
from imaginairy.utils.img_utils import pillow_fit_image_within
6468

6569
generated_imgs_path = os.path.join(outdir, "generated")
6670
os.makedirs(generated_imgs_path, exist_ok=True)
6771

6872
base_count = get_next_filenumber(generated_imgs_path)
69-
output_file_extension = output_file_extension.lower()
70-
if output_file_extension not in {"jpg", "png"}:
73+
74+
format_template, output_file_extension = os.path.splitext(format_template)
75+
if not output_file_extension:
76+
output_file_extension = ".jpg"
77+
elif output_file_extension not in {".jpg", ".png"}:
7178
raise ValueError("Must output a png or jpg")
7279

7380
if not isinstance(prompts, list):
@@ -101,15 +108,29 @@ def _record_step(img, description, image_count, step_count, prompt):
101108
if prompt.init_image:
102109
img_str = f"_img2img-{prompt.init_image_strength}"
103110

104-
basefilename = (
105-
f"{base_count:06}_{prompt.seed}_{prompt.solver_type.replace('_', '')}{prompt.steps}_"
106-
f"PS{prompt.prompt_strength}{img_str}_{prompt_normalized(prompt.prompt_text)}"
111+
now = datetime.now(timezone.utc)
112+
113+
format_data = {
114+
"file_sequence_number": f"{base_count:06}",
115+
"seed": f"{prompt.seed}",
116+
"steps": f"{prompt.steps}",
117+
"solver_type": f"{prompt.solver_type.replace('_', '')}",
118+
"prompt_strength": f"PS{prompt.prompt_strength}",
119+
"prompt_text": f"{prompt_normalized(prompt.prompt_text)}",
120+
"img_str": f"{img_str}",
121+
"file_extension": f"{output_file_extension}",
122+
"now": now,
123+
}
124+
125+
basefilename = format_filename(
126+
format_template=format_template, data=format_data
107127
)
128+
108129
for image_type in result.images:
109130
subpath = os.path.join(outdir, image_type)
110131
os.makedirs(subpath, exist_ok=True)
111132
filepath = os.path.join(
112-
subpath, f"{basefilename}_[{image_type}].{output_file_extension}"
133+
subpath, f"{basefilename}_[{image_type}]{output_file_extension}"
113134
)
114135
result.save(filepath, image_type=image_type)
115136
logger.info(f" {image_type:<22} {filepath}")

imaginairy/cli/edit.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def edit_cmd(
5353
negative_prompt,
5454
prompt_strength,
5555
outdir,
56-
output_file_extension,
56+
format_template,
5757
repeats,
5858
size,
5959
steps,
@@ -109,7 +109,7 @@ def edit_cmd(
109109
init_image=image_paths,
110110
init_image_strength=image_strength,
111111
outdir=outdir,
112-
output_file_extension=output_file_extension,
112+
format_template=format_template,
113113
repeats=repeats,
114114
size=size,
115115
steps=steps,

imaginairy/cli/imagine.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ def imagine_cmd(
8484
init_image,
8585
init_image_strength,
8686
outdir,
87-
output_file_extension,
8887
repeats,
8988
size,
9089
steps,
@@ -122,6 +121,7 @@ def imagine_cmd(
122121
control_strength,
123122
control_mode,
124123
videogen,
124+
format_template,
125125
):
126126
"""
127127
Generate images via AI.
@@ -192,7 +192,7 @@ def imagine_cmd(
192192
init_image=init_image,
193193
init_image_strength=init_image_strength,
194194
outdir=outdir,
195-
output_file_extension=output_file_extension,
195+
format_template=format_template,
196196
repeats=repeats,
197197
size=size,
198198
steps=steps,

imaginairy/cli/shared.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import click
88

99
from imaginairy import config
10+
from imaginairy.config import DEFAULT_SHARED_FILE_FORMAT_TEMPLATE
1011

1112
logger = logging.getLogger(__name__)
1213

@@ -36,7 +37,7 @@ def _imagine_cmd(
3637
init_image,
3738
init_image_strength,
3839
outdir,
39-
output_file_extension,
40+
format_template,
4041
repeats,
4142
size,
4243
steps,
@@ -220,8 +221,8 @@ def _imagine_cmd(
220221
filenames = imagine_image_files(
221222
prompts,
222223
outdir=outdir,
224+
format_template=format_template,
223225
record_step_images=show_work,
224-
output_file_extension=output_file_extension,
225226
print_caption=caption,
226227
precision=precision,
227228
make_gif=make_gif,
@@ -320,11 +321,15 @@ def temp_f():
320321
help="Where to write results to.",
321322
),
322323
click.option(
323-
"--output-file-extension",
324-
default="jpg",
325-
show_default=True,
326-
type=click.Choice(["jpg", "png"]),
327-
help="Where to write results to.",
324+
"--format",
325+
"format_template",
326+
default=DEFAULT_SHARED_FILE_FORMAT_TEMPLATE,
327+
type=str,
328+
help="Formats the file name. Default value will save '{file_sequence_number:06}_{seed}_{solver_type}{steps}_PS{prompt_strength}{img_str}_{prompt_text}' to the default or specified directory."
329+
" {original_filename}: original name without the extension;"
330+
"{file_sequence_number:pad}: sequence number in directory, can make zero-padded (e.g., 06 for six digits).;"
331+
" {seed}: seed used in generation. {steps}: number of steps used in generation. {prompt_strength}: strength of the prompt. {img_str}: the init image name. {prompt_text}: the prompt text. {solver_type}: the solver used.;"
332+
"{now:%Y-%m-%d:%H-%M-%S}: current date and time, customizable using standard strftime format codes.",
328333
),
329334
click.option(
330335
"-r",

imaginairy/cli/upscale.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,19 @@
1010

1111
logger = logging.getLogger(__name__)
1212

13-
DEFAULT_FORMAT_TEMPLATE = "{original_filename}.upscaled{file_extension}"
13+
DEFAULT_UPSCALE_FORMAT_TEMPLATE = "{original_filename}.upscaled{file_extension}"
14+
15+
DEV_UPSCALE_FORMAT_TEMPLATE = (
16+
"{file_sequence_number:06}_{algorithm}_{original_filename}.upscaled{file_extension}"
17+
)
18+
DEV_DEFAULT_OUTDIR = "./outputs/upscaled"
1419

1520

1621
@click.argument("image_filepaths", nargs=-1, required=False)
1722
@click.option(
1823
"--outdir",
19-
default="./outputs/upscaled",
20-
show_default=True,
2124
type=click.Path(),
22-
help="Where to write results to. Default will be where the directory of the original file.",
25+
help="Where to write results to. Default will be where the directory of the original file directory.",
2326
)
2427
@click.option("--fix-faces", is_flag=True)
2528
@click.option(
@@ -40,7 +43,7 @@
4043
@click.option(
4144
"--format",
4245
"format_template",
43-
default="{original_filename}.upscaled{file_extension}",
46+
default="DEFAULT",
4447
type=str,
4548
help="Formats the file name. Default value will save '{original_filename}.upscaled{file_extension}' to the original directory."
4649
" {original_filename}: original name without the extension;"
@@ -78,7 +81,12 @@ def upscale_cmd(
7881
click.echo(f"{model_name}")
7982
return
8083

81-
os.makedirs(outdir, exist_ok=True)
84+
if outdir or format_template == "DEV":
85+
if format_template == "DEV" and outdir is None:
86+
format_template = DEV_UPSCALE_FORMAT_TEMPLATE
87+
outdir = DEV_DEFAULT_OUTDIR
88+
os.makedirs(outdir, exist_ok=True)
89+
8290
image_filepaths = glob_expand_paths(image_filepaths)
8391

8492
if not image_filepaths:
@@ -88,11 +96,13 @@ def upscale_cmd(
8896
return
8997

9098
if format_template == "DEV":
91-
format_template = "{file_sequence_number:06}_{algorithm}_{original_filename}.upscaled{file_extension}"
99+
format_template = DEV_UPSCALE_FORMAT_TEMPLATE
92100
elif format_template == "DEFAULT":
93-
format_template = DEFAULT_FORMAT_TEMPLATE
101+
format_template = DEFAULT_UPSCALE_FORMAT_TEMPLATE
94102

95103
for p in tqdm(image_filepaths):
104+
if outdir is None:
105+
outdir = os.path.dirname(p)
96106
savepath = os.path.join(outdir, os.path.basename(p))
97107
if p.startswith("http"):
98108
img = LazyLoadingImage(url=p)
@@ -107,9 +117,6 @@ def upscale_cmd(
107117
if fix_faces:
108118
img = enhance_faces(img, fidelity=fix_faces_fidelity)
109119

110-
if format_template == DEFAULT_FORMAT_TEMPLATE:
111-
outdir = os.path.dirname(p) + "/"
112-
113120
file_base_name, extension = os.path.splitext(os.path.basename(p))
114121
base_count = len(os.listdir(outdir))
115122

imaginairy/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
DEFAULT_SOLVER = "ddim"
88
DEFAULT_UPSCALE_MODEL = "realesrgan-x2-plus"
99

10+
DEFAULT_SHARED_FILE_FORMAT_TEMPLATE = "{file_sequence_number:06}_{seed}_{solver_type}{steps}_PS{prompt_strength}{img_str}_{prompt_text}"
11+
DEFAULT_SHARED_OUTDIR = "./outputs"
12+
1013
DEFAULT_NEGATIVE_PROMPT = (
1114
"Ugly, duplication, duplicates, mutilation, deformed, mutilated, mutation, twisted body, disfigured, bad anatomy, "
1215
"out of frame, extra fingers, mutated hands, "

imaginairy/utils/format_file_name.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,21 @@
22
from urllib.parse import urlparse
33

44

5+
class FileFormat:
6+
def __init__(self, format_template: str, directory: dict):
7+
self.format_template = format_template
8+
self.directory = directory
9+
10+
def __str__(self):
11+
return format_filename(self.format_template, self.data)
12+
13+
514
def format_filename(format_template: str, data: dict) -> str:
615
"""
716
Formats the filename based on the provided template and variables.
817
"""
918
if not isinstance(format_template, str):
1019
raise TypeError("format argument must be a string")
11-
1220
filename = format_template.format(**data)
1321
return filename
1422

0 commit comments

Comments
 (0)