Skip to main content

Chat Explore

Our Chat Explore endpoints allow you to interface with Chat Explore, our flagship "chat with your data" assistant. Our API allows a programmatic interface by which you can supply a project or dataset and a question you'd like to ask about it, and we'll respond with an answer.

As with most other long-running requests, we adopt an asynchronous endpoints model. You can read more about it on the Asynchronous Endpoints page or continue reading here.

caution

These endpoints are currently in beta and are subject to change as we refine them.

Custom Instructions

Chat Explore has the powerful capability for you to provide Custom Instructions that allow you to attach additional context for each call specific to your use case.

note

In order for Chat Explore to factor in custom instructions attached to the project into calls, you must make these calls with the project_id parameter rather than the dataset_id parameter.

Three parameters may be specified:

  • chatContext: What you'd like Chat Explore to know about your application to provide better responses. Examples:
    • This dataset is customer engagement data
    • The units of the sales column are in millions
  • chatInstructions: Specifics on how you'd like Chat Explore to respond. Examples:
    • Respond only in Spanish
    • Provide short and concise answers only
  • chatSuggestions: The Web UI (app.akkio.com) intelligently generates a list of example questions you may ask Chat Explore as a good starting point. You can customize these instructions by providing a newline-separated list of what you'd like these suggestions to be. Example:
    What is the average net media cost by campaign ID?
    Please show me a chart of the distribution of customer ages.
    Please show me a bar chart of company size.

For information on programmatically updating these parameters for a given project, see the Projects endpoints page.

Data Formatting

Images

Similar to the UI, we support returning charts and graphs to support our responses. Each message has an images field that represents a list of Base64-encoded images attached to that message.

note

Images are currently Base64 encoded in the .png format, but may be changed. You can assume a Base64-encoded image, but do not assume it will always be a .png image.

Tables

Tables are returned as a List of <string, value> maps, where each element of the list corresponds to a row, then each element has a key representing the column name and a value representing the value of that column.

For example, here's how a two-row table of user objects might look like:

[
{
"firstName": "John",
"lastName": "Doe",
"age": 23
},
{
"firstName": "Joanna",
"lastName": "Adams",
"age": 45
}
]

Corresponding to this table:

firstNamelastNameage
JohnDoe23
JoannaAdams45
note

Values can be anything JSON-serializable - strings, numbers, floats, and so on - not necessarily a string.

Statelessness

Requests to this API are stateless. To emulate a full conversation, simply take our response from your previous query and add it to the messages array of your next query. You do not need to explicitly pass any kind of reference to your last query.

Example Request Sequence

Here's a rough outline of how you'd make a request to the Chat Explore API.

HTTP Headers

Header NameRequiredValue
X-API-KeyYesYour team's API key. See Authentication.

1. Create Request

First, we'll submit a chat creation request. This will submit the task into our asynchronous processing queue and we'll begin working on it.

POST /api/v1/chat-explore/new

{
"project_id": "<your project id>",
"messages": [
{
"role": "user",
"content": "Please give me one cool chart of this data. Your choice."
}
]
}

You'll receive an object like this containing a task id:

{
"task_id": "<task_id>"
}

Or, as a cURL command:

curl -X POST https://api.akkio.com/api/v1/chat-explore/new \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{"project_id": "your_project_id", "messages": [ { "role": "user", "content": "Please give me one cool chart of this data. Your choice." } ] }'

We'll use this in the next request.

2. Query for Task Status

Next, we'll query the status endpoint at a cadence to see whether the chat is done being created yet. This request might look something like this:

GET /api/v1/chat-explore/status/<task_id>

Note that you must use the same Task ID that you received from the task creation endpoint above.

This will provide you with a status field set to either SUBMITTED, IN_PROGRESS, FAILED, or SUCCEEDED. You can read more about each state on the Asynchronous Endpoints page.

Here's an example response you might get:

{
"status": "IN_PROGRESS",
"metadata": {
"type": "IN_PROGRESS"
}
}

You should retry ("poll") this endpoint at a regular cadence until you get a response that looks something like this:

{
"status": "SUCCEEDED",
"metadata": {
"type": "SUCCEEDED",
"location": "/api/v1/chat-explore/chats/123456"
}
}
note

