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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add request/reply support #551

Merged
merged 29 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
044823a
initial commit
KhudaDad414 Oct 20, 2023
62b7076
initial commit
KhudaDad414 Oct 25, 2023
2b40e2f
Merge remote-tracking branch 'upstream/master' into v3-playground
KhudaDad414 Oct 26, 2023
1ada3d4
initial draft
KhudaDad414 Oct 30, 2023
839c82c
Merge branch 'v3-playground' into request-reply
KhudaDad414 Oct 30, 2023
8b97e96
use better names for channels and operations
KhudaDad414 Nov 1, 2023
224391c
add readme
KhudaDad414 Nov 3, 2023
a498823
update readme
KhudaDad414 Nov 3, 2023
ac4c281
re-enable send
KhudaDad414 Nov 6, 2023
8c3f8f9
Merge branch 'master' into request-reply
KhudaDad414 Nov 8, 2023
37c929e
Merge branch 'master' into request-reply
KhudaDad414 Nov 8, 2023
a7cca8b
refactor
KhudaDad414 Nov 9, 2023
b214597
add tests
KhudaDad414 Nov 9, 2023
8b3000c
remove warnings
KhudaDad414 Nov 10, 2023
202176f
Update src/adapters/http/client.ts
KhudaDad414 Nov 15, 2023
494d8a7
Update src/lib/adapter.ts
KhudaDad414 Nov 15, 2023
73e2030
Update src/lib/functions.ts
KhudaDad414 Nov 15, 2023
02555cb
Update src/lib/functions.ts
KhudaDad414 Nov 15, 2023
8e5a1a1
Update src/lib/functions.ts
KhudaDad414 Nov 15, 2023
e585f17
final touches
KhudaDad414 Nov 15, 2023
9e99f90
modify reply generation
KhudaDad414 Nov 15, 2023
c383d35
fix reply checking logic
KhudaDad414 Nov 17, 2023
ef0ba2d
Update src/lib/functions.ts
KhudaDad414 Nov 20, 2023
5c7bd6b
Update src/lib/functions.ts
KhudaDad414 Nov 20, 2023
8854982
Merge remote-tracking branch 'upstream/master' into request-reply
KhudaDad414 Nov 20, 2023
ab29311
add receive operation
KhudaDad414 Nov 20, 2023
ddb5af3
Empty commit
KhudaDad414 Nov 20, 2023
1155325
fix for sonar
KhudaDad414 Nov 20, 2023
10cc240
fix eslint warnings
KhudaDad414 Nov 20, 2023
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
2 changes: 2 additions & 0 deletions examples/slack-reaction-listener/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.glee
59 changes: 59 additions & 0 deletions examples/slack-reaction-listener/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Slack Websocket API

This Slack Websocket API leverages the AsyncAPI specification to connect Slack with OpenAI's AI models. When a user reacts to a message on Slack, this API sends the reaction to OpenAI's server. ChatGPT then crafts a fun response, which is posted as a reply to the message thread on Slack.

## Table of Contents

