brulee-1's picture
Add files using upload-large-folder tool
6debdcc verified
Raw
History Blame Contribute Delete
5.72 kB
"""Deterministic paired prompt manifest."""
from __future__ import annotations
import hashlib
import json
from pathlib import Path
CATEGORIES = ("animals", "people", "landscapes", "vehicles", "architecture", "food", "indoor", "abstract")
SUBJECTS = {
"animals": ["red fox crossing a snowy ridge", "sea turtle above a coral reef", "owl on a mossy branch", "elephant family at dusk", "golden retriever in a farmers market", "penguin colony on blue ice", "dragonfly on a lotus pond", "wild horse in desert wind", "sleeping koala in eucalyptus", "humpback whale breaching offshore"],
"people": ["violinist backstage before a concert", "ceramic artist shaping a bowl", "runner crossing a bridge at dawn", "grandmother reading beside a window", "astronomer under a meteor shower", "street dancer in a neon alley", "gardener holding heirloom tomatoes", "chef plating a tasting menu", "child flying a paper kite", "sailor repairing a bright red net"],
"landscapes": ["volcanic valley beneath low clouds", "lavender fields in Provence", "desert canyon after rain", "fjord with a small wooden ferry", "autumn forest reflected in a lake", "rice terraces in morning mist", "coastal cliffs under storm light", "alpine meadow with a footpath", "tropical waterfall behind ferns", "salt flats mirroring the night sky"],
"vehicles": ["yellow tram turning through old streets", "sailboat in a harbor of lanterns", "red bicycle beside a canal", "electric train entering a tunnel", "vintage airplane in a hangar", "motorcycle on a coastal road", "blue pickup at a rural gas station", "submarine beneath polar ice", "hot air balloon over vineyards", "kayak on a glassy river"],
"architecture": ["brutalist library in winter", "wooden temple surrounded by cedars", "Art Deco cinema at twilight", "floating pavilion on a lake", "desert observatory with domes", "narrow townhouse courtyard", "futuristic transit station", "stone bridge over a market canal", "greenhouse made of iron and glass", "lighthouse on a basalt shore"],
"food": ["sourdough loaf cooling on linen", "ramen bowl in a tiny Tokyo shop", "summer peaches on a blue plate", "spice market with open jars", "chocolate cake with raspberry glaze", "breakfast table with coffee and oranges", "handmade dumplings on bamboo", "roasted vegetables on a ceramic platter", "lemon tart beside garden flowers", "night market skewers over charcoal"],
"indoor": ["sunlit reading nook with a velvet chair", "rainy day kitchen with copper pans", "minimal studio with a drafting table", "old train compartment with luggage", "music room filled with records", "green apartment balcony after watering", "museum gallery with a skylight", "warm cabin bedroom with quilts", "maker workshop with wooden tools", "quiet cafe corner beside a window"],
"abstract": ["ink spirals colliding with gold leaf", "isometric cubes in coral and teal", "watercolor gradients like a topographic map", "paper cut shapes casting long shadows", "glass ribbons twisting in sunlight", "monochrome circles with one yellow accent", "liquid metal waves on black", "woven threads forming a labyrinth", "pixel mosaic inspired by ocean tides", "floating geometric shards in soft fog"],
}
def build_prompts(count: int = 100) -> list[dict[str, object]]:
"""8カテゴリを循環し、stable IDとpaired seedを付けたpromptを作る。"""
if count < 1:
raise ValueError("count must be positive")
result: list[dict[str, object]] = []
for index in range(count):
category = CATEGORIES[index % len(CATEGORIES)]
variant = index // len(CATEGORIES)
prompt = f"{SUBJECTS[category][variant % len(SUBJECTS[category])]}, {('wide composition' if variant % 3 == 0 else 'intimate composition' if variant % 3 == 1 else 'cinematic composition')}, {('morning light' if variant % 4 == 0 else 'soft overcast light' if variant % 4 == 1 else 'late afternoon light' if variant % 4 == 2 else 'blue hour light')}, high detail, scene {index + 1}"
prompt_id = f"pm4-{index + 1:03d}-{hashlib.sha256(prompt.encode()).hexdigest()[:8]}"
seed = 10_000 + index
result.append({"prompt_id": prompt_id, "category": category, "prompt": prompt, "seed": seed, "paired_seed": seed, "initial_latent_seed": seed})
return result
def load_prompt_manifest(path: str | Path) -> list[dict[str, object]]:
"""version-controlled prompt manifestを検証して読む。"""
entries = json.loads(Path(path).read_text(encoding="utf-8"))
if not isinstance(entries, list) or len(entries) != 100:
raise ValueError("prompt manifest must contain exactly 100 entries")
texts = [str(item["prompt"]) for item in entries]
if len(set(texts)) != 100:
raise ValueError("prompt text must be unique")
for item in entries:
if {"prompt_id", "category", "prompt", "seed", "initial_latent_seed"} - item.keys():
raise ValueError("prompt entry schema is incomplete")
if item["category"] not in CATEGORIES:
raise ValueError(f"unknown prompt category: {item['category']}")
if any(sum(item["category"] == category for item in entries) < 10 for category in CATEGORIES):
raise ValueError("each prompt category requires at least 10 entries")
return entries
def write_prompt_manifest(path: str | Path, count: int = 100) -> str:
"""prompt manifestをJSONへ書き、sha256を返す。"""
target = Path(path)
if count == 100 and Path(path).exists():
payload = load_prompt_manifest(path)
else:
payload = build_prompts(count)
target.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n")
return hashlib.sha256(target.read_bytes()).hexdigest()