Interviu — AI Mock Interview Platform

Full-stack platform for AI-powered mock interviews with live voice-to-voice conversations, real-time audio streaming, and AI-generated feedback.

preview.png
Interviu — AI Mock Interview Platform screenshot

Technology Stack

TypeScript logoTypeScript
React logoReact
Node.js logoNode.js
WebSockets logoWebSockets
Gemini Realtime logoGemini Realtime
Anthropic logoAnthropic
PostgreSQL logoPostgreSQL
Prisma logoPrisma
Redis logoRedis
AWS logoAWS
Docker logoDocker
Vercel logoVercel

Elevator Pitch

Interviu is an end-to-end, voice-first mock interview platform designed to simulate realistic technical, system design, and behavioral interviews. Instead of relying on turn-based text prompts, Interviu establishes a bidirectional, low-latency WebSockets connection to stream audio in real-time, matching the natural cadence of a human conversation.

🛠️ The Challenge

  • **Real-Time Audio Latency**: Standard REST calls or chat completion models have high time-to-first-token (TTFT) latency, which ruins the conversational pacing of a real interview.
  • **Monaco Editor Sync**: Injecting Monaco Editor updates on every keystroke without overloading the model's token window or causing context confusion.
  • **Connection Resiliency**: Handling network flickers and dropped WebSocket connections mid-interview without losing the user's progress.
  • **Analytical Evaluation**: Providing objective, bias-free grading of the candidate's performance across communication, code quality, and problem-solving.

🏗️ Architectural Core

Real-Time VOIP & Dual-Model Pipeline

React Client (Voice Recorder & Monaco Code Editor)Web Audio API / PCM Streaming
Bidirectional WebSockets
Node.js / Express Orchestration ServerWebSocket Proxy & Event Handler
Redis CacheLow-Latency Session
PostgreSQLPrisma / Transcripts
Real-Time Voice
Gemini Live APIBidirectional Audio Stream (400ms Response)
Analytical Grade
Claude 3.5 SonnetDual-Model Evaluation & Feedback JSON

The Session Lifecycle

  • **Initialization**: The user selects their interview type (Technical/Coding, System Design, or Behavioral) and duration. The server initializes metadata, reads their resume text, and constructs a customized system prompt (~1,000 lines).
  • **Real-time Session**: The client connects to the backend over a custom WebSocket protocol, which in turn establishes a persistent connection to the Gemini Live API. Audio packages are sent continuously.
  • **Editor Synchronization**: If it's a coding round, code editor updates are captured on the client, sent to the server, and injected into the AI's prompt stream asynchronously as background updates (`[EDITOR_UPDATE]`).
  • **Graceful Disconnects**: If a client drops, the session state, interview progress, and transcript are safely held in Redis. The user can resume within a grace period.
  • **Evaluation**: When the interview finishes, the transcript is flushed to PostgreSQL, and a background worker triggers Claude to parse the transcript and compile structured JSON feedback.

🛠️ Technical Challenges & Solutions

Challenge 1: Minimizing Audio Stream Latency (400–500ms Response Times)

Problem

Standard REST calls or chat completion models have high time-to-first-token (TTFT) latency, which ruins the conversational pacing of a real interview.

Solution

Implemented a raw WebSocket proxy server. The client records user voice snippets in raw PCM format (16kHz sample rate) and streams them down the WebSocket. The server instantly pipes this binary buffer to the Google GenAI Live API connection. By avoiding HTTP overhead and complex audio conversions, the round-trip latency was compressed to 400–500ms.

Challenge 2: Live Monaco Code Editor Sync with AI Prompts

Problem

For technical rounds, the interviewer needs to look at the candidate's code real-time to ask relevant questions. However, sending the entire code editor state on every keystroke to the AI is highly resource-intensive and triggers model confusion.

Solution

Created an asynchronous update throttle. The client tracks code changes via a Monaco Editor container and debounces updates. The backend formats these updates as a special payload format `[EDITOR_UPDATE]` injected directly into Gemini's live context window silently. The system prompt instructs the AI to read these updates in the background, avoid commenting on partial code, and only address bugs or patterns naturally when the candidate speaks.

Challenge 3: Connection Resiliency & State Persistence

Problem

Voice packets are highly prone to network flickers. If a socket disconnects, losing the candidate's interview mid-way is a poor user experience.

Solution

Engineered a Redis-based session caching layer. The server caches active session details (including the Gemini token, elapsed time, current transcript arrays, and original prompt structure) with a 1-hour TTL. If a connection drops, a 'Ghost Timer' is started. If the user reconnects within 30 seconds, the server uses the cached session metadata to resume the Gemini session handle instead of spinning up a fresh session from scratch.

Challenge 4: Avoiding Evaluator Bias using Dual-Model Orchestration

Problem

Using the same LLM connection for conducting the interview and grading the candidate creates a conflict of interest and often results in shallow evaluations.

Solution

Decoupled the feedback pipeline entirely. The Gemini connection focuses solely on pacing, voice generation, and interviewer behavior. When the session terminates, the full compiled JSON transcript is sent to Anthropic's Claude 3.5 Sonnet. Claude parses the transcript against the job description and candidate seniority, producing a highly analytical evaluation containing scores, strengths, focus areas, and next steps.

📊 Key Highlights & Observability

Robust Schema Validation

Designed a custom parser that processes raw AI JSON structures, guaranteeing database schema validation and saving feedback correctly even if LLM outputs include minor syntax inconsistencies.

State Synchronization

Achieved resilient real-time state synchronization, successfully testing simultaneous code typing, voice responses, and network recovery flows.

Scaled Backend DB Load

Used Redis as a write-through buffer for short-term transactional reads during active sessions, saving Postgres resources exclusively for final evaluation records.