mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
blackified
This commit is contained in:
parent
c8ceb96091
commit
4043a4c21c
@ -26,18 +26,24 @@ from prompt_toolkit.completion import PathCompleter
|
|||||||
from prompt_toolkit.key_binding import KeyBindings
|
from prompt_toolkit.key_binding import KeyBindings
|
||||||
|
|
||||||
from invokeai.app.services.config import InvokeAIAppConfig
|
from invokeai.app.services.config import InvokeAIAppConfig
|
||||||
|
|
||||||
app_config = InvokeAIAppConfig.get_config()
|
app_config = InvokeAIAppConfig.get_config()
|
||||||
|
|
||||||
bindings = KeyBindings()
|
bindings = KeyBindings()
|
||||||
@bindings.add('c-c')
|
|
||||||
|
|
||||||
|
@bindings.add("c-c")
|
||||||
def _(event):
|
def _(event):
|
||||||
raise KeyboardInterrupt
|
raise KeyboardInterrupt
|
||||||
|
|
||||||
|
|
||||||
# release notes
|
# release notes
|
||||||
# "Use All" with size dimensions not selectable in the UI will not load dimensions
|
# "Use All" with size dimensions not selectable in the UI will not load dimensions
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
"""Configuration loader."""
|
"""Configuration loader."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -86,7 +92,7 @@ class Config:
|
|||||||
text += "\n\nUse these paths for import (yes) or choose different ones (no) [Yn]: "
|
text += "\n\nUse these paths for import (yes) or choose different ones (no) [Yn]: "
|
||||||
|
|
||||||
if db_exists and outdir_exists:
|
if db_exists and outdir_exists:
|
||||||
if (prompt(text).strip() or 'Y').upper().startswith('Y'):
|
if (prompt(text).strip() or "Y").upper().startswith("Y"):
|
||||||
self.database_path = database_path
|
self.database_path = database_path
|
||||||
self.outputs_path = outputs_path
|
self.outputs_path = outputs_path
|
||||||
return True
|
return True
|
||||||
@ -98,35 +104,39 @@ class Config:
|
|||||||
else:
|
else:
|
||||||
message_dialog(
|
message_dialog(
|
||||||
title="Path not found",
|
title="Path not found",
|
||||||
text=f"Auto-discovery of configuration failed! Could not find ({yaml_path}), Custom paths can be specified."
|
text=f"Auto-discovery of configuration failed! Could not find ({yaml_path}), Custom paths can be specified.",
|
||||||
).run()
|
).run()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def confirm_and_load_from_user(self):
|
def confirm_and_load_from_user(self):
|
||||||
default = ''
|
default = ""
|
||||||
while True:
|
while True:
|
||||||
database_path = os.path.expanduser(
|
database_path = os.path.expanduser(
|
||||||
prompt(
|
prompt(
|
||||||
"Database: Specify absolute path to the database to import into: ",
|
"Database: Specify absolute path to the database to import into: ",
|
||||||
completer=PathCompleter(expanduser=True, file_filter=lambda x: Path(x).is_dir() or x.endswith(('.db'))),
|
completer=PathCompleter(
|
||||||
|
expanduser=True, file_filter=lambda x: Path(x).is_dir() or x.endswith((".db"))
|
||||||
|
),
|
||||||
default=default,
|
default=default,
|
||||||
))
|
)
|
||||||
|
)
|
||||||
if database_path.endswith(".db") and os.path.isabs(database_path) and os.path.exists(database_path):
|
if database_path.endswith(".db") and os.path.isabs(database_path) and os.path.exists(database_path):
|
||||||
break
|
break
|
||||||
default = database_path + '/' if Path(database_path).is_dir() else database_path
|
default = database_path + "/" if Path(database_path).is_dir() else database_path
|
||||||
|
|
||||||
default = ''
|
default = ""
|
||||||
while True:
|
while True:
|
||||||
outputs_path = os.path.expanduser(
|
outputs_path = os.path.expanduser(
|
||||||
prompt(
|
prompt(
|
||||||
"Outputs: Specify absolute path to outputs/images directory to import into: ",
|
"Outputs: Specify absolute path to outputs/images directory to import into: ",
|
||||||
completer=PathCompleter(expanduser=True, only_directories=True),
|
completer=PathCompleter(expanduser=True, only_directories=True),
|
||||||
default=default,
|
default=default,
|
||||||
))
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if outputs_path.endswith("images") and os.path.isabs(outputs_path) and os.path.exists(outputs_path):
|
if outputs_path.endswith("images") and os.path.isabs(outputs_path) and os.path.exists(outputs_path):
|
||||||
break
|
break
|
||||||
default = outputs_path + '/' if Path(outputs_path).is_dir() else outputs_path
|
default = outputs_path + "/" if Path(outputs_path).is_dir() else outputs_path
|
||||||
|
|
||||||
self.database_path = database_path
|
self.database_path = database_path
|
||||||
self.outputs_path = outputs_path
|
self.outputs_path = outputs_path
|
||||||
@ -136,7 +146,7 @@ class Config:
|
|||||||
def load_paths_from_yaml(self, yaml_path):
|
def load_paths_from_yaml(self, yaml_path):
|
||||||
"""Load an Invoke AI yaml file and get the database and outputs paths."""
|
"""Load an Invoke AI yaml file and get the database and outputs paths."""
|
||||||
try:
|
try:
|
||||||
with open(yaml_path, 'rt', encoding=locale.getpreferredencoding()) as file:
|
with open(yaml_path, "rt", encoding=locale.getpreferredencoding()) as file:
|
||||||
yamlinfo = yaml.safe_load(file)
|
yamlinfo = yaml.safe_load(file)
|
||||||
db_dir = yamlinfo.get("InvokeAI", {}).get("Paths", {}).get("db_dir", None)
|
db_dir = yamlinfo.get("InvokeAI", {}).get("Paths", {}).get("db_dir", None)
|
||||||
outdir = yamlinfo.get("InvokeAI", {}).get("Paths", {}).get("outdir", None)
|
outdir = yamlinfo.get("InvokeAI", {}).get("Paths", {}).get("outdir", None)
|
||||||
@ -145,8 +155,10 @@ class Config:
|
|||||||
print(f"Failed to load paths from yaml file! {yaml_path}!")
|
print(f"Failed to load paths from yaml file! {yaml_path}!")
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
class ImportStats:
|
class ImportStats:
|
||||||
"""DTO for tracking work progress."""
|
"""DTO for tracking work progress."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -171,8 +183,10 @@ class ImportStats:
|
|||||||
out_str += f"{seconds:.2f} second(s)"
|
out_str += f"{seconds:.2f} second(s)"
|
||||||
return out_str
|
return out_str
|
||||||
|
|
||||||
|
|
||||||
class InvokeAIMetadata:
|
class InvokeAIMetadata:
|
||||||
"""DTO for core Invoke AI generation properties parsed from metadata."""
|
"""DTO for core Invoke AI generation properties parsed from metadata."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -234,6 +248,7 @@ class InvokeAIMetadata:
|
|||||||
|
|
||||||
class InvokeAIMetadataParser:
|
class InvokeAIMetadataParser:
|
||||||
"""Parses strings with json data to find Invoke AI core metadata properties."""
|
"""Parses strings with json data to find Invoke AI core metadata properties."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -319,17 +334,28 @@ class InvokeAIMetadataParser:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
match (old_scheduler):
|
match (old_scheduler):
|
||||||
case "ddim" : return "ddim"
|
case "ddim":
|
||||||
case "plms" : return "pnmd"
|
return "ddim"
|
||||||
case "k_lms" : return "lms"
|
case "plms":
|
||||||
case "k_dpm_2" : return "kdpm_2"
|
return "pnmd"
|
||||||
case "k_dpm_2_a" : return "kdpm_2_a"
|
case "k_lms":
|
||||||
case "dpmpp_2" : return "dpmpp_2s"
|
return "lms"
|
||||||
case "k_dpmpp_2" : return "dpmpp_2m"
|
case "k_dpm_2":
|
||||||
case "k_dpmpp_2_a" : return None #invalid, in 2.3.x, selecting this sample would just fallback to last run or plms if new session
|
return "kdpm_2"
|
||||||
case "k_euler" : return "euler"
|
case "k_dpm_2_a":
|
||||||
case "k_euler_a" : return "euler_a"
|
return "kdpm_2_a"
|
||||||
case "k_heun" : return "heun"
|
case "dpmpp_2":
|
||||||
|
return "dpmpp_2s"
|
||||||
|
case "k_dpmpp_2":
|
||||||
|
return "dpmpp_2m"
|
||||||
|
case "k_dpmpp_2_a":
|
||||||
|
return None # invalid, in 2.3.x, selecting this sample would just fallback to last run or plms if new session
|
||||||
|
case "k_euler":
|
||||||
|
return "euler"
|
||||||
|
case "k_euler_a":
|
||||||
|
return "euler_a"
|
||||||
|
case "k_heun":
|
||||||
|
return "heun"
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def split_prompt(self, raw_prompt: str):
|
def split_prompt(self, raw_prompt: str):
|
||||||
@ -341,7 +367,7 @@ class InvokeAIMetadataParser:
|
|||||||
if len(matches) > 0:
|
if len(matches) > 0:
|
||||||
negative_prompt = ""
|
negative_prompt = ""
|
||||||
if len(matches) == 1:
|
if len(matches) == 1:
|
||||||
negative_prompt = matches[0].strip().strip(',')
|
negative_prompt = matches[0].strip().strip(",")
|
||||||
else:
|
else:
|
||||||
for match in matches:
|
for match in matches:
|
||||||
negative_prompt += f"({match.strip().strip(',')})"
|
negative_prompt += f"({match.strip().strip(',')})"
|
||||||
@ -352,8 +378,10 @@ class InvokeAIMetadataParser:
|
|||||||
|
|
||||||
return positive_prompt, negative_prompt
|
return positive_prompt, negative_prompt
|
||||||
|
|
||||||
|
|
||||||
class DatabaseMapper:
|
class DatabaseMapper:
|
||||||
"""Class to abstract database functionality."""
|
"""Class to abstract database functionality."""
|
||||||
|
|
||||||
def __init__(self, database_path, database_backup_dir):
|
def __init__(self, database_path, database_backup_dir):
|
||||||
self.database_path = database_path
|
self.database_path = database_path
|
||||||
self.database_backup_dir = database_backup_dir
|
self.database_backup_dir = database_backup_dir
|
||||||
@ -427,8 +455,10 @@ VALUES ('{filename}', 'internal', 'general', {width}, {height}, null, null, '{me
|
|||||||
shutil.copy2(self.database_path, database_backup_path)
|
shutil.copy2(self.database_path, database_backup_path)
|
||||||
print("Done!")
|
print("Done!")
|
||||||
|
|
||||||
|
|
||||||
class MediaImportProcessor:
|
class MediaImportProcessor:
|
||||||
"""Containing class for script functionality."""
|
"""Containing class for script functionality."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -437,25 +467,28 @@ class MediaImportProcessor:
|
|||||||
def get_import_file_list(self):
|
def get_import_file_list(self):
|
||||||
"""Ask the user for the import folder and scan for the list of files to return."""
|
"""Ask the user for the import folder and scan for the list of files to return."""
|
||||||
while True:
|
while True:
|
||||||
default = ''
|
default = ""
|
||||||
while True:
|
while True:
|
||||||
import_dir = os.path.expanduser(
|
import_dir = os.path.expanduser(
|
||||||
prompt(
|
prompt(
|
||||||
"Inputs: Specify absolute path containing InvokeAI .png images to import: ",
|
"Inputs: Specify absolute path containing InvokeAI .png images to import: ",
|
||||||
completer=PathCompleter(expanduser=True, only_directories=True),
|
completer=PathCompleter(expanduser=True, only_directories=True),
|
||||||
default=default,
|
default=default,
|
||||||
))
|
)
|
||||||
|
)
|
||||||
if len(import_dir) > 0 and Path(import_dir).is_dir():
|
if len(import_dir) > 0 and Path(import_dir).is_dir():
|
||||||
break
|
break
|
||||||
default = import_dir
|
default = import_dir
|
||||||
|
|
||||||
recurse_directories = (prompt("Include files from subfolders recursively [yN]? ").strip() or 'N').upper().startswith('N')
|
recurse_directories = (
|
||||||
|
(prompt("Include files from subfolders recursively [yN]? ").strip() or "N").upper().startswith("N")
|
||||||
|
)
|
||||||
if recurse_directories:
|
if recurse_directories:
|
||||||
is_recurse = False
|
is_recurse = False
|
||||||
matching_file_list = glob.glob(import_dir + '/*.png', recursive=False)
|
matching_file_list = glob.glob(import_dir + "/*.png", recursive=False)
|
||||||
else:
|
else:
|
||||||
is_recurse = True
|
is_recurse = True
|
||||||
matching_file_list = glob.glob(import_dir + '/**/*.png', recursive=True)
|
matching_file_list = glob.glob(import_dir + "/**/*.png", recursive=True)
|
||||||
|
|
||||||
if len(matching_file_list) > 0:
|
if len(matching_file_list) > 0:
|
||||||
return import_dir, is_recurse, matching_file_list
|
return import_dir, is_recurse, matching_file_list
|
||||||
@ -477,15 +510,21 @@ class MediaImportProcessor:
|
|||||||
print(f"1) Select an existing board name. (found {len(board_names)})")
|
print(f"1) Select an existing board name. (found {len(board_names)})")
|
||||||
print("2) Specify a board name to create/add to.")
|
print("2) Specify a board name to create/add to.")
|
||||||
print("3) Create/add to board named 'IMPORT'.")
|
print("3) Create/add to board named 'IMPORT'.")
|
||||||
print(f"4) Create/add to board named 'IMPORT' with the current datetime string appended (.e.g IMPORT_{timestamp_string}).")
|
print(
|
||||||
print( "5) Create/add to board named 'IMPORT' with a the original file app_version appended (.e.g IMPORT_2.2.5).")
|
f"4) Create/add to board named 'IMPORT' with the current datetime string appended (.e.g IMPORT_{timestamp_string})."
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
"5) Create/add to board named 'IMPORT' with a the original file app_version appended (.e.g IMPORT_2.2.5)."
|
||||||
|
)
|
||||||
input_option = input("Specify desired board option: ")
|
input_option = input("Specify desired board option: ")
|
||||||
match (input_option):
|
match (input_option):
|
||||||
case "1":
|
case "1":
|
||||||
if len(board_names) < 1:
|
if len(board_names) < 1:
|
||||||
print("\r\nThere are no existing board names to choose from. Select another option!")
|
print("\r\nThere are no existing board names to choose from. Select another option!")
|
||||||
continue
|
continue
|
||||||
board_name = self.select_item_from_list(board_names, "board name", True, "Cancel, go back and choose a different board option.")
|
board_name = self.select_item_from_list(
|
||||||
|
board_names, "board name", True, "Cancel, go back and choose a different board option."
|
||||||
|
)
|
||||||
if board_name is not None:
|
if board_name is not None:
|
||||||
return board_name
|
return board_name
|
||||||
case "2":
|
case "2":
|
||||||
@ -582,7 +621,9 @@ class MediaImportProcessor:
|
|||||||
# if metadata needs update, then update metdata and copy in one shot
|
# if metadata needs update, then update metdata and copy in one shot
|
||||||
if destination_needs_meta_update:
|
if destination_needs_meta_update:
|
||||||
print("Updating metadata while copying...", end="")
|
print("Updating metadata while copying...", end="")
|
||||||
self.update_file_metadata_while_copying(filepath, file_destination_path, "invokeai_metadata", latest_json_string)
|
self.update_file_metadata_while_copying(
|
||||||
|
filepath, file_destination_path, "invokeai_metadata", latest_json_string
|
||||||
|
)
|
||||||
print("Done!")
|
print("Done!")
|
||||||
else:
|
else:
|
||||||
print("No metadata update necessary, copying only...", end="")
|
print("No metadata update necessary, copying only...", end="")
|
||||||
@ -648,7 +689,7 @@ class MediaImportProcessor:
|
|||||||
print("===============================================================================")
|
print("===============================================================================")
|
||||||
print("This script will import images generated by earlier versions of")
|
print("This script will import images generated by earlier versions of")
|
||||||
print("InvokeAI into the currently installed root directory:")
|
print("InvokeAI into the currently installed root directory:")
|
||||||
print(f' {app_config.root_path}')
|
print(f" {app_config.root_path}")
|
||||||
print("If this is not what you want to do, type ctrl-C now to cancel.")
|
print("If this is not what you want to do, type ctrl-C now to cancel.")
|
||||||
|
|
||||||
# load config
|
# load config
|
||||||
@ -683,16 +724,22 @@ class MediaImportProcessor:
|
|||||||
print("- If the same file name already exists in the destination, the file will be skipped.")
|
print("- If the same file name already exists in the destination, the file will be skipped.")
|
||||||
print("- If the same file name already has a record in the database, the file will be skipped.")
|
print("- If the same file name already has a record in the database, the file will be skipped.")
|
||||||
print("- Invoke AI metadata tags will be updated/written into the imported copy only.")
|
print("- Invoke AI metadata tags will be updated/written into the imported copy only.")
|
||||||
print("- On the imported copy, only Invoke AI known tags (latest and legacy) will be retained (dream, sd-metadata, invokeai, invokeai_metadata)")
|
print(
|
||||||
print("- A property 'imported_app_version' will be added to metadata that can be viewed in the UI's metadata viewer.")
|
"- On the imported copy, only Invoke AI known tags (latest and legacy) will be retained (dream, sd-metadata, invokeai, invokeai_metadata)"
|
||||||
print("- The new 3.x InvokeAI outputs folder structure is flat so recursively found source imges will all be placed into the single outputs/images folder.")
|
)
|
||||||
|
print(
|
||||||
|
"- A property 'imported_app_version' will be added to metadata that can be viewed in the UI's metadata viewer."
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
"- The new 3.x InvokeAI outputs folder structure is flat so recursively found source imges will all be placed into the single outputs/images folder."
|
||||||
|
)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
should_continue = prompt("\nDo you wish to continue with the import [Yn] ? ").lower() or 'y'
|
should_continue = prompt("\nDo you wish to continue with the import [Yn] ? ").lower() or "y"
|
||||||
if should_continue=='n':
|
if should_continue == "n":
|
||||||
print("\r\nCancelling Import")
|
print("\r\nCancelling Import")
|
||||||
return
|
return
|
||||||
elif should_continue=='y':
|
elif should_continue == "y":
|
||||||
print()
|
print()
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -728,6 +775,7 @@ class MediaImportProcessor:
|
|||||||
for key, version in ImportStats.count_imported_by_version.items():
|
for key, version in ImportStats.count_imported_by_version.items():
|
||||||
print(f" {key:20} : {version}")
|
print(f" {key:20} : {version}")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
processor = MediaImportProcessor()
|
processor = MediaImportProcessor()
|
||||||
@ -735,5 +783,6 @@ def main():
|
|||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\r\n\r\nUser cancelled execution.")
|
print("\r\n\r\nUser cancelled execution.")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
Loading…
Reference in New Issue
Block a user