| ---
|
| title: 'Using Chatbots with Slack'
|
| description: 'How to integrate your PySpur chatbots with Slack'
|
| ---
|
|
|
|
|
|
|
| This guide explains how to connect your PySpur chatbots to Slack, allowing users to interact with your chatbot directly through Slack channels and threads.
|
|
|
|
|
|
|
| PySpur offers two distinct ways to work with Slack:
|
|
|
| 1. **Workflow Output to Slack** - Using the `SlackNotifyNode` to send one-time results from a workflow to a Slack channel
|
| 2. **Interactive Chatbot in Slack** - Creating a fully interactive chatbot that users can converse with through Slack
|
|
|
| It's important to understand the difference between these approaches:
|
|
|
| | Feature | SlackNotifyNode | Interactive Chatbot |
|
| |---------|-----------------|---------------------|
|
| | Interaction | One-way (workflow → Slack) | Two-way conversation |
|
| | Session Management | None | Full conversation history |
|
| | Use Case | Sending alerts, summaries, notifications | Q&A, support, interactive assistance |
|
| | Implementation | Simple workflow node | Custom Slack app with API integration |
|
|
|
|
|
|
|
| Follow these steps to integrate your PySpur chatbot with Slack for interactive conversations:
|
|
|
|
|
|
|
| 1. Go to [api.slack.com/apps](https://api.slack.com/apps) and click "Create New App"
|
| 2. Choose "From scratch" and provide a name and workspace
|
| 3. In the app settings, enable the following:
|
| - Socket Mode (under "Socket Mode")
|
| - Event Subscriptions (under "Event Subscriptions")
|
| - Bot Token Scopes (under "OAuth & Permissions"):
|
| - `app_mentions:read`
|
| - `channels:history`
|
| - `chat:write`
|
| - `groups:history`
|
| - `im:history`
|
| - `mpim:history`
|
|
|
|
|
|
|
| You'll need three tokens from your Slack app:
|
| - **Bot Token** (`SLACK_BOT_TOKEN`): Found under "OAuth & Permissions" → "Bot User OAuth Token"
|
| - **Signing Secret** (`SLACK_SIGNING_SECRET`): Found under "Basic Information" → "App Credentials"
|
| - **App Token** (`SLACK_APP_TOKEN`): Generate under "Basic Information" → "App-Level Tokens" (with `connections:write` scope)
|
|
|
|
|
|
|
| Create a Python script similar to the example below. This script:
|
| - Initializes a Slack Bolt app
|
| - Listens for mentions and thread replies
|
| - Creates PySpur sessions for users
|
| - Forwards messages to your PySpur chatbot workflow
|
| - Returns responses back to Slack
|
|
|
| ```python
|
|
|
| import logging
|
| import os
|
| import sys
|
| from logging import getLogger
|
|
|
| import requests
|
| from dotenv import load_dotenv
|
| from slack_bolt import App
|
| from slack_bolt.adapter.socket_mode import SocketModeHandler
|
|
|
|
|
| load_dotenv()
|
|
|
|
|
| BOT_USER_ID = "U08HMJ15AHF"
|
| WORKFLOW_ID = "S58"
|
| PYSPUR_API_URL = "http://localhost:6080/api"
|
|
|
|
|
| logger = getLogger(__name__)
|
| logger.setLevel(logging.INFO)
|
| handler = logging.StreamHandler(sys.stderr)
|
| handler.setFormatter(
|
| logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
| )
|
| logger.addHandler(handler)
|
|
|
|
|
| app = App(
|
| token=os.environ.get("SLACK_BOT_TOKEN"),
|
| signing_secret=os.environ.get("SLACK_SIGNING_SECRET"),
|
| logger=logger,
|
| )
|
|
|
|
|
| @app.event("app_mention")
|
| def handle_app_mention(event, say, logger):
|
| logger.info(f"Received mention: {event}")
|
| thread_ts = event.get("thread_ts") or event.get("ts")
|
| user_external_id = event.get("user")
|
|
|
| try:
|
|
|
| user_data = {
|
| "external_id": user_external_id,
|
| "user_metadata": {"platform": "slack"}
|
| }
|
| user_response = requests.post(f"{PYSPUR_API_URL}/user/", json=user_data)
|
| if user_response.status_code not in [200, 409]:
|
| logger.error(f"Failed to create user: {user_response.text}")
|
| say(text="Sorry, I encountered an error processing your request.", thread_ts=thread_ts)
|
| return
|
|
|
| user_id = user_response.json().get("id")
|
|
|
|
|
| session_data = {
|
| "workflow_id": WORKFLOW_ID,
|
| "user_id": user_id,
|
| "external_id": thread_ts
|
| }
|
| session_response = requests.post(f"{PYSPUR_API_URL}/session/", json=session_data)
|
| if session_response.status_code != 200:
|
| logger.error(f"Failed to create session: {session_response.text}")
|
| say(text="Sorry, I encountered an error processing your request.", thread_ts=thread_ts)
|
| return
|
|
|
|
|
| message = app.client.conversations_history(
|
| channel=event["channel"], ts=thread_ts
|
| )
|
|
|
|
|
| url = f"{PYSPUR_API_URL}/wf/{WORKFLOW_ID}/run/?run_type=blocking"
|
| data = {
|
| "initial_inputs": {
|
| "input_node": {
|
| "user_message": message["messages"][0]["text"],
|
| "session_id": session_response.json()["id"],
|
| "message_history": []
|
| }
|
| }
|
| }
|
|
|
| response = requests.post(url, json=data)
|
| response_data = response.json()
|
|
|
|
|
| assistant_message = response_data.get("output_node", {}).get("assistant_message", "")
|
|
|
|
|
| if assistant_message:
|
| say(text=assistant_message, thread_ts=thread_ts)
|
| else:
|
| say(text="I encountered an issue processing your request.", thread_ts=thread_ts)
|
|
|
| except Exception as e:
|
| logger.error(f"Error processing request: {e}")
|
| say(text="Sorry, I encountered an error processing your request.", thread_ts=thread_ts)
|
|
|
|
|
| @app.event("message")
|
| def handle_thread_replies(event, say, logger):
|
|
|
| if (
|
| "thread_ts" in event
|
| and event.get("ts") != event.get("thread_ts")
|
| and not event.get("bot_id")
|
| ):
|
| thread_ts = event["thread_ts"]
|
| channel_id = event["channel"]
|
| user_external_id = event.get("user")
|
|
|
| try:
|
|
|
| user_data = {
|
| "external_id": user_external_id,
|
| "user_metadata": {"platform": "slack"}
|
| }
|
| user_response = requests.post(f"{PYSPUR_API_URL}/user/", json=user_data)
|
| if user_response.status_code not in [200, 409]:
|
| logger.error(f"Failed to create user: {user_response.text}")
|
| say(text="Sorry, I encountered an error processing your request.", thread_ts=thread_ts)
|
| return
|
|
|
| user_id = user_response.json().get("id")
|
|
|
|
|
| session_data = {
|
| "workflow_id": WORKFLOW_ID,
|
| "user_id": user_id,
|
| "external_id": thread_ts
|
| }
|
| session_response = requests.post(f"{PYSPUR_API_URL}/session/", json=session_data)
|
| if session_response.status_code != 200:
|
| logger.error(f"Failed to create session: {session_response.text}")
|
| say(text="Sorry, I encountered an error processing your request.", thread_ts=thread_ts)
|
| return
|
|
|
|
|
| result = app.client.conversations_replies(channel=channel_id, ts=thread_ts)
|
|
|
|
|
| chat_messages = []
|
| for message in result["messages"]:
|
| role = "assistant" if message.get("user") == BOT_USER_ID else "user"
|
| chat_messages.append({"role": role, "content": message.get("text", "")})
|
|
|
|
|
| message_history = chat_messages[:-1] if len(chat_messages) > 1 else []
|
| user_message = chat_messages[-1]["content"] if chat_messages else ""
|
|
|
|
|
| url = f"{PYSPUR_API_URL}/wf/{WORKFLOW_ID}/run/?run_type=blocking"
|
| data = {
|
| "initial_inputs": {
|
| "input_node": {
|
| "user_message": user_message,
|
| "session_id": session_response.json()["id"],
|
| "message_history": message_history,
|
| }
|
| }
|
| }
|
|
|
| response = requests.post(url, json=data)
|
| response_data = response.json()
|
|
|
|
|
| assistant_message = response_data.get("output_node", {}).get("assistant_message", "")
|
|
|
|
|
| if assistant_message:
|
| say(text=assistant_message, thread_ts=thread_ts)
|
| else:
|
| say(text="I encountered an issue processing your request.", thread_ts=thread_ts)
|
|
|
| except Exception as e:
|
| logger.error(f"Error processing thread reply: {e}")
|
| say(text="Sorry, I had trouble processing your message.", thread_ts=thread_ts)
|
|
|
| if __name__ == "__main__":
|
|
|
| handler = SocketModeHandler(app, os.environ.get("SLACK_APP_TOKEN"))
|
| handler.start()
|
| ```
|
|
|
|
|
|
|
| Create a `.env` file with your tokens:
|
|
|
| ```
|
| SLACK_BOT_TOKEN=xoxb-your-token
|
| SLACK_SIGNING_SECRET=your-signing-secret
|
| SLACK_APP_TOKEN=xapp-your-app-token
|
| ```
|
|
|
|
|
|
|
| 1. Install required packages:
|
| ```
|
| pip install slack-bolt python-dotenv requests
|
| ```
|
|
|
| 2. Make sure your PySpur server is running
|
|
|
| 3. Start your Slack integration:
|
| ```
|
| python slack_integration.py
|
| ```
|
|
|
|
|
|
|
| This integration creates a bidirectional connection between Slack and your PySpur chatbot:
|
|
|
| 1. **User Input**: When a user mentions your bot or replies in a thread, the Slack app captures this input.
|
|
|
| 2. **Session Management**: The script creates or retrieves a PySpur session for the user, using the thread timestamp as the external ID to track conversations.
|
|
|
| 3. **Message History**: For thread replies, the script retrieves the entire conversation history and formats it in the proper structure for your chatbot.
|
|
|
| 4. **PySpur API Call**: The user message and conversation history are sent to your PySpur workflow through the API.
|
|
|
| 5. **Response**: The assistant's response from your workflow is posted back to the Slack thread.
|
|
|
|
|
|
|
| This approach differs significantly from the `SlackNotifyNode`:
|
|
|
| - **SlackNotifyNode** is a one-way communication channel where your workflow sends a message to Slack when it completes. It's ideal for notifications, alerts, or sharing results of automated processes.
|
|
|
| - **Interactive Slack Integration** creates a two-way communication channel where users can have ongoing conversations with your chatbot. The integration manages sessions, tracks conversation history, and maintains context across multiple interactions.
|
|
|
|
|
|
|
| - **Support Bot**: Create a support chatbot that answers user questions about your product
|
| - **Data Query Assistant**: Allow users to query company data through natural language in Slack
|
| - **Task Manager**: Build a bot that helps users create and track tasks through conversation
|
| - **Knowledge Base**: Develop a bot that retrieves and explains information from your documentation
|
|
|
|
|
|
|
| - **Bot not responding**: Ensure your bot has been invited to the channel and has the necessary permissions
|
| - **Missing messages**: Check your log output for any API errors
|
| - **Session errors**: Verify that your PySpur server is running and accessible
|
| - **Token issues**: Double-check that all environment variables are set correctly
|
|
|