Before talking about code and architecture, some of you are probably wondering what sentiment analysis is. Generally speaking, sentiment analysis refers to the use of natural language processing in order to extract emotional states and subjective information from it.
The example presented in this blog is open source and you can find it here.
My goals during the creation of this example are:
Because this example is also about the integration between CS and PS, you need to have both of them available. If you don't know how to do it, please take a look at this link.
Now a small architectural overview before drowning in the lines of code written for this example:
All the blocks inside the blue area are the FE (Front End) part made with ADF and the rest are BE (Back End).
In the FE we have:
In the BE we have:
As with all the ADF apps, generating the backbone of this app is quite easy. The only thing needed for this is the app generator. The app generator will allow you to have an FE application connected to the CS and PS in just a few minutes. As you can see, it's ready to be used with a login and document list.
After the generation of the app, we need to add our text and image analysis component.
When the user clicks on a file in the document list, the sentiment analysis component receives the content of the node. It then sends it to the sentiment analysis service. Once the async call returns with the results, it does two things:
Some useful links:
In order to make this blog as short as possible, I will only share the important part of the code. To see the whole solution, follow this link.
Our text analysis is split into two parts; the component and the service:
In the text-analysis.service.ts, we have all the calls against the sentiment analysis service and the content service:
sentimentByNodeId(nodeId) {
return new Observable<any>(observer => {
this.getContentNode(nodeId).subscribe((dataContent) => { //get the content from the content service with the nodeId
this.sentiment(dataContent).subscribe((sentiment) => {
observer.next(sentiment);
observer.complete();
});
});
});
}
sentiment(dataContent) {
return new Observable<any>(observer => {
let headers = new Headers({'Ocp-Apim-Subscription-Key': this.key}); // ... Set content type to JSON
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({headers: headers}); // Create a request option
let body = JSON.stringify(
{
'documents': [
{
'id': '1',
'text': dataContent
}
]
}
);
this.http.post(`${this.urlService}sentiment`, body, options).subscribe((data) => {
observer.next(data);
observer.complete();
}, (err) => {
this.handleError(err);
});
});
}
In the code above, we get the content of a node from the content service. We send the result to the sentiment analysis service in order to get the sentiment of the text in it.
We will store all the data collected from the cognitive API in the node metadata. This will later allow us to collect the metadata in our process and take some action based on the value of the sentiment metadata:
saveMetadata(language, keyPhrases, sentiment, nodeId) {
let sentimentBoolean = sentiment >= 0.5;
let properties = {
'properties': {
'mla:language': language,
'mla:keyPhrases': JSON.stringify(keyPhrases),
'mla:sentiment': sentimentBoolean,
'cm:description': JSON.stringify(keyPhrases)
}
};
this.apiService.getInstance().core.nodesApi.updateNode(nodeId, properties).then(function (data) {
console.log('API called successfully. Returned data: ' + data);
}, function (error) {
console.error(error);
});
}
In the screenshot above, you can see the app which is running. When you click on the file bad.txt you can see the result of its sentiment analysis in the top right corner. Once the result is shown, it is also saved as metadata in the file. If you want to start the process, you have to add a Name and start it (See the bottom right of the screenshot).
For those of you who are familiar with the BPM world, the diagram below is almost self-explanatory:
The process starts getting a nodeId as an input.
In the second block, all the metadata related to this node is fetched from the content service through the API
If you want to import this flow and try it locally, please refer to this other blog post.
After you have correctly set up the flow, the question is, how can I start this process from our ADF project?
Starting a process with ADF is really easy. I suggest you use the adf-start-process component. For more details about this component please see this link.
Let's see how to use it:
TS:
let inputProcessVariable = [];
let variable: any = {};
variable.name = 'nodeId';
variable.value = NODE_ID_CONTENT;
inputProcessVariable.push(variable);
HTML:
<adf-start-process appId="1" [variables]="inputProcessVariable" />
What have we just done with the code above? We have started our flow with our nodeId input. From this point forward, we don't need to do anything else. The process will analyze the sentiment metadata of the content using the given nodeId and move it into the right folder.
Integration with CS and PS is quite easy. You just need to input the right information into your process. With all the information in your hands in the Process Service, use the Content Service rest API to perform the actions that you need.
All the hype at the moment in software development is about AI. Sentiment analysis is one of the cool features that we can add but you can do much more. It is only a matter of finding the right way to integrate it into your project.
Feel free to contact us using gitter, the community portal, the webinars or any of the active channels Alfresco offers to get in touch.