412 lines
20 KiB
Python
412 lines
20 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Patrick Hidden Name Artwork Generation Pipeline
|
||
|
||
Autonomous script to generate 26 ultra-detailed, visually rich digital artworks
|
||
where the name "PATRICK" is cleverly concealed within each composition.
|
||
Letters emerge organically from shapes, patterns, negative space, silhouettes,
|
||
alignment, or cumulative elements — never as plain text.
|
||
Visible only upon close inspection.
|
||
|
||
Uses the existing mcp-image-gen infrastructure (ComfyUI FLUX workflows).
|
||
Output organized in ~/Pictures/patrick_hidden_name/{theme}/{style}/
|
||
|
||
Usage:
|
||
cd /home/pplate/pi_mcps
|
||
python mcp/mcp-image-gen/patrick_hidden_gen.py
|
||
python mcp/mcp-image-gen/patrick_hidden_gen.py --dry-run
|
||
python mcp/mcp-image-gen/patrick_hidden_gen.py --model heretic
|
||
"""
|
||
|
||
import argparse
|
||
import copy
|
||
import json
|
||
import random
|
||
import time
|
||
import urllib.request
|
||
from pathlib import Path
|
||
from typing import Dict, List, Any, Optional
|
||
|
||
# --- Configuration ---
|
||
OUTPUT_ROOT = Path.home() / "Pictures" / "patrick_hidden_name"
|
||
PROGRESS_FILE = OUTPUT_ROOT / ".progress.json"
|
||
WORKFLOW_SCHNELL = Path(__file__).parent / "src/workflows/flux_schnell.json"
|
||
WORKFLOW_HERETIC = Path(__file__).parent / "src/workflows/flux2_klein_heretic.json"
|
||
|
||
# Core hidden-name prompting technique — applied to every asset
|
||
_HT = (
|
||
"the name PATRICK is cleverly and seamlessly concealed within the composition, "
|
||
"letters P-A-T-R-I-C-K emerge organically from shapes patterns negative space "
|
||
"silhouettes alignment or cumulative arrangement of multiple elements, "
|
||
"never plain text, subtle yet unmistakable once discovered, requires genuine "
|
||
"visual discovery and close inspection, natural integration into the scene, "
|
||
)
|
||
|
||
# Base quality boosters
|
||
_Q = "ultra-high detail, photorealistic rendering with cinematic lighting, intricate textures, depth of field, 8k resolution, masterpiece, best quality, "
|
||
|
||
ASSET_MANIFEST: List[Dict[str, Any]] = [
|
||
# 1. Dense crowds of marionette puppets — photoreal
|
||
{"id":"phn_01","theme":"marionettes","style":"photoreal","name":"marionette_crowd_puppets",
|
||
"prompt":_Q+_HT+"dense crowd of antique wooden marionette puppets on theatrical stage, "
|
||
"strings and body poses form PATRICK through negative space and limb alignment, "
|
||
"dramatic stage lighting with velvet curtains, realistic wood grain and fabric textures, "
|
||
"photorealistic cinematic","width":1024,"height":1024,"steps":4},
|
||
|
||
# 2. Marionettes — painterly
|
||
{"id":"phn_02","theme":"marionettes","style":"painterly","name":"marionette_theater_oil",
|
||
"prompt":_Q+_HT+"oil painting of crowded marionette theater, puppet strings and poses "
|
||
"form hidden PATRICK letters in composition, baroque style, rich colors, dramatic chiaroscuro "
|
||
"lighting, thick impasto brushwork","width":1024,"height":1024,"steps":20},
|
||
|
||
# 3. Birds — aerial formation
|
||
{"id":"phn_03","theme":"birds","style":"aerial","name":"bird_flock_formation",
|
||
"prompt":_Q+_HT+"aerial photograph of massive flock of starlings in precise murmuration, "
|
||
"bird silhouettes and gaps spell PATRICK through negative space and wing alignments, "
|
||
"golden hour light, vast sky, ultra realistic feathers and motion blur","width":1280,"height":720,"steps":4},
|
||
|
||
# 4. Birds — macro
|
||
{"id":"phn_04","theme":"birds","style":"macro","name":"bird_swarm_closeup",
|
||
"prompt":_Q+_HT+"macro photography of bird murmuration where individual bird silhouettes "
|
||
"and wing alignments subtly spell PATRICK, intricate feather detail, soft bokeh background, "
|
||
"extreme close focus","width":1024,"height":1024,"steps":4},
|
||
|
||
# 5. Tree roots — photoreal
|
||
{"id":"phn_05","theme":"tree_roots","style":"photoreal","name":"ancient_tree_roots",
|
||
"prompt":_Q+_HT+"ancient oak tree with massive tangled roots and branches that naturally "
|
||
"form letters PATRICK in their curves and intersections, forest floor moss and dappled sunlight, "
|
||
"hyper realistic bark texture, dramatic directional lighting","width":1024,"height":1024,"steps":4},
|
||
|
||
# 6. Tree roots — painterly
|
||
{"id":"phn_06","theme":"tree_roots","style":"painterly","name":"tree_root_illustration",
|
||
"prompt":_Q+_HT+"detailed botanical illustration of tree roots and branches forming hidden "
|
||
"PATRICK name through organic growth patterns, ink and watercolor, scientific accuracy with "
|
||
"artistic flair, John Muir style","width":1024,"height":1024,"steps":12},
|
||
|
||
# 7. School of fish
|
||
{"id":"phn_07","theme":"fish_school","style":"underwater","name":"fish_school_choreography",
|
||
"prompt":_Q+_HT+"underwater scene of thousands of tropical fish in synchronized school, "
|
||
"swimming patterns and gaps between bodies form PATRICK, crystal clear tropical water, "
|
||
"realistic scales and light caustics, underwater photography","width":1024,"height":1024,"steps":4},
|
||
|
||
# 8. Architecture — gothic facade
|
||
{"id":"phn_08","theme":"architecture","style":"architectural","name":"gothic_facade_hidden",
|
||
"prompt":_Q+_HT+"ornate gothic cathedral facade where windows arches and stone carvings "
|
||
"subtly align to spell PATRICK in negative space and shadow play, dramatic sunset lighting, "
|
||
"ultra detailed stone texture, architectural rendering","width":1024,"height":1024,"steps":4},
|
||
|
||
# 9. Architecture — aerial
|
||
{"id":"phn_09","theme":"architecture","style":"aerial","name":"modern_skyscraper_letters",
|
||
"prompt":_Q+_HT+"aerial view of modern city building complex where rooflines shadows and "
|
||
"window patterns form the hidden name PATRICK, golden hour, photorealistic architectural "
|
||
"rendering, top-down perspective","width":1280,"height":720,"steps":4},
|
||
|
||
# 10. Coral reef
|
||
{"id":"phn_10","theme":"coral_reef","style":"underwater","name":"vibrant_coral_reef",
|
||
"prompt":_Q+_HT+"vibrant coral reef ecosystem where branching coral fish and rock formations "
|
||
"naturally compose letters PATRICK through color and shape alignment, crystal water, "
|
||
"macro detail on polyps and textures, underwater photography","width":1024,"height":1024,"steps":4},
|
||
|
||
# 11. City skyline at night
|
||
{"id":"phn_11","theme":"city_skyline","style":"night","name":"neon_skyline_hidden",
|
||
"prompt":_Q+_HT+"futuristic city skyline at night where building lights and window patterns "
|
||
"subtly spell PATRICK in the neon glow and negative space between towers, cyberpunk atmosphere, "
|
||
"realistic reflections and bokeh, long exposure photography","width":1280,"height":720,"steps":4},
|
||
|
||
# 12. Rolling hills landscape
|
||
{"id":"phn_12","theme":"hills_landscape","style":"aerial","name":"rolling_hills_contours",
|
||
"prompt":_Q+_HT+"aerial view of rolling green hills and valleys where landscape contours "
|
||
"hedgerows and elevation shadows subtly form PATRICK, golden hour pastoral scene, "
|
||
"drone photography style","width":1280,"height":720,"steps":4},
|
||
|
||
# 13. Persian rug
|
||
{"id":"phn_13","theme":"persian_rug","style":"macro","name":"persian_rug_intricate",
|
||
"prompt":_Q+_HT+"extremely detailed close-up of hand-woven Persian rug where geometric and "
|
||
"floral patterns align to conceal name PATRICK in repeating motifs and negative space, "
|
||
"rich colors, silk texture, macro photography","width":1024,"height":1024,"steps":4},
|
||
|
||
# 14. Butterflies
|
||
{"id":"phn_14","theme":"butterflies","style":"painterly","name":"butterfly_swarm_metamorphosis",
|
||
"prompt":_Q+_HT+"swarm of colorful butterflies in flight where wing patterns and flight paths "
|
||
"collectively form hidden letters PATRICK, ethereal garden setting, detailed wing scales, "
|
||
"soft natural light, painterly illustration style","width":1024,"height":1024,"steps":12},
|
||
|
||
# 15. Circuit board
|
||
{"id":"phn_15","theme":"circuit_board","style":"macro","name":"circuit_board_traces",
|
||
"prompt":_Q+_HT+"extreme macro of complex multilayer circuit board where copper traces "
|
||
"solder points and component placement subtly spell PATRICK in wiring layout, "
|
||
"realistic metallic reflections, depth of field, technical precision","width":1024,"height":1024,"steps":4},
|
||
|
||
# 16. Ocean waves
|
||
{"id":"phn_16","theme":"ocean_waves","style":"photoreal","name":"crashing_waves_hidden",
|
||
"prompt":_Q+_HT+"dramatic crashing ocean waves where foam spray and wave crests align to "
|
||
"reveal name PATRICK in negative space and water movement, powerful seascape, "
|
||
"photorealistic water physics and light refraction","width":1280,"height":720,"steps":4},
|
||
|
||
# 17. Smoke and clouds
|
||
{"id":"phn_17","theme":"smoke_clouds","style":"painterly","name":"ethereal_smoke_clouds",
|
||
"prompt":_Q+_HT+"ethereal smoke and cloud formations in sky where swirling patterns and "
|
||
"negative space subtly spell PATRICK, dramatic volumetric lighting, painterly atmospheric "
|
||
"style, high detail turbulence and wisps","width":1024,"height":1024,"steps":12},
|
||
|
||
# 18. Dense jungle foliage
|
||
{"id":"phn_18","theme":"jungle_foliage","style":"macro","name":"dense_jungle_canopy",
|
||
"prompt":_Q+_HT+"dense tropical jungle foliage where leaves vines and light rays through "
|
||
"canopy form hidden name PATRICK through alignment and negative space, "
|
||
"ultra detailed leaf veins and moisture, macro realism","width":1024,"height":1024,"steps":4},
|
||
|
||
# 19. Roman mosaic
|
||
{"id":"phn_19","theme":"roman_mosaic","style":"architectural","name":"roman_mosaic_floor",
|
||
"prompt":_Q+_HT+"ancient Roman mosaic floor where thousands of tiny colored tiles arrange "
|
||
"to subtly hide name PATRICK in geometric pattern, realistic stone texture, "
|
||
"archaeological lighting, high detail tesserae","width":1024,"height":1024,"steps":4},
|
||
|
||
# 20. Military parade — aerial
|
||
{"id":"phn_20","theme":"military_parade","style":"aerial","name":"parade_formation_overhead",
|
||
"prompt":_Q+_HT+"aerial view of military parade formation where soldiers in perfect alignment "
|
||
"create letters PATRICK through their positions and shadows, crisp uniforms, "
|
||
"dramatic overhead perspective, photorealistic","width":1280,"height":720,"steps":4},
|
||
|
||
# 21. Stained glass
|
||
{"id":"phn_21","theme":"stained_glass","style":"architectural","name":"cathedral_stained_glass",
|
||
"prompt":_Q+_HT+"intricate stained glass window in gothic cathedral where lead lines and "
|
||
"colored glass panes form hidden name PATRICK through negative space and symbolic arrangement, "
|
||
"luminous backlighting, ultra detailed glass texture","width":1024,"height":1024,"steps":4},
|
||
|
||
# 22. Spider web
|
||
{"id":"phn_22","theme":"spider_web","style":"macro","name":"dew_spider_web_geometry",
|
||
"prompt":_Q+_HT+"macro photograph of perfect orb spider web with morning dew where radial "
|
||
"and spiral threads align to spell PATRICK in geometric structure, sparkling water droplets, "
|
||
"soft morning light, extreme detail","width":1024,"height":1024,"steps":4},
|
||
|
||
# 23. Galaxy star map
|
||
{"id":"phn_23","theme":"galaxy_stars","style":"cosmic","name":"star_map_constellation",
|
||
"prompt":_Q+_HT+"detailed star map of spiral galaxy where constellations and star clusters "
|
||
"subtly form letters PATRICK through their positions and connecting lines, "
|
||
"nebulae and cosmic dust, astronomical precision","width":1024,"height":1024,"steps":4},
|
||
|
||
# 24. Subway map
|
||
{"id":"phn_24","theme":"subway_map","style":"architectural","name":"subway_network_map",
|
||
"prompt":_Q+_HT+"highly detailed schematic subway tunnel map where intersecting colored lines "
|
||
"station markers and tunnel curves naturally spell name PATRICK in network layout, "
|
||
"clean diagrammatic style with realistic depth","width":1280,"height":720,"steps":4},
|
||
|
||
# 25. Marionettes — architectural rendering
|
||
{"id":"phn_25","theme":"marionettes","style":"architectural","name":"puppet_theater_stage",
|
||
"prompt":_Q+_HT+"architectural rendering of elaborate marionette theater stage where puppet "
|
||
"strings stage lights and scenery elements form hidden PATRICK, dramatic perspective, "
|
||
"ultra detailed wood and fabric","width":1024,"height":1024,"steps":4},
|
||
|
||
# 26. Birds — painterly
|
||
{"id":"phn_26","theme":"birds","style":"painterly","name":"bird_migration_painting",
|
||
"prompt":_Q+_HT+"painterly illustration of migrating bird flock where formation creates "
|
||
"concealed PATRICK letters, dramatic sky with volumetric clouds, rich oil painting texture, "
|
||
"romantic naturalist style","width":1024,"height":1024,"steps":20},
|
||
]
|
||
|
||
|
||
# ─────────────────────────────────────────────────────────
|
||
# Pipeline helpers (ported from cannamanage_gen.py)
|
||
# ─────────────────────────────────────────────────────────
|
||
|
||
def load_progress() -> Dict[str, Any]:
|
||
if PROGRESS_FILE.exists():
|
||
try:
|
||
with open(PROGRESS_FILE) as f:
|
||
return json.load(f)
|
||
except (json.JSONDecodeError, IOError):
|
||
pass
|
||
return {"completed": [], "failed": [], "started_at": time.strftime("%Y-%m-%dT%H:%M:%S")}
|
||
|
||
|
||
def save_progress(progress: Dict[str, Any]) -> None:
|
||
OUTPUT_ROOT.mkdir(parents=True, exist_ok=True)
|
||
with open(PROGRESS_FILE, "w") as f:
|
||
json.dump(progress, f, indent=2)
|
||
|
||
|
||
def load_workflow(model: str) -> Dict:
|
||
path = WORKFLOW_HERETIC if model == "heretic" else WORKFLOW_SCHNELL
|
||
with open(path) as f:
|
||
return json.load(f)
|
||
|
||
|
||
def submit_prompt(comfyui_url: str, workflow: Dict) -> str:
|
||
data = json.dumps({"prompt": workflow}).encode()
|
||
req = urllib.request.Request(
|
||
f"{comfyui_url}/prompt", data=data, headers={"Content-Type": "application/json"}
|
||
)
|
||
with urllib.request.urlopen(req) as resp:
|
||
return json.loads(resp.read())["prompt_id"]
|
||
|
||
|
||
def wait_for_image(comfyui_url: str, prompt_id: str, timeout: int = 300) -> Optional[Dict]:
|
||
print(" ⏳ Waiting for ComfyUI...", end="", flush=True)
|
||
start = time.time()
|
||
while time.time() - start < timeout:
|
||
try:
|
||
with urllib.request.urlopen(f"{comfyui_url}/history/{prompt_id}") as resp:
|
||
history = json.loads(resp.read())
|
||
if prompt_id in history:
|
||
print(" done.", flush=True)
|
||
outputs = history[prompt_id].get("outputs", {})
|
||
for node_out in outputs.values():
|
||
if "images" in node_out:
|
||
return node_out["images"][0]
|
||
return None
|
||
except Exception:
|
||
pass
|
||
print(".", end="", flush=True)
|
||
time.sleep(2)
|
||
print(" timeout!", flush=True)
|
||
return None
|
||
|
||
|
||
def download_image(comfyui_url: str, image_info: Dict, output_path: Path) -> bool:
|
||
try:
|
||
url = (
|
||
f"{comfyui_url}/view"
|
||
f"?filename={image_info['filename']}"
|
||
f"&subfolder={image_info.get('subfolder', '')}"
|
||
f"&type=output"
|
||
)
|
||
with urllib.request.urlopen(url) as resp:
|
||
img_data = resp.read()
|
||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||
output_path.write_bytes(img_data)
|
||
print(f" ✅ Saved: {output_path} ({len(img_data) // 1024}KB)")
|
||
return True
|
||
except Exception as e:
|
||
print(f" ❌ Download failed: {e}")
|
||
return False
|
||
|
||
|
||
def patch_workflow(workflow: Dict, asset: Dict, model: str) -> Dict:
|
||
wf = copy.deepcopy(workflow)
|
||
seed = random.randint(0, 2**32 - 1)
|
||
if model == "heretic":
|
||
wf["2"]["inputs"]["text"] = asset["prompt"]
|
||
wf["3"]["inputs"]["text"] = "plain text letters, obvious text overlay, watermark, low quality"
|
||
wf["6"]["inputs"]["width"] = asset["width"]
|
||
wf["6"]["inputs"]["height"] = asset["height"]
|
||
wf["7"]["inputs"]["steps"] = asset["steps"]
|
||
wf["13"]["inputs"]["filename_prefix"] = asset["name"]
|
||
if "10" in wf:
|
||
wf["10"]["inputs"]["noise_seed"] = seed
|
||
else:
|
||
# flux_schnell.json: node 6=pos, 33=neg, 27=latent(w/h), 13=ksampler(steps/seed), 9=save
|
||
wf["6"]["inputs"]["text"] = asset["prompt"]
|
||
wf["33"]["inputs"]["text"] = "plain text letters, obvious text overlay, watermark, low quality"
|
||
wf["27"]["inputs"]["width"] = asset["width"]
|
||
wf["27"]["inputs"]["height"] = asset["height"]
|
||
wf["13"]["inputs"]["steps"] = asset["steps"]
|
||
wf["13"]["inputs"]["seed"] = seed
|
||
wf["9"]["inputs"]["filename_prefix"] = asset["name"]
|
||
return wf
|
||
|
||
|
||
def generate_asset(comfyui_url: str, asset: Dict, model: str, progress: Dict) -> bool:
|
||
if asset["id"] in progress["completed"]:
|
||
print(f" ⏭️ Skipping already completed: {asset['name']}")
|
||
return True
|
||
|
||
print(f"\n Prompt : {asset['prompt'][:100]}...")
|
||
print(f" Size : {asset['width']}×{asset['height']} Steps: {asset['steps']}")
|
||
|
||
try:
|
||
workflow = load_workflow(model)
|
||
workflow = patch_workflow(workflow, asset, model)
|
||
prompt_id = submit_prompt(comfyui_url, workflow)
|
||
image_info = wait_for_image(comfyui_url, prompt_id)
|
||
|
||
if not image_info:
|
||
progress["failed"].append(asset["id"])
|
||
save_progress(progress)
|
||
return False
|
||
|
||
output_dir = OUTPUT_ROOT / asset["theme"] / asset["style"]
|
||
output_dir.mkdir(parents=True, exist_ok=True)
|
||
output_path = output_dir / f"{asset['name']}.png"
|
||
|
||
if download_image(comfyui_url, image_info, output_path):
|
||
progress["completed"].append(asset["id"])
|
||
save_progress(progress)
|
||
return True
|
||
else:
|
||
progress["failed"].append(asset["id"])
|
||
save_progress(progress)
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f" ❌ Error: {e}")
|
||
progress["failed"].append(asset["id"])
|
||
save_progress(progress)
|
||
return False
|
||
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser(
|
||
description="Patrick Hidden Name Artwork Generation Pipeline"
|
||
)
|
||
parser.add_argument("--dry-run", action="store_true",
|
||
help="Print manifest without generating")
|
||
parser.add_argument("--model", choices=["schnell", "heretic"], default="schnell",
|
||
help="Model: schnell (~10s/img) or heretic (~52s/img, higher quality)")
|
||
parser.add_argument("--comfyui", default="http://localhost:8188",
|
||
help="ComfyUI URL")
|
||
args = parser.parse_args()
|
||
|
||
comfyui_url = args.comfyui
|
||
|
||
print("🚀 Patrick Hidden Name Artwork Pipeline")
|
||
print(f" Output : {OUTPUT_ROOT}")
|
||
print(f" Model : {args.model}")
|
||
print(f" ComfyUI : {comfyui_url}")
|
||
print(f" Total : {len(ASSET_MANIFEST)} ultra-detailed hidden-name artworks")
|
||
print(" Technique: Letters P-A-T-R-I-C-K concealed via organic shapes/negative space")
|
||
|
||
if args.dry_run:
|
||
print()
|
||
for asset in ASSET_MANIFEST:
|
||
print(f" {asset['id']:8} | {asset['theme']:15} | {asset['style']:12} | {asset['name']}")
|
||
total_est = sum(a["steps"] * 2.5 for a in ASSET_MANIFEST) / 60
|
||
print(f"\n ⏱️ Estimated runtime (schnell @4 steps): ~{total_est:.0f} minutes")
|
||
print("\nDry run complete. Remove --dry-run to begin generation.")
|
||
return
|
||
|
||
progress = load_progress()
|
||
remaining = [a for a in ASSET_MANIFEST if a["id"] not in progress["completed"]]
|
||
print(f" Resume : {len(progress['completed'])} completed, "
|
||
f"{len(progress['failed'])} failed, {len(remaining)} remaining")
|
||
|
||
if not remaining:
|
||
print("\n✅ All assets already complete!")
|
||
return
|
||
|
||
print(f"\nStarting generation... (Ctrl+C to pause — progress is saved)")
|
||
|
||
n_done = 0
|
||
n_fail = 0
|
||
for i, asset in enumerate(ASSET_MANIFEST, 1):
|
||
if asset["id"] in progress["completed"]:
|
||
continue
|
||
print(f"\n[{asset['theme']}/{asset['style']}] [{i}/{len(ASSET_MANIFEST)}] {asset['name']}")
|
||
if generate_asset(comfyui_url, asset, args.model, progress):
|
||
n_done += 1
|
||
else:
|
||
n_fail += 1
|
||
|
||
print("\n" + "=" * 60)
|
||
print("🎉 PIPELINE COMPLETE")
|
||
print(f" ✅ Completed this run : {n_done}")
|
||
print(f" ❌ Failed this run : {n_fail}")
|
||
print(f" 📦 Total completed : {len(progress['completed'])} / {len(ASSET_MANIFEST)}")
|
||
if progress["failed"]:
|
||
print(f" Failed IDs: {', '.join(progress['failed'][-10:])}")
|
||
print(f" Assets saved to: {OUTPUT_ROOT}")
|
||
print("=" * 60)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|