DEV Community

Artur Piszek
Artur Piszek

Posted on • Originally published at piszek.com on

Adding ChatGPT to your Slack in multiplayer mode

I just deployed ChatGPT as a Slackbot at Automattic, and let me tell you: it’s so much better and cheaper than the ChatGPT App. Here is how it works:

  • You can ping @gpt in any public or private channel,
  • It will respond in a Slack thread.
  • The state is kept in that slack thread, and it counts as a continuous conversation.

Once I had the (obvious in retrospect) idea of keeping conversations as separate threads, it came together in about 3 hours of coding. The result is surprisingly awesome, as having AI help integrated with the tool we are already using (Slack) reduces cognitive load and incentivizes use.

It’s more convenient.

ChatGPT is a useful tool, but the mental load of deciding that you want to consult the AI overlord and the need to retype (or copy-paste) your message is sometimes too much of a cognitive load.

With GPT Slackbot, you can:

  • Ask it for advice under a message somebody else started
  • Consult it quickly where you already are without switching tabs
  • Return to past conversations easily.

My coworkers found it immediately helpful:

I enjoyed using this in a Slack thread more than the ChatGPT interface. And Slack is searchable, which is way better! Thank you for doing this !

Also, I like that @gpt replies to older threads, without the need to retype the context of the initial chat, which I found incredibly useful!

My coworkers

It’s cheaper

ChatGPT is priced at about $1 for 75 000 words, and you are billed per use without a subscription (like ChatGPT Plus). With the pay-per-use pricing, any member of your organization can play without committing to a subscription.

It’s more whimsical

But where it really shines is the interaction of:

  • Multiplayer mode, as anybody can jump in on the thread
  • Public use in the public channels, as people can easily learn from each other

It reminds me of the Midjourney discord bot, where you learn from other people’s prompts while waiting for your own, turning the wait time into a collaboration.

Implementing your own ChatGPT Slackbot

Consider yourself warned: You are going to see some PHP. This uses the recently released ChatGPT API.

SlackBot setup

First, you need to create a Slackbot App that will be able to be pinged and has appropriate permissions to respond:

  1. Create a new App on Slack here. Make sure you select the Bot app – I chose “From Scratch”
  2. Add Events API subscription for the app_mentions:read event
  3. Add scopes to read public and private channels and one to post in channels ( channels:history, groups:history, chat:write )
  4. Once you add all the scopes, install the app to your workspace. You need admin permissions to do that or help of a workspace admin.
  5. Copy the xoxb-.... token and save it in your project as SLACK_TOKEN

Here are all the scopes our app has:

Webhook

Once you have the Slack part figured out, you can build code to handle it. This is a very simplified code assuming that you already implemented webhook verification. (You can use it without verification, but it’s a bad idea).

This webhook will be triggered each time you ping @gpt:


$payload = json_decode( file_get_contents( 'php://input') );

// Respond to url_verification challenge
if ( 'url_verification' === $payload->type && isset( $payload->challenge ) ) {
    print wp_kses( $payload->challenge, array() );
    return;
}

if (
    ! isset( $payload->type, $payload->event ) ||
    $payload->type !== 'event_callback' ||
    $payload->event->type !== 'app_mention'
) {
    return;
}

$parent_thread_id = '';
if ( isset( $payload->event->thread_ts ) ) {
    //This is a response in thread, so we need to pass the original top message.
    $parent_thread_id = sanitize_text_field( $payload->event->thread_ts );
} else {
    $parent_thread_id = sanitize_text_field( $payload->event->ts );
}
$channel = sanitize_text_field( $payload->event->channel );

queue_async_job(
    (object) array(
        'channel' => $channel,
        'thread' => $parent_thread_id,
    ),
    'slack_gpt_respond'
);
Enter fullscreen mode Exit fullscreen mode

As you can see, all that it does after sanitizing some data is to trigger a job in a job system. This is because Slack expects your webhook to respond within 3 seconds.

The “Respond to url_verification challenge” code block makes sure you can submit this webhook in the slack interface. Now you are ready to paste the URL where this code runs as Slack event handler.

The job

This job:

  1. Retrieves the backscroll of the slack thread from the Slack API
  2. Changes the format of the messages to one used by ChatGPT API
  3. Sends the entire list to ChatGPT API
  4. Posts the response in the Slack thread.

That way, I can use Slack as the state, which requires no additional database and reduces complexity.

// This is the actual job triggered by your job system
function slack_gpt_respond( $job ) {
    $data = $job->data;
    if ( isset( $data->thread, $data->channel ) ) {
        $chatgt_response = get_chatgpt_response( $data->thread, $data->channel );
        slack_gpt_respond_in_thread( $data->thread, $data->channel, $chatgt_response );
    }
}

// We use WordPress hooks as the job system
add_action( 'wpj_slack_gpt_respond', 'slack_gpt_respond' );

function slack_gpt_respond_in_thread( $ts, $channel, $response ) {
    $data = [
        'channel' => $channel,
        'thread_ts' => $ts,
        'text' => $response,
    ];

    $res = wp_remote_post(
        'https://slack.com/api/chat.postMessage',
        array(
                'headers' => array(
                    'Content-type' => 'application/json; charset=utf-8',
                    'Authorization' => 'Bearer ' . SLACK_TOKEN,
                ),
            'body' => json_encode( $data ),
        )
    );

}

function slack_gpt_retrieve_backscroll( $thread, $channel ) {
    $response = wp_remote_get(
        "https://slack.com/api/conversations.replies?channel={$channel}&ts={$thread}",
        array(
                'headers' => array(
                    'Content-type' => 'application/json; charset=utf-8',
                    'Authorization' => 'Bearer ' . SLACK_TOKEN,
                ),
        )
    );
    $body = wp_remote_retrieve_body( $response );
    $data = json_decode( $body );

    return array_map( 'slack_message_to_gpt_message', $data->messages );
}

function slack_message_to_gpt_message( $message ) {
    $text = preg_replace( '#\s?<@[0-9A-Z]+>\s?#is', '', $message->text );
    $role = isset( $message->bot_id ) ? 'assistant' : 'user';
    return [
        'role' => $role,
        'content' => $text,
    ];
}

function get_chatgpt_response( $ts, $channel ) {
    $backscroll = slack_gpt_retrieve_backscroll( $ts, $channel );

    $api_call = wp_remote_post(
            'https://api.openai.com/v1/chat/completions',
            array(
                'headers' => array(
                    'Content-Type' => 'application/json',
                    'Authorization' => 'Bearer ' . OPENAI_TOKEN,
                ),
                'body' => json_encode( [
                    'model' => 'gpt-3.5-turbo', // ChatGPT
                    'messages' => $backscroll,
                ] ),
                'method' => 'POST',
                'data_format' => 'body',
                'timeout' => 120,
            )
        );
    if ( is_wp_error( $api_call ) ) {
        return;
    }

    $result = json_decode( $api_call['body'] );
    if ( is_wp_error( $results ) ) {
        return;
    }

    return $results->choices[0]->message->content;
}

Enter fullscreen mode Exit fullscreen mode

The post Adding ChatGPT to your Slack in multiplayer mode appeared first on Artur Piszek.

Top comments (0)