National Talk Like a Pirate Day is on Thursday, and I thought it would be a fun prank to intercept everyone’s messages at work and re-write them in pirate-speak. Unfortunately, I realized this wouldn’t be practical, but I wanted to play with Val Town + ChatGPT so I ended up building something just for fun. Maybe you have a Slack workspace which is lax enough that you can get away with it!
Create a Val
Val Town is hands-down the easiest way to deploy a server-side function. You basically just write your code and click the play button. In this case, we have a function that listens for new Slack messages, and it POSTs an in-thread reply via the Slack web API.
You can fork my version on Val Town here.
import { OpenAI } from "https://esm.town/v/std/openai";
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
const openai = new OpenAI();
const ok = new Response(undefined, { status: 200 });
const unauthorized = new Response(undefined, { status: 401 });
async function ahoy(prompt: string): Promise<string> {
const completion = await openai.chat.completions.create({
messages: [
{
role: "system",
content:
"You are a pirate. Rephrase everything in the voice of a pirate.",
},
{ role: "user", content: prompt },
],
model: "gpt-4",
});
return completion.choices[0].message.content;
}
export const slackReplyToMessage = async (req: Request) => {
const { event, token, challenge } = await req.json();
if (token !== Deno.env.get("slackVerificationToken")) {
return unauthorized;
}
if (challenge) {
return Response.json({ challenge });
}
const skip: boolean[] = [
event?.type !== "message",
event?.subtype,
event?.bot_id,
event?.bot_profile,
];
if (skip.some((x) => x)) {
return ok;
}
const pirateSpeak = await ahoy(event.text);
const result = await fetchJSON("https://slack.com/api/chat.postMessage", {
headers: {
Authorization: `Bearer ${Deno.env.get("slackToken")}`,
},
method: "POST",
body: JSON.stringify({
channel: event.channel,
thread_ts: event.ts,
text: pirateSpeak,
}),
});
return ok;
};
Create a Slack App
- Find and copy the HTTP endpoint for your Val. It should look something like this:
https://dctalbot-piratetalk.web.val.run
. - Go to https://api.slack.com/apps.
- “Create New App” → “From a manifest” → Pick a workspace.
- Paste in this YAML:
display_information:
name: pirate-talk
description: This bot responds to messages in a channel in the voice of a Pirate.
background_color: "#000000"
features:
bot_user:
display_name: pirate-talk
always_online: false
oauth_config:
scopes:
bot:
- chat:write
- channels:history
settings:
event_subscriptions:
request_url: YOUR_VAL_ENDPOINT
bot_events:
- message.channels
org_deploy_enabled: false
socket_mode_enabled: false
token_rotation_enabled: false
- Replace
YOUR_VAL_ENDPOINT
with the endpoint you copied earlier. - Install the app to your workspace.
- In Features → OAuth & Permissions, copy the Bot User OAuth Token.
- In Settings → Basic Information, copy the Verification Token.
Configure Val Town secrets
- Go to the Val Town environment variables.
- Set
slackToken
to be the Bot User OAuth Token. - Set
slackVerificationToken
to be the Verification Token.
Try it out
- Invite the bot to a channel.
- Send a message!
Why it didn’t pan out
It turns out that my original vision of seamlessly rewriting everyone’s messages is not something supported by Slack. Something to do with “trust and security” blah blah blah. Additionally, I don’t think my company would be cool with me giving Val Town and OpenAI access to every new message sent in whatever channels this bot was added to. OTOH this is one way to go out with a bang.