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); } })