nightwave / content.py
ratandeep's picture
SP3 generative song cards
8961e98 verified
Raw
History Blame Contribute Delete
11.9 kB
"""content.py — NIGHTWAVE station content banks (pure stdlib, Py3.9).
Single source of truth for the autonomous show. The SONG bank is served to the
browser (GET /api/songs) so the client renders the generative music + the
now-playing plate, and the server uses each song's title/artist for the
`song_intro` segment. The other banks feed the templated segment kinds
(station_id / weather / dedication) and the sonic logo.
Musical params on each song drive the in-browser generative engine:
key : root note name (the engine maps it to a MIDI root)
scale : major | minor | dorian | lydian | pentatonic_minor
tempo : BPM (60-90, late-night pace)
timbre : rhodes | sine_pad | triangle_pluck | soft_saw | music_box
vibe : a human label (used in the DJ's intro flavor; not load-bearing)
"""
# --- Songs (fictional; >=24, varied key/scale/tempo/timbre) ---------------- #
SONGS = [
{"title": "Neon Rain", "artist": "The Tuesday Ghosts", "vibe": "melancholy", "key": "A", "scale": "minor", "tempo": 72, "timbre": "rhodes"},
{"title": "Last Call at the Blue Hour", "artist": "Marlowe Quinn", "vibe": "jazzy", "key": "D", "scale": "dorian", "tempo": 84, "timbre": "rhodes"},
{"title": "Static Lullaby", "artist": "Velvet Antenna", "vibe": "dreamy", "key": "F", "scale": "lydian", "tempo": 64, "timbre": "sine_pad"},
{"title": "Highway of Sleeping Towns", "artist": "Cassette Sunday", "vibe": "nostalgic", "key": "C", "scale": "major", "tempo": 78, "timbre": "triangle_pluck"},
{"title": "The Diner at 3 A.M.", "artist": "Edith & the Empty Booths","vibe": "lonely", "key": "E", "scale": "minor", "tempo": 68, "timbre": "rhodes"},
{"title": "Moth to the Dial", "artist": "Low Tide Radio", "vibe": "hypnotic", "key": "G", "scale": "pentatonic_minor", "tempo": 70, "timbre": "soft_saw"},
{"title": "Snowfall on Channel Six", "artist": "The Quiet Hours", "vibe": "wistful", "key": "Bb", "scale": "major", "tempo": 74, "timbre": "music_box"},
{"title": "Paper Moon Motel", "artist": "Sundown Cardigan", "vibe": "warm", "key": "D", "scale": "major", "tempo": 80, "timbre": "triangle_pluck"},
{"title": "Ghost of a Slow Dance", "artist": "Marlowe Quinn", "vibe": "romantic", "key": "Ab", "scale": "minor", "tempo": 66, "timbre": "rhodes"},
{"title": "Telephone Wires", "artist": "The Tuesday Ghosts", "vibe": "pensive", "key": "C", "scale": "dorian", "tempo": 76, "timbre": "sine_pad"},
{"title": "Amber Streetlight", "artist": "Velvet Antenna", "vibe": "cozy", "key": "F", "scale": "major", "tempo": 82, "timbre": "rhodes"},
{"title": "Rain Check", "artist": "Cassette Sunday", "vibe": "breezy", "key": "G", "scale": "major", "tempo": 88, "timbre": "triangle_pluck"},
{"title": "Insomnia, Sweetly", "artist": "Edith & the Empty Booths","vibe": "tender", "key": "E", "scale": "minor", "tempo": 62, "timbre": "music_box"},
{"title": "The Long Way Home", "artist": "Low Tide Radio", "vibe": "hopeful", "key": "D", "scale": "lydian", "tempo": 80, "timbre": "soft_saw"},
{"title": "Vacancy", "artist": "The Quiet Hours", "vibe": "eerie", "key": "A", "scale": "pentatonic_minor", "tempo": 60, "timbre": "sine_pad"},
{"title": "Coffee Gone Cold", "artist": "Sundown Cardigan", "vibe": "bittersweet", "key": "Bb", "scale": "minor", "tempo": 70, "timbre": "rhodes"},
{"title": "Dial Tone Serenade", "artist": "Marlowe Quinn", "vibe": "jazzy", "key": "F", "scale": "dorian", "tempo": 86, "timbre": "rhodes"},
{"title": "Porchlight", "artist": "Cassette Sunday", "vibe": "gentle", "key": "C", "scale": "major", "tempo": 75, "timbre": "triangle_pluck"},
{"title": "Midnight, Repeating", "artist": "Velvet Antenna", "vibe": "hypnotic", "key": "G", "scale": "minor", "tempo": 72, "timbre": "soft_saw"},
{"title": "A Town That Isn't There", "artist": "The Tuesday Ghosts", "vibe": "mysterious", "key": "Eb", "scale": "lydian", "tempo": 68, "timbre": "sine_pad"},
{"title": "Saltwater Radio", "artist": "Low Tide Radio", "vibe": "dreamy", "key": "D", "scale": "major", "tempo": 78, "timbre": "music_box"},
{"title": "Last Bus Out", "artist": "Edith & the Empty Booths","vibe": "melancholy", "key": "A", "scale": "minor", "tempo": 66, "timbre": "rhodes"},
{"title": "Slow Channel Drift", "artist": "The Quiet Hours", "vibe": "ambient", "key": "F", "scale": "lydian", "tempo": 64, "timbre": "sine_pad"},
{"title": "Goodnight, Whoever You Are", "artist": "Sundown Cardigan", "vibe": "tender", "key": "C", "scale": "major", "tempo": 70, "timbre": "music_box"},
]
# --- Listener requests (fictional X/Twitter handles; canned, demo-safe) ----- #
# Keyed by song title; attached onto each SONGS entry below. Songs not listed
# here simply carry no request (DJ omits the attribution).
SONG_RECS = {
"Neon Rain": "@route9trucker",
"Static Lullaby": "@midnight_mara",
"The Diner at 3 A.M.": "@nightnurse_j",
"Moth to the Dial": "@dispatch_owl",
"Paper Moon Motel": "@last_call_lou",
"Telephone Wires": "@graveyard_gail",
"Insomnia, Sweetly": "@two_am_theo",
"The Long Way Home": "@haulin_hank",
"Coffee Gone Cold": "@diner_dot",
"Porchlight": "@porterst_pete",
"Last Bus Out": "@nightowl_nadia",
"Goodnight, Whoever You Are": "@signoff_sam",
}
for _song in SONGS:
_song["recommended_by"] = SONG_RECS.get(_song["title"], "")
# --- Station IDs (read between songs; the engine also plays a sonic-logo sting) #
STATION_IDS = [
"You're listening to NIGHTWAVE, ninety-eight point six — the last station on the dial.",
"This is NIGHTWAVE, keeping the lonely company till the sun comes up.",
"NIGHTWAVE, all night, every night, for everyone still awake out there.",
"You've got NIGHTWAVE — the only frequency that stays up as late as you do.",
"This is NIGHTWAVE radio, ninety-eight point six, broadcasting from somewhere warm.",
]
SONIC_LOGO = "NIGHTWAVE… the last station on the dial."
# --- Fictional weather + impossible clock (for the town that doesn't exist) -- #
WEATHER = [
"Out in Old Ferris tonight: low fog rolling off a river that isn't on any map, sixty-one degrees and a moon you could read by.",
"Weather for Hollow Pine: clear skies, a soft wind from the east, and the studio clock just struck a quarter past a number I don't recognize.",
"Over in Marrow Creek it's a still night, sixty degrees, and the rain's been falling on the same street corner for as long as I can remember.",
"Tonight in Little Embers: warm for the season, not a soul on the road, and a sky the color of a radio left on too long.",
"Down in Quietwater the fog's come in thick, fifty-eight degrees, and somewhere a porch light's been on since before I started this shift.",
]
# --- Pre-seeded listener dedications (the DJ reads these on air) ------------- #
DEDICATIONS = [
{"name": "a trucker on Route 9", "message": "for everyone driving through the dark tonight"},
{"name": "Marie", "message": "wherever the road's taken her"},
{"name": "the night-shift nurses", "message": "the ones holding the world together while it sleeps"},
{"name": "a kid who can't sleep", "message": "says the house is too quiet"},
{"name": "someone signing off a long shift", "message": "going home at last"},
{"name": "the regulars at the all-night diner", "message": "one more cup before the sun"},
{"name": "a listener named Sam", "message": "who said the nights feel longer lately"},
{"name": "anyone out there alone", "message": "you're not as alone as it feels right now"},
]
# --- Fallback "thoughts" (used only if the LLM thought segment fails) ------- #
THOUGHTS = [
"Funny thing about the small hours -- they make honest people of all of us.",
"Somebody out there is awake for a reason they haven't said out loud. This one's for you.",
"The world feels more true at this hour, I think -- when nobody's performing for anybody.",
"If you're up worrying tonight, let me carry it for a song or two. That's what the late shift is for.",
"There's a particular kind of company in a voice on the radio. I'm glad to be yours tonight.",
]
# --- Re-identification lines: the DJ names himself on every return --------- #
REJOINS = [
"You're back with Sam Dusk on NIGHTWAVE, ninety-eight point six.",
"Sam Dusk here, still with you in the small hours.",
"It's Sam Dusk, and you're listening to NIGHTWAVE all night long.",
"Welcome back -- Sam Dusk at the all-night desk on NIGHTWAVE 98.6.",
"This is Sam Dusk, keeping the lonely company on NIGHTWAVE.",
]
# Warm fallback lines for a caller turn when the model output is degenerate
# (replaces the undefined arc.sample_line the caller path used to fall back to).
CALLER_FALLBACKS = [
"That's a good one to sit with at this hour, friend. Stay right there with me.",
"I hear you, caller. Some questions are just good company on a long night. Thanks for calling in.",
"Glad you dialed in tonight. Let's let the next record answer for a while.",
"You take care out there, friend -- and thanks for keeping me company on the air.",
]
# --- Pre-caller intro: played the instant a call connects ------------------ #
CALLER_INTROS = [
"Well now -- looks like we've got a caller dialed into the station. Go ahead, "
"friend: who are you, and what's on your mind tonight?",
"There's a light blinking on the switchboard. You're on the air with Sam Dusk -- "
"tell me your name, caller, and what you'd like to ask.",
"Looks like somebody's up and reaching out. You're through to NIGHTWAVE, caller -- "
"who am I talking to, and what's keeping you awake tonight?",
]
# --- Off-dial ghost fragments (SP4 templated fallback; client renders half-heard) #
FRAGMENTS = [
"calling all night nurses near mile marker nine",
"the temperature in a town that isn't there is forty-one and falling",
"you're listening to a frequency that was never assigned",
"she dreamed the bridge was made of radio and nobody ever crossed",
"coming up, a record that was never pressed",
"this is the time signal for a clock that stopped in nineteen seventy-four",
"for the ones still driving, the road goes on a little longer",
]
# --- Procedural song-card word banks (SP3 fallback when the model can't write one) #
CARD_TITLE_A = ["Last", "Slow", "Empty", "Paper", "Static", "Amber", "Midnight", "Quiet",
"Saltwater", "Neon", "Distant", "Hollow", "Pale", "Long"]
CARD_TITLE_B = ["Train", "Hour", "Light", "Rain", "Lullaby", "Highway", "Streetlight",
"Channel", "Motel", "Wires", "Harbor", "Dream", "Window", "Radio"]
CARD_ARTIST_A = ["The", "Low", "Velvet", "Cassette", "Sundown", "Quiet", "Paper", "Slow"]
CARD_ARTIST_B = ["Tide Radio", "Antenna", "Sunday", "Hours", "Cardigan", "Ghosts",
"Overpass", "Boulevard", "Frequencies"]
# --- Allowed musical enums (for content integrity tests) -------------------- #
SCALES = ("major", "minor", "dorian", "lydian", "pentatonic_minor")
TIMBRES = ("rhodes", "sine_pad", "triangle_pluck", "soft_saw", "music_box")