2929 signing_secret = signing_secret ,
3030)
3131
32- # Get the expected slack and AWS account params to local vars.
33- SLACK_SLASH_COMMAND = os .environ ["SLACK_SLASH_COMMAND" ]
32+ # Get the expected AWS account params to local vars.
3433KNOWLEDGEBASE_ID = os .environ ["KNOWLEDGEBASE_ID" ]
3534RAG_MODEL_ID = os .environ ["RAG_MODEL_ID" ]
3635AWS_REGION = os .environ ["AWS_REGION" ]
@@ -49,53 +48,79 @@ def log_request(slack_logger, body, next):
4948 return next ()
5049
5150
52- def respond_to_slack_within_3_seconds ( body , ack ):
51+ def respond_to_mention_within_3_seconds ( message , say ):
5352 """
54- Slack Bot Slash Command requires an Ack response within 3 seconds or it
53+ Slack Bot @mention requires an Ack response within 3 seconds or it
5554 messages an operation timeout error to the user in the chat thread.
5655
5756 The SlackBolt library provides a Async Ack function then re-invokes this Lambda
58- to LazyLoad the process_command_request command that calls the Bedrock KB ReteriveandGenerate API.
57+ to LazyLoad the process_mention_request that calls the Bedrock KB RetrieveAndGenerate API.
5958
60- This function is called initially to acknowledge the Slack Slash command within 3 secs.
59+ This function is called initially to acknowledge the @mention within 3 secs.
6160 """
6261 try :
63- user_query = body ["text" ]
62+ user_query = message ["text" ]
63+ user_id = message ["user" ]
64+ thread_ts = message .get ("thread_ts" , message ["ts" ]) # Use thread_ts if in thread, otherwise use message ts
65+
6466 logger .info (
65- f"Acknowledging command: { SLACK_SLASH_COMMAND } " ,
66- extra = {"user_query" : user_query },
67+ f"Acknowledging @mention from user { user_id } " ,
68+ extra = {"user_query" : user_query , "thread_ts" : thread_ts },
6769 )
68- ack (f"\n { SLACK_SLASH_COMMAND } - Processing Request: { user_query } " )
70+
71+ # Respond in thread with a processing message
72+ say (text = "Processing your request..." , thread_ts = thread_ts )
6973
7074 except Exception as err :
71- logger .error (f"Error acknowledging command: { err } " )
72- ack (f"{ SLACK_SLASH_COMMAND } - Sorry an error occurred. Please try again later." )
75+ logger .error (f"Error acknowledging @mention: { err } " )
76+ thread_ts = message .get ("thread_ts" , message ["ts" ])
77+ say (text = "Sorry, an error occurred. Please try again later." , thread_ts = thread_ts )
7378
7479
75- def process_command_request ( respond , body ):
80+ def process_mention_request ( message , say ):
7681 """
77- Receive the Slack Slash Command user query and proxy the query to Bedrock Knowledge base ReteriveandGenerate API
78- and return the response to Slack to be presented in the users chat thread.
82+ Process the @mention user query and proxy the query to Bedrock Knowledge base RetrieveAndGenerate API
83+ and return the response to Slack to be presented in the thread.
7984 """
8085 try :
81- user_query = body ["text" ]
86+ # Extract the user's query, removing the bot mention
87+ raw_text = message ["text" ]
88+ user_id = message ["user" ]
89+ thread_ts = message .get ("thread_ts" , message ["ts" ]) # Use thread_ts if in thread, otherwise use message ts
90+
91+ # Remove bot mention from the text to get clean query
92+ # Bot mentions come in format <@U1234567890> or <@U1234567890|botname>
93+ import re
94+
95+ user_query = re .sub (r"<@[UW][A-Z0-9]+(\|[^>]+)?>" , "" , raw_text ).strip ()
96+
8297 logger .info (
83- f"Processing command: { SLACK_SLASH_COMMAND } " ,
84- extra = {"user_query" : user_query },
98+ f"Processing @mention from user { user_id } " ,
99+ extra = {"user_query" : user_query , "thread_ts" : thread_ts },
85100 )
86101
102+ if not user_query :
103+ say (
104+ text = "Hi there! Please ask me a question and I'll help you find information from our knowledge base." ,
105+ thread_ts = thread_ts ,
106+ )
107+ return
108+
87109 kb_response = get_bedrock_knowledgebase_response (user_query )
88110 response_text = kb_response ["output" ]["text" ]
89- respond (f"\n { SLACK_SLASH_COMMAND } - Response: { response_text } \n " )
111+
112+ # Reply in thread with the response
113+ say (text = response_text , thread_ts = thread_ts )
90114
91115 except Exception as err :
92- logger .error (f"Error processing command: { err } " )
93- respond (f"{ SLACK_SLASH_COMMAND } - Sorry an error occurred. Please try again later." )
116+ logger .error (f"Error processing @mention: { err } " )
117+ thread_ts = message .get ("thread_ts" , message ["ts" ])
118+ say (text = "Sorry, an error occurred while processing your request. Please try again later." , thread_ts = thread_ts )
94119
95120
96121def get_bedrock_knowledgebase_response (user_query ):
97122 """
98- Get and return the Bedrock Knowledge Base ReteriveAndGenerate response.
123+ Get and return the Bedrock Knowledge Base RetrieveAndGenerate response.
99124 Do all init tasks here instead of globally as initial invocation of this lambda
100125 provides Slack required ack in 3 sec. It doesn't trigger any bedrock functions and is
101126 time sensitive.
@@ -130,16 +155,28 @@ def get_bedrock_knowledgebase_response(user_query):
130155 return response
131156
132157
133- # Init the Slack Slash '/' command handler.
134- app .command (SLACK_SLASH_COMMAND )(
135- ack = respond_to_slack_within_3_seconds ,
136- lazy = [process_command_request ],
137- )
158+ # Handle @mentions in channels and DMs
159+ @app .event ("app_mention" )
160+ def handle_app_mention (message , say ):
161+ """Handle when the bot is @mentioned"""
162+ respond_to_mention_within_3_seconds (message , say )
163+ # Process the actual request asynchronously
164+ process_mention_request (message , say )
165+
166+
167+ # Handle direct messages
168+ @app .event ("message" )
169+ def handle_direct_message (message , say ):
170+ """Handle direct messages to the bot"""
171+ # Only respond to direct messages (not channel messages)
172+ if message .get ("channel_type" ) == "im" :
173+ respond_to_mention_within_3_seconds (message , say )
174+ process_mention_request (message , say )
138175
139176
140177# Lambda handler method.
141178@logger .inject_lambda_context
142179def handler (event : dict , context : LambdaContext ) -> dict :
143- logger .info (f "Lambda invoked for { SLACK_SLASH_COMMAND } " , extra = {"event" : event })
180+ logger .info ("Lambda invoked for Slack bot " , extra = {"event" : event })
144181 slack_handler = SlackRequestHandler (app = app )
145182 return slack_handler .handle (event , context )
0 commit comments