Converse API quick start

Integrate the ability to chat with documents into your workflow with the Converse API.

With an AI Hub community account, you can use the API to create a new conversation, upload files to the conversation, and converse with the uploaded files. You can chain API calls together, such as in a script, for a complete workflow. The example scripts below are written in Python, but you can write them in any scripting language.

You can converse with up to 50 documents in a single conversation. Each document can be up to 50 MB or 800 pages in size, up to a total upload size of 100 MB.

Info

Conversations created with APIs and those created in the AI Hub user interface (UI) are incompatible. Interact with API-created conversations only by using the API. Similarly, don’t use APIs to interact with conversations created in the UI.

API authorization

To make calls to AI Hub APIs, you must define your API token and send it with your requests.

You can generate and manage API tokens from your AI Hub user settings. See the authorization documentation for details.

Add this token in the header wherever you are calling the API. The example below shows how you would add the API token to a Python script, specifying the token in the API_TOKEN variable.

Note

Commercial users must include an IB-Context header in all Converse API requests for the call to complete in the commercial context.

import os
import time
from typing import Dict, Text, Tuple
import requests
from requests import Response

API_TOKEN = 'ADD-YOUR-API-TOKEN-HERE'

API_BASE_URL = 'https://aihub.instabase.com/api/'
url = API_BASE_URL + 'v2/aihub/converse/conversations'
API_HEADERS = {
    'Authorization': f'Bearer {API_TOKEN}',
    'IB-Context': '<USER-ID or ORGANIZATION-ID>'
}

Creating a conversation with your files

To successfully create conversation and upload files, the script must contain:

  • Your API token.

  • The path to a local input folder containing the files that you want to upload. The input folder must contain at least one file.

    • You can upload up to 100 files to a single conversation.

    • Each file can be up to 50 MB or 800 pages in size, with up to 100 MB total in a single upload batch.

    • See limitations for complete information about storage and upload limits.

  • Files to be uploaded using the multipart/form-data protocol, with each file’s name as the key and the content of the file in bytes as the value.

  • Your organization and workspace names. You can find your user, workspace, and organization names in your settings. If you don’t provide the organization and workspace names, the conversation is created under your community profile, if you have one.

    • For community users, your organization is your <USER-ID> and your workspace is my-repo.

    • For commercial users, your organization is your <ORGANIZATION-ID> and your workspace is your <USER-ID>.

  • To enable checkbox and table extraction, set enable_object_detection to true.

When run, the example script below performs the following tasks:

  1. Creates the conversation.

  2. Uploads the files from the input folder to the conversation.

  3. Processes the files, digitizing and indexing them for the conversation.

  4. Returns conversation ID, conversation name, and upload status in JSON format.

# Creates Conversation, upload and process files
def create_conversation_and_add_files(files: Dict[Text, bytes], data: Dict[Text, Any]) -> Response:
  response = requests.post(url=url, headers=API_HEADERS, files=files, data=data)
  return response

local_folder_path = '<FILE_PATH_TO_INPUT_FOLDER>'
# file path to input folder, such as '/Users/vasudua/Documents/Sample docs'
# folder must contain at least one valid file

files: Dict[Text, bytes] = {}
for file in os.listdir(local_folder_path):
  complete_path = os.path.join(local_folder_path, file)
  files[file] = open(complete_path, 'rb')

data: Dict[Text, Any] = {}
data['org'] = '<ORGANIZATION-ID>'
data['workspace'] = '<WORKSPACE-ID>'
# Set enable_object_detection to 'true' to extract tables, checkboxes
data['enable_object_detection'] = 'false'
data['name'] = 'Sample Conversation'
data['description'] = 'Sample Description'

response = create_conversation_and_add_files(files, data)

if response.ok:
  resp_data = response.json()
  conversation_id = resp_data.get('id')
  if not conversation_id:
    print('Unable to create new conversation.')

  print(f'Response from create conversation : {resp_data}')

The sample response below returns the conversation ID, name, and status of file uploads in JSON format:

{
    "id": "f2ef9702-b018-4a45-9b2e-d1fb575b42ed",
    "name": "Conversation 2023-08-23 11:40:30.669832",
    "upload_status": {
        "success": [
            {
                "name": "img.pdf"
            },
            {
                "name": "file.pdf"
            }
        ],
        "failure": []
    }
}

Checking conversation status

