Skip to main content

AI Setup & Configuration

This guide covers the complete setup process for KAIU’s AI-powered WhatsApp assistant, including environment variables, database configuration, and deployment.

Prerequisites

Node.js

Version 18+ required for LangChain and Prisma

PostgreSQL

Version 14+ with pgvector extension support

Redis

For BullMQ queue management

Meta Business Account

WhatsApp Business API access

Environment Variables

Create a .env file in the project root:
# Database
DATABASE_URL="postgresql://user:password@localhost:5432/kaiu_db?schema=public"

# Redis (BullMQ)
REDIS_URL="redis://localhost:6379" # Or use individual vars below
REDIS_HOST="localhost"
REDIS_PORT="6379"
REDIS_PASSWORD="" # Optional

# Anthropic AI
ANTHROPIC_API_KEY="sk-ant-api03-..." # Get from https://console.anthropic.com

# WhatsApp Business API
WHATSAPP_PHONE_ID="123456789012345" # From Meta Business Manager
WHATSAPP_ACCESS_TOKEN="EAAxxxx..." # Long-lived access token
WHATSAPP_VERIFY_TOKEN="your_custom_verify_token" # For webhook verification

# Server
BASE_URL="https://yourdomain.com" # For image URLs
PORT="3001"

# SSL (Development only)
NODE_TLS_REJECT_UNAUTHORIZED="0" # Set to "1" in production

Getting API Keys

1

Anthropic API Key

  1. Sign up at console.anthropic.com
  2. Navigate to API Keys
  3. Create a new key
  4. Copy and save securely (starts with sk-ant-api03-)
2

WhatsApp Business API

  1. Create a Meta Business account
  2. Set up WhatsApp Business API in Business Manager
  3. Get WHATSAPP_PHONE_ID from Phone Numbers section
  4. Generate a permanent access token (not the temporary 24h token)
3

Redis Connection

For local development:
docker run -d -p 6379:6379 redis:7-alpine
For production, use managed services:

Database Setup

1. Enable pgvector Extension

CREATE EXTENSION IF NOT EXISTS vector;
Ensure your PostgreSQL instance supports pgvector. Most managed services (Supabase, Neon, Railway) include it by default.

2. Run Prisma Migrations

# Install dependencies
npm install

# Generate Prisma client
npx prisma generate

# Run migrations
npx prisma migrate deploy

3. Verify Tables

-- Check if tables exist
SELECT tablename FROM pg_tables WHERE schemaname = 'public';

-- Should include:
-- ✓ users
-- ✓ products
-- ✓ orders
-- ✓ order_items
-- ✓ addresses
-- ✓ knowledge_base
-- ✓ whatsapp_sessions

4. Create Vector Index

-- For fast similarity search (recommended for 1K+ documents)
CREATE INDEX IF NOT EXISTS knowledge_base_embedding_idx 
ON knowledge_base 
USING ivfflat (embedding vector_cosine_ops) 
WITH (lists = 100);

Installation

Clone and Install

# Clone repository
git clone https://github.com/your-org/kaiu-backend.git
cd kaiu-backend

# Install dependencies
npm install

# Setup environment
cp .env.example .env
# Edit .env with your values

Required Packages

The AI system uses these core dependencies:
{
  "dependencies": {
    "@langchain/anthropic": "^0.1.0",
    "@langchain/core": "^0.1.0",
    "@prisma/client": "^5.0.0",
    "bullmq": "^4.0.0",
    "ioredis": "^5.3.0",
    "axios": "^1.6.0",
    "socket.io": "^4.6.0"
  },
  "devDependencies": {
    "prisma": "^5.0.0"
  }
}

Running the System

Development Mode

# Terminal 1: Start the main server
npm run dev

# Terminal 2: Start the queue worker (if separate)
node backend/whatsapp/queue.js

Production Mode

# Build
npm run build

# Start with PM2
pm2 start ecosystem.config.js

PM2 Configuration

Create ecosystem.config.js:
module.exports = {
  apps: [
    {
      name: 'kaiu-api',
      script: './backend/server.js',
      instances: 2,
      exec_mode: 'cluster',
      env: {
        NODE_ENV: 'production',
        PORT: 3001
      }
    },
    {
      name: 'kaiu-worker',
      script: './backend/whatsapp/queue.js',
      instances: 1,
      env: {
        NODE_ENV: 'production'
      }
    }
  ]
};

WhatsApp Webhook Setup

1. Configure Webhook URL

In Meta Business Manager:
  1. Go to WhatsApp > Configuration
  2. Set Webhook URL: https://yourdomain.com/webhook/whatsapp
  3. Set Verify Token: (matches WHATSAPP_VERIFY_TOKEN in .env)
  4. Subscribe to events: messages

2. Verify Webhook

Meta will send a GET request to verify:
// backend/webhook/whatsapp.js
app.get('/webhook/whatsapp', (req, res) => {
    const mode = req.query['hub.mode'];
    const token = req.query['hub.verify_token'];
    const challenge = req.query['hub.challenge'];

    if (mode === 'subscribe' && token === process.env.WHATSAPP_VERIFY_TOKEN) {
        res.status(200).send(challenge);
    } else {
        res.sendStatus(403);
    }
});

