feat(mcp): update bigmind/mcp-image-gen/webscraper servers; add image-gen batch scripts

This commit is contained in:
Patrick Plate
2026-06-11 09:02:09 +02:00
parent 0cb94122bf
commit bf721c1379
9 changed files with 2659 additions and 297 deletions
+411
View File
@@ -0,0 +1,411 @@
#!/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()