Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(solutions): slackbot #870

Closed
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions solutions/slackbot/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
OPENAI_API_KEY=
SLACK_BOT_TOKEN=
SLACK_SIGNING_SECRET=
SLACK_ADMIN_MEMBER_ID=
SLACK_SIGNING_SECRET=
24 changes: 2 additions & 22 deletions solutions/slackbot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

This is a Slackbot you can ask questions and get answers from OpenAI's GPT model.

[![Deploy on Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/examples/tree/main/solutions/slackbot&env=OPENAI_API_KEY,SLACK_BOT_TOKEN,SLACK_SIGNING_SECRET)

### Environment Variables

After completing the setup instructions below, you will have the following `.env` file in your project for testing locally, and the same environment variables added on Vercel:
Expand All @@ -10,7 +12,6 @@ After completing the setup instructions below, you will have the following `.env
OPENAI_API_KEY=
SLACK_BOT_TOKEN=
SLACK_SIGNING_SECRET=
SLACK_ADMIN_MEMBER_ID=
```

#### OpenAI API Key
Expand Down Expand Up @@ -39,12 +40,6 @@ Go to [Slack API Apps Page](https://api.slack.com/apps):
- Basic Information --> App Credentials --> Copy **Signing Secret**
- Add the secret to Vercel's environment variables as `SLACK_SIGNING_SECRET`

#### Admin's Slack Member ID

- Click on your profile picture in Slack and click **Profile**.
- Click on the three dots in the middle right corner and select **Copy member ID**.
- Add the ID to Vercel's environment variables as `SLACK_ADMIN_MEMBER_ID`.

### Enable Slack Events

After successfully deploying the app, go to [Slack API Apps Page](https://api.slack.com/apps) and select your app:
Expand All @@ -58,18 +53,3 @@ After successfully deploying the app, go to [Slack API Apps Page](https://api.sl
- `channel_created`
- Click **Save Changes**.
- Slack requires you to reinstall the app to apply the changes.

## Local Development
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to remove this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all, thank you for reviewing!

I thought the example was meant to lead users to deploy the app on Vercel and the app is less likely to need troubleshooting, I assumed that local development with localtunnel was beyond the intention of this example.

I'd gladly revert it and add this link also!


Use the [Vercel CLI](https://vercel.com/docs/cli) and [localtunnel](https://github.com/localtunnel/localtunnel) to test out this project locally:

```sh
pnpm i -g vercel
pnpm vercel dev --listen 3000 --yes
```

```sh
npx localtunnel --port 3000
```

Make sure to modify the [subscription URL](./README.md/#enable-slack-events) to the `localtunnel` URL.
11 changes: 3 additions & 8 deletions solutions/slackbot/api/_chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ type Event = {
thread_ts?: string
}

export async function sendGPTResponse(event: Event) {
const { channel, ts, thread_ts } = event

export async function sendGPTResponse({ channel, ts, thread_ts }: Event) {
try {
const thread = await slack.conversations.replies({
channel,
Expand All @@ -29,11 +27,8 @@ export async function sendGPTResponse(event: Event) {
})
} catch (error) {
if (error instanceof Error) {
await slack.chat.postMessage({
channel,
thread_ts: ts,
text: `<@${process.env.SLACK_ADMIN_MEMBER_ID}> Error: ${error.message}`,
})
// See Vercel Runtime Logs for errors: https://vercel.com/docs/observability/runtime-logs
throw new Error(`Error sending GPT response: ${error.message}`)
}
}
}
14 changes: 9 additions & 5 deletions solutions/slackbot/api/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,28 @@ export const config = {
maxDuration: 30,
devjiwonchoi marked this conversation as resolved.
Show resolved Hide resolved
}

const signingSecret = process.env.SLACK_SIGNING_SECRET!

// See https://api.slack.com/authentication/verifying-requests-from-slack
async function isValidSlackRequest(request: Request, body: any) {
const signingSecret = process.env.SLACK_SIGNING_SECRET!
const timestamp = request.headers.get('X-Slack-Request-Timestamp')!
const slackSignature = request.headers.get('X-Slack-Signature')!
const timestamp = request.headers.get('X-Slack-Request-Timestamp')
const slackSignature = request.headers.get('X-Slack-Signature')

const base = `v0:${timestamp}:${JSON.stringify(body)}`
const hmac = crypto
.createHmac('sha256', signingSecret)
.update(base)
.digest('hex')
const computedSignature = `v0=${hmac}`

return computedSignature === slackSignature
}

export async function POST(request: Request) {
const rawBody = await request.text()
const body = JSON.parse(rawBody)
const body = await request.json()
const requestType = body.type

// See https://api.slack.com/events/url_verification
if (requestType === 'url_verification') {
return new Response(body.challenge, { status: 200 })
}
Expand Down