Integrate Salesforce Org with Einstein Image Classification API

Prerequisites

Set up your Account-- Navigate to Einstein Platform Service Account .
Find your key file-- If you have already created an account, locate the einstein_platform.pem    
file that you have downloaded.

Upload Your File

Step 1: Log in to salesforce
Step 2:Click Files
Step 3:Click Upload Files
Step 4:Navigate to the directory where you saved the einstein_platform.pem file , select the file , and click Open.



Create a Remote Site

Step 1:Log in to salesforce
Step 2:From SetUp Enter Remote Site  in Quick Find box, select Remote Site Settings.
Step 3:
  • Enter a name for the Remote Site.
  • In the Remote Site URL field , enter https://api.metamind.io .

Step 4: Click Save .

Create The Apex Classes 

Class Name -- JWT

public class JWT {
    
    public String alg {get;set;}
    public String iss {get;set;}
    public String sub {get;set;}
    public String aud {get;set;}
    public String exp {get;set;}
    public String iat {get;set;}
    public Map<String,String> claims {get;set;}
    public Integer validFor {get;set;}
    public String cert {get;set;}
    public String pkcs8 {get;set;}
    public String privateKey {get;set;}
    public static final String HS256 = 'HS256';
    public static final String RS256 = 'RS256';
    public static final String NONE = 'none';
    public JWT(String alg) {
        this.alg = alg;
        this.validFor = 300;
    }
    public String issue() {
        String jwt = '';
        JSONGenerator header = JSON.createGenerator(false);
        header.writeStartObject();
        header.writeStringField('alg', this.alg);
        header.writeEndObject();
        String encodedHeader = base64URLencode(Blob.valueOf(header.getAsString()));
        JSONGenerator body = JSON.createGenerator(false);
        body.writeStartObject();
        body.writeStringField('iss', this.iss);
        body.writeStringField('sub', this.sub);
        body.writeStringField('aud', this.aud);
        Long rightNow = (dateTime.now().getTime()/1000)+1;
        body.writeNumberField('iat', rightNow);
        body.writeNumberField('exp', (rightNow + validFor));
        if (claims != null) {
            for (String claim : claims.keySet()) {
                body.writeStringField(claim, claims.get(claim));
            }
        }
        body.writeEndObject();
        jwt = encodedHeader + '.' + base64URLencode(Blob.valueOf(body.getAsString()));
        if ( this.alg == HS256 ) {
            Blob key = EncodingUtil.base64Decode(privateKey);
            Blob signature = Crypto.generateMac('hmacSHA256',Blob.valueof(jwt),key);
            jwt += '.' + base64URLencode(signature);  
        } else if ( this.alg == RS256 ) {
            Blob signature = null;
            
            if (cert != null ) {
                signature = Crypto.signWithCertificate('rsa-sha256', Blob.valueOf(jwt), cert);
            } else {
                Blob privateKey = EncodingUtil.base64Decode(pkcs8);
                signature = Crypto.sign('rsa-sha256', Blob.valueOf(jwt), privateKey);
            }
            jwt += '.' + base64URLencode(signature);  
        } else if ( this.alg == NONE ) {
            jwt += '.';
        }
        return jwt;
    }
    public String base64URLencode(Blob input){ 
        String output = encodingUtil.base64Encode(input);
        output = output.replace('+', '-');
        output = output.replace('/', '_');
        while ( output.endsWith('=')){
            output = output.subString(0,output.length()-1);
        }
        return output;
    }
    
}

Class Name -- JWTBearerFlow 

public class JWTBearerFlow {
    
    public static String getAccessToken(String tokenEndpoint, JWT jwt) {
        String access_token = null;
        String body = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=' + jwt.issue();
        HttpRequest req = new HttpRequest();                            
        req.setMethod('POST');
        req.setEndpoint(tokenEndpoint);
        req.setHeader('Content-type', 'application/x-www-form-urlencoded');
        req.setBody(body);
        Http http = new Http();               
        HTTPResponse res = http.send(req);
        if ( res.getStatusCode() == 200 ) {
            System.JSONParser parser = System.JSON.createParser(res.getBody());
            while (parser.nextToken() != null) {
                if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'access_token')) {
                    parser.nextToken();
                    access_token = parser.getText();
                    break;
                }
            }
        }
        return access_token;
    }
    
}

Class Name -- HttpFormBuilder 

