i used chatgpt to make a prompt checker for random pools, it looks like it works but i haven't rested much. if anyone is interested i could share it. i did make it generate a test file for you to drop your prompts into if it doesn't find one. i don't rally know how dangerous that could be, but the file just says "drop your text here".
import os import re from collections import Counter def ensure_file_exists(filename="prompt.txt"): if not os.path.exists(filename): with open(filename, "w", encoding="utf-8") as f: f.write("Enter your prompt here...\n") print(f"Created missing file: {filename}") return filename def load_prompt(filename): with open(filename, "r", encoding="utf-8") as f: return f.read().splitlines() # return list of lines def check_balanced_braces(lines, context=3): stack = [] errors = [] for line_num, line in enumerate(lines, start=1): for col, char in enumerate(line, start=1): if char == "{": stack.append((line_num, col)) elif char == "}": if not stack: errors.append((line_num, col, char)) else: stack.pop() for line_num, col in stack: errors.append((line_num, col, "{")) if errors: msg_lines = ["❌ Unmatched braces found:"] for line_num, col, char in errors: start = max(0, line_num - context - 1) end = min(len(lines), line_num + context) context_lines = lines[start:end] msg_lines.append(f"\nError at line {line_num}, col {col}: unexpected '{char}'") for i, l in enumerate(context_lines, start=start + 1): pointer = "" if i == line_num: pointer = " " * (col - 1) + "^" msg_lines.append(f"{i:4}: {l}\n {pointer}") else: msg_lines.append(f"{i:4}: {l}") return False, "\n".join(msg_lines) return True, "✅ Braces are balanced." def parse_pool(pool_str): """ Parse a pool into top-level options. Splits on '|' at top-level only. Keeps nested {...} intact. Converts empty options || → 'null'. """ parts = [] current = [] depth = 0 pool_str = pool_str.strip() if pool_str.startswith("{") and pool_str.endswith("}"): pool_str = pool_str[1:-1] for char in pool_str: if char == '{': depth += 1 current.append(char) elif char == '}': depth -= 1 current.append(char) elif char == '|' and depth == 0: opt = "".join(current).strip().replace("\n", " ") if not opt: opt = "null" parts.append(opt) current = [] else: current.append(char) # Append last option opt = "".join(current).strip().replace("\n", " ") if not opt: opt = "null" parts.append(opt) return parts # Global pool counter and mapping pool_counter = 0 pool_mapping = {} def compute_odds(pool_str): """ Like compute_odds(), but will catch inline nested pools inside options even if the option has other text around it. """ global pool_counter, pool_mapping pool_counter += 1 current_pool_num = pool_counter options = parse_pool(pool_str) flat_options = [] for opt in options: opt = opt.strip() # Find any {…} inside the option while '{' in opt and '}' in opt: depth = 0 start_idx = None for i, c in enumerate(opt): if c == '{': if depth == 0: start_idx = i depth += 1 elif c == '}': depth -= 1 if depth == 0 and start_idx is not None: nested_content = opt[start_idx + 1:i] before = opt[:start_idx].strip() after = opt[i+1:].strip() nested_odds = compute_odds(nested_content) display_name = f"{before} (pool {nested_odds['pool_num']}) {after}".strip() opt = display_name # replace current option with updated version break else: break # no closing brace found; should not happen flat_options.append(opt) # Merge duplicates counts = Counter(flat_options) total = sum(counts.values()) results = [(option, f"{count}/{total}", None) for option, count in counts.items()] pool_data = {'pool_num': current_pool_num, 'results': results} pool_mapping[current_pool_num] = pool_data return pool_data # Count duplicates to merge repeated entries counts = Counter(flat_options) total = sum(counts.values()) results = [] for option, count in counts.items(): prob = f"{count}/{total}" results.append((option, prob, None)) pool_data = {'pool_num': current_pool_num, 'results': results} pool_mapping[current_pool_num] = pool_data return pool_data def display_odds_conditional(pool_data, prefix=""): results = pool_data['results'] total = len(results) for i, (option, odds, ) in enumerate(results): connector = "└─" if i == total - 1 else "├─" # 1️⃣ Detect all pool numbers on this line poolmatches = re.findall(r"\(pool (\d+)\)", option) # 2️⃣ Decide whether to show pool numbers display_option = option if len(pool_matches) <= 1: # Remove all pool numbers only if ≤1 display_option = re.sub(r"\(pool \d+\)", "", option).strip() print(f"{prefix}{connector} {display_option} ({odds})") # 3️⃣ Recurse into all nested pools sub_prefix = prefix + (" " if i == total - 1 else "│ ") for sub_pool_num_str in pool_matches: sub_pool_num = int(sub_pool_num_str) if sub_pool_num in pool_mapping: display_odds_conditional(pool_mapping[sub_pool_num], prefix=sub_prefix) def display_odds_all_pools(pool_data, prefix=""): """Display odds as a tree with all nested pools on the same line.""" results = pool_data['results'] total = len(results) for i, (option, odds, ) in enumerate(results): connector = "└─" if i == total - 1 else "├─" print(f"{prefix}{connector} {option} ({odds})") # Find all pool references in this option poolmatches = re.findall(r"\(pool (\d+)\)", option) sub_prefix = prefix + (" " if i == total - 1 else "│ ") for sub_pool_num_str in pool_matches: sub_pool_num = int(sub_pool_num_str) if sub_pool_num in pool_mapping: display_odds_all_pools(pool_mapping[sub_pool_num], prefix=sub_prefix) def display_odds(pool_data, prefix=""): """Display odds as a tree with nested pools.""" results = pool_data['results'] total = len(results) for i, (option, odds, ) in enumerate(results): connector = "└─" if i == total - 1 else "├─" print(f"{prefix}{connector} {option} ({odds})") match = re.search(r"\(pool (\d+)\)", option) if match: subpool_num = int(match.group(1)) if sub_pool_num in pool_mapping: sub_prefix = prefix + (" " if i == total - 1 else "│ ") display_odds(pool_mapping[sub_pool_num], prefix=sub_prefix) def extract_top_pools(prompt): """ Extract all top-level {…} pools from the prompt. """ pools = [] current = [] depth = 0 for char in prompt: if char == '{': if depth == 0: current = [] current.append(char) depth += 1 elif char == '}': current.append(char) depth -= 1 if depth == 0: pools.append("".join(current).strip()) else: if depth > 0: current.append(char) return pools def main(): global pool_counter, pool_mapping pool_counter = 0 pool_mapping = {} filename = ensure_file_exists("prompt.txt") lines = load_prompt(filename) prompt = " ".join([line.strip() for line in lines]) ok, message = check_balanced_braces(lines) print(message) if not ok: return pools = extract_top_pools(prompt) if not pools: print("No random pools found.") return print("\nSimplified Odds (nested pools referenced by number):") for pool in pools: # Remove outer braces before computing odds stripped_pool = pool[1:-1] if pool.startswith("{") and pool.endswith("}") else pool pool_data = compute_odds(stripped_pool) print(f"\nPool {pool_data['pool_num']}:") #display_odds(pool_data) #display_odds_all_pools(pool_mapping[pool_data['pool_num']]) display_odds_conditional(pool_mapping[pool_data['pool_num']]) if name == "__main__": main() input("\nPress Enter to exit...")
🔹 Step 1: Save the Script
Copy the full code I gave you.
Paste it into a text file.
Save it as, for example:
comfy_prompt_checker.py
you should be able to just run it to generate the file it will check, then drop your prompts in whenever you need to.
after that it will check to find if there are any errors with any pools.
next it will also give you the odds for each option in the pools.
its not the best looking output but I don't really know how to python or code or anything but I wanted a tool to make sure things work out.
this is a much better second release.
should help with comfyUI random pools and keeping everything in order.
