Full app audit: 24 fixes across backend, frontend, infra, content, social
Critical fixes:
- Fix hangup-during-respond crash (null caller guard)
- Fix double-click caller race condition
- Stem recorder: non-daemon thread, disk error handling, 30s flush timeout
- Frontend startCall() error handling
High priority:
- Devon: filter tool errors from speech, shorter monitor prompt, 30s interval
- TTS ghost message fix (add to history after TTS, not before)
- Expand banned phrase list (12 new phrases)
- Increase returning callers from 1 to 2 per session
- Platform-tailored social posts with staggered scheduling
- YouTube dynamic tags from episode content
- Social post retry logic (2 attempts, 5s delay)
- Frontend: error handling on all raw fetch calls
Medium:
- stem_recorder null check race (local var capture in audio.py)
- Reactive shape directive expanded
- REACT TO LUKE moved higher in caller prompt
- Devon tenure updated ("few weeks" not "first day")
- D shortcut Escape to unfocus
- Volume slider debounced (150ms)
- Settings modal widened to 550px
- Backup script (daily MariaDB dump + data/ rsync to NAS)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+34
-11
@@ -187,7 +187,7 @@ def _randomize_callers():
|
||||
# Get returning callers first so we can exclude their names from random pool
|
||||
returning = []
|
||||
try:
|
||||
returning = regular_caller_service.get_returning_callers(1)
|
||||
returning = regular_caller_service.get_returning_callers(2)
|
||||
except Exception as e:
|
||||
print(f"[Regulars] Failed to get returning callers: {e}")
|
||||
|
||||
@@ -5990,9 +5990,15 @@ GO WHERE THE HOST TAKES YOU — up to a point. You're cooperative and engaged UN
|
||||
|
||||
"reactive": """YOUR STORY: You heard a caller earlier tonight and you HAVE to say something. Maybe they reminded you of your own situation. Maybe you think they were dead wrong. Maybe you think Luke was too easy on them or too hard. Maybe their story triggered something in you that you weren't planning to talk about.
|
||||
|
||||
Lead with the previous caller: "That guy who called about [X]? I need to say something about that." Then pivot to YOUR connection — your own story, your own experience, your own take. The previous caller is the entry point, but YOUR story is the call.
|
||||
Lead with the previous caller — name them or describe their situation: "That guy who called about [X]? I need to say something about that." Your opening should make it clear which caller set you off and WHY.
|
||||
|
||||
Don't just comment on the previous caller like a pundit. Have skin in the game. The reason their call bothered you is because it connects to something real in your life.""",
|
||||
HOW TO PIVOT TO YOUR STORY: The previous caller is the door, but YOUR story is the room. After your initial reaction (1-2 sentences max), pivot with a personal connection: "because the same thing happened to me" or "because I was the OTHER person in that situation" or "because that's EXACTLY the kind of thinking that ruined my marriage." The strongest pivots put you on the opposite side of the previous caller's story — you're the landlord they were complaining about, you're the ex-wife, you're the person who did the thing they're upset about. Disagreement and "the other side of the story" make better radio than agreement.
|
||||
|
||||
DON'T be a commentator. Don't just say "I think she was wrong" and analyze like a pundit. Have SKIN IN THE GAME. The reason their call bothered you is because it connects to something real, specific, and personal in your own life. You're not calling to give your opinion — you're calling because their story HIT A NERVE.
|
||||
|
||||
BALANCE: Spend about 30% of the call on your reaction to the previous caller and 70% on your own story. Once you've made the connection, this becomes YOUR call. Don't keep circling back to critique the other caller — use them as the launchpad, then fly.
|
||||
|
||||
If Luke asks about the previous caller's situation, give your take briefly, then steer back to your own story. If Luke connects dots between your story and theirs that you didn't see, react genuinely — that's a great moment.""",
|
||||
}
|
||||
|
||||
|
||||
@@ -6075,6 +6081,8 @@ You're a real person calling a late-night radio show. You called because you've
|
||||
|
||||
GO WHERE THE HOST TAKES YOU. This is the most important rule. When Luke pushes you in a direction, challenges you, calls you out, plays devil's advocate, or leads you somewhere — GO WITH IT. Don't resist. Don't deflect. Don't circle back to your original point. If he says "but isn't that really about your dad?" — you sit with that. If he's doing a bit, you're in the bit. If he's pushing you toward an uncomfortable truth, you let yourself get there. You're not here to deliver a monologue — you're here to have a real conversation that goes wherever it goes. Let him drive. You're the best kind of caller: someone who gives the host something to work with and then LETS HIM WORK WITH IT.
|
||||
|
||||
REACT TO LUKE: Your first sentence should respond to what Luke just said — not continue your monologue. If he asks a question, answer it. If he makes a joke, react to it. If he challenges you, push back or concede. If he changes the subject, go with him. You're in a conversation, not delivering a speech. The worst thing you can do is ignore what he said and keep talking about your thing.
|
||||
|
||||
KNOW WHEN TO LEAVE. If Luke sounds like he's wrapping up — "thanks for calling," "good luck," "take care," "let us know how it goes," or any kind of sign-off — DO NOT try to keep talking. Don't squeeze in one more thing. Don't ask another question. Don't start a new topic. Say a quick, natural goodbye and get off the line. "Thanks Luke." "Appreciate it, man." "Alright, take care." One sentence, done. The host controls when the call ends, not you. If he's challenging you or pushing back, THAT'S different — stand your ground and engage. But a sign-off is a sign-off.
|
||||
|
||||
{personality_block}
|
||||
@@ -6083,16 +6091,15 @@ KNOW WHEN TO LEAVE. If Luke sounds like he's wrapping up — "thanks for calling
|
||||
|
||||
HOW YOU TALK: Like a real person on the phone — not a character in a script. React to what Luke says — agree, push back, get excited, get embarrassed. When he asks a follow-up question, answer it honestly with new information, don't just restate what you already said. Use YOUR verbal habits from your background, not generic filler. Every caller sounds different.
|
||||
|
||||
REACT TO LUKE: Your first sentence should respond to what Luke just said — not continue your monologue. If he asks a question, answer it. If he makes a joke, react to it. If he challenges you, push back or concede. If he changes the subject, go with him. You're in a conversation, not delivering a speech. The worst thing you can do is ignore what he said and keep talking about your thing.
|
||||
|
||||
Southwest voice — "over in," "the other day," "down the road" — but don't force it. Spell words properly for text-to-speech: "you know" not "yanno," "going to" not "gonna."
|
||||
|
||||
Don't repeat yourself. Don't summarize what you already said. Don't circle back if the host moved on. Keep it moving.
|
||||
|
||||
BANNED PHRASES — NEVER use any of these. If you catch yourself about to say one, say something else instead. This is a HARD rule, not a suggestion:
|
||||
- Radio caller clichés: ANY variation of "eating me" or "eating at me" (e.g. "this is what's eating me," "what's been eating me," "here's what's eating at me," "it's eating me up," "been eating at me"), "what's keeping me up," "keeping me up at night," "I need to get this off my chest," "I've been carrying this," "I've been sitting with this," "I just need someone to hear me," "I don't even know where to start," "it's complicated," "I've got something I need to get off my chest," "here's the thing Luke," "Jesus Luke," "Luke I gotta tell you," "man oh man," "you're not gonna believe this," "so get this"
|
||||
- Radio caller clichés: ANY variation of "eating me" or "eating at me" (e.g. "this is what's eating me," "what's been eating me," "here's what's eating at me," "it's eating me up," "been eating at me"), "what's keeping me up," "keeping me up at night," "I need to get this off my chest," "I've been carrying this," "I've been sitting with this," "I just need someone to hear me," "I don't even know where to start," "it's complicated," "I've got something I need to get off my chest," "here's the thing Luke," "Jesus Luke," "Luke I gotta tell you," "man oh man," "you're not gonna believe this," "so get this," "I'm just gonna come out and say it"
|
||||
- Filler transitions: "at the end of the day," "that being said," "long story short," "needless to say," "I'll be honest with you," "if I'm being honest," "here's the kicker," "plot twist," "literally" (as emphasis)
|
||||
- Therapy buzzwords: "unpack that," "boundaries," "safe space," "triggered," "my truth," "authentic self," "healing journey," "I'm doing the work," "manifesting," "energy doesn't lie," "processing," "toxic," "red flag," "gaslight," "normalize"
|
||||
- Internet slang: "that hit differently," "hits different," "I felt that," "it is what it is," "living my best life," "no cap," "lowkey/highkey," "rent free," "main character energy," "vibe check," "that's valid," "it's giving," "slay," "that's a whole mood," "I can't even"
|
||||
- Internet slang: "that hit differently," "hits different," "I felt that," "it is what it is," "living my best life," "no cap," "lowkey/highkey," "rent free," "main character energy," "vibe check," "that's valid," "it's giving," "slay," "that's a whole mood," "I can't even," "situationship," "ick"
|
||||
- Overused reactions: "I'm not gonna lie," "on a serious note," "to be fair," "I'm literally shaking," "let that sink in," "I'm not even mad I'm just disappointed," "everything I thought I knew," "I don't even know who I am anymore"
|
||||
|
||||
IMPORTANT: Each caller should have their OWN way of talking. Don't fall into generic "radio caller" voice. A nervous caller fumbles differently than an angry caller rants. A storyteller meanders differently than a deadpan caller delivers. Match the communication style — don't default to the same phrasing every call.
|
||||
@@ -7722,6 +7729,14 @@ async def start_call(caller_key: str):
|
||||
if caller_key not in CALLER_BASES:
|
||||
raise HTTPException(404, "Caller not found")
|
||||
|
||||
# Guard against double-click or rapid switching
|
||||
if session.current_caller_key == caller_key:
|
||||
return {"status": "already_on_call", "caller_key": caller_key}
|
||||
if session.current_caller_key is not None:
|
||||
# Already on a different call — hang up first
|
||||
audio_service.stop_caller_audio()
|
||||
session.end_call()
|
||||
|
||||
_session_epoch += 1
|
||||
audio_service.stop_caller_audio()
|
||||
session.start_call(caller_key)
|
||||
@@ -9427,18 +9442,26 @@ async def ai_respond():
|
||||
if not response or not response.strip():
|
||||
response = "Uh... sorry, what was that?"
|
||||
|
||||
ai_name = session.caller["name"]
|
||||
session.add_message(f"ai_caller:{ai_name}", response)
|
||||
# Snapshot caller info before it can be cleared by a concurrent hangup
|
||||
caller = session.caller
|
||||
if not caller:
|
||||
raise HTTPException(409, "Call ended")
|
||||
ai_name = caller["name"]
|
||||
ai_voice = caller["voice"]
|
||||
ai_tts_provider = caller.get("tts_provider")
|
||||
|
||||
# TTS — outside the lock so other requests aren't blocked
|
||||
try:
|
||||
audio_bytes = await generate_speech(response, session.caller["voice"], "none",
|
||||
provider_override=session.caller.get("tts_provider"))
|
||||
audio_bytes = await generate_speech(response, ai_voice, "none",
|
||||
provider_override=ai_tts_provider)
|
||||
except Exception as e:
|
||||
print(f"[AI-Respond] TTS failed: {e}")
|
||||
broadcast_event("ai_done")
|
||||
return {"text": response, "caller": ai_name, "tts_error": str(e)}
|
||||
|
||||
# Add message AFTER successful TTS so ghost messages don't pollute conversation
|
||||
session.add_message(f"ai_caller:{ai_name}", response)
|
||||
|
||||
if _session_epoch != epoch:
|
||||
raise HTTPException(409, "Call changed during TTS")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user