Part 1: How To Use Golang With API.ai Artificial Intelligence Service

Part 1 — In this article, we will try out their /query service.

Api.ai is a service which provides a nice combination of both voice recognition and machine learning for developers. We shall use their free tier.

Api.ai has “Domains”. Domains are a whole collection of knowledge and data structures from Api.ai that are ready for use in every Api.ai agent (apps are called “agents” in Api.ai).

Api.ai has SDKs for most languages except Golang. Nevertheless, we shall use Go to write a program called “apiai.go” which will query the weather for a particular place and display the result.

I have created a folder “apiai” which will hold the Go source code “apiai.go”.

C:\go_projects\go\src\github.com\SatishTalim\apiai

We shall be running our program at the command prompt in the folder “apiai” as follows:

go run apiai.go

apiai.go

As mentioned in their docs, a sample query response is:

{
  "id": "cfcbd337-6b66-4393-a6a3-74fc5487cedb",
  "timestamp": "2016-02-16T00:30:13.529Z",
  "result": {
    "source": "agent",
    "resolvedQuery": "hi my name is Sam",
    "action": "greetings",
    "actionIncomplete": false,
    "parameters": {
      "name": "Sam"
    },
    "contexts": [
      {
        "name": "user_name",
        "parameters": {
          "name": "Sam"
        },
        "lifespan": 5
      },
      {
        "name": "greetings",
        "parameters": {
          "name": "Sam"
        },
        "lifespan": 5
      }
    ],
    "metadata": {
      "intentId": "c251ef97-0c43-404d-bf75-98e806f942be",
      "intentName": "Greetings"
    },
    "fulfillment": {
      "speech": "Hi Sam! How can I help you?"
    }
  },
  "status": {
    "code": 200,
    "errorType": "success"
  }
}

JSON-to-Go is an excellent tool that instantly converts JSON into a Go type definition. Using it, I get:

type QResponse struct {
        ID string `json:"id"`
        Timestamp time.Time `json:"timestamp"`
        Result struct {
                Source string `json:"source"`
                ResolvedQuery string `json:"resolvedQuery"`
                Action string `json:"action"`
                ActionIncomplete bool `json:"actionIncomplete"`
                Parameters struct {
                        Name string `json:"name"`
                } `json:"parameters"`
                Contexts []struct {
                        Name string `json:"name"`
                        Parameters struct {
                                Name string `json:"name"`
                        } `json:"parameters"`
                        Lifespan int `json:"lifespan"`
                } `json:"contexts"`
                Metadata struct {
                        IntentID string `json:"intentId"`
                        IntentName string `json:"intentName"`
                } `json:"metadata"`
                Fulfillment struct {
                        Speech string `json:"speech"`
                } `json:"fulfillment"`
        } `json:"result"`
        Status struct {
                Code int `json:"code"`
                ErrorType string `json:"errorType"`
        } `json:"status"`
}

Here’s the complete “apiai.go” program:

package main

import (
        "encoding/json"
        "fmt"
        "log"
        "net/http"
        "time"
)

type QResponse struct {
        ID string `json:"id"`
        Timestamp time.Time `json:"timestamp"`
        Result struct {
                Source string `json:"source"`
                ResolvedQuery string `json:"resolvedQuery"`
                Action string `json:"action"`
                ActionIncomplete bool `json:"actionIncomplete"`
                Parameters struct {
                        Name string `json:"name"`
                } `json:"parameters"`
                Contexts []struct {
                        Name string `json:"name"`
                        Parameters struct {
                                Name string `json:"name"`
                        } `json:"parameters"`
                        Lifespan int `json:"lifespan"`
                } `json:"contexts"`
                Metadata struct {
                        IntentID string `json:"intentId"`
                        IntentName string `json:"intentName"`
                } `json:"metadata"`
                Fulfillment struct {
                        Speech string `json:"speech"`
                } `json:"fulfillment"`
        } `json:"result"`
        Status struct {
                Code int `json:"code"`
                ErrorType string `json:"errorType"`
        } `json:"status"`
}

