Skip to content
reaatech

Files · Azure AI Lead Intake for Calendly SMB Lead Qualification

75 (1 binary, 655.4 kB total)attempt 1

README.md·5108 B·markdown
markdown
# Azure AI Lead Intake for Calendly SMB Lead Qualification
 
> An embedded chatbot that qualifies website visitors through a natural conversation and books a Calendly meeting when they are sales‑ready.
 
A tutorialized reference solution from [reaatech.com](https://reaatech.com), demonstrating how to build production-grade AI systems with the `@reaatech/*` package family.
 
## What this does
 
This chatbot engages website visitors in a natural conversation, asks qualifying
questions (name, email, company, interest, budget, timeline), scores the lead's
intent using keyword classification, and books a single-use Calendly meeting
when the lead is sales-ready. If a visitor requests human help, the bot
escalates via the agent-handoff protocol.
 
## Quick Start
 
```bash
cp .env.example .env
# Fill in your Azure OpenAI, Calendly, and Langfuse credentials
pnpm install
pnpm dev
```
 
## Architecture
 
Each `@reaatech/*` package plays a specific role:
 
- **`@reaatech/confidence-router`** — scores lead intent by matching user
  messages against keyword classifiers (high/medium/low intent, support) and
  returns a routing decision (ROUTE / CLARIFY / FALLBACK).
- **`@reaatech/session-continuity`** — manages multi-turn conversation state
  with token-budget tracking, session creation, and message history.
- **`@reaatech/structured-repair-core`** — repairs and validates LLM outputs
  against a Zod schema so that extracted lead data is always well-formed.
- **`@reaatech/agent-handoff`** — provides the handoff protocol (typed event
  emitter, retry logic, handoff payload) for escalating to a human agent.
- **`@reaatech/webhook-relay-core`** — processes Calendly webhook events and
  provides signature verification and event-type matching utilities.
 
## API Endpoints
 
### `POST /api/chat`
 
**Request body:**
```json
{
  "message": "I want to book a demo",
  "sessionId": "optional-existing-session"
}
```
 
**Response (200):**
```json
{
  "reply": "What's your name?",
  "sessionId": "uuid",
  "leadScore": "hot",
  "bookingLink": "https://calendly.com/book/abc",
  "needsHandoff": false
}
```
 
Returns `400` if `message` is missing or empty. Returns `500` on internal
errors.
 
### `POST /api/webhook/calendly`
 
**Request body (Calendly `invitee.created` payload):**
```json
{
  "event": "invitee.created",
  "event_type": { "uri": "..." },
  "invitee": { "uri": "...", "email": "..." },
  "scheduled_event": { "uri": "..." },
  "created_at": "2025-01-01T00:00:00Z"
}
```
 
**Response (200):**
```json
{ "ok": true }
```
 
The endpoint verifies the Calendly webhook signature, parses the event, and
updates the matching lead record to `"booked"` status.
 
## Environment Variables
 
| Variable | Description | Required |
|---|---|---|
| `AZURE_OPENAI_ENDPOINT` | Azure OpenAI service endpoint | Yes |
| `AZURE_OPENAI_API_KEY` | Azure OpenAI API key | Yes |
| `AZURE_OPENAI_DEPLOYMENT_NAME` | Azure OpenAI deployment name | Yes |
| `CALENDLY_CLIENT_ID` | Calendly OAuth client ID | Yes |
| `CALENDLY_CLIENT_SECRET` | Calendly OAuth client secret | Yes |
| `CALENDLY_REDIRECT_URI` | Calendly OAuth redirect URI | Yes |
| `CALENDLY_API_KEY` | Calendly personal access token | Yes |
| `CALENDLY_WEBHOOK_SECRET` | Calendly webhook signing secret | No |
| `LANGFUSE_PUBLIC_KEY` | Langfuse public key | Yes |
| `LANGFUSE_SECRET_KEY` | Langfuse secret key | Yes |
| `LANGFUSE_HOST` | Langfuse host URL | Yes |
| `CONFIDENCE_ROUTE_THRESHOLD` | Minimum confidence to route as sales-ready (default 0.8) | No |
| `CONFIDENCE_FALLBACK_THRESHOLD` | Confidence below this triggers polite decline (default 0.3) | No |
| `SESSION_MAX_TOKENS` | Token budget per conversation session (default 4096) | No |
 
## Calendly Setup
 
1. Generate a Personal Access Token at
   [calendly.com/integrations/api_webhooks](https://calendly.com/integrations/api_webhooks).
2. Create a webhook subscription pointing to
   `https://your-domain.com/api/webhook/calendly` with event type
   `invitee.created`.
3. Copy the webhook signing secret into `CALENDLY_WEBHOOK_SECRET`.
 
## Lead Scoring
 
The bot uses keyword-based classification with four intent labels:
 
| Label | Example Keywords | Threshold Decision |
|---|---|---|
| `high_intent` | book, demo, buy, pricing | ≥ routeThreshold → ROUTE (hot) |
| `medium_intent` | interested, learn more, cost | ≥ routeThreshold → ROUTE (warm) |
| `low_intent` | just looking, browsing, bye | < routeThreshold → FALLBACK (cold) |
| `support` | help, talk to, human, issue | routes to agent handoff |
 
- **ROUTE** — lead qualifies for a meeting; booking link is offered.
- **CLARIFY** — confidence is between thresholds; bot continues asking questions.
- **FALLBACK** — low-intent message; bot sends a polite decline.
 
## Project layout
 
```
app/                  Next.js App Router pages + API routes
src/                  services, lib, adapters
tests/                vitest suite (mirrors src/)
packages/             API references for every dependency (read these first)
DEV_PLAN.md           build plan for this recipe
```
 
## License
 
MIT — see [LICENSE](./LICENSE).