140 lines
6.1 KiB
Python
140 lines
6.1 KiB
Python
"""Horror prompt library — severity-tiered SDXL prompts + XTTS voice texts."""
|
|
|
|
import random
|
|
|
|
# Negative prompt applied to all SDXL generations
|
|
NEGATIVE_PROMPT = (
|
|
"cheerful, bright, colorful, cartoon, anime, text, watermark, "
|
|
"logo, signature, pleasant, happy, cute, well-lit, clean"
|
|
)
|
|
|
|
# (min_severity, [prompt_templates])
|
|
# Each tier's prompts are available when severity >= min_severity.
|
|
# Prompts use {detail} placeholder for procedural variation.
|
|
SEVERITY_TIERS: list[tuple[float, list[str]]] = [
|
|
(0.0, [
|
|
"dark abstract void, deep shadows, {detail}, horror atmosphere, cinematic",
|
|
"black fog rolling over dark water, {detail}, ominous, photorealistic",
|
|
"concrete corridor stretching into darkness, {detail}, liminal space, unsettling",
|
|
"dark gradient with subtle organic texture, {detail}, dread, macro photography",
|
|
"abandoned room in total darkness, single light source, {detail}, eerie silence",
|
|
"static noise pattern forming almost-shapes, {detail}, analog horror aesthetic",
|
|
"deep underground cavern, no visible exit, {detail}, claustrophobic, dark",
|
|
]),
|
|
(1.0, [
|
|
"distorted human face emerging from darkness, {detail}, uncanny valley, horror",
|
|
"long dark hallway with a figure at the end, {detail}, found footage aesthetic",
|
|
"room where the walls are slightly wrong, {detail}, liminal horror, photorealistic",
|
|
"mirror reflection that doesn't match, {detail}, psychological horror",
|
|
"staircase descending into impossible depth, {detail}, surreal horror",
|
|
"doorway opening into a void, {detail}, threshold horror, dark atmosphere",
|
|
"familiar room but every proportion is wrong, {detail}, dreamlike horror",
|
|
]),
|
|
(2.0, [
|
|
"face melting into dark liquid, {detail}, body horror, visceral, photorealistic",
|
|
"impossible architecture folding in on itself, {detail}, Escher nightmare, dark",
|
|
"multiple overlapping faces fused together, {detail}, uncanny, disturbing",
|
|
"corridor with too many doors, all slightly open, {detail}, psychological horror",
|
|
"human figure with wrong number of limbs, {detail}, body horror, dark",
|
|
"room full of eyes watching from every surface, {detail}, paranoid horror",
|
|
"teeth growing from walls, {detail}, organic horror, visceral, photorealistic",
|
|
]),
|
|
(3.0, [
|
|
"screaming void, flesh merging with architecture, {detail}, extreme body horror",
|
|
"reality fracturing into bleeding shards, {detail}, cosmic horror, overwhelming",
|
|
"mass of tangled human forms, {detail}, hellscape, Beksinski inspired, photorealistic",
|
|
"sky replaced by a massive watching face, {detail}, cosmic dread, surreal",
|
|
"ground made of writhing organic matter, {detail}, Giger inspired, dark",
|
|
"impossible geometry that hurts to perceive, {detail}, Lovecraftian, extreme",
|
|
"world turned inside out, organs as landscape, {detail}, visceral cosmic horror",
|
|
]),
|
|
]
|
|
|
|
# Procedural detail fragments inserted into {detail} placeholders
|
|
_DETAILS = [
|
|
"wet surfaces", "rust and decay", "dim red light", "flickering fluorescent",
|
|
"peeling paint", "fog and mist", "dripping liquid", "cracked surfaces",
|
|
"organic growths", "shadow patterns", "reflected light on water",
|
|
"dust particles", "cobwebs", "stained walls", "scratched metal",
|
|
"condensation", "mold patterns", "burned edges", "frozen in time",
|
|
"overlapping shadows", "single bare bulb", "moonlight through cracks",
|
|
"bioluminescent", "blood-red sky", "green pallor", "bruise-purple tint",
|
|
]
|
|
|
|
# Whisper fragments — sentence fragments, numbers, names, nonsense
|
|
_WHISPERS = [
|
|
"seven", "behind you", "don't turn around", "it remembers",
|
|
"the door", "counting", "almost time", "in the walls",
|
|
"not alone", "watching", "three two one", "forgetting",
|
|
"underneath", "the wrong room", "teeth", "it knows your name",
|
|
"listen", "the sound", "nobody left", "opening",
|
|
"he's here", "she won't stop", "the children", "below",
|
|
"always here", "never gone", "the dark", "it follows",
|
|
"coming closer", "just outside", "the mirror", "look",
|
|
"run", "too late", "the floor", "above you",
|
|
"inside", "the old house", "breathing", "footsteps",
|
|
"scratching", "dripping", "humming", "whispers",
|
|
"ha ha ha ha", "one two three four five", "again again again",
|
|
"please", "help me", "let me in", "let me out",
|
|
]
|
|
|
|
# Direct address phrases — "it sees you" moments
|
|
_DIRECT_ADDRESS = [
|
|
"you're still here",
|
|
"don't leave",
|
|
"I can see you",
|
|
"why",
|
|
"stay",
|
|
"you came back",
|
|
"I've been waiting",
|
|
"don't close your eyes",
|
|
"you can't leave",
|
|
"I know you're there",
|
|
"look at me",
|
|
"do you hear it",
|
|
"it's behind you",
|
|
"we see you",
|
|
"you're one of us now",
|
|
"don't you remember",
|
|
"you were here before",
|
|
"this is yours",
|
|
"you did this",
|
|
"welcome home",
|
|
]
|
|
|
|
|
|
def get_image_prompt(severity: float) -> str:
|
|
"""Select and fill a horror prompt appropriate for the given severity.
|
|
|
|
Higher severity unlocks more extreme prompt tiers.
|
|
A random prompt is chosen from all available tiers, weighted toward
|
|
the highest unlocked tier.
|
|
"""
|
|
available: list[tuple[float, str]] = []
|
|
for threshold, templates in SEVERITY_TIERS:
|
|
if severity >= threshold:
|
|
for tmpl in templates:
|
|
available.append((threshold, tmpl))
|
|
|
|
if not available:
|
|
available = [(0.0, t) for t in SEVERITY_TIERS[0][1]]
|
|
|
|
# Weight toward higher tiers: tier_weight = 1 + tier_index
|
|
tier_thresholds = sorted(set(t[0] for t in available))
|
|
tier_map = {t: i + 1 for i, t in enumerate(tier_thresholds)}
|
|
weights = [tier_map[threshold] for threshold, _ in available]
|
|
|
|
_, template = random.choices(available, weights=weights, k=1)[0]
|
|
detail = random.choice(_DETAILS)
|
|
return template.format(detail=detail)
|
|
|
|
|
|
def get_voice_text() -> str:
|
|
"""Random whisper fragment for XTTS voice generation."""
|
|
return random.choice(_WHISPERS)
|
|
|
|
|
|
def get_direct_address_text() -> str:
|
|
"""Random direct address phrase for 'it sees you' moments."""
|
|
return random.choice(_DIRECT_ADDRESS)
|