Some checks failed
Architecture Lint / Linter Tests (pull_request) Successful in 35s
Smoke Test / smoke (pull_request) Failing after 23s
Validate Config / YAML Lint (pull_request) Failing after 19s
Validate Config / JSON Validate (pull_request) Successful in 23s
Validate Config / Python Syntax & Import Check (pull_request) Failing after 1m4s
Validate Config / Python Test Suite (pull_request) Has been skipped
Validate Config / Shell Script Lint (pull_request) Failing after 43s
Validate Config / Cron Syntax Check (pull_request) Successful in 8s
Validate Config / Deploy Script Dry Run (pull_request) Successful in 8s
Validate Config / Playbook Schema Validation (pull_request) Successful in 27s
Validate Training Data / validate (pull_request) Successful in 23s
PR Checklist / pr-checklist (pull_request) Successful in 4m26s
Architecture Lint / Lint Repository (pull_request) Failing after 29s
- scripts/generate-pop-scenes.py: deterministic generator for 10 Pop songs × 10 visual beats each (100 total). Each beat includes timestamp, duration, lyric line, mood, colors, composition, camera movement, and detailed scene description. - training-data/scene-descriptions-pop.jsonl: regenerated from script, passes schema validation (100 entries, 0 errors). - Also mirrors output to ~/.hermes/training-data/ on generation. Closes #606
652 lines
36 KiB
Python
652 lines
36 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generate 100 lyrics→visual scene description sets for Pop songs.
|
|
|
|
Issue: timmy-config #606
|
|
Output: training-data/scene-descriptions-pop.jsonl
|
|
Also mirrors to ~/.hermes/training-data/scene-descriptions-pop.jsonl
|
|
|
|
Format per training-data/schema.json:
|
|
song, artist, genre, bpm, beat, timestamp, duration_seconds,
|
|
lyric_line, scene { mood, colors, composition, camera, description }
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
|
|
GENRE = "Pop"
|
|
DURATION_SECONDS = 4.0
|
|
|
|
SONGS = [
|
|
{
|
|
"title": "Neon Heartbeat",
|
|
"artist": "Synthwave Collective",
|
|
"bpm": 120,
|
|
"lyrics": [
|
|
"I saw your light through the pouring rain / A neon signal cutting through the pain",
|
|
"We're dancing on the edge of something real / The bass drops low and I can finally feel",
|
|
"Spin me faster through the galaxy / Every atom screaming you and me",
|
|
"The morning comes like an unpaid debt / The glow sticks fade but I don't forget",
|
|
"Sitting in the car with the engine off / Replaying every word, every laugh, every cough",
|
|
"Your silhouette against the vending machine glow / The only currency I want to know",
|
|
"Radio static, your voice cuts through / Telling me things I already knew",
|
|
"Streetlights blur like watercolor tears / We've been running from our fears for years",
|
|
"Hold my hand till the sunrise breaks / Promise me this is not a mistake",
|
|
"The city exhales and we exhale too / Neon heartbeat, me and you",
|
|
],
|
|
"moods": [
|
|
"hopeful", "euphoric", "euphoric", "bittersweet", "reflective",
|
|
"tender", "intimate", "nostalgic", "yearning", "peaceful",
|
|
],
|
|
"colors": [
|
|
["pink", "cyan"],
|
|
["neon pink", "electric blue", "white"],
|
|
["gold", "hot pink", "silver"],
|
|
["purple", "grey"],
|
|
["midnight blue", "soft gold"],
|
|
["amber", "magenta"],
|
|
["steel blue", "pale yellow"],
|
|
["violet", "teal"],
|
|
["coral", "indigo"],
|
|
["rose", "sky blue"],
|
|
],
|
|
"compositions": [
|
|
"wide establishing shot", "medium close-up", "dynamic tracking",
|
|
"static intimate", "low angle", "extreme close-up", "overhead",
|
|
"two-shot", "profile", "aerial",
|
|
],
|
|
"cameras": [
|
|
"slow dolly in", "handheld follow", "steady tracking", "locked off",
|
|
"crane up", "push in", "whip pan", "steadicam orbit", "rack focus",
|
|
"drone pull-back",
|
|
],
|
|
"descriptions": [
|
|
"Rain-slicked streets reflect neon signs in puddles. A lone figure stands under a flickering marquee, face half-lit by pink and cyan fluorescence.",
|
|
"Crowded dance floor, bodies moving in synchronized abandon. Laser beams cut through haze as the drop hits.",
|
|
"Cosmic visualization—two figures spin in zero gravity surrounded by stardust trails and holographic constellations.",
|
|
"Empty warehouse at dawn. Discarded glow sticks scatter the floor like fallen stars. One person sits against the wall, head in hands.",
|
|
"Interior car scene, dashboard glow illuminating tired eyes. Rain streaks the windshield. A cassette tape hangs from the rearview.",
|
|
"Late-night convenience store. Fluorescent hum. Two people share a candy bar, laughter echoing off linoleum tiles.",
|
|
"Bedroom at 2 AM. Radio dial glows amber. One person lies on their back, phone pressed to ear, staring at ceiling cracks.",
|
|
"Rain-blurred windshield, streetlights smearing like wet paint. Hands grip steering wheel at ten and two, knuckles white.",
|
|
"Rooftop at sunrise. Two silhouettes against a gradient sky. City skyline behind them, steam rising from coffee cups.",
|
|
"Wide cityscape at dawn. Neon signs flicker off one by one. Two figures walk away from camera down an empty boulevard.",
|
|
],
|
|
},
|
|
{
|
|
"title": "Sugar Wounds",
|
|
"artist": "Candy Knife",
|
|
"bpm": 128,
|
|
"lyrics": [
|
|
"You taste like summer but you leave like winter / Sweet on the tongue, then the frost sets in",
|
|
"I keep your letters in a mason jar / Every word a sugar-coated scar",
|
|
"The carnival left town but I'm still here / Riding the Ferris wheel of fear",
|
|
"Cotton candy dreams dissolve in rain / Sticky fingers, nothing to gain",
|
|
"You called me darling then you called me gone / Left me humming the same old song",
|
|
"Baking cookies at 3 AM / Pretending you're coming home again",
|
|
"The recipe says two cups of trust / I measured wrong and now it's dust",
|
|
"Pinwheel spinning in the garden bed / Childhood wishes, long since dead",
|
|
"I wear your sweater like armor now / Too big, too warm, too full of how",
|
|
"Sugar wounds don't bleed, they ache / A cavity where love used to bake",
|
|
],
|
|
"moods": [
|
|
"bittersweet", "melancholic", "anxious", "defeated", "lonely",
|
|
"nostalgic", "resigned", "wistful", "guarded", "aching",
|
|
],
|
|
"colors": [
|
|
["candy pink", "ice blue"],
|
|
["pastel yellow", "dusty rose"],
|
|
["rust", "faded teal"],
|
|
["lavender", "grey"],
|
|
["sepia", "burnt orange"],
|
|
["warm amber", "cream"],
|
|
["charcoal", "pale peach"],
|
|
["sunbleached red", "mint green"],
|
|
["oatmeal", "cranberry"],
|
|
["vanilla", "ash"],
|
|
],
|
|
"compositions": [
|
|
"close-up", "medium shot", "wide shot", "intimate two-shot",
|
|
"extreme close-up", "over-the-shoulder", "high angle", "low angle",
|
|
"profile", "silhouette",
|
|
],
|
|
"cameras": [
|
|
"slow push in", "static", "gentle zoom", "locked off",
|
|
"handheld subtle", "crane down", "dolly out", "pan across",
|
|
"tilt down", "pull focus",
|
|
],
|
|
"descriptions": [
|
|
"Close-up of lips touching a popsicle, summer light streaming through window blinds. Ice crystals melting on warm skin.",
|
|
"Hands placing folded letters into a glass jar on a shelf. Dust motes dance in afternoon light.",
|
|
"Abandoned carnival at dusk. A lone Ferris wheel car sways in wind. Ticket stubs scatter across dirt.",
|
|
"Rain dissolving cotton candy on a stick. Sticky rivulets run down a child's arm. Tears mix with rain.",
|
|
"Empty hallway, one coat still on the hook. Shoes by the door. A phone buzzes unanswered on the table.",
|
|
"Kitchen at night. Flour dusts the counter. One person shapes dough alone, radio playing static.",
|
|
"Measuring cups tipped over on tile. A broken eggshell. Crumbs scattered like promises.",
|
|
"Garden at golden hour. A pinwheel spins lazily. Overgrown grass whispers against a rusted swing set.",
|
|
"Oversized sweater sleeves covering hands. One person hugs themselves, looking out rain-streaked glass.",
|
|
"Empty baking sheet in an empty oven. Timer dings. No one comes to check.",
|
|
],
|
|
},
|
|
{
|
|
"title": "Parallel Lines",
|
|
"artist": "Geometry Club",
|
|
"bpm": 115,
|
|
"lyrics": [
|
|
"We walk the same street but opposite sides / Measured distance, parallel lives",
|
|
"Your window faces mine across the alley / I count the seconds till your light goes daily",
|
|
"Same train, different cars, same destination / Silent calculation, endless hesitation",
|
|
"The geometry of almost touching / Close enough to feel the air rushing",
|
|
"You order coffee the way I would / If I had the nerve to stand where you stood",
|
|
"Two shadows on the pavement never meet / A mathematician's defeat",
|
|
"I drew a line from my heart to yours / It went on forever, never reached the door",
|
|
"Same playlist, same headphones, different ears / Soundtrack to twenty-seven years",
|
|
"The map says we're zero miles apart / But zero's just a fancy way to say 'apart'",
|
|
"Parallel lines at infinity / Maybe there is where you'll wait for me",
|
|
],
|
|
"moods": [
|
|
"longing", "observational", "wistful", "frustrated", "timid",
|
|
"melancholic", "hopeful", "nostalgic", "resigned", "transcendent",
|
|
],
|
|
"colors": [
|
|
["graphite", "pale blue"],
|
|
["warm white", "shadow grey"],
|
|
["burnt sienna", "slate"],
|
|
["silver", "dusty pink"],
|
|
["espresso", "cream"],
|
|
["charcoal", "amber"],
|
|
["navy", "copper"],
|
|
["black", "neon green"],
|
|
["white", "pale gold"],
|
|
["indigo", "starlight white"],
|
|
],
|
|
"compositions": [
|
|
"split frame", "deep focus", "symmetrical", "asymmetrical",
|
|
"wide", "extreme wide", "overhead", "profile", "mirror shot",
|
|
"silhouette",
|
|
],
|
|
"cameras": [
|
|
"static split", "slow pan", "dolly parallel", "zoom",
|
|
"whip pan", "tracking", "crane up", "tilt", "mirror glide",
|
|
"fade to white",
|
|
],
|
|
"descriptions": [
|
|
"Split screen: two figures walking the same street, separated by a yellow line. Rain falls on one side, sun on the other.",
|
|
"Opposite apartment windows at night. Two silhouettes brush teeth in sync, separated by brick and glass.",
|
|
"Train platform. Two figures board different cars of the same train. Hands press against windows, never aligned.",
|
|
"Close-up of two hands almost touching, separated by a thin glass partition. Breath fogging the surface.",
|
|
"Coffee shop queue. One person watches another order. Steam rises between them like a curtain.",
|
|
"Aerial shot of two shadows on pavement, walking parallel. The sun sets, stretching them impossibly long.",
|
|
"Hand drawing a line on paper with a ruler. The pencil lead snaps at the edge of the page.",
|
|
"Two people on a bench, headphones in, eyes closed. A leaf falls between them. Neither moves.",
|
|
"Map spread on a table. Two pins, zero distance apart. A finger traces the gap, again and again.",
|
|
"Two lines of light converging at a vanishing point. A figure stands at the intersection, arms open.",
|
|
],
|
|
},
|
|
{
|
|
"title": "Glass House",
|
|
"artist": "Transparent",
|
|
"bpm": 105,
|
|
"lyrics": [
|
|
"Everyone can see what we're not saying / The glass walls amplify the silence",
|
|
"Throwing stones from inside the frame / We're the exhibit, we're the game",
|
|
"Dinner at eight, the neighbors watch / Every fork, every sip, every botched",
|
|
"Smile for the camera, smile for the crowd / Smile till the cracks get too loud",
|
|
"I swept the shards beneath the rug / But glass shines through, no matter what",
|
|
"The thermostat's set to 'pretend' / Comfortable lies with a dividend",
|
|
"Your reflection multiplies in the hall / Seven versions of you, none of them real at all",
|
|
"We built this palace out of pride / Now we're just fossils trapped inside",
|
|
"A bird flew straight into the pane / I felt the vibration, I felt the pain",
|
|
"Let's break a window, let the air in / Better to bleed than to live in sin",
|
|
],
|
|
"moods": [
|
|
"tense", "claustrophobic", "performative", "desperate", "anxious",
|
|
"resigned", "surreal", "trapped", "empathetic", "liberating",
|
|
],
|
|
"colors": [
|
|
["clear", "pale grey"],
|
|
["silver", "white"],
|
|
["bone", "chrome"],
|
|
["porcelain", "charcoal"],
|
|
["frost", "steel"],
|
|
["ivory", "smoke"],
|
|
["mirror", "shadow"],
|
|
["glass green", "pale amber"],
|
|
["feather white", "blood red"],
|
|
["sky blue", "shattered crystal"],
|
|
],
|
|
"compositions": [
|
|
"extreme wide", "fish-eye", "reflected", "framed",
|
|
"voyeuristic", "intimate", "distorted", "symmetrical",
|
|
"close-up", "liberation wide",
|
|
],
|
|
"cameras": [
|
|
"static observe", "dolly zoom", "mirror pan", "through-glass",
|
|
"peeping tom", "rack focus", "kaleidoscope spin", "crane down",
|
|
"slow motion", "explosive pull-back",
|
|
],
|
|
"descriptions": [
|
|
"Modernist glass house at twilight. Two figures sit in silence at opposite ends of a long table, fully visible to the outside world.",
|
|
"Fish-eye lens: a figure stands in a room of mirrors, surrounded by infinite reflections. Stones in hand, hesitating.",
|
|
"Voyeuristic shot from outside: neighbors watch through binoculars as a couple eats dinner. Every gesture is staged.",
|
|
"Close-up of a forced smile, cracks spiderwebbing across porcelain skin. The smile stays but the eyes betray.",
|
|
"Rug lifted slightly, revealing glittering glass shards underneath. A hand reaches to smooth the rug back down.",
|
|
"Hallway of mirrors. Seven reflections of the same person walk in imperfect sync. The real one stops; reflections continue.",
|
|
"Glass palace interior. Fossils embedded in translucent walls. Two small figures wander like museum visitors in their own home.",
|
|
"A bird's eye view of a glass roof. A small bird lies stunned on the surface. A hand presses against the glass from below.",
|
|
"Slow motion: a hammer swings toward a glass wall. The moment of impact suspended, fractures beginning to bloom.",
|
|
"Explosion of glass outward. Sunlight floods in. Two figures stand in the center, arms raised, bleeding and laughing.",
|
|
],
|
|
},
|
|
{
|
|
"title": "Summer Static",
|
|
"artist": "Beach Fossil",
|
|
"bpm": 98,
|
|
"lyrics": [
|
|
"The radio hisses between the stations / Your voice cuts through like irrigation",
|
|
"Sand in the sheets, salt in the hair / We didn't go anywhere but we were there",
|
|
"Popsicle sticks stacked like little bones / Monument to days without phones",
|
|
"Your tan line tells a story I can't read / A paperback abandoned in the weeds",
|
|
"Fireflies in a mason jar / Released too soon, didn't get far",
|
|
"The boardwalk creaks with memories / Of people we were, people we'll never be",
|
|
"Static on the line, then your laugh / Half a conversation, broken in half",
|
|
"We buried a time capsule in the dune / Marked it with a plastic spoon",
|
|
"The ice cream truck plays a funeral dirge / Summer's over, nothing left to purge",
|
|
"I'll meet you where the static ends / Where the signal clears and the heart mends",
|
|
],
|
|
"moods": [
|
|
"nostalgic", "lazy", "playful", "curious", "bittersweet",
|
|
"melancholic", "fragmented", "hopeful", "resigned", "optimistic",
|
|
],
|
|
"colors": [
|
|
["sunbleached yellow", "ocean blue"],
|
|
["sand", "salt white"],
|
|
["popsicle orange", "stick brown"],
|
|
["tan", "paperback yellow"],
|
|
["jar glass", "firefly gold"],
|
|
["weathered wood", "sunset pink"],
|
|
["static grey", "laughter pink"],
|
|
["dune beige", "plastic red"],
|
|
["ice cream white", "truck chrome"],
|
|
["clear sky", "signal green"],
|
|
],
|
|
"compositions": [
|
|
"wide beach", "intimate", "macro", "environmental",
|
|
"close-up", "establishing", "fragmented", "nostalgic",
|
|
"symbolic", "horizon",
|
|
],
|
|
"cameras": [
|
|
"slow drift", "static lazy", "macro focus", "wide still",
|
|
"handheld memory", "crane over", "glitch cut", "dune slide",
|
|
"tracking truck", "fade to clear",
|
|
],
|
|
"descriptions": [
|
|
"Beach at noon. A transistor radio hisses on a towel. A foot taps in the sand. Overexposed sky, bleached colors.",
|
|
"Interior of a beach shack. Sand covers the floor like carpet. Two people lie on a bed, staring at a cracked ceiling.",
|
|
"Close-up of popsicle sticks arranged in a tiny cairn on a picnic table. Melted juice stains the wood.",
|
|
"Overgrown weeds swallowing a discarded paperback. A tan line on an arm reaches for it, then withdraws.",
|
|
"Hands holding a mason jar of fireflies. The lid unscrews. Golden insects spiral upward into darkening air.",
|
|
"Boardwalk at dusk. Empty rides creak in wind. One person walks the planks, dragging fingers along railings.",
|
|
"Phone screen showing a call in progress. Static waveform dances. A laugh crackles through, half-caught.",
|
|
"Dune at sunset. Two figures kneel, burying a shoebox. A plastic spoon marks the spot like a flag.",
|
|
"Ice cream truck parked in empty lot. Speaker plays distorted music. One person leans against it, eyes closed.",
|
|
"Horizon line where sea meets sky. Static dissolves into clear blue. Two figures walk toward the water, hand in hand.",
|
|
],
|
|
},
|
|
{
|
|
"title": "Midnight Algorithm",
|
|
"artist": "Digital Native",
|
|
"bpm": 132,
|
|
"lyrics": [
|
|
"Scrolling through your life at 3 AM / Liking moments I'll never touch again",
|
|
"The algorithm knows me better than you do / Serves me memories I never asked to view",
|
|
"Blue light bathing my insomnia / A personalized coma, custom anesthesia",
|
|
"Swipe right on a stranger who looks like your ghost / The machine learns what I need the most",
|
|
"Notification: 'We miss you' / From an app I deleted in 2002",
|
|
"My data portrait hangs in a server farm / Every click a brushstroke, every like an arm",
|
|
"Recommended for you: a broken heart / 4.7 stars, 12K reviews, add to cart",
|
|
"The infinite scroll of almost-love / Pixelated doves, none of them enough",
|
|
"Cache cleared, history deleted / But the targeted ads say I'm not defeated",
|
|
"Log out, shut down, the screen goes black / The algorithm waits for me to come back",
|
|
],
|
|
"moods": [
|
|
"isolated", "cynical", "numb", "obsessive", "sardonic",
|
|
"existential", "consumerist", "defeated", "resigned", "cyclical",
|
|
],
|
|
"colors": [
|
|
["screen blue", "black"],
|
|
["notification red", "dark grey"],
|
|
["neon white", "midnight"],
|
|
["pixel green", "void"],
|
|
["amber alert", "ash"],
|
|
["server blinking", "concrete"],
|
|
["shopping cart orange", "pale face"],
|
|
["scroll grey", "electric pink"],
|
|
["ad yellow", "blank"],
|
|
["power-off black", "standby red"],
|
|
],
|
|
"compositions": [
|
|
"screen reflection", "extreme close-up", "data visualization",
|
|
"overhead server", "selfie mirror", "macro pixel", "wide bedroom",
|
|
"split-screen", "voyeuristic", "void",
|
|
],
|
|
"cameras": [
|
|
"static glow", "zoom into iris", "data stream", "drone through racks",
|
|
"mirror flip", "pixel push", "bedroom pan", "screen recording",
|
|
"ad transition", "fade to black",
|
|
],
|
|
"descriptions": [
|
|
"Face illuminated by phone screen in total darkness. Scroll thumb moves endlessly. Reflection in the glass shows tired eyes.",
|
|
"Phone interface close-up: 'We miss you' notification from a vintage app icon. Finger hovers, then dismisses.",
|
|
"Server room corridor. Blinking LED lights reflect in the polished floor. A lone figure walks between the racks.",
|
|
"Online shopping interface: 'Broken Heart — 4.7 stars — Add to Cart'. Cursor clicks. Credit card autofill flashes.",
|
|
"Infinite scroll animation: faces blur into faces, all slightly similar. Thumb swipes upward in perpetual motion.",
|
|
"Selfie camera view: face half-covered by phone. The background is a bedroom that hasn't been cleaned in weeks.",
|
|
"Drone shot flying through server racks. Cables like vines. Blinking lights like bioluminescence in a digital forest.",
|
|
"Split screen: left side shows a person crying, right side shows targeted ads for vacation packages and therapy apps.",
|
|
"Macro shot of a single pixel turning from grey to yellow. The transition takes ten seconds. Sound of a cash register.",
|
|
"Phone screen powers down. Face disappears into darkness. Only the standby LED remains, pulsing like a heartbeat.",
|
|
],
|
|
},
|
|
{
|
|
"title": "Concrete Lullaby",
|
|
"artist": "Urban Dreamer",
|
|
"bpm": 85,
|
|
"lyrics": [
|
|
"The subway hums my lullaby / Steel wheels singing me goodbye",
|
|
"Neon moon through fire escape / A concrete cradle, a steel-scape",
|
|
"Pigeon coos on the window ledge / Nature's refugee on the city's edge",
|
|
"The radiator hisses like the sea / A white noise symphony for you and me",
|
|
"Garbage trucks at 5 AM / The city's way of saying amen",
|
|
"Your breath syncs with the elevator chain / Rising and falling, again and again",
|
|
"Sirens wail a distant song / Telling someone else they're wrong",
|
|
"Rain on AC units, tin drum choir / Nature and machine in a tangled wire",
|
|
"The key turns, the lock says click / Home is anywhere the noise is thick",
|
|
"Sleep now, the city never does / But in your arms, the noise was ours",
|
|
],
|
|
"moods": [
|
|
"tender", "urban", "peaceful", "bittersweet", "industrial",
|
|
"intimate", "observational", "melancholic", "grounded", "loving",
|
|
],
|
|
"colors": [
|
|
["subway silver", "tunnel black"],
|
|
["neon orange", "rust red"],
|
|
["pigeon grey", "brick brown"],
|
|
["radiator white", "pipe green"],
|
|
["garbage green", "dawn grey"],
|
|
["elevator bronze", "skin tone"],
|
|
["siren red", "distant blue"],
|
|
["rain grey", "aluminum silver"],
|
|
["brass gold", "door brown"],
|
|
["streetlight amber", "embrace warmth"],
|
|
],
|
|
"compositions": [
|
|
"intimate wide", "framed", "close-up", "environmental",
|
|
"low angle", "overhead", "distant", "interior",
|
|
"macro", "two-shot",
|
|
],
|
|
"cameras": [
|
|
"subtle sway", "static observe", "gentle push", "locked off",
|
|
"low drift", "high angle down", "slow zoom", "crane through",
|
|
"macro focus", "static hold",
|
|
],
|
|
"descriptions": [
|
|
"Subway car interior at night. A sleeping head rests against a stranger's shoulder. Fluorescent lights flicker overhead.",
|
|
"Fire escape view. Neon sign glows through wrought iron. A figure sits on the metal grating, legs dangling into air.",
|
|
"Close-up of a pigeon nesting on a windowsill. Behind it, the city skyline stretches into smog.",
|
|
"Radiator hissing steam in a tiny apartment. Two figures lie on a mattress on the floor, sharing one pillow.",
|
|
"Street level at dawn. Garbage truck compressors grind. A figure in pajamas watches from a doorway, coffee in hand.",
|
|
"Elevator shaft view from below. Two faces look down through the open grate. Chains and pulleys move in darkness above.",
|
|
"Distant sirens. A figure stands at a window, hand on glass. Red and blue lights paint the wall in slow rotation.",
|
|
"Rain falling on window AC units. Water streams down aluminum fins. One unit rattles like a snare drum.",
|
|
"Key entering a lock. The deadbolt turns. The door opens to a dark hallway. A figure steps inside, shoulders dropping.",
|
|
"Two figures embracing in bed. Streetlight filters through blinds, striping the sheets. City sounds rumble below.",
|
|
],
|
|
},
|
|
{
|
|
"title": "Paper Kites",
|
|
"artist": "Wind & Wire",
|
|
"bpm": 110,
|
|
"lyrics": [
|
|
"We built a kite from unpaid bills / Flew it from the window sill",
|
|
"The string was twine from a flour sack / We laughed till our lungs nearly cracked",
|
|
"It caught a thermal near the bank / Danced above the tanks and tanks",
|
|
"Your mother called, you let it ring / We had a kite, we had a string",
|
|
"The tail was ribbon from a dress / You wore the day you said 'yes'",
|
|
"It soared above the power lines / A paper bird between the signs",
|
|
"The wind shifted, the kite went down / In the parking lot of the edge of town",
|
|
"We ran to it like it was alive / Picked it up at 4:55",
|
|
"Creased and torn but still intact / Like us, like that, like fact",
|
|
"Let's fly it again when the weather's right / Paper kites and paper light",
|
|
],
|
|
"moods": [
|
|
"playful", "defiant", "euphoric", "rebellious", "nostalgic",
|
|
"whimsical", "anxious", "tender", "resilient", "hopeful",
|
|
],
|
|
"colors": [
|
|
["bill white", "ink blue"],
|
|
["flour sack beige", "twine brown"],
|
|
["bank grey", "kite red"],
|
|
["phone black", "sky blue"],
|
|
["dress ribbon pink", "memory white"],
|
|
["power line black", "cloud white"],
|
|
["asphalt grey", "kite crumpled"],
|
|
["parking lot yellow", "running shoe"],
|
|
["crease brown", "tape silver"],
|
|
["dawn pink", "paper thin"],
|
|
],
|
|
"compositions": [
|
|
"wide", "close-up", "medium", "high angle",
|
|
"intimate", "dynamic", "low angle", "ground level",
|
|
"two-shot", "horizon",
|
|
],
|
|
"cameras": [
|
|
"handheld run", "crane up", "tracking", "static joy",
|
|
"zoom out", "dolly back", "freefall", "sprint follow",
|
|
"macro texture", "sunrise hold",
|
|
],
|
|
"descriptions": [
|
|
"Hands folding a utility bill into a kite shape on a kitchen table. Twine and tape nearby. Laughter in the background.",
|
|
"Kite launched from a fourth-story window. Two figures lean out, arms extended. The kite catches wind and soars.",
|
|
"Kite dancing above a bank building. Surveillance cameras watch from corners. The kite dips and weaves like a dare.",
|
|
"Phone buzzing on a windowsill, ignored. Two figures on the roof, flying the kite higher, competing with the clouds.",
|
|
"Close-up of a kite tail: a faded pink ribbon flutters. Flashback: the same ribbon in hair, a 'yes' whispered.",
|
|
"Kite soaring between power lines. Tense moment. The kite clears the last wire by inches. Exhale.",
|
|
"Kite crashes in an empty parking lot. Two figures run toward it, shoes slapping asphalt. The kite lies crumpled.",
|
|
"Hands smoothing creases from the kite. Tape applied to a tear. Fingers overlap. The kite is whole again.",
|
|
"Two figures sit on the curb, kite between them. The sun rises. They hold the string like a promise.",
|
|
"Wide shot: two figures launch the kite again at dawn. Paper catches golden light. The city wakes behind them.",
|
|
],
|
|
},
|
|
{
|
|
"title": "Frequency",
|
|
"artist": "Signal Lost",
|
|
"bpm": 140,
|
|
"lyrics": [
|
|
"Tuning in to the frequency of your doubt / Static between what we said and what came out",
|
|
"You broadcast love on a dying band / I receive it but I don't understand",
|
|
"The oscillator swings between hot and cold / A sine wave story, a thousandfold",
|
|
"Feedback loop of your silence / Amplified by my compliance",
|
|
"Equalize the highs, compress the lows / The mix is perfect but nobody knows",
|
|
"Phase cancellation when we kiss / Your lips are there but something's amiss",
|
|
"Modulate my heart to match your key / But the harmonics don't agree",
|
|
"White noise bed where we used to sleep / Every frequency too shallow, too deep",
|
|
"I'm scanning every station, every dial / Searching for the ghost of your smile",
|
|
"Tune out, drop off, the signal's gone / Static is the only truth from now on",
|
|
],
|
|
"moods": [
|
|
"frustrated", "technical", "anxious", "obsessive", "resigned",
|
|
"sardonic", "confused", "numb", "desperate", "defeated",
|
|
],
|
|
"colors": [
|
|
["oscilloscope green", "black"],
|
|
["radio dial amber", "dark grey"],
|
|
["sine wave blue", "white"],
|
|
["feedback red", "silence black"],
|
|
["compressor grey", "neon"],
|
|
["out-of-phase purple", "lip pink"],
|
|
["modulation rainbow", "key white"],
|
|
["white noise static", "sleep blue"],
|
|
["scan line white", "dial glow"],
|
|
["static snow", "void"],
|
|
],
|
|
"compositions": [
|
|
"macro circuit", "close-up", "abstract", "intimate",
|
|
"wide studio", "extreme close-up", "visualization", "bedroom",
|
|
"scanning", "void",
|
|
],
|
|
"cameras": [
|
|
"macro drift", "rack focus", "waveform scroll", "static shock",
|
|
"dolly through", "kiss blur", "frequency sweep", "bedroom pan",
|
|
"scan flicker", "fade to snow",
|
|
],
|
|
"descriptions": [
|
|
"Oscilloscope screen in darkness. Green waveform dances erratically. Two hands adjust knobs, never finding the right frequency.",
|
|
"Vintage radio dial glowing amber. A finger turns the knob slowly, searching. Static hisses between stations.",
|
|
"Abstract visualization: a perfect sine wave splits into two, diverging. Colors shift from blue to cold white.",
|
|
"Recording studio. Red feedback light blinks. A microphone hangs abandoned. Cables coil on the floor like snakes.",
|
|
"Mixing board close-up. Faders move automatically. Compressor needles bounce. The sound is perfect; the room is empty.",
|
|
"Two faces almost touching. A visual ripple effect distorts the kiss. Lips meet but the image cancels itself out.",
|
|
"Kaleidoscope of sound waves. Colors clash and merge. A heart shape attempts to form but breaks into discordant shards.",
|
|
"Bedroom at night. TV static illuminates two sleeping figures. The snow on screen mirrors the chaos in the room.",
|
|
"Rapid channel scan: faces, ads, news, cartoons flicker. A single smile lingers for one frame, then disappears.",
|
|
"Television snow fills the screen. Pull back to reveal the TV in an empty room. The static is the only light source.",
|
|
],
|
|
},
|
|
{
|
|
"title": "Undertow",
|
|
"artist": "Deep Current",
|
|
"bpm": 95,
|
|
"lyrics": [
|
|
"The tide went out but I stayed in / Breathing water, letting the light dim",
|
|
"Your name is written in the sand / Each wave erases where I stand",
|
|
"Seaweed tangles round my ankles now / A gentle weight that won't allow",
|
|
"The surface shimmers like a lie / Too bright, too far, too high",
|
|
"I opened my mouth to call your name / Filled it with salt instead of shame",
|
|
"The fish don't judge, the crabs don't care / Down here it's quiet, down here it's fair",
|
|
"My hair floats up like golden weed / I planted promises I didn't need",
|
|
"The undertow has my hand in its grip / Pulling me home on a one-way trip",
|
|
"Shells in my pockets, pearls in my eyes / The ocean teaches, the ocean lies",
|
|
"I'll wash up somewhere, smooth and white / A stone that once was holding tight",
|
|
],
|
|
"moods": [
|
|
"surrender", "melancholic", "peaceful", "desperate", "accepting",
|
|
"isolated", "resigned", "fatalistic", "transformative", "bittersweet",
|
|
],
|
|
"colors": [
|
|
["sea green", "sand beige"],
|
|
["foam white", "wet brown"],
|
|
["kelp brown", "pale skin"],
|
|
["surface silver", "depth black"],
|
|
["salt crystal", "blood warm"],
|
|
["fish silver", "coral pink"],
|
|
["blonde float", "deep blue"],
|
|
["undertow navy", "hand pale"],
|
|
["pearl white", "shell pink"],
|
|
["stone grey", "wave white"],
|
|
],
|
|
"compositions": [
|
|
"underwater wide", "surface", "below", "looking up",
|
|
"close-up", "environmental", "surreal", "intimate",
|
|
"macro", "shoreline",
|
|
],
|
|
"cameras": [
|
|
"submerge slow", "surface float", "drift down", "look up",
|
|
"bubble rise", "underwater pan", "surreal tilt", "sink",
|
|
"macro shell", "wash ashore",
|
|
],
|
|
"descriptions": [
|
|
"Underwater wide shot. A figure stands on the ocean floor, hair floating upward. Sunlight filters down in visible beams.",
|
|
"Surface view from below. Feet tread water above. A name written in sand on the shore, each wave licking it away.",
|
|
"Close-up of seaweed wrapping around an ankle. Gentle, vegetative embrace. Small fish dart through the fronds.",
|
|
"Looking up at the water surface from deep below. The light shimmers and distorts like a broken mirror.",
|
|
"Underwater close-up: bubbles escape from lips. Eyes closed. Salt crystals form on eyelashes.",
|
|
"A crab scuttles past. A school of silver fish parts around the figure. The seabed is soft silt.",
|
|
"Hair spreads in a golden halo. Tiny pearls scatter from a broken necklace, drifting down like slow-motion hail.",
|
|
"Hand reaching toward the surface. Fingers spread. The undertow pulls the other direction, gentle but insistent.",
|
|
"Eyes opening underwater. Pearls reflected in the irises. A seashell rests on the cheek like a tear.",
|
|
"Shoreline at dawn. A smooth stone washes up, wet and gleaming. Footsteps approach, then stop.",
|
|
],
|
|
},
|
|
]
|
|
|
|
|
|
def generate():
|
|
rows = []
|
|
for song in SONGS:
|
|
for i in range(10):
|
|
rows.append(
|
|
{
|
|
"song": song["title"],
|
|
"artist": song["artist"],
|
|
"genre": GENRE,
|
|
"bpm": song["bpm"],
|
|
"beat": i + 1,
|
|
"timestamp": f"{i * 30 // 60}:{(i * 30) % 60:02d}",
|
|
"duration_seconds": DURATION_SECONDS,
|
|
"lyric_line": song["lyrics"][i],
|
|
"scene": {
|
|
"mood": song["moods"][i],
|
|
"colors": song["colors"][i],
|
|
"composition": song["compositions"][i],
|
|
"camera": song["cameras"][i],
|
|
"description": song["descriptions"][i],
|
|
},
|
|
}
|
|
)
|
|
return rows
|
|
|
|
|
|
def validate(rows):
|
|
assert len(rows) == 100, f"Expected 100 rows, got {len(rows)}"
|
|
songs = {r["song"] for r in rows}
|
|
assert len(songs) == 10, f"Expected 10 songs, got {len(songs)}"
|
|
for r in rows:
|
|
assert "scene" in r
|
|
assert "mood" in r["scene"]
|
|
assert "colors" in r["scene"]
|
|
assert "composition" in r["scene"]
|
|
assert "camera" in r["scene"]
|
|
assert "description" in r["scene"]
|
|
assert len(r["scene"]["description"]) >= 10
|
|
print(f"Validation passed: {len(rows)} rows, {len(songs)} songs")
|
|
|
|
|
|
def write(rows, path: Path):
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
for r in rows:
|
|
f.write(json.dumps(r, ensure_ascii=False) + "\n")
|
|
print(f"Wrote {len(rows)} rows to {path}")
|
|
|
|
|
|
def main():
|
|
rows = generate()
|
|
validate(rows)
|
|
|
|
repo_path = Path(__file__).resolve().parent.parent / "training-data" / "scene-descriptions-pop.jsonl"
|
|
home_path = Path.home() / ".hermes" / "training-data" / "scene-descriptions-pop.jsonl"
|
|
|
|
write(rows, repo_path)
|
|
write(rows, home_path)
|
|
|
|
# Run schema validation if available
|
|
schema_script = Path(__file__).resolve().parent.parent / "scripts" / "validate-scene-data.py"
|
|
if schema_script.exists():
|
|
import subprocess
|
|
|
|
result = subprocess.run(
|
|
["python3", str(schema_script), "--schema", "training-data/schema.json", str(repo_path)],
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
print(result.stdout)
|
|
if result.returncode != 0:
|
|
print(result.stderr)
|
|
raise SystemExit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|