A Next.js mock interview application that lets a user upload a CV, paste a job description, run a Gemini-powered interview, answer by typing or speaking, and receive a structured performance report.
The live flow is:
- Upload a PDF CV and paste a job description
- Parse the CV and store session data
- Generate an interview blueprint with Gemini
- Run the interview turn by turn
- Read each question aloud with ElevenLabs TTS
- Let the candidate answer by typing or recording voice
- Transcribe recorded answers with ElevenLabs STT
- Generate a final interview report with Gemini
- PDF CV upload and text extraction with
pdf-parse - Demo autofill flow with a bundled sample resume
- Gemini-based interview blueprint generation
- Gemini-based interview question flow
- ElevenLabs text-to-speech for spoken interview questions
- ElevenLabs speech-to-text for recorded answers
- Redis-backed interview session state
- Supabase-backed session, question, and report storage
- S3 upload for CV file storage
- Dark-theme interview and report experience
- Vercel Analytics integration
- Next.js 16
- React 19
- TypeScript
- Tailwind CSS 4
- Gemini (
@google/generative-ai) - ElevenLabs
- Supabase
- Redis (
ioredis) - AWS S3
src/
app/
page.tsx Landing page
interview/[sessionId]/
page.tsx Interview page loader
InterviewClient.tsx Interview UI, TTS, STT, text fallback
report/[sessionId]/
page.tsx Report page loader
ReportClient.tsx Report UI
api/
upload/route.ts CV upload, parse, session creation
blueprint/route.ts Interview blueprint generation
interview/
turn/route.ts Interview turn streaming
speak/route.ts ElevenLabs TTS proxy
transcribe/route.ts ElevenLabs STT proxy
report/generate/route.ts Final report generation
lib/
gemini.ts Gemini client and schemas
redis.ts Redis client
s3.ts S3 helper
supabase.ts Supabase clients
types/
index.ts Shared TypeScript types
public/
demo/Luckman_AIResume.pdf Bundled demo resume
supabase-schema.sql Database schema
Create a .env.local file in the project root.
GEMINI_API_KEY=your_gemini_api_key
GEMINI_MODEL=gemini-2.5-flash
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
AWS_REGION=ap-south-1
AWS_ACCESS_KEY_ID=your_aws_access_key
AWS_SECRET_ACCESS_KEY=your_aws_secret_key
S3_BUCKET_NAME=your_bucket_name
REDIS_URL=rediss://default:your_password@your_host.upstash.io:6379
ELEVENLABS_API_KEY=your_elevenlabs_api_key
ELEVENLABS_VOICE_ID=your_elevenlabs_voice_idNotes:
GEMINI_MODELis optional. The app defaults togemini-2.5-flash.ELEVENLABS_VOICE_IDcontrols the interview voice used by/api/interview/speak.- Keep
.env.localout of version control.
- Install dependencies
npm install- Apply the database schema
Run supabase-schema.sql in your Supabase SQL editor.
- Start the app
npm run dev- Open the app
http://localhost:3000
The landing page includes an Autofill Demo details action.
When used, the app:
- fills the role and job description
- uses the bundled sample resume
- lets reviewers try the interview without searching for files first
/api/upload
- validates the uploaded PDF
- parses the CV text with
pdf-parse - uploads the file to S3
- stores the session in Supabase
/api/blueprint
- sends the CV and job description to Gemini
- creates a structured blueprint:
- role summary
- topics to cover
- skill gaps
- red flags
- opening question
- difficulty progression
/api/interview/turn
- uses the saved blueprint, CV summary, job description, and conversation history
- streams one question at a time
- probes deeper when answers are vague
- ends after the configured question count
/api/interview/speak
- converts each assistant question into audio using ElevenLabs TTS
/api/interview/transcribe
- sends recorded audio to ElevenLabs STT
- returns transcript text for the answer box
/api/report/generate
- evaluates the finished interview with Gemini
- stores the report in Supabase
- returns the structured report to the UI
- The interview flow is adaptive, but the overall system is still mostly linear: upload -> blueprint -> interview -> report
- The first question is intentionally kept broad and easier than later questions
- Voice and typed answers coexist; typing remains the fallback path
- Silent voice captures can auto-send after transcription, while manual mic stops leave the text editable
npm run dev
npm run build
npm run start
npm run lint- The interview loop is prompt-driven, not a full agentic controller
- Voice quality and transcription accuracy depend on browser mic support and ElevenLabs responses
- The
elevenlabspackage currently shows a deprecation warning, but the app uses directfetchcalls for the ElevenLabs routes - Authentication is still prototype-level
- The report is rendered in-app rather than exported as a PDF
- src/app/page.tsx
- src/app/api/blueprint/route.ts
- src/app/api/interview/turn/route.ts
- src/app/api/interview/speak/route.ts
- src/app/api/interview/transcribe/route.ts
- src/app/api/report/generate/route.ts