Skip to content

Instantly share code, notes, and snippets.

@afawcett
Created July 31, 2017 01:45
Show Gist options
  • Save afawcett/f8c91900e55615bcf4a6a1596a5408d0 to your computer and use it in GitHub Desktop.
Save afawcett/f8c91900e55615bcf4a6a1596a5408d0 to your computer and use it in GitHub Desktop.
Einstein Sentiment Wrappers
public with sharing class EinsteinSentimentAction {
public class Request {
@InvocableVariable
public String recordId;
@InvocableVariable
public String document;
@InvocableVariable
public String modelId;
}
public class Prediction {
@InvocableVariable
public double positive;
@InvocableVariable
public double negative;
@InvocableVariable
public double neutral;
}
@InvocableMethod(label='Classify the given text and optionally updates the given record with the results.')
public static List<EinsteinSentimentAction.Prediction> analyze(List<EinsteinSentimentAction.Request> requests) {
// TODO: Bulkify!
EinsteinSentimentAction.Request request = requests[0];
// Switch to async?
if(!System.isQueueable() && request.recordId!=null) { // TODO: Maybe put this in the callers hands as a param?
System.enqueueJob(new AsyncCallback(requests));
return null;
}
// Call Einstein API and update record (if provided)
Sentiment.Prediction prediction =
new Sentiment().getSentiment(
new VisionController().getAccessToken(),
request.document,
request.modelId);
// Update record?
if(request.recordId!=null) {
Id recordToUpdateId = (Id) request.recordId;
SObject recordToUpdate = recordToUpdateId.getSObjectType().newSObject(recordToUpdateId);
recordToUpdate.put('SentimentPositive__c', prediction.positive);
recordToUpdate.put('SentimentNegative__c', prediction.negative);
recordToUpdate.put('SentimentNeutral__c', prediction.neutral);
update recordToUpdate;
}
// Return prediction for Flow use cases
EinsteinSentimentAction.Prediction response = new EinsteinSentimentAction.Prediction();
response.positive = prediction.positive;
response.negative = prediction.negative;
response.neutral = prediction.neutral;
return new List<EinsteinSentimentAction.Prediction> { response };
}
// Class re-enters above method in an async context
public class AsyncCallback implements Queueable, Database.AllowsCallouts {
private List<EinsteinSentimentAction.Request> requests;
public AsyncCallback(List<EinsteinSentimentAction.Request> requests) {
this.requests = requests;
}
public void execute(QueueableContext context) {
EinsteinSentimentAction.analyze(requests);
}
}
}
public class Sentiment {
public Prediction getSentiment(String token, String document, String modelId) {
// Instantiate a new http object
Http h = new Http();
// Instantiate a new HTTP request
HttpRequest req = new HttpRequest();
// HTTP Header
req.setEndpoint('https://api.einstein.ai/v2/language/sentiment');
req.setHeader('Authorization', 'Bearer ' + token);
req.setHeader('Cache-Control', 'no-cache');
req.setHeader('Connection', 'keep-alive');
req.setHeader('Content-Type', HttpFormBuilder.GetContentType());
// HTTP Body
string form64 = '';
form64 += HttpFormBuilder.WriteBoundary();
form64 += HttpFormBuilder.WriteBodyParameter('modelId', EncodingUtil.urlEncode(modelId==null ? 'CommunitySentiment' : modelId, 'UTF-8'));
form64 += HttpFormBuilder.WriteBoundary();
form64 += HttpFormBuilder.WriteBodyParameter('document', document);
form64 += HttpFormBuilder.WriteBoundary(HttpFormBuilder.EndingType.CrLf);
blob formBlob = EncodingUtil.base64Decode(form64);
string contentLength = string.valueOf(formBlob.size());
req.setBodyAsBlob(formBlob);
// HTTP Header
req.setHeader('Content-Length', contentLength);
req.setMethod('POST');
// Send the request and parse response
HttpResponse res = h.send(req);
if(res.getStatusCode() == 200) {
Response resp = (Response) JSON.deserializeStrict(res.getBody().replace('object', 'object_x'), Response.class);
Prediction prediction = new Prediction();
for(Probability prob : resp.probabilities) {
if(prob.label.equals('positive')) {
prediction.positive = prob.probability;
} else if(prob.label.equals('negative')) {
prediction.negative = prob.probability;
} else if(prob.label.equals('neutral')) {
prediction.neutral = prob.probability;
}
}
return prediction;
}
// TODO: Error handling
return null;
}
public class Prediction {
public double positive;
public double negative;
public double neutral;
}
public class Response {
public List<Probability> probabilities;
public String object_x;
}
public class Probability {
public String label;
public Double probability;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment