WebSockets for Real-time AI-Powered Chatbots Interface.
PythonTo create a real-time AI-powered chatbot interface using WebSockets, we need to set up a serverless infrastructure that can handle real-time bi-directional communication with low latency. AWS API Gateway with WebSocket support is an excellent option for this use case. We will also need a compute service to run our chatbot's code; AWS Lambda is a suitable choice as it can handle the execution of our logic in response to websocket events.
In this Pulumi program, you'll see how to use AWS resources to implement a basic chatbot infrastructure. We'll walk through the following steps:
- Create an API Gateway with WebSocket support.
- Define Lambda functions that will respond to WebSocket events such as
$connect
,$disconnect
andsendMessage
. - Grant the necessary permissions for API Gateway to invoke the Lambda functions.
- Deploy the infrastructure using Pulumi.
Here's a Python program using Pulumi for creating this infrastructure:
import pulumi import pulumi_aws as aws # First, we define the Lambda function that will be invoked when the user establishes # a connection to the WebSocket. connect_function = aws.lambda_.Function("websocketConnectHandler", runtime="python3.8", code=pulumi.AssetArchive({ ".": pulumi.FileArchive("./connect"), # The path to your Lambda function code }), handler="connect.handler", # The file and method where your Lambda handler is defined role=connect_role.arn ) # Next, we define the Lambda function that will handle the disconnection events. disconnect_function = aws.lambda_.Function("websocketDisconnectHandler", runtime="python3.8", code=pulumi.AssetArchive({ ".": pulumi.FileArchive("./disconnect"), # The path to your Lambda function code }), handler="disconnect.handler", # The file and method where your Lambda handler is defined role=disconnect_role.arn ) # Then, we need a Lambda function to process the messages sent through the WebSocket. message_function = aws.lambda_.Function("websocketMessageHandler", runtime="python3.8", code=pulumi.AssetArchive({ ".": pulumi.FileArchive("./message"), # The path to your Lambda function code }), handler="message.handler", # The file and method where your Lambda handler is defined role=message_role.arn ) # Now we create the roles that will be used by our Lambda functions. policy_document = aws.iam.get_policy_document(statements=[{ "effect": "Allow", "actions": ["logs:*", "lambda:*"], "resources": ["*"], }]) connect_role = aws.iam.Role("websocketConnectRole", assume_role_policy=policy_document.json ) disconnect_role = aws.iam.Role("websocketDisconnectRole", assume_role_policy=policy_document.json ) message_role = aws.iam.Role("websocketMessageRole", assume_role_policy=policy_document.json ) # Next, we create the API Gateway for WebSockets. api = aws.apigatewayv2.Api("chatApi", protocol_type="WEBSOCKET", # Indicating that we want a WebSocket API route_selection_expression="$request.body.action", # Defines how the incoming request is routed to our Lambda function based on the incoming request body's action parameter. ) # With the API in place, let's define the routes that the API gateway will be able to handle. connect_route = aws.apigatewayv2.Route("connectRoute", api_id=api.id, route_key="$connect", # Special key for the connection establishment phase authorization_type="NONE", # No authorization required for simplicity target=pulumi.Output.all(api.id, connect_function.arn).apply( lambda args: f"integrations/{args[0]}", ) ) disconnect_route = aws.apigatewayv2.Route("disconnectRoute", api_id=api.id, route_key="$disconnect", # Special key for the disconnect event phase authorization_type="NONE", # No authorization required for simplicity target=pulumi.Output.all(api.id, disconnect_function.arn).apply( lambda args: f"integrations/{args[0]}" ) ) message_route = aws.apigatewayv2.Route("messageRoute", api_id=api.id, route_key="sendMessage", # The key defining the action to send messages authorization_type="NONE", # No authorization required for simplicity target=pulumi.Output.all(api.id, message_function.arn).apply( lambda args: f"integrations/{args[0]}", ) ) # Finally, we integrate the routes with our Lambda functions using integrations. connect_integration = aws.apigatewayv2.Integration("connectIntegration", api_id=api.id, integration_type="AWS_PROXY", # The integration type integration_uri=connect_function.invoke_arn ) disconnect_integration = aws.apigatewayv2.Integration("disconnectIntegration", api_id=api.id, integration_type="AWS_PROXY", integration_uri=disconnect_function.invoke_arn ) message_integration = aws.apigatewayv2.Integration("messageIntegration", api_id=api.id, integration_type="AWS_PROXY", integration_uri=message_function.invoke_arn ) # To enable real-time updates without constantly refreshing, we deploy the API Gateway. deployment = aws.apigatewayv2.Deployment("apiDeployment", api_id=api.id ) # We create a stage which is a snapshot of the deployment to be accessed via the web. stage = aws.apigatewayv2.Stage("apiStage", api_id=api.id, deployment_id=deployment.id, auto_deploy=True, ) # We need to grant the API Gateway permission to invoke the Lambda functions. connect_permission = aws.lambda_.Permission("connectPermission", action="lambda:InvokeFunction", function=connect_function.name, principal="apigateway.amazonaws.com", source_arn=api.execution_arn.apply( lambda arn: f"{arn}/*/$connect" ) ) disconnect_permission = aws.lambda_.Permission("disconnectPermission", action="lambda:InvokeFunction", function=disconnect_function.name, principal="apigateway.amazonaws.com", source_arn=api.execution_arn.apply( lambda arn: f"{arn}/*/$disconnect" ) ) message_permission = aws.lambda_.Permission("messagePermission", action="lambda:InvokeFunction", function=message_function.name, principal="apigateway.amazonaws.com", source_arn=api.execution_arn.apply( lambda arn: f"{arn}/*/sendMessage" ) ) # To access the WebSocket URL, we export it as an output of our Pulumi program. pulumi.export("websocket_url", api.api_endpoint)
In this program, we have:
- Created Lambda functions with corresponding roles which contain permission to log to CloudWatch and to be invoked by the API Gateway.
- Defined the WebSocket API and set up the routes and integrations with our Lambda functions.
- Provisioned an API Gateway Deployment and Stage to make our WebSocket API accessible.
- Added permissions for the API Gateway to invoke the Lambda functions.
- Exported the WebSocket URL to be accessed by clients.
To run this Pulumi program, you need to have the AWS Pulumi provider configured, as well as some placeholder code for the Lambda functions (
connect
,disconnect
, andmessage
directories with ahandler
function defined inside them). The output will be a WebSocket URL that you can use to connect and communicate with your chatbot interface.Please ensure that you replace the dummy directories (
./connect
,./disconnect
,./message
) with the actual paths to your Lambda function code equipped to handle the WebSocket events for your chatbot.Remember to handle all necessary deployment configurations like IAM permissions more securely in a production environment by narrowing down the permissions to what is strictly necessary.