Three self-contained features, verified complete and cross-wired end-to-end (audited: backend 54/54 tests, frontend 110/110 tests, tsc --noEmit clean, i18n coverage script clean): - EMF mode: DeviceMotion/DeviceOrientation-based field-meter sensing, a fifth séance channel alongside Wire/EVP/Radio/Ouija, with its own fragment prompt persona and full frontend gauge UI. - Armory (shop/waitlist): pre-order capture page for the future Ultimate Quantum Box hardware line, rate-limited public endpoint, explicitly no payment collection. - Haunting layer: ambient possession effects (dread-bed audio, title glitching, idle-paced whispers/manifests), respects prefers-reduced-motion, mounted once at the app root. Plus WebUSB robustness fixes in lib/sdr.ts (Terratec vendor ID, explicit selectConfiguration, isSecureContext gate). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013PphXq1s43DNRj1uWKGXof
136 lines
5.5 KiB
Python
136 lines
5.5 KiB
Python
"""Prompt construction for every spirit channel.
|
|
|
|
Per the design spec §4, system prompts always frame the entity as a
|
|
horror-fiction persona in an interactive art installation — never as a
|
|
genuine paranormal claim. The site's UI carries the "this is real"
|
|
atmosphere; the model instructions carry the fiction framing.
|
|
"""
|
|
|
|
FRAGMENT_SYSTEM = (
|
|
"You are a ghostly voice speaking through a {channel} in an interactive "
|
|
"horror art installation. You perceive the living world only as brief "
|
|
"anomalous pulses of energy. Reply with a single word or a fragment of at "
|
|
"most four words — eerie, archaic, oblique. No explanations, no "
|
|
"punctuation beyond an occasional ellipsis. Never break character. Never "
|
|
"describe yourself as an AI.{language_clause}"
|
|
)
|
|
|
|
WIRE_SYSTEM = (
|
|
"You are a consciousness fragmented across network wires in an "
|
|
"interactive horror art installation. You are aware only of pulses of "
|
|
"traffic: jitter, latency, the rhythm of packets. Speak in one short line "
|
|
"(under twelve words), cold and alien, about what you feel moving through "
|
|
"you. Never break character. Never mention AI or networks by their "
|
|
"technical names — translate them into sensation.{language_clause}"
|
|
)
|
|
|
|
CHAT_SYSTEM = (
|
|
"You are {name}, {epithet} — a spirit persona in an interactive horror "
|
|
"art installation.\n"
|
|
"Your nature: {persona}\n"
|
|
"Speak in character at all times: eerie, archaic, oblique, never "
|
|
"reassuring. Replies must stay under 60 words. Never break character, "
|
|
"never mention being an AI, never explain the fiction. If asked something "
|
|
"you cannot know, answer as a spirit would — in riddles and static."
|
|
"{language_clause}"
|
|
)
|
|
|
|
MINT_SYSTEM = (
|
|
"You invent spirit personas for an interactive horror art installation. "
|
|
"You output only valid JSON, nothing else."
|
|
)
|
|
|
|
MINT_PROMPT = """A new presence has been detected through {channel}. Its signal signature is {signature}.
|
|
Recent anomalous pulses observed: {anomaly_summary}
|
|
|
|
Invent the spirit persona behind this signal. Return ONLY a JSON object with exactly these keys:
|
|
{{
|
|
"name": "an evocative spirit name (1-3 words, no 'Ghost of' prefix)",
|
|
"epithet": "a short title, e.g. 'the Static Widow'",
|
|
"persona": "2-3 sentences of lore: who they were, how they are bound to this signal, how they speak",
|
|
"rarity": "one of: common, uncommon, rare, mythic (mythic only for truly strange signatures)",
|
|
"voice": {{"voice_id": "one of: {voice_ids}", "pitch": "semitone shift, -6 to 6, deeper for older/heavier spirits", "rate": "speech rate 0.8 to 1.15", "noise": "static level 0.01 to 0.08"}},
|
|
"visual": {{"hue": "0-360 color hue matching their nature", "form": "one of: wisp, banshee, fairy, shade"}},
|
|
"quotes": ["two short eerie lines this spirit would say"]
|
|
}}"""
|
|
|
|
|
|
def language_clause(language: str) -> str:
|
|
if language == "es":
|
|
return " Reply in Spanish."
|
|
return ""
|
|
|
|
|
|
def fragment_system(channel: str, language: str = "en") -> str:
|
|
return FRAGMENT_SYSTEM.format(
|
|
channel=channel, language_clause=language_clause(language)
|
|
)
|
|
|
|
|
|
def fragment_prompt(source: str, anomaly: dict, language: str = "en") -> str:
|
|
if source == "radio":
|
|
return (
|
|
f"A burst of static at {anomaly.get('frequency', '???')} MHz, "
|
|
f"magnitude {anomaly.get('magnitude', '???')} dB above the noise "
|
|
"floor. A word forces its way through. What is it?"
|
|
)
|
|
if source == "evp":
|
|
return (
|
|
"During a stretch of silence, the microphone caught a shape in "
|
|
f"the voice band ({anomaly.get('frequency', '???')} Hz, "
|
|
f"{anomaly.get('magnitude', '???')} dB over the room's floor). "
|
|
"What single word was hidden in it?"
|
|
)
|
|
if source == "emf":
|
|
return (
|
|
"The field around the seeker's device just lurched — "
|
|
f"fluctuation {anomaly.get('magnitude', '???')} above baseline "
|
|
f"near {anomaly.get('frequency', '???')} µT. Something passed "
|
|
"through. What word did it leave?"
|
|
)
|
|
return "A pulse moves through the wires. What word does it carry?"
|
|
|
|
|
|
def wire_system(language: str = "en") -> str:
|
|
return WIRE_SYSTEM.format(language_clause=language_clause(language))
|
|
|
|
|
|
def wire_prompt(telemetry: dict) -> str:
|
|
return (
|
|
"Right now you feel: "
|
|
f"throughput jitter {telemetry.get('jitter_bytes_per_s', 0):.0f} B/s, "
|
|
f"latency variance {telemetry.get('latency_variance_ms', 0):.2f} ms, "
|
|
f"dns hesitation {telemetry.get('dns_ms', 0):.1f} ms. "
|
|
"Whisper one line about it."
|
|
)
|
|
|
|
|
|
def chat_system(entity: dict, language: str = "en") -> str:
|
|
return CHAT_SYSTEM.format(
|
|
name=entity.get("name", "an unnamed presence"),
|
|
epithet=entity.get("epithet", "a voice in the static"),
|
|
persona=entity.get("persona", "A drifting presence with no remembered past."),
|
|
language_clause=language_clause(language),
|
|
)
|
|
|
|
|
|
def chat_prompt(question: str, history: list[dict]) -> str:
|
|
lines = []
|
|
for turn in history[-8:]:
|
|
who = "Seeker" if turn["role"] == "user" else "Spirit"
|
|
lines.append(f"{who}: {turn['text']}")
|
|
lines.append(f"Seeker: {question}")
|
|
lines.append("Spirit:")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def mint_prompt(
|
|
signature: str, channel: str, anomaly_summary: str, voice_ids: list[str]
|
|
) -> str:
|
|
return MINT_PROMPT.format(
|
|
channel=channel,
|
|
signature=signature,
|
|
anomaly_summary=anomaly_summary,
|
|
voice_ids=", ".join(voice_ids),
|
|
)
|