Ep47 post-mortem: fixed theme ignored by callers (backgrounds now
regenerate when theme is set), style-to-model race condition (fallback
to sonnet instead of pool[0]), removed bad pronunciation fixes, added
age-awareness to voice matching, raised MIN_RESPONSE_WORDS to 50.
Swapped problematic model mappings: conspiracy→qwen, know_it_all→mistral,
quiet_nervous→llama, emotional→kimi.
Added GET /api/show/preflight endpoint with 4 checks: model diversity,
theme penetration, voice-age alignment, response coherence (2-exchange
simulation of all callers). Frontend preflight modal with expandable
check cards.
Fixed active caller button not highlighting (moved highlight code before
potentially-failing caller info panel code).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Devon: more conversational when addressed directly (500 tokens, 3-5 sentences)
- Devon: monitor prompt rewritten to encourage more contributions
- Devon: polling interval 15s (was 30s), removed 2-message minimum
- Whisper: no fuzzy name matching for 3-char names, require first letter match
- fetch_music.py: post-fetch vocal detection filter using musicinfo tags
- scan_music_vocals.py: new script to scan existing library for vocal tracks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove caller names from Whisper hint (was corrupting transcriptions)
- Background gen switched to Claude Sonnet 4.6 (cheap models = thin backgrounds)
- "WHAT MAKES A GOOD CALLER" rewritten with concrete examples
- Grok guardrails loosened (were cutting too much edge)
- Response length guidance added to caller prompt
- Retry under-20-word responses once for more detail
- Devon monitor softened from "default silence" to balanced
- Ban stalling phrases: "where was I", "as I was saying", etc.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 2+ requirement created a catch-22: regulars couldn't return because they
needed 2 calls, but couldn't get a second call without returning. Dynamic
count already prevents flooding.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Only inject 2 returners if pool has 3+ eligible (so it's not the same every show).
With 2 eligible, inject 1. With 1 or 0, inject none.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Style-matched defaults:
- Grok 4.1 Fast for edgy callers (high_energy, confrontational, comedian etc.)
- Claude Sonnet 4.6 for emotional callers (quiet_nervous, sweet_earnest, emotional)
- Mistral Large 2512 for deadpan/mysterious/world-weary
- DeepSeek R1 Distill for storyteller/oversharer/conspiracy/rambler
- Gemini 2.5 Flash for know_it_all
- Llama 3.3 70B for first_time/reluctant callers
Category routing: Grok 4.1 Fast for dialog/devon/backgrounds, Gemini Flash for monitor/summary
Updated OPENROUTER_MODELS and OPENROUTER_PRICING with all new models
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Devon audio independent of caller hangup (separate stop events)
- Personal anecdotes capped at ~30% of responses (was every time)
- Interjection criteria tightened ("default is silence")
- Devon sees his own recent history to avoid repeating info
- Response variety: permits minimal reactions, confusion, silence
- Monitor prompt rewritten to be gatekeeping, not encouraging
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Avatar prefetch checks gender marker, re-fetches on mismatch
- Returning callers need 2+ actual calls before re-eligible (was 1)
- Promotion rate lowered 10% → 5% to prevent pool flooding
- Callback injection skipped for returning callers (already have context)
- Show history clarifies "you are NOT that caller" to prevent identity confusion
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Three strategies: single model, cycle through pool, style-matched
- 18 communication styles mapped to 7 models (Grok, Sonnet, Mistral, Qwen, DeepSeek, Gemini, Llama)
- Per-caller model locked for entire call, overridable mid-show
- Model badges on caller buttons and info panel
- Settings UI for strategy, pool, style mapping, fallback
- Fallback to Sonnet on model failure
- 6 new models added to pricing and dropdown
- Checkpoint persistence for all model state
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Pass all caller names as Whisper initial_prompt hint for correct spelling
- Post-transcription fuzzy match corrects remaining misspellings (Levenshtein)
- Prevents AI callers from "correcting" the host on their own name
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Regex strips all parentheticals and asterisk actions before TTS
- Catches (laughs nervously), *sighs*, etc. that Grok generates
- Strengthened SPEECH ONLY instructions in caller and Devon prompts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Route caller_dialog, devon_ask, background_gen to x-ai/grok-4
- Add Grok-4 to OPENROUTER_MODELS and OPENROUTER_PRICING
- Add Grok-specific banned phrases (I hear you, fair enough, that's wild, etc.)
- Add background gen guardrails for Grok (no active violence, no real public figures)
- Soften theme prompt hot-take language for organic connections
- Tighten Devon flirting guardrail (awkward not crude)
- Fix Devon "first day" contradiction on line 36
- Strip silence: preserve music intro, fix ad normalization (direct WAV reading)
- Strip silence: loop range starts 0.5s before audible music
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Preserve first silence in first DIALOG region (music intro before host speaks)
- Fix ad/ident normalization using direct WAV reading (accessor failed after splits)
- Loop range starts 0.5s before audible music, ends at last item
- Disable broken music lead-in nudge (intro preservation handles it)
- Caller dialog model set to Grok for testing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix Devon "if that makes sense" overuse (limit to once per show)
- Suppress Devon failed lookup notifications for self-initiated searches
- Strengthen show theme prompts (2/3 callers call because of theme)
- Fix sentence trimmer splitting on abbreviations (Mr. Mrs. Dr. etc.)
- Fix cost tracker data lost on server restart (persist in checkpoint)
- Ad/ident normalization targets -4dB below dialog for perceived loudness match
- Lower cross-speaker transition threshold to 5s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add show theme UI in header bar + backend API (inject into caller prompts)
- Add Irish genre category for music dropdown
- Strip silence: RMS-based speaker detection (fixes Devon not being identified)
- Strip silence: Devon-specific 3s threshold for interjections
- Strip silence: sparse track item handling in shift logic
- Strip silence: music lead-in preservation after silence removal
- Strip silence: no max gap limit (IDENT/AD regions protect breaks)
- Add analyze_gaps.py tool for per-show threshold analysis
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Hide h1 (sr-only) on homepage — banner already shows show name
- Promote tagline as visual lead after banner
- Fix avatar gender: add .gender marker files, re-fetch on mismatch
- Clear stale avatar cache so all re-fetch with correct gender
- Blacklist Celeste voice from caller pool
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove cover art from hero (duplicated in clips below)
- Merge about section into hero for single flowing layout
- Center hero content, remove side-by-side layout
- Fix _match_voices_to_styles() bypassing BLACKLISTED_VOICES —
Sebastian could get assigned to non-Silas callers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add real-time LLM/TTS cost tracking with live status bar display and post-show reports
- Fix PTT bug where Devon suggestion layout shift stopped recording via mouseleave
- Devon: facts-only during calls, full personality between calls
- Double WEIRD topic pool (109→203), bump weight to 14-25%
- Auto-generate YouTube thumbnails with bold hook text in publish pipeline
- LLM SEO: llms.txt, robots.txt for LLM crawlers, structured data, BreadcrumbList schemas
- Publish episode 37
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Massively expanded all 8 caller topic pools from ~1200 to ~2500 entries to
reduce repeat calls. Added persistent topic history (data/used_topics_history.json)
with 30-day aging to prevent cross-episode duplicates. Published episode 35.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Castopod password, DB password, BunnyCDN keys, Postiz JWT/IDs,
and monitoring token all moved to environment variables.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Whisper base → distil-large-v3 for much better live transcription accuracy
- Add context hints to transcription (caller name, screening status)
- Increase beam_size 3→5 for better decoding
- Add explicit role clarification in caller system prompt so LLM knows Luke is the host
- Prefix host messages with [Host Luke] in LLM conversation
- Fix upload_clips episode list sorting (natural numeric order)
- Episodes 26-28 transcripts, data updates, misc fixes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix TTS text pipeline: new caps handling (spell out unknown acronyms, lowercase
emphasis words), action-word lookahead for parenthetical stripping, abbreviation
expansions (US→United States, NM→New Mexico), pronunciation fixes
- Inworld TTS: camelCase API fields, speakingRate per-voice overrides, retry logic
with exponential backoff (3 attempts)
- Footer redesign: SVG icons for social/podcast links across all pages
- Stats page: show "Rate us on Spotify" instead of "not public" placeholder
- New voices, expanded caller prompts and problem scenarios
- Social posting via Postiz, YouTube upload in publish pipeline
- Episode transcripts 15-25, terms page, sitemap updates
- Fix invoice script: match Timing totals using merged Task+App intervals
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add host mic noise reduction (afftdn + anlmdn)
- Add phone EQ bandpass on caller stem
- Mute music during ads with 2s lookahead/tail
- Increase ducking release to 3s to reduce pumping
- Add Inworld voice mappings for all regular callers
- Recording toggle endpoint, stem sync fixes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Returning callers now keep their voice across sessions (stored in regulars.json)
- Backfilled voice assignments for all 11 existing regulars
- Discord button on homepage + link in all page footers
- REC and On-Air buttons now toggle together (both directions)
- Fixed host mic double-stream bug (stem_mic vs host_stream conflict)
- SEO: JSON-LD structured data on episode + how-it-works pages
- SEO: noscript fallbacks, RSS links, twitter meta tags
- Episode 9 transcript and sitemap update
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Re-label all 8 episode transcripts with LUKE:/CALLER: speaker labels
using LLM-based diarization (relabel_transcripts.py)
- Add episode.html transcript page with styled speaker labels
- Update publish_episode.py to generate speaker-labeled transcripts
and copy to website/transcripts/ for Cloudflare Pages
- Add SVG favicon with PNG fallbacks
- Fix CPU issue: tie host audio stream to on-air toggle, not per-caller
- Update how-it-works page with post-production pipeline info
- Add transcript links to episode cards in app.js
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- On-air toggle uploads status.json to BunnyCDN + purges cache, website
polls it every 15s to show live ON AIR / OFF AIR badge
- Publish script downloads Castopod's copy of audio for CDN upload
(byte-exact match), removes broken slug fallback, syncs all episode
media to CDN after publishing
- Fix f-string syntax error in publish_episode.py (Python <3.12)
- Enable CORS on BunnyCDN pull zone for json files
- CDN URLs for website OG images, stem recorder bug fixes, LLM token
budget tweaks, session context in CLAUDE.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New stem recording system captures 5 time-aligned WAV files (host, caller,
music, sfx, ads) during live shows. Standalone postprod.py processes stems
into broadcast-ready MP3 with gap removal, voice compression, music ducking,
and EBU R128 loudness normalization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Music crossfade: smooth 3-second blend between tracks instead of hard stop/start
- Emotional detection: analyze host mood from recent messages so callers adapt tone
- AI caller summaries: generate call summaries with timestamps for show history
- Returning callers: persist regular callers across sessions with call history
- Session export: generate transcripts with speaker labels and chapter markers
- Caller screening: AI pre-screens phone callers to get name and topic while queued
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Callers now have strong food opinions (Sparky's green chile, Blake's
Lotaburger, etc.), nostalgic memories of how their town used to be,
and 60% chance of having a strong reaction to a previous caller that
they bring up early in the call by name.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Weather lookup via Open-Meteo API with 30-min cache, time/day
awareness (Mountain time), moon phase calculation, seasonal context
with local events, and probabilistic situational details: road
context, phone situation, background music, recent errands, TV tonight.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>