After you’ve started a conversation, you can fetch the status of the conversation with the {API_BASE_URL}/v2/aihub/converse/conversations/{{id}} endpoint.

The example Python script makes a call to the Converse API to get the status of the conversation created in the previous step. To successfully get the status of the conversation, the script must contain:

  • Your API token.

  • The conversation ID that was returned when you created the conversation.

When run, the example script below gets the status of the conversation and returns the following information in JSON format:

  • id - Conversation ID.

  • name - Conversation name.

  • documents - Contains name and ID of the uploaded and processed files

  • state - The state of the conversation:

    • COMPLETE - ready to start a conversation.

    • FAILED - not able process any of the uploaded files.

    • RUNNING - still processing the uploaded files.

  • status - A readable status message.

def get_conversation_status(conversation_id: Text) -> Tuple[Dict, Text]:
  while True:
    response = requests.get(f'{url}/{conversation_id}', headers=API_HEADERS)
    if not response.ok:
        return None, f'Error getting conversation metadata : {response.text}'

    response_json = response.json()
    state = response_json.get('state')
    if not state:
        return None, f'Error getting state from conversation metadata : {response_json}'

    # If state of processing the documents is either COMPLETE or FAILED
    # stop polling and return.
    if state in ['COMPLETE', 'FAILED']:
      return response_json, None

    print('Documents still processing, please wait!')

    # If it is RUNNING, the script waits for 5 seconds before the next poll.
    time.sleep(5)

# Get the status of conversation
conversation_id = '<CONVERSATION_ID>'
response_json, err = get_conversation_status(conversation_id=conversation_id)
if err:
  print(f'Error occurred: {err}')

print(f'Conversation status : {response_json}')

The sample response response below returns conversation information and status:
{
    "id": "f2ef9702-b018-4a45-9b2e-d1fb575b42ed",
    "name": "Conversation 2023-08-23 11:40:30.669832",
    "description": "",
    "documents": [
        {
            "id": 15,
            "name": "file.pdf"
        },
        {
            "id": 16,
            "name": "img.pdf"
        }
    ],
    "state": "COMPLETE",
    "status": "Documents Processed"
}

Conversing with the document

After the conversation has been created, you can start conversing with the documents with the {API_BASE_URL}/v2/aihub/converse/conversations/{{id}}/prompts endpoint.

The example Python script makes a call to the AI Hub API to converse with the document. To successfully converse with the document, the script must contain:

  • Your API token.

  • The conversation ID returned when you created the conversation.

  • An input prompt. This can include any question or request supported by Converse, except for plot graphs. You must enclose the text of your request in single quotes.

  • document_ids - A document ID that was returned during the status check. You can converse with one document at a time. Document IDs are single integer values that you must pass as a list.

  • model - The default or advanced model.

When run, the example script queries the document with your question or request and returns the below information in JSON format:

  • prompt_id - Prompt ID.

  • answer - The output for the input prompt.

# The IBLLM model currently supports querying on one document at a time.
def ask_question(
    conversation_id: Text,
    query: Text,
    document_id: int,
    # default/advanced
    mode: Text = 'default') -> Text:
  payload = dict(
    question=query,
    document_ids=document_id,
    mode=mode)
  response = requests.post(f'{url}/{conversation_id}/prompts', json=payload, headers=API_HEADERS)
  if not response.ok:
    return None, f'Error occurred while asking a question : {response.text}'

  response_json = response.json()
  return response_json['answer'], None

conversation_id = '<CONVERSATION_ID>'
document_id = [<DOCUMENT_ID>]
answer, err = ask_question(conversation_id,
      'Extract the key details present in this document as a json',
      document_id=document_id
    )
if err:
  print(f'Error getting an answer for document with id {document_id}, error: {err}')

print(f'Answer for document with id {document_id}: {answer}')

The sample response below returns the key details from the document in JSON format:

{
   "prompt_id": "5b7057f8e3a04cc3a68e092bef78927e",
    "answer": "\n```json\n{\n  \"earnings\": [\n    {\n      \"type\": \"Salary\",\n      \"qty\": \"72:00\",\n      \"rate\": \"\",\n      \"current\": \"2,287.83\",\n      \"ytd\": \"42,960.31\",\n      \"amount\": \"1,652.88\",\n      \"direct_deposit\": {\n        \"type\": \"Checking\",\n        \"account_number\": \"*****7015\"\n      }\n    },\n    {\n      \"type\": \"Salary Vacation\",\n      \"qty\": \"8:00\",\n      \"rate\": \"\",\n      \"current\": \"254.20\",\n      \"ytd\": \"2,287.83\",\n      \"amount\": \"\"\n    },\n    {\n      \"type\": \"Hourly Vacation\",\n      \"qty\": \"\",\n      \"rate\": \"\",\n      \"current\": \"\",\n      \"ytd\": \"3,178.00\",\n      \"amount\": \"\"\n    },\n    {\n      \"type\": \"Holiday\",\n      \"qty\": \"\",\n      \"rate\": \"\",\n      \"current\": \"\",\n      \"ytd\": \"508.40\",\n      \"amount\": \"\"\n    }\n  ],\n  \"deductions\": [\n    {\n      \"type\": \"401k\",\n      \"gross\": \"\",\n      \"current\": \"-177.94\",\n      \"ytd\": \"-3,374.54\"\n    },\n    {\n      \"type\": \"Medicare Employee Addl Tax\",\n      \"gross\": \"\",\n      \"current\": \"0.00\",\n      \"ytd\": \"0.00\"\n    },\n    {\n      \"type\": \"Federal Withholding\",\n      \"gross\": \"\",\n      \"current\": \"-407.00\",\n      \"ytd\": \"-8,127.93\"\n    },\n    {\n      \"type\": \"Social Security Employee\",\n      \"gross\": \"\",\n      \"current\": \"-157.60\",\n      \"ytd\": \"-3,033.94\"\n    },\n    {\n      \"type\": \"Medicare Employee\",\n      \"gross\": \"\",\n      \"current\": \"-36.86\",\n      \"ytd\": \"-709.55\"\n    },\n    {\n      \"type\": \"AL-Withholding\",\n      \"gross\": \"\",\n      \"current\": \"-92.47\",\n      \"ytd\": \"-1,766.04\"\n    },\n    {\n      \"type\": \"EEVolLife\",\n      \"gross\": \"\",\n      \"current\": \"-17.28\",\n      \"ytd\": \"-311.04\"\n    }\n  ]\n}\n```\n"
}

Getting conversation details

You can fetch the details of all your API-created conversations with the {API_BASE_URL}/v2/aihub/converse/conversations endpoint.

The example Python script makes a call to the Converse API to get the details of all the conversations you’ve created with the API. To successfully get the details of the conversations, the script must contain your API token. You can fetch information about only the conversations you have created.

When run, the example script fetches and returns the following details for each conversation, in JSON format:

  • id - Conversation ID.

  • name - Conversation name.

  • description - Conversation description.

def get_conversations() -> Tuple[Dict, Text]:
  response = requests.get(f'{url}', headers=API_HEADERS)
  if not response.ok:
      return None, f'Error getting conversations : {response.text}'
  response_json = response.json()
  return response_json, None

# Get the details of the conversations created by a user
response_json, err = get_conversations()
if err:
  print(f'Error occurred: {err}')

print(f'Conversations : {response_json}')

The sample response below returns the conversation information and status:

{
    "conversations": [
        {
            "id": "66bd3eb8-36c7-4aaa-9f95-49c593add1e8",
            "name": "Conversation 2023-08-28 12:07:23.932130",
            "description": "Sample Conversation"
        },
        {
            "id": "7196d351-0302-4d67-9ce8-b06c3bec8709",
            "name": "Conversation 2023-08-28 12:09:50.449657",
            "description": ""
        }
    ]
}

Deleting conversations

You can delete conversations with the {API_BASE_URL}/v2/aihub/converse/conversations/{{id}} endpoint.

The example Python script below makes a call to the Converse API to delete a conversation. To successfully delete a conversation, the script must contain:

  • Your API token.

  • The conversation ID that needs to be deleted.

When run, the example script performs the following tasks:

  1. Deletes the conversation metadata from the database.

  2. Deletes the conversation index from the database.

  3. Deletes the conversation from the file system.

  4. Returns the delete status code 204 with no content.

# Delete conversation
def delete_conversation(
    conversation_id: Text) -> Text:
  response = requests.delete(f'{url}/{conversation_id}', headers=API_HEADERS)
  if not response.ok:
    return f'Error occurred while deleting conversation : {response.text}'
    return None
