2. Advanced topics¶
2.1. Queries¶
The part attributes you added in the Tutorial let you select parts with simple queries like tray=1
and color=green
.
However, more complex queries are also possible using Lookups and Complex boolean queries.
Lookups¶
Queries allow lookups, for instance number__gt=1
selects all parts whose number
is greater than 1.
The exact lookups that are created depend on the attribute’s datatype:
lookup |
datatypes |
description |
---|---|---|
lt |
NUMBER, DATETIME |
less than, e.g. copies__lt=2 means at most one copy |
gt |
NUMBER, DATETIME |
greater than, e.g. copies__gt=1 means at least two copies |
istartswith |
STRING |
case-insensitive starts with |
icontains |
STRING |
case-insensitive string containment test |
contains |
containment test, available when is_list=True |
These filters are also available for use in the part
endpoint, so you can for instance do:
response = api.part.get(tray=1, copies__lt=2)
Complex boolean queries¶
The query system mentioned above also allows complex compound queries using boolean operators:
operator |
description |
example |
---|---|---|
AND operator |
copies__lt=2+tray=1 |
|
OR operator |
copies__lt=2|tray=1 |
|
~ |
NOT operator |
~tray=1 |
() |
precedence copies__lt=2+(title__icontains=x|~tray=1) |
2.2. Endpoint Operations¶
The AM-Vision API supports the following on all endpoints:
POST-ing individual items
GET-ting individual items as well as multiple via querystring filters
PUT-ting items in bulk
DELETE-ing items in bulk.
GET querystring filtering¶
All endpoints support a degree of filtering on resource fields. for example GET /api/batch/?title__icontains=demo
.
Supported filters per endpoint are listed in the API reference.
PUT update-or-create¶
for the PUT operation, a list of items is given. Each item is looked up by its id. If it already exists, the item is updated. If it does not exist, the item is created.
DELETE with filters¶
for the DELETE operation, the same set of filters can be used as for the GET endpoint. objects matching the filters will then be deleted in one call.
Examples¶
Here are some example bulk operations:
# some update-or-create examples
api.batch_category.put([
{'id': 'by_tray', 'title': "View by tray"},
{'id': 'by_method', 'title': "View by method"}
])
api.query.put([
{'id': 'Green', 'query': 'dye=GREEN', 'sorting': True},
{'id': 'Black', 'query': 'dye=BLACK', 'sorting': True},
])
# some deletion examples
# delete the black and green query
api.query.delete(id='Black,Green')
# delete all parts with more than two copies
api.part.delete(copies__gt=1)
2.3. Webhooks¶
The AM-Vision API can let you know when certain events occur by doing a POST to an endpoint in your own API. The following events are supported:
Event |
Description |
---|---|
batch.start |
The operator started scanning a batch |
batch.end |
The operator stopped scanning a batch |
batch.reset |
The operator reset a batch (dropped existing assignments) |
batch.archive |
The operator archived a batch |
batch.unarchive |
The operator unarchived a batch |
batch.advance |
The operator advanced a batch |
scan.capture |
A scan was taken by the AM-Vision |
scan.reject |
A scan was rejected by the operator |
scan.assign |
A scan was assigned to a part by the operator or AM-Vision |
scan.unassign |
A scan was unassigned from a part by the operator |
You can subscribe to an event like this:
api.webhook.post({
'event': 'scan.assign',
'target': 'http://yourapi.com/on_scan_assigned/'
})
By default, the webhook POST will use the headers {"Content-Type": "application/json"}
.
But you can supply your own custom headers, for instance for authentication:
api.webhook.post({
'event': 'scan.assign',
'target': 'http://yourapi.com/on_scan_assigned/',
'headers': {
"Content-Type": "application/json",
"Authorization": "Token XYZ"
},
})
The content of the webhook is a serialization of the object that the event relates to, as well as a
summary of the webhook subscription. Here’s an example of a batch.advance
webhook (all batch-related webhooks look similar):
{
'hook': {
'id': 18,
'event': 'batch.advance',
'target': 'http://localhost:9000/test/'
},
'data': {
'url': '/api/batch/999/',
'created': '2022-01-19T12:05:16.655027+01:00',
'modified': '2022-01-19T12:10:30.787503+01:00',
'id': '999',
'title': '999_Hp5_201114',
'archived': false,
'finalized': false,
'category': None,
'query': 'job_id=999&prev_step=Printing',
'summary': {
'assigned': 3,
'reprinted': 0,
'parts': 3,
'unassigned_scans': 1,
'needs_processing': false,
'processing_status': 'READY',
'processing_ratio': 1.0,
'conflicted': 0,
'currently_scanning': None
},
'has_output_assignments': true,
'active_scan_session': '176719ae-29fb-4eb0-b41f-45f60e23f59d',
'auto_delete': false,
'attributes': {},
'contents': { ... }
}
}
Here’s an example of a scan.assign
webhook (all scan-related webhooks look similar):
{
'hook': {
'event': 'scan.assign',
'id': 8,
'target': 'http://localhost:9000/hook/'
},
'data': {
'url': '/api/scan/a208efd4-8e5a-11ec-a226-33350b016b70/',
'created': '2022-02-15T13:27:25.838162+01:00',
'modified': '2022-02-15T13:27:28.635543+01:00',
'uuid': 'a208efd4-8e5a-11ec-a226-33350b016b70'
'batch': {'id': 'demo_set_4', 'title': 'Demo set 4'},
'output': {'id': '1'},
'design_material': 'a1e76973c62d6c279aa7f50380fb713ac5cfb3b3_MTR_PRT_SLS_MAT_PA2200',
'scan_session': '6bc50ccc-d65a-47cb-88dc-3a66f441b167',
'assignment: {
'assigned_copies': 1,
'assignment': '30fbda68-7a2b-4b2d-a880-8ae7873792cc',
'last_added_copies': 1,
'total_copies': 1,
'design_material': 'a1e76973c62d6c279aa7f50380fb713ac5cfb3b3_MTR_PRT_SLS_MAT_PA2200',
'expected_copies': 1,
'part_id': 'demo-SLS_nema17_25mm_10___1',
'part_title': 'SLS_Nema17 25mm 10',
'reprint': False,
"reprint_comment":"None",
"reprint_reasons":[]
},
'scan_urls': [
'/data/scans/a208efd4-8e5a-11ec-a226-33350b016b70/scan_cam01.png',
'/data/scans/a208efd4-8e5a-11ec-a226-33350b016b70/scan_cam02.png',
'/data/scans/a208efd4-8e5a-11ec-a226-33350b016b70/scan_cam04.png',
'/data/scans/a208efd4-8e5a-11ec-a226-33350b016b70/scan_cam03.png',
'/data/scans/a208efd4-8e5a-11ec-a226-33350b016b70/scan_cam05.png'
],
'scan_urls_full': [
'/data/scans/a208efd4-8e5a-11ec-a226-33350b016b70/scan_cam01.full.png',
'/data/scans/a208efd4-8e5a-11ec-a226-33350b016b70/scan_cam02.full.png',
'/data/scans/a208efd4-8e5a-11ec-a226-33350b016b70/scan_cam04.full.png',
'/data/scans/a208efd4-8e5a-11ec-a226-33350b016b70/scan_cam03.full.png',
'/data/scans/a208efd4-8e5a-11ec-a226-33350b016b70/scan_cam05.full.png'
],
},
}
The main event of interest is probably batch.advance. The idea is that the operator explicitly marks a batch as finished and your API can then update the batch and parts. For instance by:
Moving the parts to the next processing step, and re-uploading them to the AM-Vision for the second round sorting.
Automatically reprinting parts when scan assignments have the ‘reprint’ field set.
Forwarding the camera images from the AM-Vision to your customers.
You can unsubscribe from webhook notifications by DELETE-ing your subscription (using the id sent in every webhook POST):
# equivalent to DELETE /api/webhook/8
api.webhook(8).delete()
2.4. Notifications¶
You can send notifications to the UI for important events or errors. Here are some examples:
api.notification.post({'title': "Running importer"})
api.notification.post({
'title': 'New batch uploaded',
'body': 'batch title',
'icon': 'fa fa-download',
'auto_close': True
})
api.notification.post({
'title': 'Error running importer',
'body': 'error message',
'icon': 'fa fa-exclamation-circle',
'auto_close': False
})
2.5. BatchCategories¶
BatchCategories are a simple way to categorize your batches, displayed as tabs in the AM-Vision UI. BatchCategories contain the following fields:
- id:
A unique slug id for the batch category
- title:
Human-readable title for the batch category
This example creates a single tab to batch_category batches by Print tray:
batch_categories = [
{
"id": "by_tray",
"title": "By Tray"
},
]
api.batch_category.put(batch_categories)
You can then place batches in this tab by specifying the batch_category
field in the batch definition.