3. Handle Incoming Messages

app.post('/webhook/whatsapp', async (req, res) => {
    const { entry } = req.body;
    
    for (const change of entry[0].changes) {
        const message = change.value.messages?.[0];
        if (message?.type === 'text') {
            await whatsappQueue.add('process-message', {
                wamid: message.id,
                from: message.from,
                text: message.text.body
            });
        }
    }
    
    res.sendStatus(200);
});

Memory Optimization

Current Configuration (Retriever.js:13-20)

async function getEmbeddingPipe() {
    if (!embeddingPipe) {
        console.log("🔌 Loading Embedding Model (BYPASSED FOR RENDER FREE TIER OOM PROTECTION)...");
        // Bypass transformer load to save 300MB of RAM
        embeddingPipe = () => { return { toList: () => new Array(1536).fill(0.0) } };
    }
    return embeddingPipe;
}
This bypasses embedding generation to save ~300MB RAM on free-tier hosting. For production, enable real embeddings (see RAG System).

Production Embedding Setup

For servers with >1GB RAM, use real embeddings:
import { pipeline } from '@xenova/transformers';

let embeddingPipe = null;

async function getEmbeddingPipe() {
    if (!embeddingPipe) {
        console.log("🔌 Loading Embedding Model...");
        embeddingPipe = await pipeline(
            'feature-extraction',
            'Xenova/all-MiniLM-L6-v2'
        );
    }
    return embeddingPipe;
}

Testing the Setup

1. Test Database Connection

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function testConnection() {
    try {
        const count = await prisma.product.count();
        console.log(`✅ Database connected. Products: ${count}`);
    } catch (error) {
        console.error('❌ Database error:', error);
    }
}

testConnection();

2. Test Redis Connection

import IORedis from 'ioredis';

const redis = new IORedis(process.env.REDIS_URL);

redis.on('connect', () => console.log('✅ Redis connected'));
redis.on('error', (err) => console.error('❌ Redis error:', err));

3. Test Claude API

import { ChatAnthropic } from '@langchain/anthropic';
import { HumanMessage } from '@langchain/core/messages';

const model = new ChatAnthropic({
    modelName: 'claude-3-haiku-20240307',
    anthropicApiKey: process.env.ANTHROPIC_API_KEY,
});

const response = await model.invoke([
    new HumanMessage('Hola, ¿cómo estás?')
]);

console.log('✅ Claude response:', response.content);

4. Test WhatsApp Webhook

# Send test message
curl -X POST https://yourdomain.com/webhook/whatsapp \
  -H "Content-Type: application/json" \
  -d '{
    "entry": [{
      "changes": [{
        "value": {
          "messages": [{
            "id": "wamid.test123",
            "from": "573001234567",
            "type": "text",
            "text": { "body": "Hola" }
          }]
        }
      }]
    }]
  }'

Deployment

Render.com

# render.yaml
services:
  - type: web
    name: kaiu-api
    env: node
    buildCommand: npm install && npx prisma generate
    startCommand: npm start
    envVars:
      - key: DATABASE_URL
        sync: false
      - key: ANTHROPIC_API_KEY
        sync: false
      - key: NODE_TLS_REJECT_UNAUTHORIZED
        value: "1"

  - type: worker
    name: kaiu-worker
    env: node
    buildCommand: npm install
    startCommand: node backend/whatsapp/queue.js

Railway.app

// railway.json
{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "NIXPACKS"
  },
  "deploy": {
    "startCommand": "npm start",
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 10
  }
}

Docker

FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npx prisma generate

EXPOSE 3001

CMD ["node", "backend/server.js"]

Health Checks

Add a health endpoint:
app.get('/health', async (req, res) => {
    const checks = {
        database: false,
        redis: false,
        anthropic: false
    };

    try {
        await prisma.$queryRaw`SELECT 1`;
        checks.database = true;
    } catch {}

    try {
        await redis.ping();
        checks.redis = true;
    } catch {}

    const allHealthy = Object.values(checks).every(v => v);
    res.status(allHealthy ? 200 : 503).json(checks);
});

Troubleshooting

Ensure .env file exists and contains:
ANTHROPIC_API_KEY="sk-ant-api03-..."
Restart the server after updating.
Check DATABASE_URL format:
postgresql://user:password@host:5432/database?schema=public
Verify PostgreSQL is running:
psql -h localhost -U user -d database -c "SELECT 1"
Ensure Redis is running:
redis-cli ping # Should return PONG
Or start Docker container:
docker run -d -p 6379:6379 redis:7-alpine
Check worker is running:
node backend/whatsapp/queue.js
Verify Redis connection in logs. Ensure REDIS_URL or REDIS_HOST/REDIS_PORT are correct.
Install pgvector on PostgreSQL:
CREATE EXTENSION IF NOT EXISTS vector;
If not available, use a managed service that supports it (Supabase, Neon).

Next Steps

Knowledge Base Management

Populate the knowledge base with company policies

Prompt Engineering

Optimize system prompts for better responses

Build docs developers (and LLMs) love