Skip to content

Interview Preparation

Two-minute explanation

“WebVoice Studio is a static React application for private, local voice AI. A setup wizard chooses an LLM, speech recognizer, and synthesizer. Microphone audio passes through an AudioWorklet and VAD/STT worker. The transcript enters a model-independent LLM runtime that streams text, thinking, and optional tool events. If TTS is enabled, sentence chunks are synthesized and queued while generation continues. The hard parts are provider normalization, browser memory, cancellation, and barge-in.”

Likely questions

Why use workers and worklets? Audio and transcription are timing-sensitive and computationally expensive; isolating them protects UI responsiveness.

How do you cancel a response? An abort controller, engine-specific abort, and TTS stop operation are coordinated; stale refs prevent later events from mutating state.

How are tools made portable? The runtime emits normalized tool events, executes through a validated registry, then appends either structured or prompt-formatted tool turns.

What is the biggest limitation? Large model downloads and hardware/browser variability make the experience less predictable than a hosted API.

How would you scale the product? Add an optional remote runtime behind the same adapter contract, while retaining the local path for privacy and offline use.

Stories

  • Hard: coordinating streaming LLM text, sentence TTS, playback, and interruption.
  • Proud: making several incompatible in-browser inference engines feel like one runtime.
  • Improve: add browser integration coverage and stronger production telemetry that does not expose sensitive content.

Deeper technical questions

Why keep refs alongside React state? Worker callbacks and async generators outlive individual renders. Refs expose the latest call/activity/preferences state without rebuilding every callback or accepting stale closures.

Why split sentences instead of buffering the whole response? It lowers time-to-first-audio. Prefetching overlaps the next synthesis call with current playback, but requires ordered queues and abort cleanup.

Why support four LLM engines? Browser support and memory vary dramatically. A common adapter lets the product offer a small fallback, custom kernels, and WebLLM without duplicating conversation orchestration.

What would change for a hosted product? Keep the event and adapter contracts, add an authenticated remote adapter, move conversation persistence and moderation server-side, and preserve the local mode for privacy-sensitive users.

Demonstrable implementation details

Point to useVoiceAgent for lifecycle orchestration, llm-runtime.ts for provider normalization and tool rounds, stt-worker-esm.js for off-main-thread transcription, tts.ts for provider switching, and vite.config.ts for cross-origin isolation.