Search our Blogs
Showing results for 
Search instead for 
Do you mean 
 

Build your own Haven OnDemand Combination API and call it from code using Python

Data analytics processing is often a multitude of tasks that takes a series of sub-processes to complete.

 

In this blog, we will show you how to build a combination API which combines the Speech Recognition API and the Sentiment Analysis API to analyze the sentiments of the speech from a media content. We will also show you how to call a combination API using the Python programming language and the HOD library for Python.

If you are new to Haven OnDemand, please click here to create an account. Once your account is set up, click here to copy the API key so you can use it to call Haven OnDemand APIs.

 

Create a combination API

We will login Haven OnDemand and browse to the Combinations page. For detailed instructions how to build a combination API, please watch this tutorial video

 

img1.png

 

At the Combinations page, click the Create New button to open a GUI canvas, where we will select APIs, and visually connect them in the sequence we want to build our combination. In this project, we need the Speech Recognition API, a Utility component called JsonPathExtract and the Sentiment Analysis API.

After adding the Speech Recognition API to the canvas, we click on the plus sign at the file endpoint of the API block, click the + Input button on the popup dialog to select the input type for the API.

img2.png

 

Click the X sign on the result block to remove the result block and click the plus sign at the result endpoint and select the JsonPathExtract component from the popup list box.

 

img3.png

 

Click the edit area of the block connected to the path of the JsonPathExtract component and enter the following string:

$.document[0].content

The string above tells JsonPathExtract how to extract the content value from the JSON response of the Speech Recognition API which has the format shown below:

{
    "document": [
    	  {
        "content": "some text …"
        }
    ]
}

Now add the Sentiment Analysis API to the canvas and connect the text endpoint of the API to the output of the JsonPathExtract as shown below.

 

img4.png

 

Next, click on the Describe tab and name the combination API speechsentimentanalysis. And give the combination a Display name and Description with any meaningful text.

 

img5.png

 

Also rename the file input to mediaFile. And rename the output and the result to recognized_text and sentiment_result respectively.

Let’s save the API and do a quick test by clicking on the Test tab. At the test form, select a local media file and hit the Submit button.

If the test went through successfully, we will get the result printed out on the page and the Publish tab becomes enabled. Click the Publish tab and the Publish button at the bottom to publish the combination API

After the combination API was published successfully, we will see the newly created Combination name, Display name and other information as shown below.After the combination API was published successfully, we will see the newly created Combination name, Display name and other information as shown below.img6.png

 

After the combination API was published successfully, we will see the newly created Combination name, Display name and other information as shown below.

 

img7.png

 

Create the Python app

Let’s now create a Python app called speechsentiment.py and install the HOD library for Python so we can easily call HOD APIs. Click here to download the complete app project.

 

from havenondemand.hodclient import *
from havenondemand.hodresponseparser import *
import sys

client = HODClient("YOUR-API-KEY")
parser = HODResponseParser()

# implement callback functions 

# 
params = {}
params["file"] = [("mediaFile", "testdata/attendant.mp3")]
client.post_request_combination(params, "speechsentimentanalysis", True, asyncRequestCompleted)

Firstly, we import the Haven OnDemand client library and create an instance of the client library called client. For convenience, we also import the HODResponseParser library and create an instance called parser which helps us parse the response and detect if there is any error occurred.

 

Secondly, we define the params variable and specify the file parameter as shown above. In this demo, we use the default language en-US, therefore, test media content should be in US English if you want to try with your own media content.

 

Finally, we call the post_request_combination function, passing the params, the name of our combination API, the async mode and the callback function named asyncRequestCompleted.

 

The Speech Recognition API call requires the asynchronous mode, so we must set the async=True. In fact, any API call which tends to take a long time (more than 2 mins) to process, should be called in asynchronous mode, otherwise we end up getting a timeout error message.

 

Implement the asyncRequestCompleted callback function

In response to an asynchronous request, the result will be a JSON string containing the ID of the task called jobID. And the jobID can be used for querying the actual result or the status of the API call.

 

def asyncRequestCompleted(response):
    jobID = parser.parse_jobid(response)
    if jobID is None:
        errorObj = parser.get_last_error()
        for e in errorObj.errors:
            print("Error code: %d\n" % (e.error))
            print("Reason: %s\n" % (e.reason))

    else:
        client.get_job_status(jobID, requestCompleted)