public class HttpFormBuilder {
    //  The boundary is alligned so it doesn't produce padding characters when base64 encoded.
    private final static string Boundary = '1ff13444ed8140c7a32fc4e6451aa76d';

    public static string GetContentType() {
        return 'multipart/form-data; charset="UTF-8"; boundary="' + Boundary + '"';
    }

   
    private static string SafelyPad(
        string value,
        string valueCrLf64,
        string lineBreaks) {
        string valueCrLf = '';
        blob valueCrLfBlob = null;
        while (valueCrLf64.endsWith('=')) {
            value += ' ';
            valueCrLf = value + lineBreaks;
            valueCrLfBlob = blob.valueOf(valueCrLf);
            valueCrLf64 = EncodingUtil.base64Encode(valueCrLfBlob);
        }
        return valueCrLf64;
    }
  
    public static string WriteBoundary() {
        string value = '--' + Boundary + '\r\n';
        blob valueBlob = blob.valueOf(value);

        return EncodingUtil.base64Encode(valueBlob);
    }

  
    public static string WriteBoundary(
        EndingType ending) {
        string value = '';

        if (ending == EndingType.Cr) {
          
            value += '\n';
        } else if (ending == EndingType.None) {
           
            value += '\r\n';
        }
       
        value += '--' + Boundary + '--';

        blob valueBlob = blob.valueOf(value);

        return EncodingUtil.base64Encode(valueBlob);
    }

    public static string WriteBodyParameter(
        string key,
        string value) {
        string contentDisposition = 'Content-Disposition: form-data; name="' + key + '"';
        string contentDispositionCrLf = contentDisposition + '\r\n\r\n';
        blob contentDispositionCrLfBlob = blob.valueOf(contentDispositionCrLf);
        string contentDispositionCrLf64 = EncodingUtil.base64Encode(contentDispositionCrLfBlob);
        string content = SafelyPad(contentDisposition, contentDispositionCrLf64, '\r\n\r\n');
        string valueCrLf = value + '\r\n';
        blob valueCrLfBlob = blob.valueOf(valueCrLf);
        string valueCrLf64 = EncodingUtil.base64Encode(valueCrLfBlob);

        content += SafelyPad(value, valueCrLf64, '\r\n');

        return content;
    }

   
    public enum EndingType {
        Cr,
        CrLf,
        None
    }
}

Class Name--Vision 

public class Vision {
    public static String VISION_API = 'https://api.metamind.io/v1/vision';
    public static String PREDICT = VISION_API + '/predict';
    public static List<Prediction> predictUrl(String url, String access_token, String model) {
        return predictInternal(url, access_token, model, false);
    }
    public static List<Prediction> predictBase64(String base64String, String access_token, String model) {
        return predictInternal(base64String, access_token, model, true);
    }
    public static List<Prediction> predictBlob(blob fileBlob, String access_token, String model) {
        return predictInternal(EncodingUtil.base64Encode(fileBlob), access_token, model, true);
    }
    private static List<Prediction> predictInternal(String sample, String access_token, String model, boolean isBase64) {
        string contentType = HttpFormBuilder.GetContentType();
        //  Compose the form
        string form64 = '';
        form64 += HttpFormBuilder.WriteBoundary();
        form64 += HttpFormBuilder.WriteBodyParameter('modelId', EncodingUtil.urlEncode(model, 'UTF-8'));
        form64 += HttpFormBuilder.WriteBoundary();
        if(isBase64) {
            form64 += HttpFormBuilder.WriteBodyParameter('sampleBase64Content', sample);
        } else {
            form64 += HttpFormBuilder.WriteBodyParameter('sampleLocation', sample);
        }
        form64 += HttpFormBuilder.WriteBoundary(HttpFormBuilder.EndingType.CrLf);
        blob formBlob = EncodingUtil.base64Decode(form64);
        string contentLength = string.valueOf(formBlob.size());
        //  Compose the http request
        HttpRequest httpRequest = new HttpRequest();
        httpRequest.setBodyAsBlob(formBlob);
        httpRequest.setHeader('Connection', 'keep-alive');
        httpRequest.setHeader('Content-Length', contentLength);
        httpRequest.setHeader('Content-Type', contentType);
        httpRequest.setMethod('POST');
        httpRequest.setTimeout(120000);
        httpRequest.setHeader('Authorization','Bearer ' + access_token);
        httpRequest.setEndpoint(PREDICT);
        Http http = new Http();
        List<Prediction> predictions = new List<Prediction>();
        try {
            HTTPResponse res = http.send(httpRequest);
            if (res.getStatusCode() == 200) {
                System.JSONParser parser = System.JSON.createParser(res.getBody());
                while (parser.nextToken() != null) {
                    if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'probabilities')) {
                        parser.nextToken();
                        if (parser.getCurrentToken() == JSONToken.START_ARRAY) {
                            while (parser.nextToken() != null) {
                                // Advance to the start object marker to
                                //  find next probability object.
                                if (parser.getCurrentToken() == JSONToken.START_OBJECT) {
                                    // Read entire probability object
                                    Prediction probability = (Prediction)parser.readValueAs(Vision.Prediction.class);
                                    predictions.add(probability);
                                }
                            }
                        }
                        break;
                    }
                }
            }
            //System.debug(res.toString());
            //System.debug('STATUS:'+res.getStatus());
            //System.debug('STATUS_CODE:'+res.getStatusCode());
        } catch(System.CalloutException e) {
            System.debug('ERROR:' + e);
        }
        return(predictions);
    }
    public class Prediction {
        public String label {get;set;}
        public Double probability {get;set;}
    }
}

