AI-Powered Slack Bot
This project involved building a serverless Slack bot, ThreadDigest, that uses OpenAI’s GPT models to produce concise summaries of conversations. The bot responds to slash commands and @mentions, fetches recent messages and returns summaries in near real time. The architecture leverages AWS Lambda to run on demand without persistent infrastructure, and integrates Slack’s Events API and Slash Commands using Lambda function URLs for simplicity.

Key contributions

  • Slack bot that responds to /summary commands and @mentions, summarizing messages from channels and threads.
  • Event‑driven architecture with AWS Lambda (Python 3.11) and no persistent infrastructure.
  • Integration with Slack Events API and Slash Commands via Lambda Function URLs.
  • Secure credential management using AWS Secrets Manager.
  • Robust signature verification, message parsing, retry logic and error handling.
  • Support for dynamic user and channel name resolution.
  • App Home interface built using Slack Block Kit for onboarding and quick help.

Highlights

  • Natural‑language summaries in Slack with near real‑time performance.
  • Clean, minimal deployment with no external dependencies.
  • Hands‑on experience with the Slack platform, OpenAI API and serverless operations.

How It Works

  • A user sends a command (@mention or /summary) to the bot
  • Slack sends an event to AWS Lambda, which triggers a Lambda function
  • Lambda verifies the request signature and processes the Slack event
  • The bot fetches relevant conversation history using the Slack API
  • It sends messages to the OpenAI API for summarization
  • The generated summary is posted back to Slack

Implementation

Slack part

  1. Go to https://api.slack.com/apps
  2. Create a new app (from scratch)
  3. Enable the following:
  4. App Home: Enable Home Tab
  5. Event Subscriptions: Enable and provide AWS Lambda function URL endpoint
  6. Bot Token Scopes:
app_mentions:read       # Allow the bot to read messages where it's mentioned
channels:history        # Read message history from public channels
channels:read           # List public channels in the workspace
chat:write              # Post messages as the bot
commands                # Enable use of slash commands (e.g., /summary)
groups:history          # Read message history from private groups
groups:read             # List private groups the bot is a member of
im:history              # Read message history from direct messages
im:write                # Send direct messages as the bot
users:read              # Read basic user info (for name resolution in summaries)
  1. Events to Subscribe:
app_home_opened        # Triggered when a user opens the App Home tab
app_mention            # Triggered when the bot is mentioned in a channel
message.channels       # Triggered for new messages in public channels
message.im             # Triggered for new messages in direct messages (IMs)
  1. Install the app to your workspace and retrieve the OAuth token (starts with “xoxb-…”) and Slack signing secret

OpenAI Part

  1. Generate OpenAI API token (starting with “sk-…”)

AWS Part

  1. Navigate to AWS Secrets Manager and create a secret
{
  "slack_bot_token": "xoxb-...",
  "openai_api_key": "sk-...",
  "slack_signing_secret": "..."
}
  1. Create IAM role for Lambda function with permissions
secretsmanager:GetSecretValue
lambda:InvokeFunction

Attach these inline policies to the role:

{
  "Effect": "Allow",
  "Action": [
    "logs:CreateLogGroup",
    "logs:CreateLogStream",
    "logs:PutLogEvents"
  ],
  "Resource": "arn:aws:logs:*:*:*"
}
// Secrets Manager read‑write
{
  "Effect": "Allow",
  "Action": [
    "secretsmanager:GetSecretValue",
    "secretsmanager:PutSecretValue"
  ],
  "Resource": "arn:aws:secretsmanager:*:*:secret:slackSummariserCreds*"
}
  1. Create a Lambda function using e.g. Python 3.11.
  • Set handler to lambda_function.lambda_handler (depending on your code)
  • Attach IAM Role from previous step
  • Create environment variable referring to your secret, e.g.
SECRETS_ID = slackSummariserCreds
  • Upload the Lambda code zip package

Lambda Function

  • Core Features

    • Summarizes Slack conversations using OpenAI (GPT-4o)
    • Supports threads, channels, and DMs
    • Handles slash commands like /summary 2h #general
    • Includes shared files and attachments in context
    • Deduplicates requests to avoid double-processing
    • Verifies Slack request signatures
    • Caches user/channel lookups to reduce API calls
    • Handles API errors and shows friendly messages
    • Supports help prompts and onboarding
  • Workflow Breakdown:

    • Event Entry Point:
      Lambda is triggered by Slack events or internal jobs and routes based on the request type.
    • Signature Verification:
      Validates requests using Slack’s signing secret.
    • Command Detection:
      Recognizes patterns like summary 2h #general from DMs, mentions, or slash commands.
    • Request Deduplication:
      Prevents duplicate requests by caching request IDs.
    • Request Routing:
      Routes to worker mode, slash processor, or inline summarization based on the request.
    • Message Fetching:
      Pulls messages and threads from the Slack API, excluding bot messages.
    • Text Normalization:
      Converts Slack formatting (e.g., @user, #channel, user groups) to readable text.
    • Summarization via OpenAI:
      Calls gpt-4o with a structured prompt and handles retries or truncating if needed.
    • Posting the Result:
      Replies in the same thread or channel with the summary.
    • Caching and Cleanup:
      Caches metadata lookups and clears expired entries regularly.

Lessons Learned

  • Avoid Duplicate Processing with Caching

    • Slack can resend the same event multiple times.
    • Adding hashed request IDs and short-term caches prevents duplicate summaries and spammy replies.
  • Slack Mentions Require Careful Resolution

    • Slack uses internal IDs like <@U12345> and <#C67890> that must be converted into human-readable names.
    • Extra effort is needed for user groups, apps, and workflows to avoid unresolved IDs in summaries.
  • Don’t Rely on Channel Names Alone

    • Channel names can be ambiguous or change over time.
    • Always validate channel names using the Slack API and support both #name and <#ID|name> formats.
  • Use Background Workers for Slash Commands

    • Slack slash commands expect quick responses.
    • Offload the summarization to a separate asynchronous Lambda call to avoid timeouts and improve user experience.
  • Handle Bot Loops Proactively

    • Bot messages can trigger the bot itself if not filtered.
    • Filtering out messages from the bot’s own user ID avoids endless loops.
  • Respect OpenAI API Limits

    • Large conversations can exceed token limits or cause 400 errors.
    • Add safeguards to truncate long inputs and retry intelligently on failure.
  • Fail Gracefully with User-Friendly Errors

    • If the bot isn’t in a channel or a Slack API fails, show helpful guidance.
    • For example: suggest /invite @ThreadDigest instead of just failing silently.
  • Slack User Input Needs Normalization

    • Users often mix up @general and #general.
    • Add validation and correction messages to guide users toward the correct format.
  • Summarizing Threads Is Essential

    • Many key conversations happen in thread replies, especially in channels like #alerts or #support.
    • Including all thread messages produces more complete and useful summaries.
  • User Caches Reduce Slack API Load

    • Repeated lookups for users, channels, and apps are expensive.
    • Adding positive and negative caching significantly improves performance and reliability.
  • Be Conservative with Regex Matching

    • Overeager regexes can misinterpret raw IDs or unrelated strings.
    • Keep match patterns strict and scoped to known formats to avoid false positives.