REST API

Here we present the REST API for running Catch-Phrase NLIs. Access is permitted via an API key and endpoints allow for session management, submitting natural language questions or commands, choosing among interpretations, and confirming commands. There are also end points to get a list of the available corpora, list questions in a corpus, and to execute every question in a corpus and get an execution report. Calls to these endpoints return JSON objects..

We include the python code at the bottom of this page that shows this API being called for an example of the D & D NLI running at proxy port 8005 on https://c-phrase.com. To get a quick working example, we recommend that you execute that code in your python environment.

API Key

Set the parameter X-API-Key in your header to access the NLI. The API-Key itself is literally the NLI username, then a space, followed by the password. All endpoints require this to be set. For the access to the example database this is set as:

headers = {
    'X-API-Key':"rest-test Weeble-123"
}
    

Endpoints

Session Management

Because calls to Catch-Phrase occasionally require dialog management for things such as resolving ambiguities or confirming updates, we maintain session identifiers to hold dialog state. For the sake of better logging readability, these session identifiers are simply random integer values from 0 to 1 billion.

Get Session

POST /c-phrase/v1/session

Description

Sessions are opened with a POST and do not take a payload.

Responses
200, 400

The return value is a JSON object with the single parameter session which gives the literal session value that should be passed in on subsequent calls.

Close Session

POST /c-phrase/v1/close-session

Description

To better manage resources, it is strongly advised that sessions are closed at the end of their use. This is achieved via a POST with a payload containing the session parameter (note this also works via GET).

Responses
200, 400

Natural Language Requests

POST /c-phrase/v1/request

Description

The main entry point of the API is the /c-phrase/v1/request route that accepts an utterance paired with a session and depending on how Catch-Phrase interprets the request it returns a response object of type table-answer,list-answer, choice-list, confirmation-request or error. The call should be made using a POST but, for convenience it can also be called with GET.

Responses

200, 400

Table Answer

Table answers either are returned as a direct result of a request, or as the result of choosing an interpretation within a choice list.

  • https://c-phrase.com:8005/c-phrase/v1/request?session=714095900&text=lawful evil dragons HP over 300
  • returns:
     {
      "table-answer": {
        "columns": [
          "name",
          "image",
          "hit point",
          "armor class",
          "challenge rating",
          "type",
          "size",
          "alignment",
          "strength",
          "dexterity",
          "constitution",
          "intelligence",
          "wisdom",
          "charisma"
        ],
        "paraphrase": "lawful evil dragons HP over 300",
        "rows": [
          {
            "alignment": "Lawful Evil",
            "armor class": "22",
            "challenge rating": "23",
            "charisma": "21",
            "constitution": "27",
            "dexterity": "10",
            "hit point": "481",
            "image": "link",
            "intelligence": "18",
            "name": "Dragon, Chromatic, Blue, Ancient",
            "size": "Gargantuan",
            "strength": "29",
            "type": "Dragon",
            "wisdom": "17"
          },
          {
            "alignment": "Lawful Evil",
            "armor class": "21",
            "challenge rating": "22",
            "charisma": "19",
            "constitution": "25",
            "dexterity": "12",
            "hit point": "385",
            "image": "link",
            "intelligence": "20",
            "name": "Dragon, Chromatic, Green, Ancient",
            "size": "Gargantuan",
            "strength": "27",
            "type": "Dragon",
            "wisdom": "17"
          }
        ],
        "sql": "SELECT DISTINCT \n  X1.name, \n  ('' || 'images' || '
                                ') AS images, \n  X1.hp, \n  X1.ac, \n  X1.challenge_rating, \n  X1.type, \n  X1.size, \n  X1.alignment2, \n  X1.strength, \n  X1.dexterity, \n  X1.constitution, \n  X1.intelligence, \n  X1.wisdom, \n  X1.charisma\n\nFROM\n  monster AS X1\nWHERE \n  X1.hp>300 AND \n  X1.type='Dragon' AND \n  X1.alignment2='Lawful Evil'",
        "type": "table"
      },
      "type": "table-answer"
    }
                    

