Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Before this course spends two full modules on the mechanics of turn-taking, you need the one-paragraph version so the rest of the stack makes sense around it. A voice agent has to constantly decide three things in real time: is the user still talking, has the user finished their turn, and is it safe for the agent to start talking without talking over someone. Text chat never has to answer any of these questions — there's always an explicit 'send' button. Voice has no send button, which is why voice agents need Voice Activity Detection (VAD) to sense presence of speech, endpointing logic to decide a turn is over, and barge-in handling to let the user interrupt. Getting this wrong is the single most common reason a voice demo feels 'off' even when the ASR, LLM, and TTS are each individually excellent — the seams between them are where quality actually lives.
A minimal turn-taking state machine below models three states — listening, thinking, speaking — and the events that move between them, without any real audio yet. You'll wire real VAD in Module 5; this is the skeleton it will plug into.
from enum import Enum, auto
class TurnState(Enum):
LISTENING = auto()
THINKING = auto()
SPEAKING = auto()
class TurnTaker:
def __init__(self):
self.state = TurnState.LISTENING
self.log = []
def on_event(self, event: str) -> None:
prev = self.state
if self.state == TurnState.LISTENING and event == "endpoint_detected":
self.state = TurnState.THINKING
elif self.state == TurnState.THINKING and event == "reply_ready":
self.state = TurnState.SPEAKING
elif self.state == TurnState.SPEAKING and event == "reply_finished":
self.state = TurnState.LISTENING
elif self.state == TurnState.SPEAKING and event == "user_barge_in":
self.state = TurnState.LISTENING # user interrupted -- yield the turn
self.log.append((prev.name, event, self.state.name))
tt = TurnTaker()
for e in ["endpoint_detected", "reply_ready", "user_barge_in", "endpoint_detected", "reply_ready", "reply_finished"]:
tt.on_event(e)
for prev, event, now in tt.log:
print(f"{prev:<10} --[{event}]--> {now}")python3 main.py