Class Name -- VisionController 

public class VisionController {
    // You can upload the `einstein_platform.pem` into your Salesforce org as `File` sObject and read it as below
    public String getAccessToken() {
        // Ignore the File upload part and "jwt.pkcs" if you used a Salesforce certificate to sign up 
        // for an Einstein Platform account
        ContentVersion base64Content = [SELECT Title, VersionData FROM ContentVersion where Title='einstein_platform' OR  Title='predictive_services' ORDER BY Title LIMIT 1];
        String keyContents = base64Content.VersionData.tostring();
        keyContents = keyContents.replace('-----BEGIN RSA PRIVATE KEY-----', '');
        keyContents = keyContents.replace('-----END RSA PRIVATE KEY-----', '');
        keyContents = keyContents.replace('\n', '');
        // Get a new token
        JWT jwt = new JWT('RS256');
        // jwt.cert = 'JWTCert'; // Uncomment this if you used a Salesforce certificate to sign up for an Einstein Platform account
        jwt.pkcs8 = keyContents; // Comment this if you are using jwt.cert
        jwt.iss = 'developer.force.com';
        jwt.sub = 'sireesharatnam9@gmail.com';
        jwt.aud = 'https://api.metamind.io/v1/oauth2/token';
        jwt.exp = '3600';
        String access_token = JWTBearerFlow.getAccessToken('https://api.metamind.io/v1/oauth2/token', jwt);
        return access_token;    
    }
    public List<Vision.Prediction> getCallVisionUrl() {
        // Get a new token
        String access_token = getAccessToken();
        // Make a prediction using URL to a file
        return Vision.predictUrl('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSkE0RljI_f3ssEs06QjwVsh_NmcQuCEd6E4ItPbwWH-DkhA1oIyg',access_token,'GeneralImageClassifier');
    }
    public List<Vision.Prediction> getCallVisionContent() {
        // Get a new token
        String access_token = getAccessToken();
        // Make a prediction for an image stored in Salesforce
        // by passing the file as blob which is then converted to base64 string
        ContentVersion content = [SELECT Title,VersionData FROM ContentVersion where Id = '06841000000LkfCAAS' LIMIT 1];
        return Vision.predictBlob(content.VersionData, access_token, 'GeneralImageClassifier');
    }
}

Create VisualForce Page

VisualForce Page Name -- Predict

<apex:page Controller="VisionController">
  <apex:form >
  <apex:pageBlock >
      <apex:image url="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSkE0RljI_f3ssEs06QjwVsh_NmcQuCEd6E4ItPbwWH-DkhA1oIyg">
      </apex:image>
      <br/>
      <apex:repeat value="{!AccessToken}" var="accessToken">
          Access Token:<apex:outputText value="{!accessToken}" /><br/>
    </apex:repeat>
      <br/>
      <apex:repeat value="{!callVisionUrl}" var="prediction">
          <apex:outputText value="{!prediction.label}" />:<apex:outputText value="{!prediction.probability}" /><br/>
      </apex:repeat>
  </apex:pageBlock>

  </apex:form>
</apex:page>

Click Preview




Comments

Popular posts from this blog

Configur Docusign For Salesforce

How To Make DataTable Column Resizable

Lightning:recordForm - Lightning Data Service