List Answer

List answers are similar to table answers, but they are over a single column:

  • https://c-phrase.com:8005/c-phrase/v1/request?session=714095900&text=names of Chaotic Good or Chaotic Neutral Feys
  • returns:
    {
      "list-answer": {
        "list": [
          "Boggle",
          "Darkling",
          "Darkling Elder",
          "Eladrin, Autumn",
          "Eladrin, Spring",
          "Eladrin, Summer",
          "Eladrin, Winter",
          "Korred",
          "Satyr",
          "Siren"
        ],
        "paraphrase": "names of Chaotic Good or Chaotic Neutral Feys",
        "sql": "..."
      },
      "type": "list-answer"
    }
                 

Choice List

A choice list gives all the interpretations for an ambiguous question. Immediately after a choice list is returned, then one of the interpretations may be picked on the next call via the choice endpoint. This in turn will generate a table answer, a list answer or, possibly, an error.

  • https://c-phrase.com:8005/c-phrase/v1/request?session=714095900&text=Dragons taking non-standard damage
  • returns:
    {
      "choices": [
        {
          "index": "1",
          "message": "",
          "text": "imunity_of_monster monsters type  Dragon"
        },
        {
          "index": "2",
          "message": "",
          "text": "resistance_of_monster monsters type  Dragon"
        },
        {
          "index": "3",
          "message": "",
          "text": "susceptiblity_of_monster monsters type  Dragon"
        }
      ],
      "type": "choice-list"
    }
                 
  • This response may be immediately followed up by a choose interpretation operation (see here) https://c-phrase.com:8005/c-phrase/v1/choice?session=714095900&choice=2
  • This then returns:
    {
      "table-answer": {
        "columns": [
          "monster",
          "damage"
        ],
        "paraphrase": "Dragons taking non-standard damage",
        "rows": [
          {
            "damage": "Poison",
            "monster": "Ambush Drake"
          },
          {
            "damage": "Acid",
            "monster": "Dragon, Turtle"
          }
        ],
        "sql": "...",
        "type": "table"
      },
      "type": "table-answer"
    }
                 

Confirmation Request

Confirmation Requests are returned when a successful update command is processed by catch phrase that needs to be confirmed.

  • https://c-phrase.com:8005/c-phrase/v1/request?session=714095900&text=delete location name Weeble
  • returns:
    {
      "confirmation": "delete locations name  Weeble",
      "type": "confirmation-request"
    }
                    

    For this to actually be reflected in the database it must be immediately followed up with a call to https://c-phrase.com:8005/c-phrase/v1/confirm?session=714095900

  • returns:
    {
      "message": "1 row(s) affected by delete locations name  Weeble",
      "type": "confirmed"
    }
    
                        

Error

Errors are returned when something fails.

  • https://c-phrase.com:8005/c-phrase/v1/request?session=714095900&text=saskwatch
  • returns:
    {
      "error": {
        "message": "'saskwatch' not recognized.",
        "type": "cp-fail-no-mapping"
      },
      "type": "error"
    }
                    

Interaction

As presented above, often the responses from Catch-Phrase require interaction. This is either to pick one of several alternative interpretations or to confirm an update operation. In both cases an error will return if the interaction operation does not immediate follow the returned choice list or confirmation request object

Choose Interpretation

POST /c-phrase/v1/choice

Description

When the response object is a choice-list the API can pick which of the interpretations to execute. The is achieved via a POST on /c-phrase/v1/choice. This in turn will result in a table-answer,list-answer or confirmation response object. The call should be made using a POST but, for convenience it can also be called with GET.

Confirm

POST /c-phrase/v1/confirm

Description

All update commands need to be explicitly confirmed via the API. This happens when a response object is a confirmation message. To confirm, one performs POST with the session as the parameter to /c-phrase/v1/confirm. Confirmations are only available as an immediate operation on the next turn.The call should be made using a POST but, for convenience it can also be called with GET.

Working with Corpora

Get Corpora

