| import yaml |
| import random |
| import os |
| import json |
| import tempfile |
| import gradio as gr |
| from .config import FEATURES_FILE, FEATURE_SEQUENCE, SECTIONS, EXAMPLES_DIR |
|
|
| def load_features(): |
| with open(FEATURES_FILE, "r") as f: |
| return yaml.safe_load(f) |
|
|
| features_data = load_features() |
|
|
| def get_detail(category, subcategory, key): |
| """Retrieves the detailed description for a given key in a category/subcategory.""" |
| return features_data.get(category, {}).get(subcategory, {}).get(key, key) |
|
|
| def generate_prompt(*args): |
| """ |
| Assembles the prompt based on dropdown selections and extra text info. |
| """ |
| character_name = args[0] |
| num_features = len(FEATURE_SEQUENCE) |
| feature_keys = args[1:num_features+1] |
| |
| |
| extra_infos = args[1 + num_features*2 : 1 + num_features*2 + len(SECTIONS)] |
|
|
| template = features_data.get("templates", {}).get("default", "") |
| |
| context = {} |
| for i, (cat, subcat, t_key) in enumerate(FEATURE_SEQUENCE): |
| key = feature_keys[i] |
| context[t_key] = get_detail(cat, subcat, key) |
| |
| |
| acc_list = [] |
| |
| for i, (cat, subcat, t_key) in enumerate(FEATURE_SEQUENCE): |
| if subcat == 'accessory' and feature_keys[i] != "None": |
| acc_list.append(context[t_key]) |
| |
| if acc_list: |
| context['accessories'] = ", and has " + " as well as ".join(acc_list) |
| else: |
| context['accessories'] = "" |
| |
| |
| if extra_infos[0]: |
| context['age'] += f", {extra_infos[0]}" |
| if extra_infos[1]: |
| context['distinguishing_feature'] += f", also {extra_infos[1]}" |
| if extra_infos[2]: |
| if context['accessories']: |
| context['accessories'] += f", further complemented by {extra_infos[2]}" |
| else: |
| context['accessories'] = f", complemented by {extra_infos[2]}" |
| if extra_infos[3]: |
| context['atmosphere'] += f", additionally {extra_infos[3]}" |
| if extra_infos[4]: |
| context['camera'] += f", art style notes: {extra_infos[4]}" |
| |
| try: |
| base_prompt = template.format(**context) |
| if character_name and character_name.strip() and character_name != "Unnamed Hero": |
| return f"A portrait of {character_name}, {base_prompt}" |
| return base_prompt |
| except Exception as e: |
| return f"Error building prompt: {e}" |
|
|
| def handle_regeneration(*args): |
| """Randomizes checkboxes and returns new values for dropdowns.""" |
| num_features = len(FEATURE_SEQUENCE) |
| current_values = list(args[:num_features]) |
| checkboxes = args[num_features : num_features*2] |
| |
| new_values = [] |
| for i, (is_random, (cat, subcat, t_key)) in enumerate(zip(checkboxes, FEATURE_SEQUENCE)): |
| if is_random: |
| choices = list(features_data[cat][subcat].keys()) |
| new_values.append(random.choice(choices)) |
| else: |
| new_values.append(current_values[i]) |
| |
| return new_values |
|
|
| def save_character(*args): |
| """Saves all current UI values to a JSON file.""" |
| character_name = args[0] |
| num_features = len(FEATURE_SEQUENCE) |
| feature_keys = args[1:num_features+1] |
| checkboxes = args[num_features+1 : num_features+1 + num_features] |
| extra_infos = args[num_features+1 + num_features : num_features+1 + num_features + len(SECTIONS)] |
| |
| data = { |
| "name": character_name, |
| "features": {FEATURE_SEQUENCE[i][2]: feature_keys[i] for i in range(num_features)}, |
| "randomization": {FEATURE_SEQUENCE[i][2]: checkboxes[i] for i in range(num_features)}, |
| "extra_info": {SECTIONS[i].lower(): extra_infos[i] for i in range(len(SECTIONS))} |
| } |
| |
| |
| safe_name = "".join([c if c.isalnum() else "_" for c in character_name]).strip("_") |
| filename = f"{safe_name}_data.json" if safe_name else "rpg_character_data.json" |
| |
| temp_dir = tempfile.mkdtemp() |
| path = os.path.join(temp_dir, filename) |
| with open(path, 'w') as f: |
| json.dump(data, f, indent=4) |
| return path |
|
|
| def load_character(file): |
| """Loads UI values from a JSON file.""" |
| if file is None: |
| return [gr.update()] * (1 + len(FEATURE_SEQUENCE) * 2 + len(SECTIONS)) |
| |
| try: |
| file_path = file.name if hasattr(file, 'name') else file |
| with open(file_path, 'r') as f: |
| data = json.load(f) |
| |
| updates = [] |
| |
| updates.append(data.get("name", "Unnamed Hero")) |
| |
| |
| for _, _, t_key in FEATURE_SEQUENCE: |
| updates.append(data.get("features", {}).get(t_key, gr.update())) |
| |
| |
| for _, _, t_key in FEATURE_SEQUENCE: |
| updates.append(data.get("randomization", {}).get(t_key, gr.update())) |
| |
| |
| for section in SECTIONS: |
| updates.append(data.get("extra_info", {}).get(section.lower(), "")) |
| |
| return updates |
| except Exception as e: |
| print(f"Error loading character: {e}") |
| return [gr.update()] * (1 + len(FEATURE_SEQUENCE) * 2 + len(SECTIONS)) |
|
|
| def get_example_list(): |
| """Returns a list of JSON filenames in the examples directory.""" |
| if not os.path.exists(EXAMPLES_DIR): |
| return [] |
| return [f for f in os.listdir(EXAMPLES_DIR) if f.endswith('.json')] |
|
|
| def load_example_character(filename): |
| """Loads a character config from the examples directory.""" |
| if not filename: |
| return [gr.update()] * (1 + len(FEATURE_SEQUENCE) * 2 + len(SECTIONS)) |
| |
| path = os.path.join(EXAMPLES_DIR, filename) |
| return load_character(path) |
|
|