REST API
        Here we present the endpoints available on running NLIs. These endpoints return JSON expressions that
        represent table and list answers as well as a special choice list which lets users pick the proper interpretation
        of their question in case of ambiguity. There is also a simple endpoint to generate fresh session identifiers
        to track concurrent dialogues. The table below presents these endpoints. The  python code 
        at the bottom of this file shows this API being called for an example of the D & D NLI running at proxy port 8005 on
        https://c-phrase.com.
    
Endpoints
| Method | Endpoint | Purpose | Return Type | 
|---|---|---|---|
| GET | /c-phrase/v1/session | 
            Gets a new session id. | session | 
| GET | /c-phrase/v1/request?session={int}&text={text} | 
             Asks the NLI to answer the given question text within the specified session.  | 
            table-answer, list-answer, choice-list or error | 
| GET | /c-phrase/v1/choice?session={int}&choice={int} | 
            Chooses the n-th interpretation of the previous choice list within the given session. | table-answer, list-answer or error | 
| GET | /c-phrase/v1/completions | 
            Return a list of tokens that could be used for search bar completions. | token-list | 
Return Types
    All returned results are JSON expressions. In the examples below access the d_and_d NLI running on
        port 8005 of the host https://c-phrase.com. If you paste these examples into your browser's
        address bar or postman, they should work.
    
Session
Sessions are integer ids that keep track of specific ongoing dialogues. There can be multiple concurrent sessions.
- 
    
https://c-phrase.com:8005/c-phrase/v1/session - returns:
             
{ "session": "714095900" } 
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 (see below)
- 
    
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 with more than 300 hit points", "rows": [ { "alignment": { "span": { "#text": "Lawful\u00e6Evil", "@className": "text-click-and-like" } }, "armor class": { "span": { "#text": "22", "@className": "text-numeric" } }, "challenge rating": { "span": { "#text": "23", "@className": "text-numeric" } }, "charisma": { "span": { "#text": "21", "@className": "text-numeric" } }, "constitution": { "span": { "#text": "27", "@className": "text-numeric" } }, "dexterity": { "span": { "#text": "10", "@className": "text-numeric" } }, "hit point": { "span": { "#text": "481", "@className": "text-numeric" } }, "image": { "a": { "#text": "images", "@className": "text-link", "@href": "https://www.google.com/search?q=Dragon, Chromatic, Blue, Ancient in dungeons and dragons&udm=2", "@target": "_blank" } }, "intelligence": { "span": { "#text": "18", "@className": "text-numeric" } }, "name": { "span": { "#text": "Dragon,\u00e6Chromatic,\u00e6Blue,\u00e6Ancient", "@className": "text-click-and-like" } }, "size": { "span": { "#text": "Gargantuan", "@className": "text-click-and-like" } }, "strength": { "span": { "#text": "29", "@className": "text-numeric" } }, "type": { "span": { "#text": "Dragon", "@className": "text-click-and-like" } }, "wisdom": { "span": { "#text": "17", "@className": "text-numeric" } } }, { "alignment": { "span": { "#text": "Lawful\u00e6Evil", "@className": "text-click-and-like" } }, "armor class": { "span": { "#text": "21", "@className": "text-numeric" } }, "challenge rating": { "span": { "#text": "22", "@className": "text-numeric" } }, "charisma": { "span": { "#text": "19", "@className": "text-numeric" } }, "constitution": { "span": { "#text": "25", "@className": "text-numeric" } }, "dexterity": { "span": { "#text": "12", "@className": "text-numeric" } }, "hit point": { "span": { "#text": "385", "@className": "text-numeric" } }, "image": { "a": { "#text": "images", "@className": "text-link", "@href": "https://www.google.com/search?q=Dragon, Chromatic, Green, Ancient in dungeons and dragons&udm=2", "@target": "_blank" } }, "intelligence": { "span": { "#text": "20", "@className": "text-numeric" } }, "name": { "span": { "#text": "Dragon,\u00e6Chromatic,\u00e6Green,\u00e6Ancient", "@className": "text-click-and-like" } }, "size": { "span": { "#text": "Gargantuan", "@className": "text-click-and-like" } }, "strength": { "span": { "#text": "27", "@className": "text-numeric" } }, "type": { "span": { "#text": "Dragon", "@className": "text-click-and-like" } }, "wisdom": { "span": { "#text": "17", "@className": "text-numeric" } } } ], "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" } } 
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\u00e6Elder", "Eladrin,\u00e6Autumn", "Eladrin,\u00e6Spring", "Eladrin,\u00e6Summer", "Eladrin,\u00e6Winter", "Korred", "Satyr", "Siren" ], "paraphrase": "names of Chaotic Good or Chaotic Neutral Feys", "sql": "SELECT DISTINCT \n X1.name\nFROM\n monster AS X1\nWHERE \n X1.type='Fey' AND \n (X1.alignment2 IN('Chaotic Good','Chaotic Neutral'))\n ORDER BY X1.name IS NULL, X1.name ASC" } } 
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": "", "sql": "", "text": "records of immunity monsters type Dragon" }, { "index": "2", "message": "", "sql": "", "text": "records of resistance monsters type Dragon" }, { "index": "3", "message": "", "sql": "", "text": "records of vulnerability monsters type Dragon" } ] } - 
    You may now immediately follow this up with: 
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": { "span": { "#text": "Poison", "@className": "text-click-and-like" } }, "monster": "Ambush\u00e6Drake" }, { "damage": { "span": { "#text": "Acid", "@className": "text-click-and-like" } }, "monster": "Dragon,\u00e6Turtle" } ], "sql": "SELECT DISTINCT \n \n (SELECT F1.name \n FROM monster AS F1 \n WHERE F1.monster_id = X1.monster) \n AS \"monster name for monster\", \n X1.damage\n\nFROM\n monster_resistant_to_damage AS X1,\n monster AS X2\nWHERE \n X1.monster=X2.monster_id AND \n X2.type='Dragon'", "type": "table" } } 
Available Token List
This returns the list of tokens that your application might want to do use in composing questions.
- 
    