conversation_id = '<CONVERSATION_ID>'
err = delete_conversation(conversation_id)
if err:
  print(f'{err}')
else:
  print(f'Conversation - {conversation_id} deleted successfully')

Adding documents to a conversation

You can add documents to a conversation with the {API_BASE_URL}/v2/aihub/converse/conversations/{{id}}/documents endpoint.

The example Python script below makes a call to the Converse API to add a document to a conversation. To successfully add a document to an existing conversation, the script must contain:

  • Your API token.

  • The conversation ID to which you need to add a new document.

  • The path to a local input folder containing the files that you want to upload.

    • You can upload up to 50 files to a single conversation.

    • Each file can be up to 50 MB or 800 pages in size, up to a total upload size of 100 MB.

    • The input folder must contain at least one file.

  • Files to be uploaded using the multipart/form-data protocol, with each file’s name as the key and the content of the file in bytes as the value.

When run, the example script performs the following tasks:

  1. Uploads the files from the input folder to the conversation. The input folder must contain at least one valid file.

  2. Processes the files, digitizing and indexing them for the conversation.

  3. Returns the upload status of the files, in JSON format:

# Add a document to an existing conversation
def add_files_to_conversation(conversation_id: Text, files: Dict[Text, bytes]) -> Response:
  response = requests.post(f'{url}/{conversation_id}/documents', headers=API_HEADERS, files=files)
  return response

local_folder_path = '<FILE_PATH_TO_INPUT_FOLDER>'
# NOTE: The folder must contain at least one valid file, or the endpoint returns a 400 BAD REQUEST result.

files: Dict[Text, bytes] = {}
for file in os.listdir(local_folder_path):
  complete_path = os.path.join(local_folder_path, file)
  files[file] = open(complete_path, 'rb')

conversation_id = '<CONVERSATION_ID>'
response = add_files_to_conversation(conversation_id, files)
if response.ok:
  resp_data = response.json()
  print(f'Response from add new file to an existing conversation : {resp_data}')

The sample response below returns the status of file uploads in JSON format:

{
    "upload_status": {
        "success": [
            {
                "name": "w2.pdf"
            },
            {
                "name": "paystub.pdf"
            }
        ],
        "failure": []
    }
}

Deleting documents from a conversation

You can delete documents from a conversation with the {API_BASE_URL}/v2/aihub/converse/conversations/{{id}}/documents endpoint.

The example Python script below makes a call to the Converse API to delete documents from a conversation. To successfully delete a document from an existing conversation, the script must contain:

  • Your API token.

  • conversation_id: The conversation ID from which you need to delete a document.

  • ids: One or more document IDs, as an array, that were returned during the status check.

When run, the example script performs the following tasks:

  1. Deletes the document metadata from the database.

  2. Deletes the document index from the database.

  3. Deletes the document from the file system.

  4. Returns the delete status code 204 with no content.

# delete documents from conversation
def delete_document(
    conversation_id: Text,
    ids: List[int]) -> Text:
  payload = dict(
    ids=ids)
  response = requests.delete(f'{url}/{conversation_id}/documents', json=payload, headers=API_HEADERS)
  if not response.ok:
    return f'Error occurred while deleting documents : {response.text}'
  return None

conversation_id = '<CONVERSATION_ID'
ids = [<DOCUMENT_ID_1_>, <DOCUMENT_ID_2>]
err = delete_document(conversation_id,
                              ids=ids)
if err:
  print(f'{err}')
else:
  print(f'Documents {ids} deleted successfully')

Updating conversation information

You can update the name and description of a conversation with the {API_BASE_URL}/v2/aihub/converse/conversations/{{id}}?name={{name}}&description={{description}} endpoint.

The example Python script below makes a call to the Converse API to update the name and description of a conversation. To successfully update a conversation, the script must contain:

  • Your API token.

  • The conversation ID to be updated.

  • The name to be updated.

  • The description to be updated.

When run, the example script performs the following tasks:

  1. Updates the name and description of the conversation.

  2. Returns the response with 204 HTTP status code, indicating that the request has been successfully completed.

# Update an existing Conversation

def update_conversation(conversation_id: Text, name: Text, description: Text) -> Response:
  response = requests.put(f'{url}/{conversation_id}?name={name}&description={description}', headers=API_HEADERS)
  return response

