Python SDK (v2)

aitoai is the official Python client. It ships a client for the v2 API โ€” available since aitoai 0.7.0 โ€” alongside the v1 client, and a command-line tool. Every snippet on this page that talks to the sandbox runs as written.

Install

pip install aitoai

That installs the API clients only (requests, packaging, jsonschema, aiohttp, ndjson). The command-line tool, schema inference and file conversion need the dataframe toolchain, which is an extra (since aitoai 0.7.0):

pip install 'aitoai[cli]'

Pick the API version

Each API version has its own package, and its meaning never changes:

from aito.v2 import Client      # the v2 API
from aito.v1 import Client      # the v1 API

aito.Client is the default version, and moves only on a major release of the package: since aitoai 1.0.0 it is the v2 client (0.x: v1). It is fine for a quickstart; production code should import the version it means, so an SDK upgrade cannot change the API underneath it.

The pre-0.7 paths (aito.client.AitoClient, aito.client.v2.AitoClientV2, aito.api) were removed in aitoai 1.0.0: importing one raises an ImportError that names the replacement. To stay on the v1 API, from aito.v1 import Client, or pin aitoai<1.

Connect

from aito.v2 import Client

client = Client('https://shared.aito.ai/db/aito-demo',
                'yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi', env='v2')
print(client.get_version()['version'])

The first argument is the base URL of the database, not an endpoint. On a hosted, multi-database server that is the database URL (โ€ฆ/db/<name>); a self-hosted server holds a single database, so its base URL is the server itself, with no /db/ path:

from aito.v2 import Client

client = Client('http://127.0.0.1:9005', '<read-write-key>')   # the Docker image

Running locally? The base URL is http://127.0.0.1:9005, with no /db/โ€ฆ path (a /db/โ€ฆ URL returns 404 there). The key is the READ_WRITE_APIKEY you pinned with -e. If you started the container without keys, it generated a pair: read it from the volume with docker exec aito cat /io/state/.aito-api-keys. Do not rely on docker logs: from v2.11.2 the log shows the keys in full only on first boot, and masked after that.

env selects an environment; leave it out for master. The client checks the key on construction, so a wrong URL or key fails here rather than on the first query.

Query and predict

Each operation is a method that posts to its own endpoint and returns a parsed response. A predicted value is hit.value, its probability hit.probability:

from aito.v2 import Client

client = Client('https://shared.aito.ai/db/aito-demo',
                'yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi', env='v2')

res = client.predict(from_table='invoices',
                     where={'Description': {'$match': 'cloud services'}},
                     predict='GLCode', limit=3, why=True)
top = res.first
print(top.value, round(top.probability, 3))
print(top.why['type'])             # the explanation tree, as in the curl examples

rows = client.query({'from': 'products', 'where': {'name': {'$match': 'milk'}},
                     'select': ['name', 'price'], 'limit': 2})
for row in rows:
    print(row['name'], row['price'])

The other operations follow the same shape: search, recommend, match, relate, estimate, aggregate, evaluate and batch, plus query for any body the universal _query endpoint accepts (that is also the way to send an operation the client has no method for). get_schema() reads the schema, and delete_collection(name) drops a collection.

Errors and warnings

Errors carry the machine-readable code from the API, so you branch on the code rather than on the message text:

from aito.v2 import Client, Error

client = Client('https://shared.aito.ai/db/aito-demo',
                'yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi', env='v2')
try:
    client.predict(from_table='invoices', predict='no_such_field')
except Error as err:
    print(err.status_code, err.code)

Responses also carry the engine's non-fatal warnings โ€” the only signal that it answered a slightly different query than the one you sent (an unknown field in where, say). They are logged by default; on_warning='raise' makes them errors:

from aito.v2 import Client

client = Client('https://shared.aito.ai/db/aito-demo',
                'yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi', env='v2')
res = client.query({'from': 'invoices', 'where': {'no_such_column': 'x'}})
for warning in res.warnings:
    print(warning.code)

Load your own data

Writes need a read-write key for your own instance, because the sandbox is read-only. The quickest writable instance is the free Docker image, running on your own machine; hosted instances are provisioned on request (support@aito.ai). Declare a collection, upload rows in batches, then optimize once after the bulk load:

from aito.v2 import Client

client = Client('http://127.0.0.1:9005', '<read-write-key>')
# a hosted instance: Client('https://your-instance.aito.ai/db/your-db', '<read-write-key>')

client.create_collection('invoices', {
    'ProductName': {'type': 'Text', 'analyzer': 'english'},
    'Description': {'type': 'Text', 'analyzer': 'english'},
    'TotalAmount': {'type': 'Decimal'},
    'GLCode': {'type': 'String'},
})
client.upload_entries('invoices', rows, batch_size=1000)   # rows: a list of dicts
client.optimize('invoices')

The field names match the sandbox's invoices, so the predict call above works unchanged against your own instance once it holds rows.

To try a change without touching master, branch an environment with client.branch_env('staging') and point a client at it with env='staging'; see Environments. The SDK repository's examples/v2_quickstart.py does the whole round trip โ€” create, load, predict, explain, evaluate, drop.

Versions

aitoaiWhat changed for v2 users
0.6.0First v2 client (aito.client.v2.AitoClientV2)
0.7.0aito.v2 / aito.v1 packages and the default aito.Client; the CLI toolchain moved to the [cli] extra
1.0.0aito.Client is v2; the pre-0.7 import paths are removed (the CLI stays on v1 through 1.x)

The full history is in the changelog.