http://c-phrase.com:8005/c-phrase/v1/completions - returns:
             
{ 'completions': ['after', 'later than', 'ago', 'earlier',...] } 
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" } } 
Calling the REST API from Python
    This performs the examples above plus a final 'bar chart example' called from python for the D&D NLI running
    at proxy port 8005 at https://c-phrase.link. We shall leave the D&D NLI running, so executing this
    code in a python console should work.
    Note the use of the /api/csrf route to obtain a
    csrf_token and then /api/login route to authenticate under that token.
    Subsequent calls then use the authenticated token. The D&D NLI is open to the world, so this is not required.
    But if D&D were to run requiring a password, then it would be.
        
import requests
import json
host = 'https://c-phrase.com:8005'
auth = {
    'username':'rest-test',
    'password':'Mongoose-123'
}
s = requests.Session()
csrf_token = s.get(host + '/api/csrf').text
h = {'X-CSRFToken': csrf_token}
response = s.post(host + '/api/login', headers=h, json=auth)
session = json.loads(s.get(host + "/c-phrase/v1/session", headers=h).text)['session']
answer = json.loads(s.get(host + f"/c-phrase/v1/request?session={session}&text=lawful evil dragons with more than 300 hit points", headers=h).text)
print(answer['table-answer']['sql'])
answer = json.loads(s.get(host + f"/c-phrase/v1/request?session={session}&text=names of Chaotic Good or Chaotic Neutral Feys", headers=h).text)
print(answer['list-answer']['paraphrase'])
answer = json.loads(s.get(host + f"/c-phrase/v1/request?session={session}&text=average strength of fiends", headers=h).text)
print(answer['table-answer']['paraphrase'])
answer = json.loads(s.get(host + f"/c-phrase/v1/request?session={session}&text=Dragons taking non-standard damage", headers=h).text)
if 'choices' in answer:
    answer = json.loads(s.get(host + f"/c-phrase/v1/choice?session={session}&choice=2", headers=h).text)
    print(answer['table-answer']['rows'][0]['monster'])
answer = json.loads(s.get(host + f"/c-phrase/v1/request?session={session}&text=saskwatch", headers=h).text)
print(answer['error']['message'])
answer = json.loads(s.get(host + f"/c-phrase/v1/request?session={session}&text=how many monsters per type", headers=h).text)
print(answer['table-answer']['type'])
answer = json.loads(s.get(host + f"/c-phrase/v1/completions", headers=h).text)
print(answer)