- [Overview](#overview)
- [Prerequisites](#prerequisites)
- [Configuration](#configuration)
- [Usage](#usage)
- [Environment Variables](#environment-variables)

## Overview

The API listens for reaction events in Slack, processes them through OpenAI's API to generate responses, and sends those back to Slack as a threaded message.

## Prerequisites

- Node.js (version 12 or higher)
- A Slack app with permissions to read reactions and post messages
- Access to OpenAI API

## Configuration

Before running the project, you must update the `asyncapi.yaml` file with the current `ticket` and `app_id` for the Slack WebSocket connection:

```yaml
channels:
SlackEventStream:
address: /link/?ticket=[ticket]&app_id=[app_id]
```

Replace `[ticket]` and `[app_id]` with the respective values for your Slack app.

## Usage

Set the environment variables by creating a `.env` file in the root of the project:

```plaintext
SLACK_HTTP=xoxb-**********
CHAT_API=openai_token
```

Start the API server with:

```sh
npm run dev
```

The API will now listen for Slack reaction events, interact with OpenAI, and post responses on Slack.

## Environment Variables

The following environment variables are necessary for the API to function:

- `SLACK_HTTP`: Your Slack app's OAuth token.
- `CHAT_API`: Your OpenAI API key.

Ensure these are set in your environment.
169 changes: 169 additions & 0 deletions examples/slack-reaction-listener/asyncapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
asyncapi: 3.0.0
info:
title: Slack Websocket and OpenAI API
version: 1.0.0
servers:
OpenAI_HTTPS:
host: api.openai.com
protocol: https
Slack_WebSocket:
host: wss-primary.slack.com
protocol: wss
Slack_HTTPS:
host: slack.com
protocol: https
channels:
SlackPostMessage:
bindings:
http:
method: post
address: /api/chat.postMessage
servers:
- $ref: "#/servers/Slack_HTTPS"
messages:
slackResponse:
payload:
type: object
properties:
channel:
type: string
text:
type: string
OpenAICompletion:
bindings:
http:
method: post
servers:
- $ref: "#/servers/OpenAI_HTTPS"
address: /v1/chat/completions
messages:
OpenAIRequest:
$ref: "#/components/messages/OpenAIRequest"
SlackEventStream:
servers:
- $ref: "#/servers/Slack_WebSocket"
address: /link/?ticket={ticket}&app_id={app_id}
Copy link
Member

Choose a reason for hiding this comment

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

just remember that these should go through websocket binding query field - but of course if that is not supported, parameters are good temporary solution, although in future address should be validated by parser, if not yet

Copy link
Member Author

Choose a reason for hiding this comment

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

Will update it to use the bindings.

Copy link
Member Author

Choose a reason for hiding this comment

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

parameters:
ticket:
default: 5a271cc5-80c7-d-bbd0-fd8a62d5767a
app_id:
default: b02112d9364cb2fee8a0a920b8b4b0103cb03fab023b4e30f6ee2efb98f
messages:
SlackReactionAdded:
$ref: "#/components/messages/SlackReactionAdded"
GenericErrorPayload:
$ref: "#/components/messages/GenericErrorPayload"
operations:
sentSlackMessage:
action: send
channel:
$ref: "#/channels/SlackPostMessage"
messages:
- $ref: "#/components/messages/slackResponse"
AckEvent:
action: send
channel:
$ref: "#/channels/SlackEventStream"
messages:
- $ref: "#/components/messages/slackAckEvent"
SendToOpenAI:
action: send
channel:
$ref: "#/channels/OpenAICompletion"
messages:
- $ref: "#/components/messages/slackResponse"
ReceiveFromOpenAI:
action: receive
channel:
$ref: "#/channels/OpenAICompletion"
messages:
- $ref: "#/components/messages/OpenAICompletionResponse"
reply:
channel:
$ref: "#/channels/SlackPostMessage"
HandleSlackReaction:
reply:
channel:
$ref: "#/channels/SlackEventStream"
Comment on lines +89 to +91
Copy link
Member

Choose a reason for hiding this comment

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

this feels weird, as your app is reaction listener, and I bet slack websocket server that you listen to do not expect any reply from the app that you're creating. So you receive stream and that is it

Copy link
Member Author

Choose a reason for hiding this comment

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

It actually needs a reply. if slack doesn't receive a confirmation it will resend the message multiple times.
https://api.slack.com/apis/connections/socket#acknowledge

action: receive
channel:
$ref: "#/channels/SlackEventStream"
messages:
- $ref: "#/components/messages/SlackReactionAdded"
- $ref: "#/components/messages/GenericErrorPayload"
components:
messages:
slackAckEvent:
payload:
type: object
properties:
envelope_id:
type: string
slackResponse:
payload:
type: object
properties:
channel:
type: string
text:
type: string
OpenAIRequest:
payload:
type: object
properties:
model:
type: string
enum: ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "text-davinci-002"]
messages:
type: array
items:
type: object
properties:
role:
type: string
enum: ["user"]
content:
type: string
temperature:
type: number
minimum: 0.0
maximum: 1.0
required:
- model
- messages
- temperature
OpenAICompletionResponse:
payload:
type: object
properties:
choices:
type: array
items:
type: object
properties:
finish_reason:
type: string
enum: ['stop']
message:
type: object
properties:
content:
type: string
role:
type: string
enum: ['assistant']
required:
- finish_reason
- message
required:
- choices
SlackReactionAdded:
payload:
type: object
GenericErrorPayload:
payload:
type: string
x-remoteServers:
- Slack_HTTPS
- Slack_WebSocket
- OpenAI_HTTPS
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { GleeFunction } from "@asyncapi/glee"

const myFunction: GleeFunction = async ({ payload }) => {
const { envelope_id } = payload
const reaction = payload?.payload?.event?.reaction
if (!reaction) return
return {
reply: [
{
payload: {
envelope_id
}
}
],
send: [{
server: "OpenAI_HTTPS",
channel: "OpenAICompletion",
headers: {
'Authorization': `Bearer ${process.env.CHAT_API}`
},
payload: {
model: "gpt-3.5-turbo",
messages: [{ "role": "user", "content": `Someone reacted with "${reaction}" emoji to my message on Slack, write something fun and short to them.` }],
temperature: 0.7
}
}]
}


}

export default myFunction
28 changes: 28 additions & 0 deletions examples/slack-reaction-listener/functions/ReceiveFromOpenAI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { GleeFunction } from "@asyncapi/glee"

const myFunction: GleeFunction = async (event) => {
const { payload } = event.request.request
const slack_event = payload?.payload?.event

if (!slack_event) return

const thread_ts = slack_event.item.ts
const channel = slack_event.item.channel
const text = event.payload.choices[0].message.content


return {
send: [{
channel: "SlackPostMessage",
server: "Slack_HTTPS",
payload: {
channel, thread_ts, text
},
headers: {
Authorization: `Bearer ${process.env.SLACK_HTTP}`,
}
}]
}
}

export default myFunction
7 changes: 7 additions & 0 deletions examples/slack-reaction-listener/glee.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default async function () {
return {
docs: {
enabled: false
}
}
}
Loading
Loading