func main() {
        url := fmt.Sprintf("https://api.api.ai/v1/query?v=20150910&query=weather&lang=en&latitude=35.925&longitude=-86.8688889&sessionId=1234567890")

        // Build the request
        req, err := http.NewRequest("GET", url, nil)
        if err != nil {
                log.Fatal("NewRequest: ", err)
                return
        }        
        // Replace 9ea93023b7274cfbb392b289658cff0b by your Client access token
        req.Header.Add("Authorization", "Bearer 9ea93023b7274cfbb392b289658cff0b")

        // For control over HTTP client headers,
        // redirect policy, and other settings,
        // create a Client
        // A Client is an HTTP client
        client := &http.Client{}

        // Send the request via a client
        // Do sends an HTTP request and
        // returns an HTTP response
        resp, err := client.Do(req)
        if err != nil {
                log.Fatal("Do: ", err)
                return
        }
        
        // Callers should close resp.Body
        // when done reading from it
        // Defer the closing of the body
        defer resp.Body.Close()       
        
        // Fill the record with the data from the JSON
        var record QResponse   
        
        // Use json.Decode for reading streams of JSON data
        if err := json.NewDecoder(resp.Body).Decode(&record); err != nil {
                log.Println(err)
        }

        fmt.Println("Status = ", record.Status.Code)
        fmt.Println("Response = ", record.Result.Fulfillment.Speech)
}

https://docs.api.ai/docs/reference allow you to submit queries and get text-to-speech results.

All the URLs have the following base:

https://api.api.ai/v1/

The query endpoint is used to process natural language, either in the form of text or a sound file. The query requests return structured data in JSON format with an action and parameters for that action. Get /query — Takes natural language text and information as query parameters and returns information as JSON.

We are going to find out the weather at Franklin, Tennessee, USA.

Query parameters

Clipboard01

https://api.api.ai/v1/query?v=20150910&query=weather&lang=en&latitude=35.925&longitude=-86.8688889&sessionId=1234567890

With the parameters in the above table, our URL is as shown above.

fmt.Sprintf

“Sprintf” formats and returns a string without printing it anywhere.

func NewRequest(method, urlStr string, body io.Reader) (*Request, error)

“NewRequest” returns a new “Request” given a method, URL, and an optional body. “NewRequest” returns a “Request” suitable for use with “Client.Do”.

func (h Header) Add(key, value string)

“Add” adds the key, value pair to the header. It appends to any existing values associated with key.

// Replace 9ea93023b7274cfbb392b289658cff0b by your Client access token 
req.Header.Add(“Authorization”, “Bearer 9ea93023b7274cfbb392b289658cff0b”)

For each API request, include the above HTTP header.

client := &http.Client{}

A “Client” is an HTTP client.

resp, err := client.Do(req)

“Do” sends an HTTP request and returns an HTTP response. When “err” is nil, “resp” always contains a non-nil “resp.Body”. Callers should close “resp.Body” when done reading from it. Use “Defer” for closing the body. “resp.Body” is of type “io.Reader”.

defer resp.Body.Close()

Next, “NewDecoder” returns a new decoder that reads from “io.Reader”. A “Decoder” reads and decodes JSON objects from an input stream.

func NewDecoder(r io.Reader) *Decoder

“Decode” reads the next JSON-encoded value from its input and stores it in the value pointed to by v.

func (dec *Decoder) Decode(v interface{}) error

Finally, we extract the information from our populated “QResponse” struct variable “record”.

Here’s a sample output of the program:

Response = It’s currently 63 degrees and cloudy in Franklin, Tennessee. It will be intermittent clouds and around 62 degrees this afternoon. Expect a thunderstorms evening, with temperatures around 66 degrees.

That’s it!

One thought on “Part 1: How To Use Golang With API.ai Artificial Intelligence Service

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.