conversation_id = '<CONVERSATION_ID>'
name = '<CONVERSATION_NAME>'
description = '<CONVERSATION_DESCRIPTION>'
response = update_conversation(conversation_id, name, description)
print (response)
if response.ok:
  print(f'Updated the conversation: {response}')

End-to-end example script

This example Python script shows a complete, end-to-end workflow based on calls to AI Hub APIs. Such a script must include the API token, as well as information about the folder to upload.

In this example, variables are used to specify the required information:

  • API_TOKEN: The API token you received from Instabase.

  • local_folder_path: The paths and filenames of the files you want to upload.

  • org: Organization under which to create the conversation.

  • workspace: Workspace under which to create the conversation.

  • name: The name of the conversation.

  • description: The description of the conversation.

When run, this script performs the following tasks:

  1. Creates a new conversation.

  2. Uploads and process the files added to the conversation.

  3. Gets the status of the conversation.

  4. Extracts the key details from the uploaded document in JSON format.

import os
import time
from typing import Dict, Text, Tuple
import requests
from requests import Response

url = 'https://aihub.instabase.com/api/v2/aihub/converse/conversations'
API_TOKEN = '<Your_bearer_token>'
local_folder_path = '/Users/vasudua/Documents/Sample docs'
conversation_name = 'sample conversation'
conversation_description = 'sample description'
org_id = '<ORGANIZATION-ID>'
workspace = '<WORKSPACE-ID>'

API_HEADERS = {
  'Authorization': f'Bearer {API_TOKEN}'
}

def create_conversation_and_add_files(files: Dict[Text, bytes], data: Dict[Text, Any]) -> Response:
  response = requests.post(url=url, headers=API_HEADERS, files=files, data=data)
  return response


def get_conversation_status(conversation_id: Text) -> Tuple[Dict, Text]:
  while True:
    response = requests.get(f'{url}/{conversation_id}', headers=API_HEADERS)
    if not response.ok:
      return None, f'Error getting conversation metadata : {response.text}'

    resp_data = response.json()

    state = resp_data.get('state')
    if not state:
      return None, f'Error getting state from conversation metadata : {resp_data}'

    # If state of processing the documents is either COMPLETE or FAILED
    # stop polling and return.
    if state in ['COMPLETE', 'FAILED']:
      return resp_data, None

    print('Documents still processing, please wait!')

    # If it is RUNNING, wait for 5 seconds before the next poll.
    time.sleep(5)

def ask_question(
    query: Text,
    document_id: int,
    # default/advanced
    mode: Text = 'default') -> Text:
  payload = dict(
    question=query,
    # The IBLLM model currently supports querying on one document at a time.
    document_ids=[document_id],
    mode=mode)
  response = requests.post(f'{url}/{conversation_id}/prompts', json=payload, headers=API_HEADERS)
  if not response.ok:
    return None, f'Error occurred while asking a question : {response.text}'

  resp_data = response.json()
  return resp_data['answer'], None

# filename to content map. Supports multiples files with each key as a unique filename
# and value as the content.
# NOTE: Adding at least one file is required, or the endpoint returns a 400 BAD REQUEST.
files: Dict[Text, bytes] = {}
for file in os.listdir(local_folder_path):
  complete_path = os.path.join(local_folder_path, file)
  files[file] = open(complete_path, 'rb')

data: Dict[Text, Any] = {}
data['org'] = org_id
data['workspace'] = workspace
# Set enable_object_detection to 'true' to extract tables, chckboxes
data['enable_object_detection'] = 'false'
data['name'] = conversation_name
data['description'] = conversation_description

response = create_conversation_and_add_files(files, data)
if response.ok:
  resp_data = response.json()
  conversation_id = resp_data.get('id')
  if not conversation_id:
    print('No conversation id found in response.')

  print(f'Response from CreateConversation : {resp_data}')

  # Get the status of conversation creation by querying the Conversation resource.
  resp_data, err = get_conversation_status(conversation_id=conversation_id)
  if err:
    print(f'Error occurred: {err}')

  print(f'Conversation Metadata and processing status : {resp_data}')

  documents = resp_data.get('documents')
  if not documents:
    print(f'Unable to get documents from response : {documents}')

  for document in documents:
    answer, err = ask_question(
      'Extract the key details present in this document as a json',
      document_id=document['id']
    )
    if err:
      print(f'Error getting an answer for document with id {document["id"]}, error: {err}')

    print(f'Answer for document with name `{document["name"]}`: {answer}')