Skip to content

Roudolph1010/nextjs-vapi-voice-intake

Repository files navigation

Voice Intake — Vapi + Next.js Boilerplate

A production-ready boilerplate for AI-powered voice intake workflows. Built with Next.js, TypeScript, Tailwind CSS, shadcn/ui, and the Vapi Web SDK.

The app implements a four-step voice intake flow: Setup → Voice Session → Review → Export, connected to Vapi for real-time voice conversations.

Quick Start

npm install
cp .env.local.example .env.local
# Add your Vapi keys to .env.local
npm run dev

Open http://localhost:3000.

Environment Variables

Create a .env.local file:

NEXT_PUBLIC_VAPI_PUBLIC_KEY=your_vapi_public_key
NEXT_PUBLIC_VAPI_ASSISTANT_ID=your_assistant_id  # optional
Variable Required Description
NEXT_PUBLIC_VAPI_PUBLIC_KEY Yes Your Vapi public API key from the Vapi dashboard
NEXT_PUBLIC_VAPI_ASSISTANT_ID No Pre-configured Vapi assistant ID. If omitted, an inline assistant config is used.

If the public key is not set, the setup screen shows a configuration guide and disables the start button.

Architecture

src/
├── app/                    # Next.js App Router
│   ├── layout.tsx
│   └── page.tsx            # Main page with step routing
├── components/
│   ├── setup/              # Session config form + system status panel
│   ├── voice-session/      # Call controls, progress sidebar, live notes
│   ├── transcript/         # Real-time transcript panel with search
│   ├── summary/            # Structured review with inline editing
│   ├── export/             # Export with copy/download + JSON preview
│   ├── step-indicator.tsx  # Wizard progress bar
│   └── event-log.tsx       # Debug event log drawer
├── lib/
│   ├── schemas.ts          # Zod schemas for all data shapes
│   ├── templates.ts        # Intake template definitions (configurable)
│   ├── transcript-utils.ts # Formatting, search, plain-text export
│   ├── summary-mapper.ts   # Export generation, completion calculation
│   ├── env.ts              # Environment variable access
│   └── vapi/
│       ├── types.ts        # VapiAdapter interface
│       ├── live-adapter.ts # Real Vapi Web SDK wrapper
│       └── index.ts        # Barrel export
└── store/
    ├── session-store.ts    # App step, call status, config
    ├── transcript-store.ts # Transcript entries
    └── summary-store.ts    # Section data and extractions

Key Design Decisions

  • Adapter pattern for Vapi: Voice integration goes through a VapiAdapter interface (lib/vapi/types.ts). The live implementation wraps @vapi-ai/web. Swap voice providers by implementing the same interface.
  • Template-driven sections: Intake templates are plain TypeScript objects in lib/templates.ts. Add new templates by adding entries to the array — no code changes needed elsewhere.
  • Zustand stores: Three focused stores (session, transcript, summary) keep state simple and avoid prop drilling.
  • Zod schemas: All data shapes are validated with Zod and used as the source of TypeScript types.

How the Vapi Integration Works

  1. The VapiAdapter interface defines: init, start, stop, setMuted, on (events), and destroy.
  2. createLiveAdapter(publicKey) creates a Vapi Web SDK instance and maps its events:
    • call-start / call-end → call status updates
    • message (transcript type, final) → transcript entries
    • error → error handling
  3. If an assistantId is provided, start() uses that. Otherwise it creates an inline assistant with a default system prompt, voice, and first message.
  4. The adapter is initialized in VoiceSessionView and wired to Zustand stores.

What's Included as Placeholder

Feature Status
Email delivery UI placeholder — wire your email API
Section extraction Manual for now — plug in your NLP/LLM extraction
Section progress tracking Updates from store — connect to extraction logic

Extending

Add a new template

Edit src/lib/templates.ts and add an entry to the templates array. Each template needs id, name, description, and a sections array.

Add extraction logic

In VoiceSessionView, subscribe to transcript updates and call useSummaryStore.updateSection() to populate sections with extracted content as the conversation progresses.

Swap voice providers

Implement the VapiAdapter interface from lib/vapi/types.ts for your provider, then update the adapter creation in VoiceSessionView.

Add email delivery

Replace the placeholder in ExportView with a call to your email API (e.g., Resend, SendGrid, or a Next.js API route).

Tech Stack

About

AI-powered voice intake workflow built with Next.js, Vapi Web SDK, and TypeScript. Multi-step voice session with real-time transcription, structured summary extraction, and export.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors