Files
helix-engage-server/src/messaging/messaging-conversation.service.ts
saridsa2 2c947517af feat: WhatsApp AI assistant — provider-agnostic messaging with Gupshup
Provider-agnostic WhatsApp integration for AI-driven appointment booking:

- MessagingProvider interface (sendText, sendButtons, sendList, parseInbound)
- GupshupProvider implementation (Gupshup WhatsApp API)
- MessagingService — AI orchestration with tools (department/doctor/slot
  lists via interactive WhatsApp messages, appointment booking, caller
  resolution + context injection)
- Redis conversation history (24h TTL, matches WhatsApp session window)
- Webhook controller at POST /api/messaging/webhook

Swappable to Ozonetel or Meta Cloud API by implementing MessagingProvider
and switching MESSAGING_PROVIDER env var.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 14:45:26 +05:30

42 lines
1.4 KiB
TypeScript

import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import Redis from 'ioredis';
import { ConversationEntry } from './types';
@Injectable()
export class MessagingConversationService {
private readonly logger = new Logger(MessagingConversationService.name);
private readonly redis: Redis;
private readonly ttlSec = 24 * 60 * 60; // 24h — matches WhatsApp session window
private readonly maxHistory = 20;
constructor(config: ConfigService) {
const redisUrl = config.get<string>('redis.url') ?? 'redis://localhost:6379';
this.redis = new Redis(redisUrl);
}
private key(phone: string): string {
return `wa:conv:${phone}`;
}
async getHistory(phone: string): Promise<ConversationEntry[]> {
const raw = await this.redis.get(this.key(phone));
if (!raw) return [];
try {
return JSON.parse(raw);
} catch {
return [];
}
}
async addMessages(phone: string, entries: ConversationEntry[]): Promise<void> {
const existing = await this.getHistory(phone);
const updated = [...existing, ...entries].slice(-this.maxHistory);
await this.redis.setex(this.key(phone), this.ttlSec, JSON.stringify(updated));
}
async clear(phone: string): Promise<void> {
await this.redis.del(this.key(phone));
}
}