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).