Spaces:
Running
on
Zero
Running
on
Zero
import os | |
import json | |
import random | |
import re | |
# Load JSON files | |
def load_json_file(file_name): | |
file_path = os.path.join("data", file_name) | |
with open(file_path, "r") as file: | |
return json.load(file) | |
# Load gender-specific JSON files | |
FEMALE_DEFAULT_TAGS = load_json_file("female_default_tags.json") | |
MALE_DEFAULT_TAGS = load_json_file("male_default_tags.json") | |
FEMALE_BODY_TYPES = load_json_file("female_body_types.json") | |
MALE_BODY_TYPES = load_json_file("male_body_types.json") | |
FEMALE_CLOTHING = load_json_file("female_clothing.json") | |
MALE_CLOTHING = load_json_file("male_clothing.json") | |
FEMALE_ADDITIONAL_DETAILS = load_json_file("female_additional_details.json") | |
MALE_ADDITIONAL_DETAILS = load_json_file("male_additional_details.json") | |
# Load non-gender-specific JSON files | |
ARTFORM = load_json_file("artform.json") | |
PHOTO_TYPE = load_json_file("photo_type.json") | |
ROLES = load_json_file("roles.json") | |
HAIRSTYLES = load_json_file("hairstyles.json") | |
PLACE = load_json_file("place.json") | |
LIGHTING = load_json_file("lighting.json") | |
COMPOSITION = load_json_file("composition.json") | |
POSE = load_json_file("pose.json") | |
BACKGROUND = load_json_file("background.json") | |
PHOTOGRAPHY_STYLES = load_json_file("photography_styles.json") | |
DEVICE = load_json_file("device.json") | |
PHOTOGRAPHER = load_json_file("photographer.json") | |
ARTIST = load_json_file("artist.json") | |
DIGITAL_ARTFORM = load_json_file("digital_artform.json") | |
class PromptGenerator: | |
def __init__(self, seed=None): | |
self.rng = random.Random(seed) | |
self.next_data = self.load_next_data() | |
def split_and_choose(self, input_str): | |
choices = [choice.strip() for choice in input_str.split(",")] | |
return self.rng.choices(choices, k=1)[0] | |
def get_choice(self, input_str, default_choices): | |
if input_str.lower() == "disabled": | |
return "" | |
elif "," in input_str: | |
return self.split_and_choose(input_str) | |
elif input_str.lower() == "random": | |
return self.rng.choices(default_choices, k=1)[0] | |
else: | |
return input_str | |
def clean_consecutive_commas(self, input_string): | |
cleaned_string = re.sub(r',\s*,', ', ', input_string) | |
return cleaned_string | |
def process_string(self, replaced, seed): | |
replaced = re.sub(r'\s*,\s*', ', ', replaced) | |
replaced = re.sub(r',+', ', ', replaced) | |
original = replaced | |
first_break_clipl_index = replaced.find("BREAK_CLIPL") | |
second_break_clipl_index = replaced.find("BREAK_CLIPL", first_break_clipl_index + len("BREAK_CLIPL")) | |
if first_break_clipl_index != -1 and second_break_clipl_index != -1: | |
clip_content_l = replaced[first_break_clipl_index + len("BREAK_CLIPL"):second_break_clipl_index] | |
replaced = replaced[:first_break_clipl_index].strip(", ") + replaced[second_break_clipl_index + len("BREAK_CLIPL"):].strip(", ") | |
clip_l = clip_content_l | |
else: | |
clip_l = "" | |
first_break_clipg_index = replaced.find("BREAK_CLIPG") | |
second_break_clipg_index = replaced.find("BREAK_CLIPG", first_break_clipg_index + len("BREAK_CLIPG")) | |
if first_break_clipg_index != -1 and second_break_clipg_index != -1: | |
clip_content_g = replaced[first_break_clipg_index + len("BREAK_CLIPG"):second_break_clipg_index] | |
replaced = replaced[:first_break_clipg_index].strip(", ") + replaced[second_break_clipg_index + len("BREAK_CLIPG"):].strip(", ") | |
clip_g = clip_content_g | |
else: | |
clip_g = "" | |
t5xxl = replaced | |
original = original.replace("BREAK_CLIPL", "").replace("BREAK_CLIPG", "") | |
original = re.sub(r'\s*,\s*', ', ', original) | |
original = re.sub(r',+', ', ', original) | |
clip_l = re.sub(r'\s*,\s*', ', ', clip_l) | |
clip_l = re.sub(r',+', ', ', clip_l) | |
clip_g = re.sub(r'\s*,\s*', ', ', clip_g) | |
clip_g = re.sub(r',+', ', ', clip_g) | |
if clip_l.startswith(", "): | |
clip_l = clip_l[2:] | |
if clip_g.startswith(", "): | |
clip_g = clip_g[2:] | |
if original.startswith(", "): | |
original = original[2:] | |
if t5xxl.startswith(", "): | |
t5xxl = t5xxl[2:] | |
# Add spaces after commas | |
replaced = re.sub(r',(?!\s)', ', ', replaced) | |
original = re.sub(r',(?!\s)', ', ', original) | |
clip_l = re.sub(r',(?!\s)', ', ', clip_l) | |
clip_g = re.sub(r',(?!\s)', ', ', clip_g) | |
t5xxl = re.sub(r',(?!\s)', ', ', t5xxl) | |
return original, seed, t5xxl, clip_l, clip_g | |
def load_next_data(self): | |
next_data = {} | |
next_path = os.path.join("data", "next") | |
for category in os.listdir(next_path): | |
category_path = os.path.join(next_path, category) | |
if os.path.isdir(category_path): | |
next_data[category] = {} | |
for file in os.listdir(category_path): | |
if file.endswith(".json"): | |
file_path = os.path.join(category_path, file) | |
with open(file_path, "r", encoding="utf-8") as f: | |
json_data = json.load(f) | |
next_data[category][file[:-5]] = json_data | |
return next_data | |
def process_next_data(self, prompt, separator, category, field, value, attributes=False): | |
if category in self.next_data and field in self.next_data[category]: | |
field_data = self.next_data[category][field] | |
items = field_data.get("items", []) | |
preprompt = str(field_data.get("preprompt", "")).strip() | |
field_separator = f" {str(field_data.get('separator', ', ')).strip()} " | |
endprompt = str(field_data.get("endprompt", "")).strip() | |
if value == "None": | |
return prompt | |
elif value == "Random": | |
selected_items = [self.rng.choice(items)] | |
elif value == "Multiple Random": | |
count = self.rng.randint(1, 3) | |
selected_items = self.rng.sample(items, min(count, len(items))) | |
else: | |
selected_items = [value] | |
formatted_items = [] | |
for item in selected_items: | |
item_str = str(item) | |
if attributes and "attributes" in field_data and item_str in field_data["attributes"]: | |
item_attributes = field_data["attributes"].get(item_str, []) | |
if item_attributes: | |
selected_attributes = self.rng.sample(item_attributes, min(3, len(item_attributes))) | |
formatted_items.append(f"{item_str} ({', '.join(map(str, selected_attributes))})") | |
else: | |
formatted_items.append(item_str) | |
else: | |
formatted_items.append(item_str) | |
formatted_values = field_separator.join(formatted_items) | |
formatted_addition = [] | |
if preprompt: | |
formatted_addition.append(preprompt) | |
formatted_addition.append(formatted_values) | |
if endprompt: | |
formatted_addition.append(endprompt) | |
formatted_output = " ".join(formatted_addition).strip() | |
prompt += f" {formatted_output}" | |
return prompt | |
def generate_prompt(self, seed, custom, subject, gender, artform, photo_type, body_types, default_tags, roles, hairstyles, | |
additional_details, photography_styles, device, photographer, artist, digital_artform, | |
place, lighting, clothing, composition, pose, background, input_image, **next_params): | |
kwargs = locals() | |
del kwargs['self'] | |
seed = kwargs.get("seed", 0) | |
if seed is not None: | |
self.rng = random.Random(seed) | |
components = [] | |
custom = kwargs.get("custom", "") | |
if custom: | |
components.append(custom) | |
is_photographer = kwargs.get("artform", "").lower() == "photography" or ( | |
kwargs.get("artform", "").lower() == "random" | |
and self.rng.choice([True, False]) | |
) | |
subject = kwargs.get("subject", "") | |
gender = kwargs.get("gender", "female") | |
if is_photographer: | |
selected_photo_style = self.get_choice(kwargs.get("photography_styles", ""), PHOTOGRAPHY_STYLES) | |
if not selected_photo_style: | |
selected_photo_style = "photography" | |
components.append(selected_photo_style) | |
if kwargs.get("photography_style", "") != "disabled" and kwargs.get("default_tags", "") != "disabled" or subject != "": | |
components.append(" of") | |
default_tags = kwargs.get("default_tags", "random") | |
body_type = kwargs.get("body_types", "") | |
if not subject: | |
if default_tags == "random": | |
if body_type != "disabled" and body_type != "random": | |
selected_subject = self.get_choice(kwargs.get("default_tags", ""), FEMALE_DEFAULT_TAGS if gender == "female" else MALE_DEFAULT_TAGS).replace("a ", "").replace("an ", "") | |
components.append("a ") | |
components.append(body_type) | |
components.append(selected_subject) | |
elif body_type == "disabled": | |
selected_subject = self.get_choice(kwargs.get("default_tags", ""), FEMALE_DEFAULT_TAGS if gender == "female" else MALE_DEFAULT_TAGS) | |
components.append(selected_subject) | |
else: | |
body_type = self.get_choice(body_type, FEMALE_BODY_TYPES if gender == "female" else MALE_BODY_TYPES) | |
components.append("a ") | |
components.append(body_type) | |
selected_subject = self.get_choice(kwargs.get("default_tags", ""), FEMALE_DEFAULT_TAGS if gender == "female" else MALE_DEFAULT_TAGS).replace("a ", "").replace("an ", "") | |
components.append(selected_subject) | |
elif default_tags == "disabled": | |
pass | |
else: | |
components.append(default_tags) | |
else: | |
if body_type != "disabled" and body_type != "random": | |
components.append("a ") | |
components.append(body_type) | |
elif body_type == "disabled": | |
pass | |
else: | |
body_type = self.get_choice(body_type, FEMALE_BODY_TYPES if gender == "female" else MALE_BODY_TYPES) | |
components.append("a ") | |
components.append(body_type) | |
components.append(subject) | |
params = [ | |
("roles", ROLES), | |
("hairstyles", HAIRSTYLES), | |
("additional_details", FEMALE_ADDITIONAL_DETAILS if gender == "female" else MALE_ADDITIONAL_DETAILS), | |
] | |
for param in params: | |
components.append(self.get_choice(kwargs.get(param[0], ""), param[1])) | |
for i in reversed(range(len(components))): | |
if components[i] in PLACE: | |
components[i] += ", " | |
break | |
if kwargs.get("clothing", "") != "disabled" and kwargs.get("clothing", "") != "random": | |
components.append(", dressed in ") | |
clothing = kwargs.get("clothing", "") | |
components.append(clothing) | |
elif kwargs.get("clothing", "") == "random": | |
components.append(", dressed in ") | |
clothing = self.get_choice(kwargs.get("clothing", ""), FEMALE_CLOTHING if gender == "female" else MALE_CLOTHING) | |
components.append(clothing) | |
if kwargs.get("composition", "") != "disabled" and kwargs.get("composition", "") != "random": | |
components.append(", ") | |
composition = kwargs.get("composition", "") | |
components.append(composition) | |
elif kwargs.get("composition", "") == "random": | |
components.append(", ") | |
composition = self.get_choice(kwargs.get("composition", ""), COMPOSITION) | |
components.append(composition) | |
if kwargs.get("pose", "") != "disabled" and kwargs.get("pose", "") != "random": | |
components.append(", ") | |
pose = kwargs.get("pose", "") | |
components.append(pose) | |
elif kwargs.get("pose", "") == "random": | |
components.append(", ") | |
pose = self.get_choice(kwargs.get("pose", ""), POSE) | |
components.append(pose) | |
components.append("BREAK_CLIPG") | |
if kwargs.get("background", "") != "disabled" and kwargs.get("background", "") != "random": | |
components.append(", ") | |
background = kwargs.get("background", "") | |
components.append(background) | |
elif kwargs.get("background", "") == "random": | |
components.append(", ") | |
background = self.get_choice(kwargs.get("background", ""), BACKGROUND) | |
components.append(background) | |
if kwargs.get("place", "") != "disabled" and kwargs.get("place", "") != "random": | |
components.append(", ") | |
place = kwargs.get("place", "") | |
components.append(place) | |
elif kwargs.get("place", "") == "random": | |
components.append(", ") | |
place = self.get_choice(kwargs.get("place", ""), PLACE) | |
components.append(place + ", ") | |
lighting = kwargs.get("lighting", "").lower() | |
if lighting == "random": | |
selected_lighting = ", ".join(self.rng.sample(LIGHTING, self.rng.randint(2, 5))) | |
components.append(", ") | |
components.append(selected_lighting) | |
elif lighting == "disabled": | |
pass | |
else: | |
components.append(", ") | |
components.append(lighting) | |
components.append("BREAK_CLIPG") | |
components.append("BREAK_CLIPL") | |
if is_photographer: | |
if kwargs.get("photo_type", "") != "disabled": | |
photo_type_choice = self.get_choice(kwargs.get("photo_type", ""), PHOTO_TYPE) | |
if photo_type_choice and photo_type_choice != "random" and photo_type_choice != "disabled": | |
random_value = round(self.rng.uniform(1.1, 1.5), 1) | |
components.append(f", ({photo_type_choice}:{random_value}), ") | |
params = [ | |
("device", DEVICE), | |
("photographer", PHOTOGRAPHER), | |
] | |
components.extend([self.get_choice(kwargs.get(param[0], ""), param[1]) for param in params]) | |
if kwargs.get("device", "") != "disabled": | |
components[-2] = f", shot on {components[-2]}" | |
if kwargs.get("photographer", "") != "disabled": | |
components[-1] = f", photo by {components[-1]}" | |
else: | |
digital_artform_choice = self.get_choice(kwargs.get("digital_artform", ""), DIGITAL_ARTFORM) | |
if digital_artform_choice: | |
components.append(f"{digital_artform_choice}") | |
if kwargs.get("artist", "") != "disabled": | |
components.append(f"by {self.get_choice(kwargs.get('artist', ''), ARTIST)}") | |
components.append("BREAK_CLIPL") | |
prompt = " ".join(components) | |
prompt = re.sub(" +", " ", prompt) | |
replaced = prompt.replace("of as", "of") | |
replaced = self.clean_consecutive_commas(replaced) | |
# Process next_params | |
for category, fields in next_params.items(): | |
for field, value in fields.items(): | |
prompt = self.process_next_data(prompt, ", ", category, field, value) | |
return self.process_string(replaced, seed) | |
def add_caption_to_prompt(self, prompt, caption): | |
if caption: | |
return f"{prompt}, {caption}" | |
return prompt |