Spaces:
Paused
Paused
Download apps/api/src/app/services/curriculum.py from nathycodes/presentercoach: direct link, hf CLI and curl.
- Browser
- Download file 73.7 kB
-
https://huggingface.co/spaces/nathycodes/presentercoach/resolve/main/apps/api/src/app/services/curriculum.py
- Command line
-
hf download hf://spaces/nathycodes/presentercoach/apps/api/src/app/services/curriculum.py
-
curl -L -o curriculum.py https://huggingface.co/spaces/nathycodes/presentercoach/resolve/main/apps/api/src/app/services/curriculum.py
73.7 kB
| from __future__ import annotations | |
| from datetime import date, datetime | |
| from typing import Any | |
| from sqlalchemy.orm import Session | |
| from app import models | |
| FOCUS_TRACK_LABELS = { | |
| "tech_storytelling": "Engaging Tech Storytelling & YouTube/Creator Presence", | |
| "keynote_clarity": "Conference Keynote & Architecture Clarity", | |
| "camera_confidence": "On-Camera Confidence, Pace & Zero Fillers", | |
| "executive_pitch": "Founder / Product Demo & Executive Pitching", | |
| } | |
| CURRICULUM_DAYS: list[dict[str, Any]] = [ | |
| # ─── WEEK 1: Camera Presence & Vocal Foundation ─── | |
| { | |
| "day": 1, | |
| "week": 1, | |
| "week_theme": "Camera Presence & Vocal Foundation", | |
| "title": "Baseline 60-Second Tech Intro", | |
| "skill_focus": "Baseline Assessment", | |
| "duration_sec": 60, | |
| "mode": "Pitch", | |
| "goal": "Establish baseline", | |
| "warm_up": "Take 3 slow 4-second nasal breaths, roll your shoulders back, and speak 'Crisp code, clear story, calm lens' three times with chest resonance.", | |
| "challenge": "Look directly into the camera lens for 60 seconds and introduce who you are, what technology problem excites you right now, and what you are building or learning.", | |
| "teleprompter_script": ( | |
| "Hi, I am practicing daily to become a sharper, more engaging technology presenter.\n\n" | |
| "Right now, the area of technology that excites me most is how modern software tools turn complex ideas into products anyone can use.\n\n" | |
| "Over the next thirty days, I am focusing on speaking with a steady rhythm, clean pauses instead of filler words, and natural eye contact right into the lens.\n\n" | |
| "Here is one project I am working on today—and why it matters." | |
| ), | |
| "outline_cues": [ | |
| "0:00 — Direct lens smile + crisp 1-sentence who-you-are hook", | |
| "0:15 — One tech problem or shift you care deeply about", | |
| "0:35 — What you are currently building, shipping, or exploring", | |
| "0:50 — Clean closing takeaway + hold lens contact for 1 beat", | |
| ], | |
| "target_keywords": ["building", "technology", "problem", "matters"], | |
| }, | |
| { | |
| "day": 2, | |
| "week": 1, | |
| "week_theme": "Camera Presence & Vocal Foundation", | |
| "title": "Talking to the Lens Like One Engineer", | |
| "skill_focus": "Eye Contact & Warmth", | |
| "duration_sec": 75, | |
| "mode": "Storytelling", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "Place a small mental target on the physical camera ring. Smile lightly before pressing record so your opening frame starts warm.", | |
| "challenge": "Explain your favorite programming language, framework, or developer tool as if recommending it across a coffee table to one trusted colleague—holding >75% lens contact.", | |
| "teleprompter_script": ( | |
| "If we sat down for coffee and you asked me which tool actually saves me hours every single week, here is my honest answer.\n\n" | |
| "Most tools promise productivity, however they quietly add configuration overhead.\n\n" | |
| "What makes my go-to tool different is speed of feedback. First, you see results in seconds. Second, errors tell you how to fix them.\n\n" | |
| "So if you have not tried it on a real weekend build yet, start small—you will feel the difference immediately." | |
| ), | |
| "outline_cues": [ | |
| "Hook: 'If you asked me which tool actually saves me hours every week...'", | |
| "Contrast: Why most alternatives feel heavy or slow", | |
| "First & Second concrete moments where this tool shines", | |
| "Takeaway: One small way the viewer should try it today", | |
| ], | |
| "target_keywords": ["first", "second", "however", "because"], | |
| }, | |
| { | |
| "day": 3, | |
| "week": 1, | |
| "week_theme": "Camera Presence & Vocal Foundation", | |
| "title": "Replacing Fillers with Power Pauses", | |
| "skill_focus": "Filler Elimination", | |
| "duration_sec": 90, | |
| "mode": "Interview", | |
| "goal": "Reduce fillers", | |
| "warm_up": "Read 4 sentences out loud and intentionally freeze silently for 1 full second at every period—lips closed, shoulders relaxed.", | |
| "challenge": "Explain how an API request travels from a phone screen to a database and back. Whenever you feel 'um', 'uh', or 'like' rising, substitute a silent 1-second pause.", | |
| "teleprompter_script": ( | |
| "Every time you tap a button in a mobile app, a remarkably fast relay race happens behind the scenes.\n\n" | |
| "First, your phone packages that tap into an HTTPS request. [Pause]\n\n" | |
| "Second, an API gateway checks your identity and routes the call to the right backend service. [Pause]\n\n" | |
| "Third, the service queries the database, shapes only the fields you need, and streams JSON back in milliseconds.\n\n" | |
| "Therefore, great app speed is rarely magic—it is clean boundaries at every hop." | |
| ), | |
| "outline_cues": [ | |
| "Hook: Tap-to-screen relay race metaphor", | |
| "Step 1: Client packages request [1s silent pause]", | |
| "Step 2: Gateway auth + routing [1s silent pause]", | |
| "Step 3: Database query + crisp takeaway", | |
| ], | |
| "target_keywords": ["first", "second", "third", "therefore", "request"], | |
| }, | |
| { | |
| "day": 4, | |
| "week": 1, | |
| "week_theme": "Camera Presence & Vocal Foundation", | |
| "title": "140 WPM Keynote Cadence Control", | |
| "skill_focus": "Speaking Pace", | |
| "duration_sec": 90, | |
| "mode": "Reading", | |
| "goal": "Improve pace", | |
| "warm_up": "Hum gently on an exhale for 8 seconds, then count 1-to-10 at a relaxed, deliberate one-number-per-half-second tempo.", | |
| "challenge": "Deliver a 90-second product update staying inside 125–155 WPM—fast enough to hold attention, unhurried enough that technical nouns land crisply.", | |
| "teleprompter_script": ( | |
| "Today we are shipping an update that cuts cold-start latency in half for every user on mobile connections.\n\n" | |
| "For months, we noticed that first-time loads felt sluggish on real-world cellular networks, even though our lab benchmarks looked green.\n\n" | |
| "Because we trimmed bundle bloat and moved heavy parsing off the main thread, pages now become interactive in under one second.\n\n" | |
| "Here is what that unlocks for your daily workflow starting right now." | |
| ), | |
| "outline_cues": [ | |
| "Headline metric right up front (cut latency in half)", | |
| "Real-world problem vs lab benchmark gap", | |
| "Two crisp changes that made it possible", | |
| "What users will feel immediately today", | |
| ], | |
| "target_keywords": ["latency", "because", "interactive", "workflow"], | |
| }, | |
| { | |
| "day": 5, | |
| "week": 1, | |
| "week_theme": "Camera Presence & Vocal Foundation", | |
| "title": "Plain-English Jargon Translation", | |
| "skill_focus": "Clarity & Simplicity", | |
| "duration_sec": 90, | |
| "mode": "Storytelling", | |
| "goal": "Reduce fillers", | |
| "warm_up": "Pick one buzzword ('distributed cache', 'vector embedding', 'zero-knowledge proof') and state what it does in 10 one-syllable words.", | |
| "challenge": "Explain caching, indexing, or AI embeddings on camera so clearly that both a smart product manager and a senior engineer nod along.", | |
| "teleprompter_script": ( | |
| "Think of a database index like the alphabetical tabs at the back of a thick cookbook.\n\n" | |
| "Without an index, finding one recipe means flipping through all five hundred pages every single time someone gets hungry.\n\n" | |
| "With an index, you jump straight to the exact page in two steps. However, every extra index costs a tiny bit of work whenever you add a new recipe.\n\n" | |
| "So the real engineering craft is indexing what people search constantly—and leaving the rest lean." | |
| ), | |
| "outline_cues": [ | |
| "Everyday visual analogy in sentence one", | |
| "What happens without it (the painful slow path)", | |
| "What happens with it + the honest engineering tradeoff", | |
| "One-sentence rule of thumb to remember", | |
| ], | |
| "target_keywords": ["index", "however", "so", "tradeoff"], | |
| }, | |
| { | |
| "day": 6, | |
| "week": 1, | |
| "week_theme": "Camera Presence & Vocal Foundation", | |
| "title": "Breaking Monotone Technical Delivery", | |
| "skill_focus": "Vocal Variety & Energy", | |
| "duration_sec": 90, | |
| "mode": "Pitch", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "Say the sentence 'We cut build time from twenty minutes to forty seconds' three ways: whispered curiosity, bold emphasis on numbers, and warm celebration.", | |
| "challenge": "Present a dramatic 'Before vs. After' technical improvement using deliberate pitch contrast on numbers and contrast words.", | |
| "teleprompter_script": ( | |
| "Twenty-two minutes. That is how long every engineer on our team used to wait just to know if a one-line fix passed CI.\n\n" | |
| "People lost focus, switched tabs, and batched risky changes together.\n\n" | |
| "Then we parallelized test shards and cached build layers. Twenty-two minutes dropped to forty-five seconds.\n\n" | |
| "Suddenly, shipping stopped feeling like waiting at an airport—and started feeling like creative flow again." | |
| ), | |
| "outline_cues": [ | |
| "Punchy number opener with vocal weight ('Twenty-two minutes.')", | |
| "Human frustration of the 'Before' state", | |
| "The technical unlock + dramatic 'After' number", | |
| "Emotional payoff: what changed for the humans", | |
| ], | |
| "target_keywords": ["minutes", "seconds", "because", "flow"], | |
| }, | |
| { | |
| "day": 7, | |
| "week": 1, | |
| "week_theme": "Camera Presence & Vocal Foundation", | |
| "title": "Week 1 Checkpoint: 2-Min Architecture Walkthrough", | |
| "skill_focus": "Integrated Presence", | |
| "duration_sec": 120, | |
| "mode": "Pitch", | |
| "goal": "Improve pace", | |
| "warm_up": "20-second posture check + lens framing check (eyes near top third of frame) + 2 deep breaths.", | |
| "challenge": "Deliver a crisp 2-minute walkthrough of a system or app you know well—combining steady 135 WPM pace, <2 fillers/min, and >70% lens eye contact.", | |
| "teleprompter_script": ( | |
| "Let me walk you through how our system turns a raw user recording into actionable coaching in under a minute.\n\n" | |
| "First, the browser captures live video, audio loudness, and facial landmarks locally so real-time feedback feels instant.\n\n" | |
| "Second, when you save a take, the API validates the recording and stores session metrics cleanly.\n\n" | |
| "Third, our analysis pipeline scores speaking pace, filler habits, and structure, then generates targeted drills for your very next rep.\n\n" | |
| "Therefore, every single practice session compounds into measurable progress." | |
| ), | |
| "outline_cues": [ | |
| "Promise hook: What the system accomplishes end-to-end", | |
| "First layer: Client-side capture & real-time signals", | |
| "Second layer: API validation & reliable persistence", | |
| "Third layer: Scoring + coaching loop + closing takeaway", | |
| ], | |
| "target_keywords": ["first", "second", "third", "therefore", "system"], | |
| }, | |
| # ─── WEEK 2: Clarity, Structure & Technical Explanations ─── | |
| { | |
| "day": 8, | |
| "week": 2, | |
| "week_theme": "Clarity, Structure & Technical Explanations", | |
| "title": "The 3-Point Rule for Technical Talks", | |
| "skill_focus": "Structural Signposting", | |
| "duration_sec": 105, | |
| "mode": "Pitch", | |
| "goal": "Improve pace", | |
| "warm_up": "Hold up 1, 2, 3 fingers off-camera as you rehearse your three transitions out loud.", | |
| "challenge": "Explain why a team should adopt (or avoid) a specific technology using strict 3-pillar signposting: Headline → First, Second, Third → Bottom line.", | |
| "teleprompter_script": ( | |
| "Before migrating any production backend, evaluate three concrete signals—not hype.\n\n" | |
| "First, look at operational simplicity: can an on-call engineer debug it at 2 a.m.?\n\n" | |
| "Second, measure ecosystem maturity: are drivers, observability, and hiring proven?\n\n" | |
| "Third, calculate migration cost versus customer value: does this directly improve reliability or shipping velocity?\n\n" | |
| "Thus, when all three align, move decisively; otherwise, invest in your core product." | |
| ), | |
| "outline_cues": [ | |
| "Headline rule: 3 signals before any migration", | |
| "First: 2 a.m. debuggability", | |
| "Second: Ecosystem & observability maturity", | |
| "Third: Customer value vs migration tax + Bottom line", | |
| ], | |
| "target_keywords": ["first", "second", "third", "thus", "reliability"], | |
| }, | |
| { | |
| "day": 9, | |
| "week": 2, | |
| "week_theme": "Clarity, Structure & Technical Explanations", | |
| "title": "Hooking Viewers in the First 8 Seconds", | |
| "skill_focus": "Cold-Open Hooks", | |
| "duration_sec": 75, | |
| "mode": "Storytelling", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "Eliminate throat-clearing openers ('Hey guys, so today I wanted to...'). Start directly on the tension!", | |
| "challenge": "Start your recording with zero preamble—deliver an 8-second cold-open hook about a surprising software myth, then back it up in 60 seconds.", | |
| "teleprompter_script": ( | |
| "Adding more servers made our application slower—not faster. Here is why.\n\n" | |
| "When traffic spiked last quarter, we doubled our compute instances, expecting response times to drop.\n\n" | |
| "However, every new instance opened fresh connections against a single unpooled database, saturating locks within seconds.\n\n" | |
| "Once we added connection pooling and read replicas, latency dropped eighty percent on half the hardware.\n\n" | |
| "So before scaling horizontally, always find the shared bottleneck first." | |
| ), | |
| "outline_cues": [ | |
| "0:00–0:08 Cold open paradox ('Adding more servers made us slower.')", | |
| "0:08–0:30 What we expected vs what broke", | |
| "0:30–0:55 Connection pooling fix & exact metric win", | |
| "0:55–1:15 Memorable engineering principle", | |
| ], | |
| "target_keywords": ["however", "so", "first", "latency", "database"], | |
| }, | |
| { | |
| "day": 10, | |
| "week": 2, | |
| "week_theme": "Clarity, Structure & Technical Explanations", | |
| "title": "Explaining Tradeoffs Without Rambling", | |
| "skill_focus": "Concise Reasoning", | |
| "duration_sec": 120, | |
| "mode": "Debate", | |
| "goal": "Reduce fillers", | |
| "warm_up": "Practice the crisp formula: 'Option A wins when X; Option B wins when Y; for our constraints, choose A because Z.'", | |
| "challenge": "Compare SQL vs NoSQL, Monolith vs Microservices, or Local vs Cloud AI in 2 minutes without circling back or repeating yourself.", | |
| "teleprompter_script": ( | |
| "Choosing between local on-device AI and cloud frontier models comes down to three tradeoffs: privacy, latency, and reasoning depth.\n\n" | |
| "First, local models win when sensitive audio or documents cannot leave the user's machine and sub-second offline response matters.\n\n" | |
| "However, cloud models win when tasks require broad world knowledge and multi-step synthesis across huge contexts.\n\n" | |
| "Therefore, the smartest modern apps combine both: fast local models for instant feedback, paired with cloud reasoning only when needed." | |
| ), | |
| "outline_cues": [ | |
| "Frame the 3 axes up front (privacy, latency, depth)", | |
| "When Path A wins decisively", | |
| "However — when Path B wins decisively", | |
| "Therefore — clear hybrid recommendation", | |
| ], | |
| "target_keywords": ["first", "however", "therefore", "latency", "models"], | |
| }, | |
| { | |
| "day": 11, | |
| "week": 2, | |
| "week_theme": "Clarity, Structure & Technical Explanations", | |
| "title": "Visual Analogies for Invisible Systems", | |
| "skill_focus": "Mental Models", | |
| "duration_sec": 90, | |
| "mode": "Storytelling", | |
| "goal": "Improve pace", | |
| "warm_up": "Use slight hand gestures inside the chest-to-shoulder frame to illustrate spatial relationships.", | |
| "challenge": "Use a vivid physical-world analogy to explain load balancing, rate limiting, Kubernetes, or Git branching on camera.", | |
| "teleprompter_script": ( | |
| "Rate limiting works just like the metered green light on a busy highway on-ramp during rush hour.\n\n" | |
| "If five hundred cars surge onto the freeway at the exact same second, every lane grinds to a standstill for miles.\n\n" | |
| "By spacing entries one car every two seconds, traffic on the main highway keeps flowing at sixty miles per hour.\n\n" | |
| "Similarly, an API rate limiter protects every customer's experience when one noisy client suddenly spikes." | |
| ), | |
| "outline_cues": [ | |
| "Concrete real-world picture (highway ramp meter)", | |
| "What breaks without it (gridlock)", | |
| "How the mechanism restores smooth flow", | |
| "Bridge back to software architecture", | |
| ], | |
| "target_keywords": ["rate", "traffic", "api", "protects"], | |
| }, | |
| { | |
| "day": 12, | |
| "week": 2, | |
| "week_theme": "Clarity, Structure & Technical Explanations", | |
| "title": "Teleprompter Naturalness Mastery", | |
| "skill_focus": "Conversational Script Reading", | |
| "duration_sec": 90, | |
| "mode": "Reading", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "Set teleprompter font size comfortable near the top of your screen so your eyes barely move left-to-right.", | |
| "challenge": "Read today's scripted product announcement using Auto-Scroll Teleprompter mode while sounding 100% spontaneous—using micro-smiles, eyebrow lifts, and natural breaths.", | |
| "teleprompter_script": ( | |
| "Have you ever recorded a great product demo, watched it back, and realized you stared six inches below the lens the entire time?\n\n" | |
| "We built an on-lens studio teleprompter right into your browser to solve that exact problem.\n\n" | |
| "Because your script sits right beneath your camera, your eyes stay locked with your audience while your pacing stays effortless.\n\n" | |
| "Try one ninety-second take today—and watch how much more confident your playback looks." | |
| ), | |
| "outline_cues": [ | |
| "Conversational question hook with warm eyebrow lift", | |
| "Announce the solution cleanly", | |
| "Explain why it feels natural on playback", | |
| "Friendly direct invitation to try it", | |
| ], | |
| "target_keywords": ["because", "camera", "script", "confident"], | |
| }, | |
| { | |
| "day": 13, | |
| "week": 2, | |
| "week_theme": "Clarity, Structure & Technical Explanations", | |
| "title": "Answering Tough Technical Questions on Camera", | |
| "skill_focus": "Composure Under Pressure", | |
| "duration_sec": 90, | |
| "mode": "Interview", | |
| "goal": "Reduce fillers", | |
| "warm_up": "Practice the 2-second 'Acknowledge + Direct Answer' pause: nod once, inhale, state the answer in sentence one.", | |
| "challenge": "Answer a skeptical question—'Why won't big incumbents crush your product in six months?' or 'What is the biggest flaw in your architecture?'—with calm honesty.", | |
| "teleprompter_script": ( | |
| "That is a fair question, and the honest answer is that every architecture has a ceiling if traffic grows tenfold.\n\n" | |
| "First, our current single-region database keeps latency low and iteration fast for our current scale.\n\n" | |
| "However, we already isolated tenant writes behind clean queue boundaries so we can shard horizontally before contention hits.\n\n" | |
| "So we are intentionally optimizing for learning speed today without painting ourselves into a corner tomorrow." | |
| ), | |
| "outline_cues": [ | |
| "Calm acknowledgment + direct answer in sentence 1", | |
| "First: Why today's design is deliberately pragmatic", | |
| "However: The escape hatch already built in", | |
| "So: Strategic takeaway with steady lens contact", | |
| ], | |
| "target_keywords": ["first", "however", "so", "latency", "architecture"], | |
| }, | |
| { | |
| "day": 14, | |
| "week": 2, | |
| "week_theme": "Clarity, Structure & Technical Explanations", | |
| "title": "Week 2 Checkpoint: 3-Minute Live Product Demo Pitch", | |
| "skill_focus": "Structured Demo Delivery", | |
| "duration_sec": 150, | |
| "mode": "Pitch", | |
| "goal": "Improve pace", | |
| "warm_up": "Review your Week 1 vs Week 2 filler rate on Progress, then set 1 intention for this checkpoint take.", | |
| "challenge": "Deliver a 2.5-minute product demo pitch: Hook → User Pain → How It Works (3 steps) → Proof/Metric → Clear Call to Action.", | |
| "teleprompter_script": ( | |
| "Great engineers often build extraordinary software—yet lose the room in the first thirty seconds when presenting it on camera.\n\n" | |
| "The problem is rarely knowledge; it is lack of structured daily feedback on pace, filler habits, and lens presence.\n\n" | |
| "First, our studio pairs an on-lens teleprompter with live WPM and eye-contact cues.\n\n" | |
| "Second, every saved session generates concrete coaching drills tailored to your exact bottlenecks.\n\n" | |
| "Third, weekly comparisons let you watch your Day 1 self side-by-side against today.\n\n" | |
| "Start with just one daily take—and turn presenting into your unfair career advantage." | |
| ), | |
| "outline_cues": [ | |
| "0:00 Hook: Great builders losing the room on camera", | |
| "0:25 Root problem: No tight feedback loop", | |
| "0:50 First, Second, Third product pillars", | |
| "2:00 Closing vision & crisp call to action", | |
| ], | |
| "target_keywords": ["first", "second", "third", "problem", "feedback"], | |
| }, | |
| # ─── WEEK 3: Technology News & Engaging Storytelling ─── | |
| { | |
| "day": 15, | |
| "week": 3, | |
| "week_theme": "Technology News & Engaging Storytelling", | |
| "title": "60-Second Breaking Tech News Briefing", | |
| "skill_focus": "News Synthesis", | |
| "duration_sec": 60, | |
| "mode": "Storytelling", | |
| "goal": "Improve pace", | |
| "warm_up": "Open the Tech News tab, pick a fresh story, or use today's built-in AI infrastructure briefing.", | |
| "challenge": "Deliver a sharp 60-second tech news segment: What just happened → Why builders should care → Your 1-sentence take.", | |
| "teleprompter_script": ( | |
| "A major shift is happening in AI engineering this year: inference cost per token has fallen nearly tenfold, yet total compute spend is climbing.\n\n" | |
| "Why? Because teams are moving from single chat prompts to multi-step background agents that verify code, run tests, and query tools autonomously.\n\n" | |
| "For developers, this means latency budgets and evaluation harnesses now matter far more than prompt tricks.\n\n" | |
| "My take: the winners next year will be the teams with the cleanest verification loops." | |
| ), | |
| "outline_cues": [ | |
| "Headline shift: Inference cheaper, total agent compute rising", | |
| "Why it is happening (single prompt -> multi-step tool loops)", | |
| "What changes for builders right now", | |
| "Sharp personal prediction in the final 10 seconds", | |
| ], | |
| "target_keywords": ["because", "inference", "agents", "latency"], | |
| }, | |
| { | |
| "day": 16, | |
| "week": 3, | |
| "week_theme": "Technology News & Engaging Storytelling", | |
| "title": "The Engineering Postmortem War Story", | |
| "skill_focus": "Narrative Tension", | |
| "duration_sec": 120, | |
| "mode": "Storytelling", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "Great tech stories need stakes! State the exact moment you knew something was wrong in your first two sentences.", | |
| "challenge": "Tell a 2-minute story about a tricky bug, outage, or failed experiment: The Stakes → The Red Herring → The Root Cause → The Lesson.", | |
| "teleprompter_script": ( | |
| "At 4:55 p.m. on a Friday launch, our checkout dashboard suddenly flatlined to zero orders—while CPU and memory looked completely normal.\n\n" | |
| "At first, everyone suspected the payment gateway. However, test charges succeeded in sandbox.\n\n" | |
| "Twenty minutes in, we inspected a tiny CSS deployment and realized an invisible modal overlay was intercepting mobile taps on Safari.\n\n" | |
| "We rolled back in ninety seconds, and orders surged back. Therefore, we added real-browser synthetic click tests to every deploy." | |
| ), | |
| "outline_cues": [ | |
| "Scene & stakes (Friday launch, zero orders, green metrics)", | |
| "The red herring we chased first", | |
| "The surprising root cause discovery", | |
| "The permanent guardrail lesson", | |
| ], | |
| "target_keywords": ["first", "however", "therefore", "launch"], | |
| }, | |
| { | |
| "day": 17, | |
| "week": 3, | |
| "week_theme": "Technology News & Engaging Storytelling", | |
| "title": "Contrarian Tech Opinion with Evidence", | |
| "skill_focus": "Persuasive Point of View", | |
| "duration_sec": 105, | |
| "mode": "Debate", | |
| "goal": "Reduce fillers", | |
| "warm_up": "State a bold opinion calmly—persuasion on camera comes from measured certainty, not volume.", | |
| "challenge": "Challenge a popular tech consensus (e.g., 'Boring tech beats bleeding-edge stacks for 90% of startups') backed by concrete evidence and fair nuance.", | |
| "teleprompter_script": ( | |
| "Unpopular engineering opinion: choosing 'boring' proven technology is the fastest way to build a radical product.\n\n" | |
| "First, every hour you spend debugging an alpha framework is an hour stolen from talking to users.\n\n" | |
| "Second, battle-tested databases and web frameworks have decades of documented failure modes.\n\n" | |
| "However, save your innovation budget for the one core algorithm or UX workflow that truly differentiates you.\n\n" | |
| "So keep your plumbing boring—so your product can be bold." | |
| ), | |
| "outline_cues": [ | |
| "Bold contrarian thesis in sentence 1", | |
| "First & Second concrete proofs", | |
| "Fair nuance ('However, where you SHOULD innovate')", | |
| "Quotable closing line ('Keep plumbing boring so product is bold')", | |
| ], | |
| "target_keywords": ["first", "second", "however", "so", "product"], | |
| }, | |
| { | |
| "day": 18, | |
| "week": 3, | |
| "week_theme": "Technology News & Engaging Storytelling", | |
| "title": "Founder & Builder Origin Story Arc", | |
| "skill_focus": "Authentic Connection", | |
| "duration_sec": 120, | |
| "mode": "Storytelling", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "Recall the exact personal frustration that sparked a project you care about.", | |
| "challenge": "Share the origin story behind something you built or why you entered tech: Frustration → Spark → First Prototype → Where It's Going.", | |
| "teleprompter_script": ( | |
| "The best developer tools almost always start as a personal scratch you could not ignore.\n\n" | |
| "A year ago, I dreaded watching my own recorded tech talks because nobody teaches engineers how to speak naturally to a glass camera lens.\n\n" | |
| "So I hacked together a weekend prototype that tracked my speaking pace and filler words right inside the browser.\n\n" | |
| "Today, that weekend experiment guides my daily practice—because confidence on camera is a trainable skill, not a personality trait." | |
| ), | |
| "outline_cues": [ | |
| "Universal truth hook", | |
| "Personal moment of frustration", | |
| "The scrappy weekend prototype", | |
| "Mission statement: why it matters for others", | |
| ], | |
| "target_keywords": ["so", "because", "camera", "prototype", "confidence"], | |
| }, | |
| { | |
| "day": 19, | |
| "week": 3, | |
| "week_theme": "Technology News & Engaging Storytelling", | |
| "title": "90-Second Live Headline Synthesis", | |
| "skill_focus": "Bullet-Cue Fluency", | |
| "duration_sec": 90, | |
| "mode": "Storytelling", | |
| "goal": "Reduce fillers", | |
| "warm_up": "Switch the Studio Teleprompter to 'Cue Cards' mode so you speak from 4 bullets instead of reading full sentences!", | |
| "challenge": "Speak ONLY from the 4 bullet cues (no word-for-word reading!) to break down a major trend in developer tooling, cloud, or AI.", | |
| "teleprompter_script": ( | |
| "Speak freely from your 4 bullet cues today:\n" | |
| "1. State the headline trend in plain English.\n" | |
| "2. Give one concrete developer workflow example.\n" | |
| "3. Name one risk or hype trap to watch out for.\n" | |
| "4. Close with what you are testing personally this week." | |
| ), | |
| "outline_cues": [ | |
| "1. Headline trend in 1 crisp sentence", | |
| "2. Concrete developer workflow example ('For instance...')", | |
| "3. Honest risk or hype trap ('However...')", | |
| "4. What I am testing next ('Therefore...')", | |
| ], | |
| "target_keywords": ["however", "therefore", "workflow", "testing"], | |
| }, | |
| { | |
| "day": 20, | |
| "week": 3, | |
| "week_theme": "Technology News & Engaging Storytelling", | |
| "title": "Human Impact Behind Technical Specs", | |
| "skill_focus": "Audience Empathy", | |
| "duration_sec": 105, | |
| "mode": "Pitch", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "For every technical metric ('99.99% uptime', '40KB bundle'), ask: 'Whose Tuesday afternoon gets better because of this?'", | |
| "challenge": "Turn three dry technical specs into human stories—connecting engineering craft to real people on slow phones, tight budgets, or high-stakes jobs.", | |
| "teleprompter_script": ( | |
| "When we say we trimmed our web app bundle by eighty percent, that sounds like a dry benchmark.\n\n" | |
| "However, in the real world, that means a founder checking analytics on a congested train or a student on a budget phone gets instant answers instead of a blank spinner.\n\n" | |
| "First, offline-first caching respects unreliable networks. Second, responsive layouts respect small screens.\n\n" | |
| "Ultimately, performance engineering is empathy written in code." | |
| ), | |
| "outline_cues": [ | |
| "Start with the dry technical spec", | |
| "Translate it immediately to a human moment", | |
| "First & Second ways software respects the user", | |
| "Closing line: 'Performance engineering is empathy in code'", | |
| ], | |
| "target_keywords": ["however", "first", "second", "performance"], | |
| }, | |
| { | |
| "day": 21, | |
| "week": 3, | |
| "week_theme": "Technology News & Engaging Storytelling", | |
| "title": "Week 3 Checkpoint: 3-Min Tech Show Segment", | |
| "skill_focus": "Broadcast Storytelling", | |
| "duration_sec": 180, | |
| "mode": "Storytelling", | |
| "goal": "Improve pace", | |
| "warm_up": "Pick a headline from Tech News, generate a 2-Min Explainer Storyboard, and customize your personal angle.", | |
| "challenge": "Host a complete 3-minute technology commentary segment as if recording for YouTube or a company all-hands—combining hook, story, analogy, and sharp takeaway.", | |
| "teleprompter_script": ( | |
| "Welcome back. Today we are unpacking one of the biggest shifts in modern software development—and what it actually means for how we build.\n\n" | |
| "First, let us look at what just changed beneath the surface.\n\n" | |
| "Second, think of the underlying architecture through a simple mental model so we separate real signal from marketing noise.\n\n" | |
| "However, every new capability introduces fresh failure modes around reliability and security.\n\n" | |
| "Therefore, here are the two practical habits worth adopting on your projects this month." | |
| ), | |
| "outline_cues": [ | |
| "0:00 Broadcast cold open + promise to the viewer", | |
| "0:30 First: What changed + concrete facts", | |
| "1:15 Second: Analogy that makes the mechanism click", | |
| "2:00 However / Therefore: Risks + 2 actionable takeaways", | |
| ], | |
| "target_keywords": ["first", "second", "however", "therefore", "architecture"], | |
| }, | |
| # ─── WEEK 4: High-Stakes Presenting, Polish & Signature Style ─── | |
| { | |
| "day": 22, | |
| "week": 4, | |
| "week_theme": "High-Stakes Presenting, Polish & Signature Style", | |
| "title": "90-Second Executive Engineering Briefing", | |
| "skill_focus": "Bottom-Line-Up-Front (BLUF)", | |
| "duration_sec": 90, | |
| "mode": "Pitch", | |
| "goal": "Improve pace", | |
| "warm_up": "Executives decide in 20 seconds: state Recommendation → Impact → Risk Mitigation → Ask.", | |
| "challenge": "Pitch a technical roadmap decision in 90 seconds using Bottom-Line-Up-Front (BLUF) clarity.", | |
| "teleprompter_script": ( | |
| "My recommendation is to dedicate two weeks this sprint to automated end-to-end checkout reliability before launching our new tier.\n\n" | |
| "First, last month's regressions cost twelve hours of engineering firefighting and delayed two releases.\n\n" | |
| "Second, a deterministic test suite cuts release verification from two hours to six minutes.\n\n" | |
| "Therefore, investing ten days now protects revenue on launch day and accelerates every sprint after." | |
| ), | |
| "outline_cues": [ | |
| "Sentence 1: Clear recommendation up front", | |
| "First: Cost of status quo in hours/risk", | |
| "Second: Measurable speedup from proposed investment", | |
| "Therefore: Strategic payoff + crisp ask", | |
| ], | |
| "target_keywords": ["first", "second", "therefore", "reliability"], | |
| }, | |
| { | |
| "day": 23, | |
| "week": 4, | |
| "week_theme": "High-Stakes Presenting, Polish & Signature Style", | |
| "title": "Pattern Interrupts & Re-Engaging Attention", | |
| "skill_focus": "Audience Retention", | |
| "duration_sec": 120, | |
| "mode": "Storytelling", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "Plan a deliberate 'reset phrase' at 0:45 ('Now pause and look at what happens next...').", | |
| "challenge": "Deliver a 2-minute technical talk that intentionally resets audience attention at the 45-second and 90-second marks using rhetorical questions and pace shifts.", | |
| "teleprompter_script": ( | |
| "Most presentations lose half the room right around the forty-five-second mark—not because the topic is dull, but because the rhythm never changes.\n\n" | |
| "First, establish your core technical premise clearly and briskly.\n\n" | |
| "Now pause for a second: what actually happens when real users hit this system at peak load?\n\n" | |
| "That single question wakes up every listener's brain because curiosity demands an answer.\n\n" | |
| "So vary your cadence, ask sharp questions, and earn attention every forty-five seconds." | |
| ), | |
| "outline_cues": [ | |
| "0:00 Premise setup at brisk 145 WPM", | |
| "0:45 Pattern interrupt: Slow down + ask sharp question", | |
| "1:15 Concrete technical payoff", | |
| "1:45 Crisp closing principle", | |
| ], | |
| "target_keywords": ["first", "because", "so", "system"], | |
| }, | |
| { | |
| "day": 24, | |
| "week": 4, | |
| "week_theme": "High-Stakes Presenting, Polish & Signature Style", | |
| "title": "Graceful Recovery When Losing Your Place", | |
| "skill_focus": "Live Resilience", | |
| "duration_sec": 90, | |
| "mode": "Interview", | |
| "goal": "Reduce fillers", | |
| "warm_up": "Practice bridging calmly without apologizing: 'Let me zoom back out to the core point...'", | |
| "challenge": "Speak impromptu on a moderately complex tech topic; mid-way through, intentionally stop for 2 seconds, smile calmly, use a clean bridge phrase, and finish strong with zero 'um/sorry'.", | |
| "teleprompter_script": ( | |
| "Even seasoned keynote speakers occasionally lose a detail mid-sentence under bright studio lights.\n\n" | |
| "Amateurs apologize, look down, and fill the air with 'um, sorry, wait'.\n\n" | |
| "Professionals simply pause, breathe, look squarely into the lens, and bridge with: 'Here is the core point that matters most.'\n\n" | |
| "Because the audience does not have your script, calm silence always looks intentional." | |
| ), | |
| "outline_cues": [ | |
| "Open impromptu on how a favorite system works", | |
| "At 0:40, intentionally pause silently for 2 full seconds", | |
| "Bridge cleanly: 'Stepping back, here is what matters most...'", | |
| "Land a confident closing sentence", | |
| ], | |
| "target_keywords": ["because", "pause", "matters", "lens"], | |
| }, | |
| { | |
| "day": 25, | |
| "week": 4, | |
| "week_theme": "High-Stakes Presenting, Polish & Signature Style", | |
| "title": "Product Launch Keynote Opener", | |
| "skill_focus": "Keynote Presence", | |
| "duration_sec": 120, | |
| "mode": "Pitch", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "Stand up if possible (or sit tall at the front edge of your chair) for maximum breath support and keynote energy!", | |
| "challenge": "Deliver a 2-minute Apple/Stripe-style product launch opener blending scripted precision on the headline lines with natural warmth in the middle.", | |
| "teleprompter_script": ( | |
| "Every developer remembers the magic of shipping their very first idea to the web—and the frustration of how complicated modern deployment slowly became.\n\n" | |
| "Today, we are making shipping feel effortless again.\n\n" | |
| "First, zero-config previews spin up on every branch in three seconds.\n\n" | |
| "Second, built-in observability highlights real user bottlenecks automatically.\n\n" | |
| "Third, rollbacks happen in a single click—so your team can ship boldly every single day." | |
| ), | |
| "outline_cues": [ | |
| "Shared developer memory + tension", | |
| "Keynote reveal line with 1-second pause before & after", | |
| "Three crisp capabilities (3s previews, observability, 1-click rollback)", | |
| "Inspiring close with warm lens smile", | |
| ], | |
| "target_keywords": ["first", "second", "third", "so", "shipping"], | |
| }, | |
| { | |
| "day": 26, | |
| "week": 4, | |
| "week_theme": "High-Stakes Presenting, Polish & Signature Style", | |
| "title": "Crisp On-Camera Tutorial Teaching", | |
| "skill_focus": "Instructional Clarity", | |
| "duration_sec": 120, | |
| "mode": "Reading", | |
| "goal": "Improve pace", | |
| "warm_up": "Use the teaching triad: 'What we will build → Why we do this step → Common pitfall to avoid.'", | |
| "challenge": "Teach a 3-step technical mini-tutorial on camera (e.g., setting up JWT auth, writing a clean SQL query, or debugging network waterfalls) in 2 minutes.", | |
| "teleprompter_script": ( | |
| "In the next two minutes, you will learn how to fix slow API waterfalls in any frontend app.\n\n" | |
| "First, open your network tab and spot sequential requests that wait on each other unnecessarily.\n\n" | |
| "Second, group independent fetches with Promise.all so they fire in parallel.\n\n" | |
| "However, watch out for one pitfall: use Promise.allSettled when an optional panel should not crash the whole page.\n\n" | |
| "Try this on your dashboard route today and watch load time drop." | |
| ), | |
| "outline_cues": [ | |
| "Promise: What the viewer learns in 2 minutes", | |
| "Step 1: How to diagnose the issue", | |
| "Step 2: Exact pattern to apply", | |
| "Pitfall guardrail ('However...') + quick win", | |
| ], | |
| "target_keywords": ["first", "second", "however", "parallel"], | |
| }, | |
| { | |
| "day": 27, | |
| "week": 4, | |
| "week_theme": "High-Stakes Presenting, Polish & Signature Style", | |
| "title": "Fireside Q&A Rapid-Fire Precision", | |
| "skill_focus": "Impromptu Brevity", | |
| "duration_sec": 120, | |
| "mode": "Interview", | |
| "goal": "Reduce fillers", | |
| "warm_up": "Answer each question in 3 sentences max: Direct answer → Concrete example → Takeaway.", | |
| "challenge": "Answer TWO rapid-fire tech interview / podcast questions back-to-back in 60 seconds each: (1) Biggest shift in software right now? (2) Best habit you ever built as an engineer?", | |
| "teleprompter_script": ( | |
| "Question One: What is the biggest shift in software engineering right now?\n" | |
| "Answer in three crisp sentences with one real example.\n\n" | |
| "Question Two: What is the single highest-leverage habit you have built in your career?\n" | |
| "Answer in three crisp sentences and land cleanly at two minutes." | |
| ), | |
| "outline_cues": [ | |
| "Q1 (0:00–1:00): Headline answer -> Example -> Takeaway", | |
| "Clean 1.5s transition breath at 1:00", | |
| "Q2 (1:00–2:00): Habit -> Story -> Advice to listener", | |
| ], | |
| "target_keywords": ["because", "first", "habit", "software"], | |
| }, | |
| { | |
| "day": 28, | |
| "week": 4, | |
| "week_theme": "High-Stakes Presenting, Polish & Signature Style", | |
| "title": "Zero-Filler 2-Minute Mastery Sprint", | |
| "skill_focus": "Peak Articulation", | |
| "duration_sec": 120, | |
| "mode": "Debate", | |
| "goal": "Reduce fillers", | |
| "warm_up": "Slow your opening sentence by 10%—most fillers happen when your mouth outruns your next thought.", | |
| "challenge": "Speak for a full 2 minutes on any technology topic of your choice with ZERO filler words (<1.0/min) while keeping pace above 125 WPM.", | |
| "teleprompter_script": ( | |
| "Today is a precision challenge: two full minutes of clear, unhurried technical commentary with zero filler crutches.\n\n" | |
| "First, state a technology thesis you genuinely believe in.\n\n" | |
| "Second, walk through two real-world examples from products or systems you admire.\n\n" | |
| "Third, pause deliberately before your final sentence—and deliver a closing line worth quoting." | |
| ), | |
| "outline_cues": [ | |
| "0:00 Calm, unhurried thesis statement", | |
| "0:30 Example 1 with crisp transitions", | |
| "1:15 Example 2 + contrast ('However...')", | |
| "1:50 1-second silent pause -> Quotable closing line", | |
| ], | |
| "target_keywords": ["first", "second", "third", "however"], | |
| }, | |
| { | |
| "day": 29, | |
| "week": 4, | |
| "week_theme": "High-Stakes Presenting, Polish & Signature Style", | |
| "title": "Dress Rehearsal: Signature 3-Min Tech Talk", | |
| "skill_focus": "Signature Voice", | |
| "duration_sec": 180, | |
| "mode": "Storytelling", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "Load your own custom script or outline into the Studio Teleprompter and set Cue Cards or Auto-Scroll.", | |
| "challenge": "Deliver a 3-minute dress rehearsal of a signature talk, product demo, or YouTube episode you want to publish in the real world.", | |
| "teleprompter_script": ( | |
| "Open with a bold problem or surprising insight from your own work.\n\n" | |
| "First, show why conventional approaches fall short.\n\n" | |
| "Second, reveal the core insight or architecture that changes the game, anchored in a vivid analogy.\n\n" | |
| "Third, share measurable proof or a real war story.\n\n" | |
| "Finally, leave your audience with one concrete action they can take today." | |
| ), | |
| "outline_cues": [ | |
| "0:00 Cold-open hook with energy & direct lens lock", | |
| "0:40 Conventional approach & why it breaks", | |
| "1:30 Core insight + visual analogy + proof", | |
| "2:30 Actionable takeaway + confident sign-off", | |
| ], | |
| "target_keywords": ["first", "second", "third", "problem"], | |
| }, | |
| { | |
| "day": 30, | |
| "week": 4, | |
| "week_theme": "High-Stakes Presenting, Polish & Signature Style", | |
| "title": "Graduation Capstone & Day 1 Comparison", | |
| "skill_focus": "Mastery & Reflection", | |
| "duration_sec": 120, | |
| "mode": "Pitch", | |
| "goal": "Stronger eye contact", | |
| "warm_up": "Breathe deeply, smile at the lens, and own the frame—you have built a real presenting habit.", | |
| "challenge": "Re-record your Tech Presenter Introduction & Vision (2 minutes), then open Progress & Compare to watch Day 30 side-by-side against Day 1!", | |
| "teleprompter_script": ( | |
| "Thirty days ago, I started practicing on camera to turn technical ideas into clear, compelling stories.\n\n" | |
| "First, I learned to replace rushed filler words with calm, deliberate pauses.\n\n" | |
| "Second, I learned to speak directly to the camera lens as if conversing with one curious builder.\n\n" | |
| "Third, I learned to structure complex engineering ideas into hooks, analogies, and clear takeaways.\n\n" | |
| "Here is the technology problem I am tackling next—and why I am excited to share the journey." | |
| ), | |
| "outline_cues": [ | |
| " Hook: Who you are as a builder & tech communicator today", | |
| " First, Second, Third breakthroughs in how you communicate", | |
| " The exciting technical frontier you are tackling next", | |
| " Open Progress & Compare afterward to watch Day 30 vs Day 1!", | |
| ], | |
| "target_keywords": ["first", "second", "third", "camera", "stories"], | |
| }, | |
| ] | |
| DAILY_WARMUPS: list[dict[str, Any]] = [ | |
| { | |
| "id": "warmup-breath-pace", | |
| "title": "4-4-6 Diaphragmatic Pace Reset", | |
| "category": "Breath & Calm", | |
| "duration_sec": 60, | |
| "steps": [ | |
| "Sit or stand tall with your collarbone open and camera at eye height.", | |
| "Inhale quietly through your nose for 4 seconds, expanding your lower ribs.", | |
| "Hold gently for 4 seconds with zero jaw or throat tension.", | |
| "Exhale on a steady 'ssss' hiss for 6 seconds—repeat 4 cycles before hitting Record.", | |
| ], | |
| "read_aloud_text": "Steady breath creates steady authority. My pace gives every listener time to think.", | |
| }, | |
| { | |
| "id": "warmup-tech-plosives", | |
| "title": "Crisp Tech Consonant & Plosive Articulation", | |
| "category": "Articulation", | |
| "duration_sec": 75, | |
| "steps": [ | |
| "Loosen your jaw and exaggerate lip and tongue movement by 20%.", | |
| "Read the technical articulation phrase below slowly once, then at brisk 145 WPM.", | |
| "Keep word endings ('-ed', '-ts', '-ks') crisp rather than swallowed.", | |
| ], | |
| "read_aloud_text": ( | |
| "Packet pipelines parse predictable payloads; distributed databases deduplicate durable commits; " | |
| "clean caches cut cold-start compute costs." | |
| ), | |
| }, | |
| { | |
| "id": "warmup-pitch-staircase", | |
| "title": "Vocal Variety & Pitch Staircase", | |
| "category": "Expressiveness", | |
| "duration_sec": 60, | |
| "steps": [ | |
| "Read sentence 1 in a low, grounded register (calm certainty).", | |
| "Read sentence 2 with upward curiosity on the question.", | |
| "Read sentence 3 punching the contrast numbers and pausing before the final word.", | |
| ], | |
| "read_aloud_text": ( | |
| "Most systems fail quietly at the edges. What happens when ten thousand users reconnect at once? " | |
| "Latency drops from twelve seconds... to eighty milliseconds." | |
| ), | |
| }, | |
| { | |
| "id": "warmup-silent-pause", | |
| "title": "The 1-Second Power Pause Metronome", | |
| "category": "Filler Control", | |
| "duration_sec": 60, | |
| "steps": [ | |
| "Read each clause aloud while looking straight into the camera ring.", | |
| "At every [PAUSE], close your lips completely and count 'one-thousand' silently.", | |
| "Notice how calm silence sounds confident rather than awkward.", | |
| ], | |
| "read_aloud_text": ( | |
| "Great presenters never rush the punchline. [PAUSE] First, they frame the tension. [PAUSE] " | |
| "Second, they reveal the mechanism. [PAUSE] Finally, they let the takeaway breathe." | |
| ), | |
| }, | |
| ] | |
| CAMERA_CHALLENGES: list[dict[str, Any]] = [ | |
| { | |
| "id": "challenge-lens-lock", | |
| "title": "60s Lens-Lock Challenge", | |
| "badge": "Camera Presence", | |
| "mode": "Storytelling", | |
| "goal": "Stronger eye contact", | |
| "duration_sec": 60, | |
| "target_metric": "eye_contact >= 75%", | |
| "prompt": "Explain how HTTPS or public-key encryption keeps data safe—without breaking eye contact with the camera lens for more than 2 seconds at a time.", | |
| "outline_cues": [ | |
| "Analogy: A padlock anyone can snap shut, but only one key opens", | |
| "How browser + server agree on a secret session key", | |
| "Why this protects every login and payment online", | |
| ], | |
| "target_keywords": ["key", "browser", "secure", "because"], | |
| }, | |
| { | |
| "id": "challenge-zero-filler-sprint", | |
| "title": "90s Zero-Filler Architecture Sprint", | |
| "badge": "Articulation", | |
| "mode": "Interview", | |
| "goal": "Reduce fillers", | |
| "duration_sec": 90, | |
| "target_metric": "filler_rate <= 1.5/min", | |
| "prompt": "Walk through what happens when you type a URL into a browser and press Enter. Replace every urge to say 'um', 'uh', or 'like' with a silent pause.", | |
| "outline_cues": [ | |
| "First: DNS lookup translates domain to IP", | |
| "Second: TCP + TLS handshake establishes secure channel", | |
| "Third: HTTP response streams HTML & renders pixels", | |
| ], | |
| "target_keywords": ["first", "second", "third", "browser", "response"], | |
| }, | |
| { | |
| "id": "challenge-cold-open-hooks", | |
| "title": "Triple Cold-Open Hook Lab", | |
| "badge": "Engagement", | |
| "mode": "Pitch", | |
| "goal": "Stronger eye contact", | |
| "duration_sec": 60, | |
| "target_metric": "Expressive tone + Smile", | |
| "prompt": "Deliver 3 different 15-second video hooks back-to-back for the same tech project: (1) Surprising Stat Hook, (2) Relatable Frustration Hook, (3) Bold Contrarian Hook.", | |
| "outline_cues": [ | |
| "Hook 1 (0:00–0:20): Start with a dramatic number or benchmark", | |
| "Hook 2 (0:20–0:40): 'Have you ever spent three hours debugging...'", | |
| "Hook 3 (0:40–1:00): 'Everyone thinks X solves Y—however...'", | |
| ], | |
| "target_keywords": ["however", "because", "seconds"], | |
| }, | |
| { | |
| "id": "challenge-explain-3-levels", | |
| "title": "Explain It at 3 Levels (Non-Tech → Dev → CTO)", | |
| "badge": "Clarity", | |
| "mode": "Storytelling", | |
| "goal": "Improve pace", | |
| "duration_sec": 120, | |
| "target_metric": "125–155 WPM + High Clarity", | |
| "prompt": "Pick one concept (APIs, Containers, Vector Search, or Caching) and explain it in 35s to a smart friend, 40s to a junior developer, and 40s to a CTO focused on cost & reliability.", | |
| "outline_cues": [ | |
| "Level 1 (Friend): Zero jargon, everyday analogy", | |
| "Level 2 (Developer): How you wire it in code & debug it", | |
| "Level 3 (CTO): Latency, cost, scale, and operational risk", | |
| ], | |
| "target_keywords": ["first", "second", "latency", "cost", "reliability"], | |
| }, | |
| { | |
| "id": "challenge-hot-seat-postmortem", | |
| "title": "Impromptu Incident Briefing Hot-Seat", | |
| "badge": "Executive Calm", | |
| "mode": "Interview", | |
| "goal": "Improve pace", | |
| "duration_sec": 90, | |
| "target_metric": "Steady 130–150 WPM", | |
| "prompt": "Imagine an API outage was just mitigated 5 minutes ago. Deliver a calm, transparent 90-second video update to customers & teammates: Impact → Root Cause → Fix → Prevention.", | |
| "outline_cues": [ | |
| "Status first: Service is restored and healthy", | |
| "Impact window & who was affected", | |
| "Plain-English root cause (no blame)", | |
| "Two concrete guardrails shipping this week", | |
| ], | |
| "target_keywords": ["first", "because", "therefore", "restored"], | |
| }, | |
| ] | |
| def get_or_create_profile(db: Session, user_id: int) -> models.PresenterProfile: | |
| profile = ( | |
| db.query(models.PresenterProfile) | |
| .filter(models.PresenterProfile.user_id == user_id) | |
| .first() | |
| ) | |
| if profile is None: | |
| profile = models.PresenterProfile( | |
| user_id=user_id, | |
| display_name="Tech Presenter", | |
| primary_role="Software Engineer & Tech Presenter", | |
| focus_track="tech_storytelling", | |
| experience_level="intermediate", | |
| target_wpm_min=125, | |
| target_wpm_max=155, | |
| max_filler_rate=2.0, | |
| min_eye_contact=0.70, | |
| daily_minutes_goal=15, | |
| weaknesses=["filler_words", "eye_contact"], | |
| speaking_goal_statement="Become a confident, articulate, engaging technology presenter through daily camera practice.", | |
| curriculum_start_date=date.today(), | |
| ) | |
| db.add(profile) | |
| db.commit() | |
| db.refresh(profile) | |
| return profile | |
| def serialize_profile(profile: models.PresenterProfile) -> dict[str, Any]: | |
| return { | |
| "id": profile.id, | |
| "display_name": profile.display_name, | |
| "primary_role": profile.primary_role, | |
| "focus_track": profile.focus_track, | |
| "focus_track_label": FOCUS_TRACK_LABELS.get(profile.focus_track, profile.focus_track), | |
| "experience_level": profile.experience_level, | |
| "target_wpm_min": profile.target_wpm_min, | |
| "target_wpm_max": profile.target_wpm_max, | |
| "max_filler_rate": profile.max_filler_rate, | |
| "min_eye_contact": profile.min_eye_contact, | |
| "daily_minutes_goal": profile.daily_minutes_goal, | |
| "weaknesses": profile.weaknesses if isinstance(profile.weaknesses, list) else [], | |
| "speaking_goal_statement": profile.speaking_goal_statement, | |
| "curriculum_start_date": profile.curriculum_start_date.isoformat(), | |
| } | |
| def _personalize_day_tip(day_entry: dict[str, Any], profile: models.PresenterProfile) -> str: | |
| weaknesses = set(profile.weaknesses if isinstance(profile.weaknesses, list) else []) | |
| tips: list[str] = [] | |
| if "filler_words" in weaknesses: | |
| tips.append(f"Keep fillers under {profile.max_filler_rate:.1f}/min by pausing silently at paragraph breaks.") | |
| if "eye_contact" in weaknesses: | |
| tips.append(f"Aim for {int(profile.min_eye_contact * 100)}%+ lens contact using top-of-frame teleprompter cues.") | |
| if "rushing_pace" in weaknesses: | |
| tips.append(f"Hold pace inside your {profile.target_wpm_min}–{profile.target_wpm_max} WPM target zone.") | |
| if "monotone_delivery" in weaknesses: | |
| tips.append("Emphasize contrast words ('however', 'suddenly', numbers) with deliberate pitch lift.") | |
| if "rambling_explanations" in weaknesses: | |
| tips.append("Land each bullet cue in 2–3 crisp sentences before moving to the next point.") | |
| track_note = { | |
| "tech_storytelling": "Frame this take like a high-retention creator segment for curious builders.", | |
| "keynote_clarity": "Project calm stage authority with clean architectural signposts.", | |
| "camera_confidence": "Prioritize relaxed shoulders, warm facial expression, and unhurried breaths.", | |
| "executive_pitch": "Lead with business & user impact in your opening sentence.", | |
| }.get(profile.focus_track, "") | |
| combined = " ".join(([track_note] + tips[:2])).strip() | |
| return combined or f"Target {profile.target_wpm_min}–{profile.target_wpm_max} WPM as a {profile.primary_role}." | |
| def record_curriculum_completion( | |
| db: Session, | |
| user_id: int, | |
| day_number: int, | |
| session_id: int | None = None, | |
| score: float | None = None, | |
| reflection_notes: str | None = None, | |
| ) -> models.CurriculumDayCompletion: | |
| if day_number < 1 or day_number > 30: | |
| raise ValueError("day_number must be between 1 and 30") | |
| row = ( | |
| db.query(models.CurriculumDayCompletion) | |
| .filter( | |
| models.CurriculumDayCompletion.user_id == user_id, | |
| models.CurriculumDayCompletion.day_number == day_number, | |
| ) | |
| .first() | |
| ) | |
| numeric_score = round(float(score or 0), 1) | |
| if row is None: | |
| row = models.CurriculumDayCompletion( | |
| user_id=user_id, | |
| day_number=day_number, | |
| completed_session_id=session_id, | |
| best_score=numeric_score, | |
| attempts_count=1, | |
| reflection_notes=reflection_notes, | |
| completed_at=datetime.utcnow(), | |
| ) | |
| db.add(row) | |
| else: | |
| row.attempts_count = (row.attempts_count or 1) + (1 if session_id else 0) | |
| if session_id is not None: | |
| row.completed_session_id = session_id | |
| if score is not None and numeric_score >= (row.best_score or 0): | |
| row.best_score = numeric_score | |
| if reflection_notes is not None: | |
| row.reflection_notes = reflection_notes | |
| row.updated_at = datetime.utcnow() | |
| db.commit() | |
| db.refresh(row) | |
| return row | |
| def get_curriculum_plan(db: Session, user_id: int) -> dict[str, Any]: | |
| profile = get_or_create_profile(db, user_id) | |
| completions = ( | |
| db.query(models.CurriculumDayCompletion) | |
| .filter(models.CurriculumDayCompletion.user_id == user_id) | |
| .all() | |
| ) | |
| by_day = {row.day_number: row for row in completions} | |
| completed_count = len(by_day) | |
| recommended_day = 1 | |
| for d in range(1, 31): | |
| if d not in by_day: | |
| recommended_day = d | |
| break | |
| else: | |
| recommended_day = 30 | |
| days_out: list[dict[str, Any]] = [] | |
| for entry in CURRICULUM_DAYS: | |
| day_num = entry["day"] | |
| comp = by_day.get(day_num) | |
| tip = _personalize_day_tip(entry, profile) | |
| dur_sec = int(entry.get("duration_sec", 90)) | |
| success_str = ( | |
| f"{profile.target_wpm_min}–{profile.target_wpm_max} WPM · " | |
| f"≤ {profile.max_filler_rate:.1f} fillers/min · " | |
| f"≥ {int(profile.min_eye_contact * 100)}% lens eye-contact" | |
| ) | |
| days_out.append({ | |
| **entry, | |
| "week_title": entry.get("week_theme", f"Week {entry['week']}"), | |
| "focus_skill": entry.get("skill_focus", "Camera Presence"), | |
| "duration_min": max(5, round(dur_sec / 6)), | |
| "warmup": entry.get("warm_up", ""), | |
| "camera_challenge": entry.get("challenge", ""), | |
| "prompt": entry.get("challenge", ""), | |
| "bullet_cues": entry.get("outline_cues", []), | |
| "success_metric": success_str, | |
| "personalized_tip": tip, | |
| "completed": comp is not None, | |
| "is_recommended_today": day_num == recommended_day, | |
| "completed_session_id": comp.completed_session_id if comp else None, | |
| "best_score": comp.best_score if comp else None, | |
| "attempts_count": comp.attempts_count if comp else 0, | |
| "reflection_notes": (comp.reflection_notes or "") if comp else "", | |
| "completed_at": comp.completed_at.isoformat() if comp and comp.completed_at else None, | |
| "personalized_coach_tip": tip, | |
| "target_metrics": { | |
| "wpm_min": profile.target_wpm_min, | |
| "wpm_max": profile.target_wpm_max, | |
| "max_filler_rate": profile.max_filler_rate, | |
| "min_eye_contact_pct": int(profile.min_eye_contact * 100), | |
| }, | |
| }) | |
| avg_best_score = ( | |
| round(sum(c.best_score for c in completions) / len(completions), 1) | |
| if completions | |
| else 0.0 | |
| ) | |
| week_defs = [ | |
| (1, "Camera Presence & Vocal Foundation", "Build relaxed camera eye-line, steady vocal pace, and silent pauses instead of filler words."), | |
| (2, "Structuring Technical Ideas", "Turn complex architectures, APIs, and tradeoffs into crisp 3-beat explanations."), | |
| (3, "Tech News & Builder Storytelling", "Synthesize live industry shifts into engaging 60s briefings, analogies, and hot takes."), | |
| (4, "Executive Demos, Q&A & Keynote Polish", "Deliver high-stakes product demos, incident updates, and conference-grade talks."), | |
| ] | |
| weeks_out = [] | |
| for wk_num, wk_title, wk_theme in week_defs: | |
| wk_days = [d for d in days_out if d["week"] == wk_num] | |
| weeks_out.append({ | |
| "week": wk_num, | |
| "title": wk_title, | |
| "theme": wk_theme, | |
| "completed_count": sum(1 for d in wk_days if d["completed"]), | |
| "total_count": len(wk_days), | |
| }) | |
| today_mission = next((d for d in days_out if d["day"] == recommended_day), days_out[0]) | |
| return { | |
| "profile": serialize_profile(profile), | |
| "summary": { | |
| "total_days": 30, | |
| "completed_days": completed_count, | |
| "completion_pct": round((completed_count / 30) * 100, 1), | |
| "recommended_day": recommended_day, | |
| "current_week": today_mission["week"], | |
| "avg_completed_score": avg_best_score, | |
| }, | |
| "weeks": weeks_out, | |
| "today_mission": today_mission, | |
| "days": days_out, | |
| } | |
| def get_personalized_exercises(db: Session, user_id: int) -> dict[str, Any]: | |
| profile = get_or_create_profile(db, user_id) | |
| recent_metrics = ( | |
| db.query(models.SessionMetrics) | |
| .filter(models.SessionMetrics.user_id == user_id) | |
| .order_by(models.SessionMetrics.recorded_at.desc()) | |
| .limit(8) | |
| .all() | |
| ) | |
| targeted: list[dict[str, Any]] = [] | |
| weaknesses = set(profile.weaknesses if isinstance(profile.weaknesses, list) else []) | |
| avg_wpm = ( | |
| round(sum(m.wpm for m in recent_metrics) / len(recent_metrics), 1) | |
| if recent_metrics | |
| else None | |
| ) | |
| avg_filler_rate = ( | |
| round(sum(m.filler_rate for m in recent_metrics) / len(recent_metrics), 2) | |
| if recent_metrics | |
| else None | |
| ) | |
| eye_vals = [m.eye_contact_score for m in recent_metrics if m.eye_contact_score is not None] | |
| avg_eye = round(sum(eye_vals) / len(eye_vals), 2) if eye_vals else None | |
| avg_vocab = ( | |
| round(sum(m.vocabulary_density for m in recent_metrics) / len(recent_metrics), 3) | |
| if recent_metrics | |
| else None | |
| ) | |
| # Top filler words across recent sessions | |
| filler_totals: dict[str, int] = {} | |
| for m in recent_metrics: | |
| if isinstance(m.filler_breakdown, dict): | |
| for word, count in m.filler_breakdown.items(): | |
| filler_totals[str(word)] = filler_totals.get(str(word), 0) + int(count or 0) | |
| top_filler_words = [w for w, _ in sorted(filler_totals.items(), key=lambda x: x[1], reverse=True)[:3]] | |
| # 1. Filler-targeted drill | |
| if (avg_filler_rate is not None and avg_filler_rate > profile.max_filler_rate) or "filler_words" in weaknesses: | |
| reason = ( | |
| f"Recent filler rate is {avg_filler_rate}/min (target ≤ {profile.max_filler_rate}/min)" | |
| + (f" — top fillers: {', '.join(top_filler_words)}." if top_filler_words else ".") | |
| if avg_filler_rate is not None | |
| else "Selected in your presenter profile priority areas." | |
| ) | |
| targeted.append({ | |
| "id": "targeted-filler-pause", | |
| "priority": "high", | |
| "focus_area": "Filler Elimination", | |
| "title": "Silent Beat-Pause Replacement Drill", | |
| "why_recommended": reason, | |
| "duration_sec": 75, | |
| "mode": "Interview", | |
| "goal": "Reduce fillers", | |
| "prompt": "Explain a technical tradeoff you made recently in 75 seconds. Every time a clause ends—or you feel a filler word forming—close your lips for 1 beat before continuing.", | |
| "teleprompter_script": ( | |
| "Today I am practicing clean transitions without filler words.\n\n" | |
| "First, here is the engineering problem we needed to solve. [Pause 1s]\n\n" | |
| "Second, here is the tradeoff we chose and what we deliberately left out. [Pause 1s]\n\n" | |
| "Therefore, the system stayed simple to operate and fast to ship." | |
| ), | |
| "outline_cues": [ | |
| "State the problem cleanly -> [1s silent breath]", | |
| "State the chosen approach -> [1s silent breath]", | |
| "State the measurable result -> hold lens contact", | |
| ], | |
| "target_keywords": ["first", "second", "therefore"], | |
| }) | |
| # 2. Pace-targeted drill | |
| if ( | |
| (avg_wpm is not None and (avg_wpm > profile.target_wpm_max or (0 < avg_wpm < profile.target_wpm_min))) | |
| or "rushing_pace" in weaknesses | |
| ): | |
| if avg_wpm is not None and avg_wpm > profile.target_wpm_max: | |
| reason = f"Your recent pace averaged {avg_wpm} WPM (above your {profile.target_wpm_min}–{profile.target_wpm_max} WPM target zone)." | |
| drill_title = "140 WPM Unhurried Keynote Pacing Drill" | |
| elif avg_wpm is not None and 0 < avg_wpm < profile.target_wpm_min: | |
| reason = f"Your recent pace averaged {avg_wpm} WPM (below your {profile.target_wpm_min}–{profile.target_wpm_max} WPM target zone)." | |
| drill_title = "Crisp Momentum & Energy Cadence Drill" | |
| else: | |
| reason = "Selected in your presenter profile to lock in steady keynote cadence." | |
| drill_title = "140 WPM Keynote Cadence Calibration" | |
| targeted.append({ | |
| "id": "targeted-wpm-calibration", | |
| "priority": "high", | |
| "focus_area": "Speaking Pace", | |
| "title": drill_title, | |
| "why_recommended": reason, | |
| "duration_sec": 60, | |
| "mode": "Reading", | |
| "goal": "Improve pace", | |
| "prompt": f"Use Auto-Scroll Teleprompter at 1.0x speed to deliver this 140-word tech passage in ~60 seconds ({profile.target_wpm_min}–{profile.target_wpm_max} WPM).", | |
| "teleprompter_script": ( | |
| "Great technical presenters control time rather than letting nervous adrenaline dictate their speed.\n\n" | |
| "When we rush through architecture diagrams or live demos, listeners miss the single insight that makes everything click.\n\n" | |
| "Instead, anchor your voice at a steady conversational rhythm. First, state your headline clearly. Second, illustrate it with one concrete example. Third, pause before your takeaway.\n\n" | |
| "Notice how much more authoritative your voice sounds when every sentence has room to land." | |
| ), | |
| "outline_cues": [ | |
| "0:00–0:15 Steady opening headline", | |
| "0:15–0:45 First, Second, Third points at even tempo", | |
| "0:45–1:00 Unhurried closing takeaway", | |
| ], | |
| "target_keywords": ["first", "second", "third", "rhythm"], | |
| }) | |
| # 3. Eye-contact targeted drill | |
| if (avg_eye is not None and avg_eye < profile.min_eye_contact) or "eye_contact" in weaknesses: | |
| reason = ( | |
| f"Recent camera lens eye contact averaged {int(avg_eye * 100)}% (target ≥ {int(profile.min_eye_contact * 100)}%)." | |
| if avg_eye is not None | |
| else "Selected in your presenter profile to strengthen direct camera connection." | |
| ) | |
| targeted.append({ | |
| "id": "targeted-lens-anchor", | |
| "priority": "medium", | |
| "focus_area": "Camera Eye Contact", | |
| "title": "Top-of-Frame Cue-Card Lens Anchor", | |
| "why_recommended": reason, | |
| "duration_sec": 60, | |
| "mode": "Storytelling", | |
| "goal": "Stronger eye contact", | |
| "prompt": "Speak from 3 short cue bullets in Cue-Card Teleprompter mode while keeping your gaze inside the top lens guide for at least 75% of the recording.", | |
| "teleprompter_script": ( | |
| "Speak naturally to the lens using 3 quick glances max:\n" | |
| "• Hook: Why developer experience makes or breaks adoption.\n" | |
| "• Story: A tool you loved within 5 minutes of installing.\n" | |
| "• Takeaway: One friction point you want to delete from your own project." | |
| ), | |
| "outline_cues": [ | |
| "Why DX drives adoption (eyes locked on lens)", | |
| "5-minute 'aha' story with a favorite tool", | |
| "One friction point to delete this week", | |
| ], | |
| "target_keywords": ["developer", "experience", "adoption"], | |
| }) | |
| # 4. Storytelling & structure drill (always ensure at least 2 targeted drills) | |
| if len(targeted) < 2 or "rambling_explanations" in weaknesses or (avg_vocab is not None and avg_vocab < 0.55): | |
| targeted.append({ | |
| "id": "targeted-hook-mechanism-impact", | |
| "priority": "medium", | |
| "focus_area": "Concise Tech Storytelling", | |
| "title": "Hook → Mechanism → Impact 90s Builder Drill", | |
| "why_recommended": "Builds tight narrative discipline so complex technical ideas land in 90 seconds without rambling.", | |
| "duration_sec": 90, | |
| "mode": "Pitch", | |
| "goal": "Improve pace", | |
| "prompt": "Pick any feature or engineering concept and explain it in strict 30-second blocks: (1) Problem Hook, (2) How It Works Under the Hood, (3) Measurable Impact.", | |
| "teleprompter_script": ( | |
| "Here is the problem most teams hit as soon as their app grows past its first thousand users.\n\n" | |
| "Under the hood, the bottleneck happens because every page reload repeats expensive queries.\n\n" | |
| "By introducing a lightweight cache invalidation strategy, response times drop from seconds to milliseconds—and infrastructure bills stay predictable." | |
| ), | |
| "outline_cues": [ | |
| "0:00–0:30 Problem Hook: What breaks at scale", | |
| "0:30–1:00 Mechanism: Why it happens & how the fix works", | |
| "1:00–1:30 Impact: Speed + cost + user delight", | |
| ], | |
| "target_keywords": ["problem", "because", "strategy", "milliseconds"], | |
| }) | |
| normalized_targeted = [ | |
| { | |
| **item, | |
| "target_metric": item.get("focus_area", "Presenter Delivery"), | |
| "duration_seconds": item.get("duration_sec", 75), | |
| "bullet_cues": item.get("outline_cues", []), | |
| } | |
| for item in targeted | |
| ] | |
| normalized_warmups = [ | |
| { | |
| **wu, | |
| "duration_seconds": wu.get("duration_sec", 60), | |
| "instructions": " ".join(wu.get("steps", [])), | |
| "script": wu.get("read_aloud_text", ""), | |
| } | |
| for wu in DAILY_WARMUPS | |
| ] | |
| normalized_challenges = [ | |
| { | |
| **ch, | |
| "duration_seconds": ch.get("duration_sec", 90), | |
| "difficulty": ch.get("badge", "Challenge"), | |
| "focus": ch.get("target_metric", ch.get("goal", "Clarity")), | |
| "teleprompter_script": "\n\n".join(ch.get("outline_cues", [])), | |
| "bullet_cues": ch.get("outline_cues", []), | |
| } | |
| for ch in CAMERA_CHALLENGES | |
| ] | |
| return { | |
| "diagnostic_snapshot": { | |
| "sessions_analyzed": len(recent_metrics), | |
| "avg_wpm": avg_wpm, | |
| "avg_filler_rate": avg_filler_rate, | |
| "avg_eye_contact_pct": int(avg_eye * 100) if avg_eye is not None else None, | |
| "top_filler_words": top_filler_words, | |
| }, | |
| "recent_averages": { | |
| "session_count": len(recent_metrics), | |
| "avg_wpm": avg_wpm or 0, | |
| "avg_filler_rate": avg_filler_rate or 0, | |
| "avg_eye_contact_pct": int(avg_eye * 100) if avg_eye is not None else 0, | |
| "avg_delivery_score": round(sum(m.delivery_score for m in recent_metrics) / len(recent_metrics), 1) if recent_metrics else 0, | |
| "avg_overall_score": round(sum(m.overall_score for m in recent_metrics) / len(recent_metrics), 1) if recent_metrics else 0, | |
| }, | |
| "targeted_exercises": normalized_targeted, | |
| "daily_warmups": normalized_warmups, | |
| "camera_challenges": normalized_challenges, | |
| } | |