whatsapp-claude-gpt
Version:
WhatsApp-Claude-GPT is a WhatsApp chatbot that supports multiple AI providers for chat, optional image generation/editing, and voice (speech-to-text and text-to-speech). It’s built for natural, contextual conversations and can now also handle reminders an
109 lines (89 loc) • 3.48 kB
text/typescript
import logger from './logger';
import { Client, LocalAuth, Message } from "whatsapp-web.js";
import qrcode from 'qrcode-terminal';
import Roboto from "./bot/roboto";
import WhatsappHandler from "./bot/wsp-web";
import Reminders from "./services/reminder-service";
import { configValidation, logConfigInfo } from "./utils";
import { CONFIG } from "./config";
require('dotenv').config();
configValidation()
logConfigInfo();
async function start() {
try {
const puppeteerArgs: string[] = [
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--no-first-run',
'--disable-gpu'
];
// Chromium only accepts --no-zygote when sandbox is also disabled, so keep
// those flags coupled for Docker/root environments that require them.
if (CONFIG.BotConfig.puppeteerNoSandbox) {
puppeteerArgs.unshift('--no-sandbox', '--disable-setuid-sandbox', '--no-zygote');
}
const wspClient = new Client({
authStrategy: new LocalAuth(),
puppeteer: {
args: puppeteerArgs,
}
});
// Set the WhatsApp client immediately after construction so all downstream
// consumers can access it as soon as it becomes available.
WhatsappHandler.setWspClient(wspClient);
logger.info('Starting WhatsApp client...');
wspClient.on('qr', qr => {
logger.info('QR Code received, scan please');
qrcode.generate(qr, { small: true });
});
wspClient.on('authenticated', () => {
logger.info('Client authenticated');
});
wspClient.on('auth_failure', async (msg) => {
logger.error(`Authentication failure: ${msg}`);
});
wspClient.on('ready', () => {
logger.info('Client is ready!');
// Start the reminder checker now that the WhatsApp client is available.
Reminders.startReminderChecker();
});
// Capture unhandled rejections from the message listener so a single
// failing message does not crash the process.
wspClient.on('message', (message: Message) => {
void Roboto.readWspMessage(message).catch((e) => {
logger.error(`[index] Unhandled error in readWspMessage: ${e.message}`);
});
});
await wspClient.initialize();
const shutdown = async (signal: string) => {
logger.info(`Received ${signal}, shutting down gracefully...`);
try {
Reminders.stopReminderChecker();
await wspClient.destroy();
logger.info('WhatsApp client destroyed');
} catch (e: any) {
logger.error(`Error destroying WhatsApp client: ${e.message}`);
}
process.exit(0);
};
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
} catch (e: any) {
logger.error(`ERROR: ${e.message}`);
}
}
// Global handlers for unhandled rejections and uncaught exceptions.
// These prevent silent process crashes and log the error for debugging.
process.on('unhandledRejection', (reason: any, promise: Promise<any>) => {
logger.error(`[process] Unhandled Rejection at: ${promise}, reason: ${reason?.message || reason}`);
});
process.on('uncaughtException', (error: Error) => {
logger.error(`[process] Uncaught Exception: ${error.message}`);
// For uncaught exceptions we perform a controlled shutdown
// because the process may be in an inconsistent state.
try {
Reminders.stopReminderChecker();
} catch (_) { /* ignore errors during emergency cleanup */ }
process.exit(1);
});
start();