The location field is always relative to the API root (https://api.akkio.com/api/v1), not the overall website root (https://api.akkio.com). You'll need to remember to construct the end URL from the site name, API root, and the provided location.

Or, as a cURL command:

curl https://api.akkio.com/api/v1/chat-explore/status/task_id_from_previous_result \
-H "X-API-Key: your_api_key"

Armed with this information, we'll move to the last request.

3. Query for Result

Armed with the location we got from the status call, we'll make a request for the end chat.

GET /api/v1/chat-explore/chats/123456

note

If you're interested in the images returned and you would prefer it to be formatted as a string-serialized Plotly JSON object instead of the default base64-encoded .png, pass in a image_format=plotly_json query parameter, and they'll be returned as such.

You'll get a response that looks something like this:

{
"owner": "<owner id>",
"org": "<org id>",
"messages": [
{
"role": "assistant",
"content": "Let's create a scatter plot to visualize the relationship between the living area (in square feet) and the price of the properties.",
"images": null,
"table": null
},
{
"role": "assistant",
"content": "A chart or table will be rendered here. Chat Explore doesn't have direct access to your chart, so it can't read what's on it.",
"images": [
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAArwAAAH0CAYAAADfWf7fAAAgAElEQVR4XuydBZhUVRvH/7uzXXR3CSKolI0BIgooAtLd3d3d3SXd0goifGIrCijSXdLNdkzs97xnmGU2WO7szs5s/O/zfM+HO+eec+7vnJn7u+9977ku0dHR0eBGAiRAAiRAAiRAAiRAAumUgAuFN52OLA [...] AAASUVORK5CYII="
],
"table": null
}
]
}

Or, as a cURL command:

curl https://api.akkio.com/api/v1/chat-explore/chats/123456 \
-H "X-API-Key: your_api_key"

You can take this result and use it however you wish.

Programmatic Examples

We're working on building a set of programmatic wrapper SDKs that provides easy, prebuilt integration in a variety of languages, but here's some examples of how you might interface with this in Python!

Two files exist here -- chat-explore-api.py and utils.py. The first imports the second.

# File: `utils.py`
import time
import requests

API_KEY = None
BASE_URL = "api.akkio.com/api"
VERSION = "v1"
PROTOCOL = "https"
ENDPOINT = "chat-explore"


def create_chat_request(project_id, content):
"""
Make API request for chat creation

Returns:
dict: json response
"""

MODE = "new"

url = f"{PROTOCOL}://{BASE_URL}/{VERSION}/{ENDPOINT}/{MODE}"
headers = {"X-API-Key": API_KEY, "Content-Type": "application/json"}
data = {
"project_id": project_id,
"messages": [
{
"role": "user",
"content": content,
}
],
}

response = requests.post(
url,
json=data,
headers=headers,
timeout=120,
)

# Check for HTTP errors
response.raise_for_status()

return response.json()


def check_task_status(task_id):
"""
Check task status from Chat creation POST call

Returns:
dict: json response
"""

MODE = "status"

url = f"{PROTOCOL}://{BASE_URL}/{VERSION}/{ENDPOINT}/{MODE}/{task_id}"
headers = {"X-API-Key": API_KEY, "Content-Type": "application/json"}

response = requests.get(
url,
headers=headers,
timeout=120,
)

# Check for HTTP errors
response.raise_for_status()

return response.json()


def get_chat_results(chat_id):
"""
Get chat results based on chat_id

Returns:
dict: json response
"""

MODE = "chats"

url = f"{PROTOCOL}://{BASE_URL}/{VERSION}/{ENDPOINT}/{MODE}/{chat_id}"
headers = {"X-API-Key": API_KEY, "Content-Type": "application/json"}

response = requests.get(
url,
headers=headers,
timeout=120,
)

# Check for HTTP errors
response.raise_for_status()
return response.json()
# File: chat-explore-api.py
import json
import os
import time

import utils # the other file, provided above

# Setup
API_KEY = "<REPLACE ME>"

utils.API_KEY = API_KEY

# Directory to save responses
resp_directory = "chat_responses"
os.makedirs(resp_directory, exist_ok=True) # Ensure directory exists

# Get project ID from UI (is there any way to query a list of all projects in a Team?)
project_id = "<REPLACE ME>"

# This can get passed in from top level application
content = "Show me a report of spend by device for each placement in a bar chart"

creation_resp = utils.create_chat_request(project_id, content)
print(creation_resp)

task_id = creation_resp["task_id"]

# Set a timeout for 5 minutes (300 seconds)
timeout = 300
start_time = time.time() # Get the current time to measure against the timeout

# Loop until the task status is "SUCCEEDED"
while True:
status = utils.check_task_status(task_id)
print(status)
if status["status"] == "SUCCEEDED":
chat_id = status["metadata"]["location"].split("/chats/")[1]
chat_response = utils.get_chat_results(chat_id)

# File path with project_id and task_id
file_name = f"project_{project_id}_taskid_{task_id}.txt"
file_path = os.path.join(resp_directory, file_name)

# Save the response to a text file
with open(file_path, "w") as file:
json.dump(chat_response, file, indent=4)
print(f"Response saved to {file_path}")
break
elif status["status"] == "FAILED":
print("Task failed.")
break

elif time.time() - start_time > timeout:
print("Task timed out.")
break

# Wait for some time before checking again to avoid overwhelming the server
time.sleep(5) # Sleep for 5 seconds

Additional Resources