-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathlambda_function.py
146 lines (117 loc) · 4.84 KB
/
lambda_function.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/bin/python3
"""
This is a Slack app that uses the Slack Events API and
AWS Lambda to provide a Slack bot that can be used to
answer questions based on articles in a knowledge base.
"""
import json
from slack_bolt import App
from slack_bolt.adapter.aws_lambda import SlackRequestHandler
from slack_sdk.errors import SlackApiError
app = App(process_before_response=True)
def send_message_to_user(user_id, message):
try:
# Open a direct message channel with the user
response = app.client.conversations_open(users=user_id)
channel_id = response['channel']['id'] # type: ignore
# Send the message to the user
app.client.chat_postMessage(channel=channel_id, text=message)
except SlackApiError as e:
print(f"Error sending message: {e}")
@app.event('message')
def handle_message_events(body, say):
# Only importing here to optimize Lambda start up time
from completion import get_completion
from embedding import get_data, get_document_embeddings, construct_prompt
event = body['event']
message = event['text']
# It's possible that the message is from a bot user.
# If so, we don't want to respond to it or it might cause
# a infinite loop - and putting your AWS bill on fire!
is_user_message = (
event['type'] == 'message' and
(not event.get('subtype')) and
(not event.get('bot_id'))
)
if not is_user_message:
return
print(f'User said `{message}`.')
df = get_data()
embeddings = get_document_embeddings()
prompt_with_articles_as_context = construct_prompt(message, embeddings, df)
reply_text = get_completion(prompt_with_articles_as_context)
say(reply_text)
@app.command('/submit_train_article')
def handle_submit_train_article_command(ack, respond, command):
ack()
try:
_response = app.client.views_open(
trigger_id=command['trigger_id'],
view={
'type': 'modal',
'callback_id': 'submit_train_article_view',
'title': {'type': 'plain_text', 'text': 'Feed new article to Bot'},
'blocks': [
{
'type': 'input',
'block_id': 'title_block',
'label': {'type': 'plain_text', 'text': 'Title'},
'element': {'type': 'plain_text_input', 'action_id': 'title_input'},
},
{
'type': 'input',
'block_id': 'heading_block',
'label': {'type': 'plain_text', 'text': 'Heading'},
'element': {'type': 'plain_text_input', 'action_id': 'heading_input'},
},
{
'type': 'input',
'block_id': 'content_block',
'label': {'type': 'plain_text', 'text': 'Content'},
'element': {'type': 'plain_text_input', 'multiline': True, 'action_id': 'content_input'},
},
],
'submit': {'type': 'plain_text', 'text': 'Submit'},
},
)
except Exception as e:
print('Error opening modal: {}'.format(e))
respond('Modal opened')
@app.view('submit_train_article_view')
def handle_new_train_article_submission(ack, body):
values = body['view']['state']['values']
title = values['title_block']['title_input']['value']
heading = values['heading_block']['heading_input']['value']
content = values['content_block']['content_input']['value']
print(f'Adding training data: {title}, {heading}, {content}')
ack(text='Training data submitted!')
# "Lazy loading" to avoid long Lambda start up times
from embedding import process_new_article
result = process_new_article(title, heading, content)
if result:
# send message with Slack client `client`
send_message_to_user(
body['user']['id'],
f'New training data added: with index ({title}, {heading})',
)
else:
send_message_to_user(
body['user']['id'],
'Something went wrong when adding new training data!',
)
def lambda_handler(event, context):
# Sometimes Slack might fire a 2nd attempt, etc
# if the first attempt fails or expires after some time.
# In that case we can try to achieve idempotency by checking
# the X-Slack-Retry-Num and skip processing the event, so that
# only the first attempt is processed.
# Ref: https://api.slack.com/apis/connections/events-api#retries
if event['headers'].get('x-slack-retry-num'):
return {
'statusCode': 200,
'body': 'ok',
}
# For debugging
print(json.dumps(event))
slack_handler = SlackRequestHandler(app=app)
return slack_handler.handle(event, context)