AINode.jsAutomation

Slack Bot with GPT-4o Integration

TT
TopicTrick Team
Slack Bot with GPT-4o Integration

Slack Bot with GPT-4o Integration

Your team's knowledge is scattered across Slack threads, docs, and people's heads. This Slack bot brings GPT-4o directly into your workspace — answering questions, summarizing threads, drafting messages, and running AI commands via slash commands.

This is Tool 15 of the Build 50 AI Automation Tools course.


What You'll Build

  • Mention @YourBot in any channel to ask questions
  • DM the bot for private AI assistance
  • /summarize — summarize the current channel's recent activity
  • /draft — draft a message or document
  • Maintain conversation history per thread

Setup

bash
mkdir slack-ai-bot && cd slack-ai-bot
npm init -y
npm install @slack/bolt openai dotenv
bash
# .env
SLACK_BOT_TOKEN=xoxb-your-bot-token
SLACK_SIGNING_SECRET=your-signing-secret
OPENAI_API_KEY=sk-your-key-here
PORT=3000

The Bot

js
// src/bot.js
import 'dotenv/config';
import { App } from '@slack/bolt';
import OpenAI from 'openai';

const app = new App({
  token:         process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
});

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

// In-memory conversation history per thread
const threadHistories = new Map();

function getHistory(threadTs) {
  if (!threadHistories.has(threadTs)) {
    threadHistories.set(threadTs, []);
  }
  return threadHistories.get(threadTs);
}

async function askGPT(userMessage, threadTs, systemPrompt) {
  const history = getHistory(threadTs);
  history.push({ role: 'user', content: userMessage });

  const messages = [
    {
      role: 'system',
      content: systemPrompt || `You are a helpful AI assistant in a Slack workspace. Be concise and direct — Slack messages should be brief. Use *bold* for emphasis, bullet points for lists. Do not use markdown headers.`,
    },
    ...history.slice(-10), // Last 10 messages for context
  ];

  const response = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages,
    temperature: 0.7,
    max_tokens: 1000,
  });

  const reply = response.choices[0].message.content;
  history.push({ role: 'assistant', content: reply });
  threadHistories.set(threadTs, history);

  return reply;
}

// Respond to @mentions in channels
app.event('app_mention', async ({ event, say }) => {
  // Remove the bot mention from the message
  const userMessage = event.text.replace(/<@[A-Z0-9]+>/g, '').trim();
  if (!userMessage) {
    await say({ text: 'Hi! How can I help you?', thread_ts: event.ts });
    return;
  }

  const threadTs = event.thread_ts || event.ts;
  const reply = await askGPT(userMessage, threadTs);
  await say({ text: reply, thread_ts: event.ts });
});

// Respond to direct messages
app.message(async ({ message, say }) => {
  if (message.subtype || !message.text) return;
  const reply = await askGPT(message.text, message.ts);
  await say(reply);
});

// /summarize slash command
app.command('/summarize', async ({ command, ack, client, say }) => {
  await ack();

  const { data } = await client.conversations.history({
    channel: command.channel_id,
    limit: 50,
  });

  const messages = data.messages
    .filter(m => !m.bot_id)
    .reverse()
    .map(m => `${m.user || 'user'}: ${m.text}`)
    .join('\n');

  const summary = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [
      { role: 'system', content: 'Summarize this Slack channel conversation in 3-5 bullet points. Be concise.' },
      { role: 'user', content: messages },
    ],
    temperature: 0.3,
  });

  await say({
    text: `*Channel Summary:*\n${summary.choices[0].message.content}`,
    channel: command.channel_id,
  });
});

// /draft slash command
app.command('/draft', async ({ command, ack, say }) => {
  await ack();
  const topic = command.text;
  if (!topic) return say('Usage: /draft <what to draft>');

  const draft = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [
      { role: 'system', content: 'Draft a clear, professional Slack message on the given topic. Keep it under 200 words.' },
      { role: 'user', content: topic },
    ],
    temperature: 0.7,
  });

  await say({
    text: `*Draft:*\n${draft.choices[0].message.content}`,
    channel: command.channel_id,
  });
});

// /explain slash command
app.command('/explain', async ({ command, ack, say }) => {
  await ack();
  const topic = command.text;
  if (!topic) return say('Usage: /explain <topic or term>');

  const explanation = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [
      { role: 'system', content: 'Explain the topic clearly and concisely for a technical audience. Use analogies where helpful. Keep it under 150 words.' },
      { role: 'user', content: topic },
    ],
    temperature: 0.5,
  });

  await say(`*${topic}:*\n${explanation.choices[0].message.content}`);
});

(async () => {
  await app.start(process.env.PORT ?? 3000);
  console.log(`Slack AI Bot running on port ${process.env.PORT ?? 3000}`);
})();

Local Development with ngrok

Slack requires a public HTTPS URL for event subscriptions. Use ngrok for development:

bash
npm install -g ngrok
ngrok http 3000
# Copy the https://xxx.ngrok.io URL

In your Slack app dashboard:

  1. Event Subscriptions → Request URL: https://xxx.ngrok.io/slack/events
  2. Slash Commands → Request URL: https://xxx.ngrok.io/slack/events
  3. Click Verify — should show "Verified"

Adding Knowledge Base Context

Make the bot aware of company-specific knowledge:

js
const SYSTEM_PROMPT = `You are an AI assistant for Acme Corp's engineering team.
Company context:
- We use React + Node.js + PostgreSQL
- Our CI/CD runs on GitHub Actions deploying to AWS ECS
- The on-call rotation is managed via PagerDuty
- Slack channels: #engineering (general), #deployments (release updates), #incidents

Answer questions using this context where relevant. For code questions, use our tech stack.`;

// Pass to askGPT as the systemPrompt parameter

Production Deployment

bash
# Deploy to Railway
railway up

# Or run with PM2
pm2 start src/bot.js --name slack-bot
pm2 save
pm2 startup

Update your Slack app's event subscription URL to your production URL.


Build 50 AI Automation Tools — Tool 15 of 50

Your Slack AI bot is live. Continue to Tool 16 to build an AI SMS response bot with Twilio.


    Summary

    • Slack Bolt handles authentication, event routing, and slash commands with minimal boilerplate
    • In-memory thread history enables multi-turn conversations within Slack threads
    • Slash commands give power users quick access to specific AI capabilities
    • ngrok enables local development without deploying — essential for fast Slack app iteration
    • For production, move thread history to Redis so history persists across bot restarts

    Continue to Tool 16: AI SMS Response Bot with Twilio →