1- # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2- # SPDX-License-Identifier: MIT-0.
3-
4- """
5- AWS Lambda hosted Slack ChatBot integration to Amazon Bedrock Knowledge Base.
6- Expects Slack Bot Slash Command given by the SLACK_SLASH_COMMAND param and presents
7- a user query to the Bedrock Knowledge Base described by the KNOWLEDGEBASE_ID parameter.
8-
9- The user query is used in a Bedrock KB ReteriveandGenerate API call and the KB
10- response is presented to the user in Slack.
11-
12- Slack integration based on SlackBolt library and examples given at:
13- https://github.com/slackapi/bolt-python/blob/main/examples/aws_lambda/lazy_aws_lambda.py
14- """
15-
16- __version__ = "0.0.1"
17- __status__ = "Development"
18- __copyright__ = "Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved."
19- __author__ = "Dean Colcott <https://www.linkedin.com/in/deancolcott/>"
20-
211import os
222import json
233import boto3
24- import logging
254from slack_bolt import App
265from slack_bolt .adapter .aws_lambda import SlackRequestHandler
6+ from aws_lambda_powertools import Logger
7+ from aws_lambda_powertools .utilities .parameters import get_parameter
8+ from aws_lambda_powertools .utilities .typing import LambdaContext
279
28-
29- # Get params from SSM
30- def get_parameter (parameter_name ):
31- ssm = boto3 .client ("ssm" )
32- try :
33- response = ssm .get_parameter (Name = parameter_name , WithDecryption = True )
34- # Parse the JSON string from the parameter
35- parameter_value = response ["Parameter" ]["Value" ]
36-
37- # Remove the JSON structure and extract just the value
38- try :
39- json_value = json .loads (parameter_value )
40- # Get the first value from the dictionary
41- value = next (iter (json_value .values ()))
42- return value
43- except (json .JSONDecodeError , StopIteration ):
44- # If parsing fails or dictionary is empty, return the raw value
45- return parameter_value
46-
47- except Exception as e :
48- print (f"Error getting parameter { parameter_name } : { str (e )} " )
49- raise e
50-
10+ # Initialize Powertools Logger
11+ logger = Logger ()
5112
5213# Get parameter names from environment variables
5314bot_token_parameter = os .environ ["SLACK_BOT_TOKEN_PARAMETER" ]
5415signing_secret_parameter = os .environ ["SLACK_SIGNING_SECRET_PARAMETER" ]
5516
56- # Retrieve the parameters from SSM Parameter Store
57- bot_token = get_parameter (bot_token_parameter )
58- signing_secret = get_parameter (signing_secret_parameter )
17+ # Retrieve and parse parameters from SSM Parameter Store
18+ bot_token_raw = get_parameter (bot_token_parameter , decrypt = True )
19+ signing_secret_raw = get_parameter (signing_secret_parameter , decrypt = True )
20+
21+ # Parse JSON values and extract tokens
22+ bot_token = json .loads (bot_token_raw )["token" ]
23+ signing_secret = json .loads (signing_secret_raw )["secret" ]
5924
6025# Initialize Slack app
6126app = App (
@@ -72,16 +37,15 @@ def get_parameter(parameter_name):
7237GUARD_RAIL_ID = os .environ ["GUARD_RAIL_ID" ]
7338GUARD_VERSION = os .environ ["GUARD_RAIL_VERSION" ]
7439
75- print (f"GR_ID,{ GUARD_RAIL_ID } " )
76- print (f"GR_V, { GUARD_VERSION } " )
40+ logger .info (f"Guardrail ID: { GUARD_RAIL_ID } , Version: { GUARD_VERSION } " )
7741
7842
7943@app .middleware
80- def log_request (logger , body , next ):
44+ def log_request (_ , body , next ):
8145 """
8246 SlackBolt library logging.
8347 """
84- logger .debug (body )
48+ logger .debug ("Slack request received" , extra = { " body" : body } )
8549 return next ()
8650
8751
@@ -97,16 +61,15 @@ def respond_to_slack_within_3_seconds(body, ack):
9761 """
9862 try :
9963 user_query = body ["text" ]
100- logging .info (
101- f"${ SLACK_SLASH_COMMAND } - Acknowledging command: { SLACK_SLASH_COMMAND } - User Query: { user_query } \n "
64+ logger .info (
65+ f"Acknowledging command: { SLACK_SLASH_COMMAND } " ,
66+ extra = {"user_query" : user_query },
10267 )
103- ack (f"\n $ { SLACK_SLASH_COMMAND } - Processing Request: { user_query } " )
68+ ack (f"\n { SLACK_SLASH_COMMAND } - Processing Request: { user_query } " )
10469
10570 except Exception as err :
106- print (f"${ SLACK_SLASH_COMMAND } - Error: { err } " )
107- respond (
108- f"${ SLACK_SLASH_COMMAND } - Sorry an error occurred. Please try again later. Error: { err } "
109- )
71+ logger .error (f"Error acknowledging command: { err } " )
72+ ack (f"{ SLACK_SLASH_COMMAND } - Sorry an error occurred. Please try again later." )
11073
11174
11275def process_command_request (respond , body ):
@@ -115,21 +78,19 @@ def process_command_request(respond, body):
11578 and return the response to Slack to be presented in the users chat thread.
11679 """
11780 try :
118- # Get the user query
11981 user_query = body ["text" ]
120- logging .info (
121- f"${ SLACK_SLASH_COMMAND } - Responding to command: { SLACK_SLASH_COMMAND } - User Query: { user_query } "
82+ logger .info (
83+ f"Processing command: { SLACK_SLASH_COMMAND } " ,
84+ extra = {"user_query" : user_query },
12285 )
12386
12487 kb_response = get_bedrock_knowledgebase_response (user_query )
12588 response_text = kb_response ["output" ]["text" ]
126- respond (f"\n $ { SLACK_SLASH_COMMAND } - Response: { response_text } \n " )
89+ respond (f"\n { SLACK_SLASH_COMMAND } - Response: { response_text } \n " )
12790
12891 except Exception as err :
129- print (f"${ SLACK_SLASH_COMMAND } - Error: { err } " )
130- respond (
131- f"${ SLACK_SLASH_COMMAND } - Sorry an error occurred. Please try again later. Error: { err } "
132- )
92+ logger .error (f"Error processing command: { err } " )
93+ respond (f"{ SLACK_SLASH_COMMAND } - Sorry an error occurred. Please try again later." )
13394
13495
13596def get_bedrock_knowledgebase_response (user_query ):
@@ -164,10 +125,8 @@ def get_bedrock_knowledgebase_response(user_query):
164125 },
165126 }
166127
167- response = client .retrieve_and_generate (
168- input = query_input , retrieveAndGenerateConfiguration = config
169- )
170- logging .info (f"Bedrock Knowledge Base Response: { response } " )
128+ response = client .retrieve_and_generate (input = query_input , retrieveAndGenerateConfiguration = config )
129+ logger .info ("Bedrock Knowledge Base Response received" , extra = {"response" : response })
171130 return response
172131
173132
@@ -179,11 +138,11 @@ def get_bedrock_knowledgebase_response(user_query):
179138
180139# Init the Slack Bolt logger and log handlers.
181140SlackRequestHandler .clear_all_log_handlers ()
182- logging .basicConfig (format = "%(asctime)s %(message)s" , level = logging .DEBUG )
183141
184142
185143# Lambda handler method.
186- def handler (event , context ):
187- print (f"${ SLACK_SLASH_COMMAND } - Event: { event } \n " )
144+ @logger .inject_lambda_context
145+ def handler (event : dict , context : LambdaContext ) -> dict :
146+ logger .info (f"Lambda invoked for { SLACK_SLASH_COMMAND } " , extra = {"event" : event })
188147 slack_handler = SlackRequestHandler (app = app )
189148 return slack_handler .handle (event , context )
0 commit comments