GET /c-phrase/v1/corpora

A simple GET on /c-phrase/v1/corpora returns a list of corpora configured for the NLI. This returns a list of the corpus names.

Get Questions

GET /c-phrase/v1/questions

A simple GET on /c-phrase/v1/questions?corpus={corpus_name} returns a list of the questions in the given corpus.

Evaluate Corpus

POST /c-phrase/v1/evaluate

A POST on /c-phrase/v1/evaluate with a payload of the corpus_name will evaluate every question in the corpus and return an execution report as a table answer. The call should be made using a POST but, for convenience it can also be called with GET.

Calling the REST API from Python

We recommend that you get this code working in your environment to quickly get a working example. Then adapt to call your own running NLI.

import requests
import json

base_url = 'https://c-phrase.com:8005'

headers = {'X-API-Key':"rest-test Weeble-123"}

response = requests.post(base_url + "/c-phrase/v1/session", headers=headers, json={})
session = json.loads(response.text)['session']

payload = {
    "text": "lawful evil dragons with more than 300 hit points",
    "session": session
}

# Request as a POST
response = requests.post(base_url + f"/c-phrase/v1/request", json=payload, headers=headers)
answer = json.loads(response.text)
print(answer['table-answer']['sql'])

# Request as a GET
response = requests.get(base_url + f"/c-phrase/v1/request?session={session}&text=names of Chaotic Good or Chaotic Neutral Feys",
                        headers=headers)
answer = json.loads(response.text)
print(answer['list-answer']['paraphrase'])

payload = {
    "text": "average strength of fiends",
    "session": session
}

response = requests.post(base_url + f"/c-phrase/v1/request", json=payload, headers=headers)
answer = json.loads(response.text)
print(answer['table-answer']['paraphrase'])

payload = {
    "text": "Dragons taking non-standard damage",
    "session": session
}
response = requests.post(base_url + f"/c-phrase/v1/request", json=payload, headers=headers)
answer = json.loads(response.text)

if 'choices' in answer:
    response = requests.post(base_url + f"/c-phrase/v1/choice",
                            json={"session": session, "choice": 2}, headers=headers)
    answer = json.loads(response.text)
    print(answer['table-answer']['rows'][0]['monster'])

response = requests.post(base_url + f"/c-phrase/v1/request", json={"session": session, "text":"saskwatch"}, headers=headers)
answer = json.loads(response.text)
print(answer['error']['message'])

# Request as a GET
response = requests.get(base_url + f"/c-phrase/v1/request?session={session}&text=how many monsters per type", headers=headers)
answer = json.loads(response.text)

response = requests.post(base_url + f"/c-phrase/v1/request", json={"session": session, "text":"saskwatch"}, headers=headers)
answer = json.loads(response.text)


response = requests.get(base_url + f"/c-phrase/v1/corpora", headers=headers)
answer = json.loads(response.text)

corpus_name = answer['corpora'][0]
response = requests.get(base_url + f"/c-phrase/v1/questions?corpus_name={corpus_name}", headers=headers)
answer = json.loads(response.text)

response = requests.post(base_url + f"/c-phrase/v1/evaluate",
                         json={"session":session,"corpus_name":corpus_name},
                         headers=headers)
answer = json.loads(response.text)

response = requests.post(base_url + f"/c-phrase/v1/request", json={"session": session, "text":'add location name "Weeble" description "Humpf"'}, headers=headers)
answer = json.loads(response.text)

response = requests.post(base_url + f"/c-phrase/v1/request", json={"session": session, "text":'add location name "Wonk"'}, headers=headers)
answer = json.loads(response.text)

response = requests.post(base_url + f"/c-phrase/v1/request", json={"session": session, "text":'delete location name Weeble'}, headers=headers)
answer = json.loads(response.text)

response = requests.post(base_url + f"/c-phrase/v1/confirm", json={"session": session}, headers=headers)
answer = json.loads(response.text)

response = requests.post(base_url + "/c-phrase/v1/close-session", json={"session": session}, headers=headers)