Job interviews can be stressful, and practice is key to building confidence. While traditional mock interviews with friends or mentors are valuable, they are not always available when you need them. In this tutorial, you will learn how to build an AI-powered interview practice tool that provides real-time feedback to help improve interview skills.
By the end of this tutorial, you will have built a complete interview practice tool with the following core functionalities:
A real-time interview simulation tool using WebSocket connections
An AI-powered speech processing pipeline that converts audio to text
An intelligent response system that provides interviewer-like interactions
A persistent storage system for managing interview sessions and history using Durable Objects
Before you start
All of the tutorials assume you have already completed the Get started guide, which gets you set up with a Cloudflare Workers account, C3 ↗, and Wrangler.
Use a Node version manager like Volta ↗ or nvm ↗ to avoid permission issues and change Node.js versions. Wrangler, discussed later in this guide, requires a Node version of 16.17.0 or later.
Prerequisites
This tutorial demonstrates how to use multiple Cloudflare products and while many features are available in free tiers, some components of Workers AI may incur usage-based charges. Please review the pricing documentation for Workers AI before proceeding.
1. Create a new Worker project
Create a Cloudflare Workers project using the Create Cloudflare CLI (C3) tool and the Hono framework.
Create a new Worker project by running the following commands, using ai-interview-tool as the Worker name:
For What would you like to start with?, choose Framework Starter.
For Which development framework do you want to use?, choose Hono.
Complete the framework's own CLI wizard.
For Do you want to use git for version control?, choose Yes.
For Do you want to deploy your application?, choose No (we will be making some changes before deploying).
To develop and test your Cloudflare Workers application locally:
Navigate to your Workers project directory in your terminal:
Start the development server by running:
When you run wrangler dev, the command starts a local development server and provides a localhost URL where you can preview your application.
You can now make changes to your code and see them reflected in real-time at the provided localhost address.
2. Define TypeScript types for the interview system
Now that the project is set up, create the TypeScript types that will form the foundation of the interview system. These types will help you maintain type safety and provide clear interfaces for the different components of your application.
Create a new file types.ts that will contain essential types and enums for:
Interview skills that can be assessed (JavaScript, React, etc.)
Different interview positions (Junior Developer, Senior Developer, etc.)
Interview status tracking
Message handling between user and AI
Core interview data structure
3. Configure error types for different services
Next, set up custom error types to handle different kinds of errors that may occur in your application. This includes:
Database errors (for example, connection issues, query failures)
Interview-related errors (for example, invalid input, transcription failures)
Authentication errors (for example, invalid sessions)
Create the following errors.ts file:
4. Configure authentication middleware and user routes
In this step, you will implement a basic authentication system to track and identify users interacting with your AI interview practice tool. The system uses HTTP-only cookies to store usernames, allowing you to identify both the request sender and their corresponding Durable Object. This straightforward authentication approach requires users to provide a username, which is then stored securely in a cookie. This approach allows you to:
Identify users across requests
Associate interview sessions with specific users
Secure access to interview-related endpoints
Create the Authentication Middleware
Create a middleware function that will check for the presence of a valid authentication cookie. This middleware will be used to protect routes that require authentication.
Create a new middleware file middleware/auth.ts:
This middleware:
Checks for a username cookie
Throws an Error if the cookie is missing
Makes the username available to downstream handlers via the context
Create Authentication Routes
Next, create the authentication routes that will handle user login. Create a new file routes/auth.ts:
Finally, update main application file to include the authentication routes. Modify src/index.ts:
Now we have a basic authentication system that:
Provides a login endpoint at /api/v1/auth/login
Securely stores the username in a cookie
Includes middleware to protect authenticated routes
5. Create a Durable Object to manage interviews
Now that you have your authentication system in place, create a Durable Object to manage interview sessions. Durable Objects are perfect for this interview practice tool because they provide the following functionalities:
Maintains states between connections, so users can reconnect without losing progress.
Provides a SQLite database to store all interview Q&A, feedback and metrics.
Enables smooth real-time interactions between the interviewer AI and candidate.
Handles multiple interview sessions efficiently without performance issues.
Creates a dedicated instance for each user, giving them their own isolated environment.
First, you will need to configure the Durable Object in wrangler.toml file. Add the following configuration:
Next, create a new file interview.ts to define our Interview Durable Object:
Now we need to export the Durable Object in our main src/index.ts file:
Since the Worker code is written in TypeScript, you should run the following command to add the necessary type definitions:
Set up SQLite database schema to store interview data
Now you will use SQLite at the Durable Object level for data persistence. This gives each user their own isolated database instance. You will need two main tables:
interviews: Stores interview session data
messages: Stores all messages exchanged during interviews
Before you create these tables, create a service class to handle your database operations. This encapsulates database logic and helps you:
Manage database schema changes
Handle errors consistently
Keep database queries organized
Create a new file called services/InterviewDatabaseService.ts:
Update the Interview Durable Object to use the database service by modifying src/interview.ts:
Add methods to create and retrieve interviews in services/InterviewDatabaseService.ts:
Add RPC methods to the Interview Durable Object to expose database operations through API. Add this code to src/interview.ts:
6. Create REST API endpoints
With your Durable Object and database service ready, create REST API endpoints to manage interviews. You will need endpoints to:
Create new interviews
Retrieve all interviews for a user
Create a new file for your interview routes at routes/interview.ts:
The getInterviewDO helper function uses the username from our authentication cookie to create a unique Durable Object ID. This ensures each user has their own isolated interview state.
Update your main application file to include the routes and protect them with authentication middleware. Update src/index.ts:
Now you have two new API endpoints:
POST /api/v1/interviews: Creates a new interview session
GET /api/v1/interviews: Retrieves all interviews for the authenticated user
You can test these endpoints running the following command:
Create a new interview:
Get all interviews:
7. Set up WebSockets to handle real-time communication
With the basic interview management system in place, you will now implement Durable Objects to handle real-time message processing and maintain WebSocket connections.
Update the Interview Durable Object to handle WebSocket connections by adding the following code to src/interview.ts:
Next, update the interview routes to include a WebSocket endpoint. Add the following to routes/interview.ts:
The WebSocket system provides real-time communication features for interview practice tool:
Each interview session gets its own dedicated WebSocket connection, allowing seamless communication between the candidate and AI interviewer
The Durable Object maintains the connection state, ensuring no messages are lost even if the client temporarily disconnects
To keep connections stable, it automatically responds to ping messages with pongs, preventing timeouts
Candidates and interviewers receive instant updates as the interview progresses, creating a natural conversational flow
8. Add audio processing capabilities with Workers AI
Now that WebSocket connection set up, the next step is to add speech-to-text capabilities using Workers AI. Let's use Cloudflare's Whisper model to transcribe audio in real-time during the interview.
The audio processing pipeline will work like this:
Client sends audio through the WebSocket connection
Our Durable Object receives the binary audio data
We pass the audio to Whisper for transcription
The transcribed text is saved as a new message
We immediately send the transcription back to the client
The client receives a notification that the AI interviewer is generating a response
Create audio processing pipeline
In this step you will update the Interview Durable Object to handle the following:
Detect binary audio data sent through WebSocket
Create a unique message ID for tracking the processing status
Notify clients that audio processing has begun
Include error handling for failed audio processing
Broadcast status updates to all connected clients
First, update Interview Durable Object to handle binary WebSocket messages. Add the following methods to your src/interview.ts file:
Your handleBinaryAudio method currently logs when it receives audio data. Next, you'll enhance it to transcribe speech using Workers AI's Whisper model.
Configure speech-to-text
Now that audio processing pipeline is set up, you will now integrate Workers AI's Whisper model for speech-to-text transcription.
Configure the Worker AI binding in your wrangler.toml file by adding:
Next, generate TypeScript types for our AI binding. Run the following command:
You will need a new service class for AI operations. Create a new file called services/AIService.ts:
You will need to update the Interview Durable Object to use this new AI service. To do this, update the handleBinaryAudio method in src/interview.ts:
When users speak during the interview, their audio will be automatically transcribed and stored as messages in the interview session. The transcribed text will be immediately available to both the user and the AI interviewer for generating appropriate responses.
9. Integrate AI response generation
Now that you have audio transcription working, let's implement AI interviewer response generation using Workers AI's LLM capabilities. You'll create an interview system that:
Maintains context of the conversation
Provides relevant follow-up questions
Gives constructive feedback
Stays in character as a professional interviewer
Set up Workers AI LLM integration
First, update the AIService class to handle LLM interactions. You will need to add methods for:
Processing interview context
Generating appropriate responses
Handling conversation flow
Update the services/AIService.ts class to include LLM functionality:
Create the conversation prompt
Prompt engineering is crucial for getting high-quality responses from the LLM. Next, you will create a system prompt that:
Sets the context for the interview
Defines the interviewer's role and behavior
Specifies the technical focus areas
Guides the conversation flow
Add the following method to your services/AIService.ts class:
Implement response generation logic
Finally, integrate the LLM response generation into the interview flow. Update the handleBinaryAudio method in the src/interview.ts Durable Object to:
Process transcribed user responses
Generate appropriate AI interviewer responses
Maintain conversation context
Update the handleBinaryAudio method in src/interview.ts:
Conclusion
You have successfully built an AI-powered interview practice tool using Cloudflare's Workers AI. In summary, you have:
Created a real-time WebSocket communication system using Durable Objects
Implemented speech-to-text processing with Workers AI Whisper model
Built an intelligent interview system using Workers AI LLM capabilities
Designed a persistent storage system with SQLite in Durable Objects