Lex is Amazon’s service for building conversational interfaces into any application using voice and text. It is powered by the same algorithms used by Amazon Alexa and offers the integrations needed to quickly build a chatbot.

With the help following code, anyone can create custom Chatbot for lighting/communities in Salesforce using amazon lex.

Prerequisites

We need to create an account on AWS.

Server-Side Controller Code

//// AMAZON_LEX_BOT server controller

public with sharing class LexChatBotCtrl {

    @AuraEnabled
    public static string postChatText(string chatText) {
        // AWS account’s Access key
        String accessKey = '*************************************';
        // AWS account’s Secrete key 
        String secretKey = '************************************'; 
        String host = 'runtime.lex.us-east-1.amazonaws.com';
        String queue = '/bot/<botname>/alias/<aliasname>/user/4o9wwdhx6nlheferh6a73fujd3118f5w/text';</aliasname></botname>
        String hashAlgo = 'HmacSHA256';
        String url = 'https://' + host + queue;
        String formattedDateString = System.now().formatGmt('yyyyMMdd'T'HHmmss'Z'');
        String currentDate = formattedDateString;
        String currentDateRaw = formattedDateString;
        String currentDateOnly = System.now().formatGmt('YYYYMMdd');
        String regionName = 'us-east-1';
        String serviceName = 'lex';

        ////////////////////////////////////
        // BODY
        ////////////////////////////////////

        String strBody = '';
        strBody = '{ "inputText" : "' + chatText + '" }';

        ////////////////////////////////////
        // 1 - CANONICAL REQUEST
        ////////////////////////////////////

        String strCanonicalRequest = '';
        strCanonicalRequest += 'POST' + 'n';
        strCanonicalRequest += queue + 'n';
        strCanonicalRequest += '' + 'n';
        strCanonicalRequest += 'content-type:application/x-www-form-urlencoded; charset=utf-8n';
        strCanonicalRequest += 'host:runtime.lex.us-east-1.amazonaws.comn';
        strCanonicalRequest += 'x-amz-date:' + currentDate + 'n';
        strCanonicalRequest += 'n';
        strCanonicalRequest += 'content-type;host;x-amz-date';

        // Payload
        String strPayloadHash = EncodingUtil.convertToHex(Crypto.generateDigest('SHA256', Blob.valueOf(strBody))); 

        strCanonicalRequest += 'n' + strPayloadHash;

        ////////////////////////////////////
        // 2 - STRING TO SIGN
        ////////////////////////////////////

        String strStringToSign = '';
        strStringToSign += 'AWS4-HMAC-SHA256n';
        strStringToSign += currentDateRaw + 'n';
        strStringToSign += currentDateOnly + '/' + regionName + '/' + serviceName + '/aws4_request';

        // Payload
        String strCanonicalHash = EncodingUtil.convertToHex(Crypto.generateDigest('SHA256', Blob.valueOf(strCanonicalRequest))); 
        strStringToSign += 'n' + strCanonicalHash;

        ////////////////////////////////////
        // 3 - SIGNATURE
        ////////////////////////////////////

        String kSecret = 'AWS4' + secretKey;
        Blob kDate = Crypto.generateMac(hashAlgo, Blob.valueOf(EncodingUtil.urlEncode(currentDateOnly, 'UTF-8')), Blob.valueOf(kSecret));
        Blob kRegion = Crypto.generateMac(hashAlgo, Blob.valueOf(EncodingUtil.urlEncode(regionName, 'UTF-8')), kDate);
        Blob kService = Crypto.generateMac(hashAlgo, Blob.valueOf(EncodingUtil.urlEncode(serviceName, 'UTF-8')), kRegion);
        Blob kSigning = Crypto.generateMac(hashAlgo, Blob.valueOf(EncodingUtil.urlEncode('aws4_request', 'UTF-8')), kService);
        String strSignature = EncodingUtil.convertToHex(Crypto.generateMac(hashAlgo, Blob.valueOf(strStringToSign), kSigning));

        ////////////////////////////////////
        // 4 - AUTHORIZATION HEADER
        ////////////////////////////////////

        String strAuthorizationHeader = 'AWS4-HMAC-SHA256 ';
        strAuthorizationHeader += 'Credential=' + accessKey + '/' + currentDateOnly + '/' + regionName + '/' + serviceName + '/aws4_request, ';
        strAuthorizationHeader += 'SignedHeaders=content-type;host;x-amz-date, ';
        strAuthorizationHeader += 'Signature=' + strSignature;

        ////////////////////////////////////
        // POST
        ////////////////////////////////////

        Http http = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndPoint(url);
        req.setHeader('Authorization', strAuthorizationHeader);
        req.setHeader('content-type', 'application/x-www-form-urlencoded; charset=utf-8');
        req.setHeader('host', host);
        req.setHeader('Content-Length', String.valueOf(strBody.length()));
        req.setHeader('x-amz-date', currentDate);
        req.setMethod('POST');
        req.setBody(strBody);

        HttpResponse response = http.send(req);

        // Parse the JSON response
        if (response.getStatusCode() != 200) {
            System.debug('The status code returned was not expected: ' +
            response.getStatusCode() + ' ' + response.getStatus());
        }
        return response.getBody();
    }
}

Lighting Component Code

<!--Amazon Lex Chatbot component-->
<aura:component description="ChatBotService" controller="LexChatBotCtrl" implements="force:appHostable,flexipage:availableForAllPageTypes">
    <aura:attribute name="chatList" type="List" />
    <aura:attribute name="userChat" type="String"/>
    <div class="demo-only slds-grid" style="height:340px;max-width:340px;background:#f4f6f9;padding:1rem;">
        <div class="slds-panel slds-grid slds-grid_vertical slds-nowrap">
            <div class="slds-form slds-form_stacked slds-grow slds-scrollable_y">
                <div class="slds-panel__section slds-border_bottom">
                    <aura:iteration items="{!v.chatList}" var="chatItem">
                        <div> 
                            <span class="slds-badge">{!chatItem.userName}</span>
                            <p>
                                {!chatItem.chatText}
                            </p>
                            <br/>
                        </div>
                    </aura:iteration>
                </div>
            </div>
        </div>
    </div>
    <div class="demo-only slds-grid" style="height:100px;max-width:340px;background:#f4f6f9;padding:1rem;">
        <div class="slds-panel slds-grid slds-grid_vertical slds-nowrap">
            <div class="slds-form slds-form_stacked slds-grow slds-scrollable_y">
                <div class="slds-panel__section slds-border_bottom">
                    <ui:inputText class="slds-input" value="{!v.userChat}" keyup="{!c.postUserChat}" placeholder="Chat here ..." /> 
                </div>
            </div>
        </div>
    </div>
</aura:component>

Client-Side Controller Code

/**
* AWS_LEX_CHATBOT Client side controller
*/
({
    postUserChat: function(component, event, helper) {
        if (event.getParams().keyCode !== 13) {
            return;
        }
        var chatList = component.get(“v.chatList”);
        var action = component.get(“c.postChatText”);
        chatList.push({“
            chatText”: component.get(“v.userChat”),
            “userName”: ‘Me: ‘
        });
        action.setParams({“
            chatText”: component.get(“v.userChat”)
        });
        component.set(“v.userChat”, “”);
        action.setCallback(this, function(response) {
            var data = JSON.parse(response.getReturnValue());
            chatList.push({“
                chatText”: data.message,
                “userName”: ‘Personal Assistant: ‘
            });
            component.set(“v.chatList”, chatList);
        }
    });
    $A.enqueueAction(action);
}
})