eugenio_romano

How to integrate cognitive services using ADF, CS and PS

Blog Post created by eugenio_romano Employee on Jul 12, 2017

Sentiment analysis

 

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.

Introduction

The example presented in this blog is open source and you can find it here.

My goals during the creation of this example are:

  1. Integration between CS (Content services) and PS (Process services)
  2. Enable Sentiment Analysis in Alfresco
  3. Use ADF Angular framework to speed up the development

 

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.

 

Architecture

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:

  • ADF that provides all the necessary components (login, document-list, viewer, breadcrumbs, forms, etc..) to interact with CS and PS writing almost zero code.
  • alfresco-js-api which interacts between the CS and PS.
  • Sentiment component created for this post. You can find the related code here, but we will talk more about it below.  

 

In the BE we have:

  • Alfresco Content Service that will provide the text or the images for analysis.
  • A cognitive service (in this case, I used the Microsoft cognitive services but you can substitute the service layer with the services that you prefer).
  • Alfresco Process Service that allows us to execute actions such as moving the files into another folder depending on the results of the content sentiment analysis service.

 

ADF App

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:

  1. It shows the sentiment information, buzzwords and language recognition in a fancy, visual way.
  2. It saves the language sentiment and buzzword data in the node metadata.

 

Some useful links:

  • If you want to see the complete code which was used to create this app, please refer to this GitHub link.
  • To correctly configure the sentiment app, please refer to the instructions in the README of the project.

 

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.

 

Text analysis

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.

 

Save sentiment info as metadata

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

The sentiment app Screenshot

 

 

 

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).

 

PS Flow

 

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 the sentiment is <0.5, the content will be moved to the "Bad Folder"
  • If the sentiment is >=0.5,  the content will be moved to the "Good Folder"


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.

 

Conclusion

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.

Outcomes