Inside the callback function, first we use the HODResponseParser library to parse the JSON response for extracting the jobID. We also need to check if the API call has been successfully submitted to Haven OnDemand server. That is why we should always check if the returned value from the parser “is None”. If there was an error, we will call the parser to get the error and print it out to the console.

 

We will call the get_job_status function to check the status of the task identified by the jobID value. We also specify the requestCompleted callback function.

 

Implement the requestCompleted callback function

When the requestCompleted callback function is called, we use the HODResponseParser library to parse the JSON response for extracting the payload. All programs have to deal with errors, and so does this app. That is why we check to see if the returned value from the parser “payloadObj is None”, meaning the response contains some error or a special status. Within the error handling loop, we will detect the error code from e.error and take appropriate actions. The code can be ErrorCode.QUEUED if the task is on the queue in Haven OnDemand server waiting for its turn to be processed. In this case, we cause a delay of 2 seconds then issue a get_job_status call again. The code can be ErrorCode.IN_PROGRESS if the task is being processed in Haven OnDemand server. In this case, we cause a delay of 10 seconds then poll with a get_job_status call again until the task is done or an error happens, in which case we print out the error reason and details.

 

def requestCompleted(response):
    payloadObj = parser.parse_payload(response)
    if payloadObj is None:
        errorObj = parser.get_last_error()
            for e in errorObj.errors:
		    if e.error == ErrorCode.QUEUED:
                    time.sleep(2)
			  client.get_job_status(e.jobID, requestCompleted)
		        return
		    elif e.error == ErrorCode.IN_PROGRESS:
			  time.sleep(10)
			  client.get_job_status(e.jobID, requestCompleted)
			  return
		    else:
			  print("Error code: %d\n" % (e.error))
                    print("Reason: %s\n" % (e.reason))

If there is no error, then we can walk through the payloadObj JSON array to extract values.

 

The payload of the response from a combination API is enclosed in a results JSON array. Each item in the result array is a JSON object with 2 pairs of key/value.

{
    "result":[
        {"name": "some name","value":"some value"}
    ]
}

Where, the value of the name key is the text string we specified as the name of an output when creating the combination. And the value of the value key is the actual result of the output from the combination API. The data format of the value can be a text string or a JSON object depending on the output type of a component in a combination endpoint.

In our demo speechsentimentanalysis Combination, we have 2 outputs named recognized_text and sentiment_result. Thus, the results JSON array will have 2 items.

{
    "results": [
        {"name":"recognize_text","value":"some text …"},
        {"name":"sentiment_result","value":{}},
    ]
}

 

The value of the recognized_text is the content extracted from the response of the Speech Recognition API by the JsonPathExtract component. While the value of the sentiment_result is the actual response of the Sentiment Analysis API as a JSON object.

We can parse the payload of the response of our Combination as follows:

else:
        resp = ""
        results = payloadObj["results"]
        for result in results:
            if result['name'] == "recognized_text":
                resp += result['name'] + "\n"
                resp += result['value'] + "\n"
            elif result['name'] == "sentiment_result":
                resp += result['name'] + "\n"
                positives = result['value']["positive"]
                resp += "Positive:\n"
                for pos in positives:
                    if pos.get('sentiment'):
                        resp += "Sentiment: " + pos["sentiment"] + "\n"
                    if pos.get('topic'):
                        resp += "Topic: " + pos["topic"] + "\n"
                    resp += "Score: " + "%f " % (pos["score"]) + "\n"
                negatives = result['value']["negative"]
                resp += "Negative:\n"
                for neg in negatives:
                    if neg.get('sentiment'):
                        resp += "Sentiment: " + neg["sentiment"] + "\n"
                    if neg.get('topic'):
                        resp += "Topic: " + neg["topic"] + "\n"
                    resp += "Score: " + "%f " % (neg["score"]) + "\n"
                aggregate = result['value']["aggregate"]
                resp += "Aggregate:\n"
                resp += "Sentiment: " + aggregate["sentiment"] + "\n"
                resp += "Score: " + "%f " % (aggregate["score"])
        print(resp)

Using Haven OnDemand Combinations we can visually combine APIs together to build a new API and make it possible to perform complex tasks in just one API call.

 

Complete Program

You can download this from https://github.com/HPE-Haven-OnDemand/SpeechSentimentAnalysis.

Further Reading

For more examples of Combinations and code calls, you might be interested in these pages from our documentation:

Social Media
About the Author
Topics
† The opinions expressed above are the personal opinions of the authors, not of HPE. By using this site, you accept the Terms of Use and Rules of Participation