Removed API v1
This commit is contained in:
parent
dee77c295a
commit
5efd58f561
10 changed files with 0 additions and 1293 deletions
|
|
@ -1 +0,0 @@
|
||||||
from . import camera, stage, base, plugins, task
|
|
||||||
|
|
@ -1,253 +0,0 @@
|
||||||
from openflexure_microscope.api.utilities import gen, JsonResponse
|
|
||||||
from openflexure_microscope.api.views import MicroscopeView
|
|
||||||
|
|
||||||
from flask import Response, Blueprint, jsonify, request
|
|
||||||
import logging
|
|
||||||
|
|
||||||
|
|
||||||
class StreamAPI(MicroscopeView):
|
|
||||||
def get(self):
|
|
||||||
"""
|
|
||||||
Real-time MJPEG stream from the microscope camera
|
|
||||||
|
|
||||||
.. :quickref: State; Camera stream
|
|
||||||
|
|
||||||
:>header Accept: image/jpeg
|
|
||||||
:>header Content-Type: image/jpeg
|
|
||||||
:status 200: stream active
|
|
||||||
"""
|
|
||||||
# Restart stream worker thread
|
|
||||||
self.microscope.camera.start_worker()
|
|
||||||
|
|
||||||
return Response(
|
|
||||||
gen(self.microscope.camera),
|
|
||||||
mimetype="multipart/x-mixed-replace; boundary=frame",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SnapshotAPI(MicroscopeView):
|
|
||||||
def get(self):
|
|
||||||
"""
|
|
||||||
Single snapshot from the camera stream
|
|
||||||
|
|
||||||
.. :quickref: State; Camera snapshot
|
|
||||||
|
|
||||||
:>header Accept: image/jpeg
|
|
||||||
:>header Content-Type: image/jpeg
|
|
||||||
:status 200: stream active
|
|
||||||
"""
|
|
||||||
# Restart stream worker thread
|
|
||||||
self.microscope.camera.start_worker()
|
|
||||||
|
|
||||||
return Response(self.microscope.camera.get_frame(), mimetype="image/jpeg")
|
|
||||||
|
|
||||||
|
|
||||||
class StateAPI(MicroscopeView):
|
|
||||||
def get(self):
|
|
||||||
"""
|
|
||||||
JSON representation of the microscope object.
|
|
||||||
|
|
||||||
.. :quickref: State; Microscope state
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
GET /state/ HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
**Example response**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
HTTP/1.1 200 OK
|
|
||||||
Vary: Accept
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"camera": {
|
|
||||||
"preview_active": false,
|
|
||||||
"record_active": false,
|
|
||||||
"stream_active": true
|
|
||||||
},
|
|
||||||
"plugin": {},
|
|
||||||
"stage": {
|
|
||||||
"backlash": {
|
|
||||||
"x": 128,
|
|
||||||
"y": 128,
|
|
||||||
"z": 128
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"x": -8080,
|
|
||||||
"y": 5665,
|
|
||||||
"z": -12600
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
:>header Content-Type: application/json
|
|
||||||
:status 200: state available
|
|
||||||
"""
|
|
||||||
return jsonify(self.microscope.state)
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigAPI(MicroscopeView):
|
|
||||||
def get(self):
|
|
||||||
"""
|
|
||||||
JSON representation of the microscope config.
|
|
||||||
|
|
||||||
.. :quickref: Config; Get microscope config
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
GET /config/ HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
**Example response**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
HTTP/1.1 200 OK
|
|
||||||
Vary: Accept
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"id": "0e2c6fac5421429aac67c7903107bdd8",
|
|
||||||
"name": "docuscope-2000",
|
|
||||||
"fov": [4100, 3146],
|
|
||||||
"camera_settings": {
|
|
||||||
"image_resolution": [2592, 1944],
|
|
||||||
"numpy_resolution": [1312, 976],
|
|
||||||
"video_resolution": [832, 624],
|
|
||||||
"jpeg_quality": 75,
|
|
||||||
"picamera_settings": {
|
|
||||||
"analog_gain": 1.0,
|
|
||||||
"digital_gain": 1.0,
|
|
||||||
"awb_gains": [0.92578125, 2.94921875],
|
|
||||||
"awb_mode": "off",
|
|
||||||
"exposure_mode": "off",
|
|
||||||
"framerate": 24.0,
|
|
||||||
"saturation": 0,
|
|
||||||
"shutter_speed": 5378
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"stage_settings": {
|
|
||||||
"backlash": {
|
|
||||||
"x": 256,
|
|
||||||
"y": 256,
|
|
||||||
"z": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"plugins": [
|
|
||||||
"openflexure_microscope.plugins.default.autofocus:AutofocusPlugin",
|
|
||||||
"openflexure_microscope.plugins.default.scan:ScanPlugin",
|
|
||||||
"openflexure_microscope.plugins.default.camera_calibration:Plugin"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
:>header Content-Type: application/json
|
|
||||||
:status 200: state available
|
|
||||||
"""
|
|
||||||
return jsonify(self.microscope.read_settings(json_safe=True))
|
|
||||||
|
|
||||||
def post(self):
|
|
||||||
"""
|
|
||||||
Modify microscope configuration
|
|
||||||
|
|
||||||
.. :quickref: Config; Set microscope config
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
POST /config HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"id": "0e2c6fac5421429aac67c7903107bdd8",
|
|
||||||
"name": "docuscope-2000",
|
|
||||||
"fov": [4100, 3146],
|
|
||||||
"camera_settings": {
|
|
||||||
"image_resolution": [2592, 1944],
|
|
||||||
"numpy_resolution": [1312, 976],
|
|
||||||
"video_resolution": [832, 624],
|
|
||||||
"jpeg_quality": 75,
|
|
||||||
"picamera_settings": {
|
|
||||||
"analog_gain": 1.0,
|
|
||||||
"digital_gain": 1.0,
|
|
||||||
"awb_gains": [0.92578125, 2.94921875],
|
|
||||||
"awb_mode": "off",
|
|
||||||
"exposure_mode": "off",
|
|
||||||
"framerate": 24.0,
|
|
||||||
"saturation": 0,
|
|
||||||
"shutter_speed": 5378
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"stage_settings": {
|
|
||||||
"backlash": {
|
|
||||||
"x": 256,
|
|
||||||
"y": 256,
|
|
||||||
"z": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"plugins": [
|
|
||||||
"openflexure_microscope.plugins.default.autofocus:AutofocusPlugin",
|
|
||||||
"openflexure_microscope.plugins.default.scan:ScanPlugin",
|
|
||||||
"openflexure_microscope.plugins.default.camera_calibration:Plugin"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:<json string id: Unique string identifier of the microscope.
|
|
||||||
:<json string name: Friendly name for the microscope
|
|
||||||
:<json array fov: Field of view (motor steps per full width and height of frame)
|
|
||||||
:<json json camera_settings: - **image_resolution** *(array)*: Resolution of full image captures
|
|
||||||
- **numpy_resolution** *(array)*: Resolution of full numpy array captures
|
|
||||||
- **video_resolution** *(array)*: Resolution of video recordings, low res image captures, and the preview stream
|
|
||||||
- **jpeg_quality** *(int)*: Quality in which to store JPEG capture data
|
|
||||||
- **picamera_settings** *(json)*: Key-value pairs to apply directly to any attached PiCamera object
|
|
||||||
:<json json stage_settings: - **backlash** *(json)*: x, y, and z backlash compensation, in motor steps
|
|
||||||
:<json array plugins: Array of plugin paths to load. Requires reloading the microscope object after applying
|
|
||||||
|
|
||||||
:<header Content-Type: application/json
|
|
||||||
:status 200: capture created
|
|
||||||
|
|
||||||
"""
|
|
||||||
payload = JsonResponse(request)
|
|
||||||
|
|
||||||
logging.debug("Updating settings from POST request:")
|
|
||||||
logging.debug(payload.json)
|
|
||||||
|
|
||||||
self.microscope.apply_settings(payload.json)
|
|
||||||
self.microscope.save_settings()
|
|
||||||
|
|
||||||
return jsonify(self.microscope.read_settings(json_safe=True))
|
|
||||||
|
|
||||||
|
|
||||||
def construct_blueprint(microscope_obj):
|
|
||||||
|
|
||||||
blueprint = Blueprint("base_blueprint", __name__)
|
|
||||||
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/stream", view_func=StreamAPI.as_view("stream", microscope=microscope_obj)
|
|
||||||
)
|
|
||||||
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/snapshot",
|
|
||||||
view_func=SnapshotAPI.as_view("snapshot", microscope=microscope_obj),
|
|
||||||
)
|
|
||||||
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/state", view_func=StateAPI.as_view("state", microscope=microscope_obj)
|
|
||||||
)
|
|
||||||
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/config", view_func=ConfigAPI.as_view("config", microscope=microscope_obj)
|
|
||||||
)
|
|
||||||
|
|
||||||
return blueprint
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
from flask import Blueprint
|
|
||||||
|
|
||||||
from . import capture, preview, function
|
|
||||||
|
|
||||||
|
|
||||||
def construct_blueprint(microscope_obj):
|
|
||||||
|
|
||||||
blueprint = Blueprint("camera_blueprint", __name__)
|
|
||||||
|
|
||||||
# Tag routes
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/capture/<capture_id>/tags",
|
|
||||||
view_func=capture.TagsAPI.as_view("capture_tags", microscope=microscope_obj),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Capture routes
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/capture/<capture_id>/download/<filename>",
|
|
||||||
view_func=capture.DownloadAPI.as_view(
|
|
||||||
"capture_download", microscope=microscope_obj
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/capture/<capture_id>/download",
|
|
||||||
view_func=capture.DownloadRedirectAPI.as_view(
|
|
||||||
"capture_download_redirect", microscope=microscope_obj
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/capture/<capture_id>/",
|
|
||||||
view_func=capture.CaptureAPI.as_view("capture", microscope=microscope_obj),
|
|
||||||
)
|
|
||||||
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/capture/",
|
|
||||||
view_func=capture.ListAPI.as_view("capture_list", microscope=microscope_obj),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Preview routes
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/preview/<string:operation>",
|
|
||||||
view_func=preview.GPUPreviewAPI.as_view(
|
|
||||||
"gpu_preview", microscope=microscope_obj
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Function routes
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/overlay",
|
|
||||||
view_func=function.OverlayAPI.as_view("overlay", microscope=microscope_obj),
|
|
||||||
)
|
|
||||||
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/zoom", view_func=function.ZoomAPI.as_view("zoom", microscope=microscope_obj)
|
|
||||||
)
|
|
||||||
|
|
||||||
return blueprint
|
|
||||||
|
|
@ -1,459 +0,0 @@
|
||||||
from openflexure_microscope.api.utilities import get_bool, JsonResponse
|
|
||||||
from openflexure_microscope.api.views import MicroscopeView
|
|
||||||
from openflexure_microscope.utilities import filter_dict
|
|
||||||
|
|
||||||
from flask import jsonify, request, abort, url_for, redirect, send_file
|
|
||||||
|
|
||||||
|
|
||||||
class ListAPI(MicroscopeView):
|
|
||||||
def get(self):
|
|
||||||
"""
|
|
||||||
Get list of image captures.
|
|
||||||
|
|
||||||
.. :quickref: Captures; Get collection of captures
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
:query include_unavailable: return json representations of captures that have been completely deleted
|
|
||||||
|
|
||||||
:>jsonarr boolean available: availability of capture data
|
|
||||||
:>jsonarr string filename: filename of capture
|
|
||||||
:>jsonarr string id: unique id of the capture object
|
|
||||||
:>jsonarr boolean keep_on_disk: keep the capture file on microscope after closing
|
|
||||||
:>jsonarr boolean locked: file locked for modifications (mostly used for video recording)
|
|
||||||
:>jsonarr string path: path on pi storage to the capture file, if available
|
|
||||||
:>jsonarr boolean stream: capture stored in-memory as a BytesIO stream
|
|
||||||
:>jsonarr json uri: - **download** *(string)*: api uri to the capture file download
|
|
||||||
- **state** *(string)*: api uri to the capture json representation
|
|
||||||
|
|
||||||
:>header Content-Type: application/json
|
|
||||||
:status 200: capture found
|
|
||||||
:status 404: no capture found with that id
|
|
||||||
"""
|
|
||||||
include_unavailable = get_bool(request.args.get("include_unavailable"))
|
|
||||||
|
|
||||||
if include_unavailable:
|
|
||||||
captures = [image.state for image in self.microscope.camera.images]
|
|
||||||
else:
|
|
||||||
captures = [
|
|
||||||
image.state
|
|
||||||
for image in self.microscope.camera.images
|
|
||||||
if image.state["available"]
|
|
||||||
]
|
|
||||||
|
|
||||||
return jsonify(captures)
|
|
||||||
|
|
||||||
def delete(self):
|
|
||||||
"""
|
|
||||||
Delete all captures (not yet implemented)
|
|
||||||
|
|
||||||
.. :quickref: Captures; Delete all captures
|
|
||||||
"""
|
|
||||||
for image in self.microscope.camera.images:
|
|
||||||
image.delete()
|
|
||||||
|
|
||||||
captures = [image.state for image in self.microscope.camera.images]
|
|
||||||
|
|
||||||
return jsonify(captures)
|
|
||||||
|
|
||||||
def post(self):
|
|
||||||
"""
|
|
||||||
Create a new image capture.
|
|
||||||
|
|
||||||
.. :quickref: Captures; New capture
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
POST /camera/capture HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"filename": "myfirstcapture",
|
|
||||||
"temporary": false,
|
|
||||||
"use_video_port": true,
|
|
||||||
"bayer": true,
|
|
||||||
"size": {
|
|
||||||
"width": 640,
|
|
||||||
"height": 480
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:<json string filename: filename of stored capture
|
|
||||||
:<json boolean temporary: delete the capture file on microscope after closing
|
|
||||||
:<json boolean use_video_port: capture still image from the video port
|
|
||||||
:<json boolean bayer: keep raw capture data in the image file
|
|
||||||
:<json json size: - **x** *(int)*: x-axis resize
|
|
||||||
- **y** *(int)*: y-axis resize
|
|
||||||
|
|
||||||
:>json boolean available: availability of capture data
|
|
||||||
:>json string filename: filename of capture
|
|
||||||
:>json string id: unique id of the capture object
|
|
||||||
:>json boolean temporary: delete the capture file on microscope after closing
|
|
||||||
:>json boolean locked: file locked for modifications (mostly used for video recording)
|
|
||||||
:>json string path: path on pi storage to the capture file, if available
|
|
||||||
:>json boolean stream: capture stored in-memory as a BytesIO stream
|
|
||||||
:>json json uri: - **download** *(string)*: api uri to the capture file download
|
|
||||||
- **state** *(string)*: api uri to the capture json representation
|
|
||||||
|
|
||||||
:<header Content-Type: application/json
|
|
||||||
:status 200: capture created
|
|
||||||
"""
|
|
||||||
payload = JsonResponse(request)
|
|
||||||
|
|
||||||
filename = payload.param("filename")
|
|
||||||
temporary = payload.param("temporary", default=False, convert=bool)
|
|
||||||
use_video_port = payload.param("use_video_port", default=False, convert=bool)
|
|
||||||
bayer = payload.param("bayer", default=True, convert=bool)
|
|
||||||
metadata = payload.param("metadata", default={}, convert=dict)
|
|
||||||
tags = payload.param("tags", default=[], convert=list)
|
|
||||||
|
|
||||||
resize = payload.param("size", default=None)
|
|
||||||
if resize:
|
|
||||||
if ("width" in resize) and ("height" in resize):
|
|
||||||
resize = (
|
|
||||||
int(resize["width"]),
|
|
||||||
int(resize["height"]),
|
|
||||||
) # Convert dict to tuple
|
|
||||||
else:
|
|
||||||
abort(404)
|
|
||||||
|
|
||||||
# Explicitally acquire lock (prevents empty files being created if lock is unavailable)
|
|
||||||
with self.microscope.camera.lock:
|
|
||||||
output = self.microscope.camera.new_image(
|
|
||||||
temporary=temporary, filename=filename
|
|
||||||
)
|
|
||||||
|
|
||||||
self.microscope.camera.capture(
|
|
||||||
output.file, use_video_port=use_video_port, resize=resize, bayer=bayer
|
|
||||||
)
|
|
||||||
|
|
||||||
# Inject system metadata
|
|
||||||
system_metadata = {
|
|
||||||
"microscope_settings": self.microscope.read_settings(),
|
|
||||||
"microscope_state": self.microscope.state,
|
|
||||||
"microscope_id": self.microscope.id,
|
|
||||||
"microscope_name": self.microscope.name,
|
|
||||||
}
|
|
||||||
output.system_metadata.update(system_metadata)
|
|
||||||
|
|
||||||
# Insert custom metadata
|
|
||||||
output.put_metadata(metadata)
|
|
||||||
|
|
||||||
# Insert custom tags
|
|
||||||
output.put_tags(tags)
|
|
||||||
|
|
||||||
return jsonify(output.state)
|
|
||||||
|
|
||||||
|
|
||||||
class CaptureAPI(MicroscopeView):
|
|
||||||
def get(self, capture_id):
|
|
||||||
"""
|
|
||||||
Get JSON representation of a capture
|
|
||||||
|
|
||||||
.. :quickref: Capture; Get capture
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
GET /camera/capture/d0b2067abbb946f19351e075c5e7cd5b/ HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
**Example response**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
HTTP/1.1 200 OK
|
|
||||||
Vary: Accept
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"available": true,
|
|
||||||
"bytestream": false,
|
|
||||||
"keep_on_disk": false,
|
|
||||||
"locked": false,
|
|
||||||
"metadata": {
|
|
||||||
"filename": "2018-11-16_10-21-53.jpeg",
|
|
||||||
"id": "d0b2067abbb946f19351e075c5e7cd5b",
|
|
||||||
"path": "capture/2018-11-16_10-21-53.jpeg",
|
|
||||||
"time": "2018-11-16_10-21-53"
|
|
||||||
}
|
|
||||||
"uri": {
|
|
||||||
"download": "/api/v1/capture/d0b2067abbb946f19351e075c5e7cd5b/download",
|
|
||||||
"state": "/api/v1/capture/d0b2067abbb946f19351e075c5e7cd5b/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:>json boolean available: availability of capture data
|
|
||||||
:>json string filename: filename of capture
|
|
||||||
:>json string id: unique id of the capture object
|
|
||||||
:>json boolean keep_on_disk: keep the capture file on microscope after closing
|
|
||||||
:>json boolean locked: file locked for modifications (mostly used for video recording)
|
|
||||||
:>json string path: path on pi storage to the capture file, if available
|
|
||||||
:>json boolean stream: capture stored in-memory as a BytesIO stream
|
|
||||||
:>json json uri: - **download** *(string)*: api uri to the capture file download
|
|
||||||
- **state** *(string)*: api uri to the capture json representation
|
|
||||||
|
|
||||||
"""
|
|
||||||
capture_obj = self.microscope.camera.image_from_id(capture_id)
|
|
||||||
|
|
||||||
if not capture_obj:
|
|
||||||
return abort(404) # 404 Not Found
|
|
||||||
|
|
||||||
# Get capture state
|
|
||||||
capture_metadata = capture_obj.state
|
|
||||||
|
|
||||||
# Add API routes to returned state
|
|
||||||
uri_dict = {
|
|
||||||
"uri": {
|
|
||||||
"state": "{}".format(url_for(".capture", capture_id=capture_obj.id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# If available, also add download link
|
|
||||||
if capture_metadata["available"]:
|
|
||||||
uri_dict["uri"]["download"] = "{}download/{}".format(
|
|
||||||
url_for(".capture", capture_id=capture_obj.id), capture_obj.filename
|
|
||||||
)
|
|
||||||
|
|
||||||
capture_metadata.update(uri_dict)
|
|
||||||
|
|
||||||
return jsonify(capture_metadata)
|
|
||||||
|
|
||||||
def delete(self, capture_id):
|
|
||||||
"""
|
|
||||||
Delete all capture data from the Pi, even if `keep_on_disk=true;`.
|
|
||||||
|
|
||||||
.. :quickref: Capture; Delete capture.
|
|
||||||
"""
|
|
||||||
capture_obj = self.microscope.camera.image_from_id(capture_id)
|
|
||||||
|
|
||||||
if not capture_obj:
|
|
||||||
return abort(404) # 404 Not Found
|
|
||||||
|
|
||||||
capture_obj.delete()
|
|
||||||
|
|
||||||
return jsonify({"return": capture_id})
|
|
||||||
|
|
||||||
def put(self, capture_id):
|
|
||||||
"""
|
|
||||||
Add arbitrary metadata to the capture
|
|
||||||
|
|
||||||
.. :quickref: Capture; Update capture metadata
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
PUT /camera/capture/d0b2067abbb946f19351e075c5e7cd5b HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"user_id": "ofm_1234",
|
|
||||||
"patient_number": 1452,
|
|
||||||
}
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:<header Content-Type: application/json
|
|
||||||
:status 200: metadata updated
|
|
||||||
"""
|
|
||||||
|
|
||||||
capture_obj = self.microscope.camera.image_from_id(capture_id)
|
|
||||||
|
|
||||||
if not capture_obj:
|
|
||||||
return abort(404) # 404 Not Found
|
|
||||||
|
|
||||||
data_dict = JsonResponse(request).json
|
|
||||||
|
|
||||||
capture_obj.put_metadata(data_dict)
|
|
||||||
|
|
||||||
capture_metadata = capture_obj.state
|
|
||||||
|
|
||||||
return jsonify(capture_metadata)
|
|
||||||
|
|
||||||
|
|
||||||
class DownloadRedirectAPI(MicroscopeView):
|
|
||||||
def get(self, capture_id):
|
|
||||||
"""
|
|
||||||
Return image data for a capture.
|
|
||||||
|
|
||||||
Return capture data as an image file with the requested filename.
|
|
||||||
I.e., `/(capture_id)/download/foo.jpeg` will download the image as
|
|
||||||
`foo.jpeg`, regardless of the capture's initially set filename.
|
|
||||||
|
|
||||||
Route automatically redirects to download the capture under it's currently set filename.
|
|
||||||
I.e., `/(capture_id)/download` will
|
|
||||||
redirect to `/(capture_id)/download/(filename)`.
|
|
||||||
|
|
||||||
.. :quickref: Capture; Download capture image
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
GET /camera/capture/d0b2067abbb946f19351e075c5e7cd5b/download/2018-11-20_16-04-17.jpeg HTTP/1.1
|
|
||||||
Accept: image/jpeg
|
|
||||||
|
|
||||||
:>header Accept: image/jpeg
|
|
||||||
:query thumbnail: return an image thumbnail e.g. ?thumbnail=true
|
|
||||||
|
|
||||||
:>header Content-Type: image/jpeg
|
|
||||||
:status 200: capture data found
|
|
||||||
:status 404: no capture found with that id
|
|
||||||
|
|
||||||
"""
|
|
||||||
capture_obj = self.microscope.camera.image_from_id(capture_id)
|
|
||||||
|
|
||||||
if not capture_obj or not capture_obj.state["available"]:
|
|
||||||
return abort(404) # 404 Not Found
|
|
||||||
|
|
||||||
thumbnail = get_bool(request.args.get("thumbnail"))
|
|
||||||
|
|
||||||
return redirect(
|
|
||||||
url_for(
|
|
||||||
".capture_download",
|
|
||||||
capture_id=capture_id,
|
|
||||||
filename=capture_obj.filename,
|
|
||||||
thumbnail=thumbnail,
|
|
||||||
),
|
|
||||||
code=307,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class DownloadAPI(MicroscopeView):
|
|
||||||
def get(self, capture_id, filename):
|
|
||||||
|
|
||||||
capture_obj = self.microscope.camera.image_from_id(capture_id)
|
|
||||||
|
|
||||||
if not capture_obj or not capture_obj.state["available"]:
|
|
||||||
return abort(404) # 404 Not Found
|
|
||||||
|
|
||||||
thumbnail = get_bool(request.args.get("thumbnail"))
|
|
||||||
|
|
||||||
# If no filename is specified, redirect to the capture's currently set filename
|
|
||||||
if not filename:
|
|
||||||
return redirect(
|
|
||||||
url_for(
|
|
||||||
"capture_download",
|
|
||||||
capture_id=capture_id,
|
|
||||||
filename=capture_obj.filename,
|
|
||||||
thumbnail=thumbnail,
|
|
||||||
),
|
|
||||||
code=307,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Download the image data using the requested filename
|
|
||||||
if thumbnail:
|
|
||||||
img = capture_obj.thumbnail
|
|
||||||
else:
|
|
||||||
img = capture_obj.data
|
|
||||||
|
|
||||||
return send_file(img, mimetype="image/jpeg")
|
|
||||||
|
|
||||||
|
|
||||||
class TagsAPI(MicroscopeView):
|
|
||||||
def get(self, capture_id):
|
|
||||||
"""
|
|
||||||
Return tag list for a capture.
|
|
||||||
|
|
||||||
.. :quickref: Capture; Show capture tags
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
GET /camera/capture/d0b2067abbb946f19351e075c5e7cd5b/tags HTTP/1.1
|
|
||||||
Accept: text/json
|
|
||||||
|
|
||||||
:>header Accept: text/json
|
|
||||||
|
|
||||||
:>header Content-Type: text/json
|
|
||||||
:status 200: capture data found
|
|
||||||
:status 404: no capture found with that id
|
|
||||||
"""
|
|
||||||
capture_obj = self.microscope.camera.image_from_id(capture_id)
|
|
||||||
|
|
||||||
if not capture_obj or not capture_obj.state["available"]:
|
|
||||||
return abort(404) # 404 Not Found
|
|
||||||
|
|
||||||
metadata_tags = filter_dict(capture_obj.state, ["metadata", "tags"])
|
|
||||||
|
|
||||||
return jsonify(metadata_tags)
|
|
||||||
|
|
||||||
def put(self, capture_id):
|
|
||||||
"""
|
|
||||||
Add tags to the capture
|
|
||||||
|
|
||||||
.. :quickref: Capture; Update capture tags
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
PUT /camera/capture/d0b2067abbb946f19351e075c5e7cd5b/tags HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
["tests", "mytag", "someothertag"]
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:<header Content-Type: application/json
|
|
||||||
:status 200: metadata updated
|
|
||||||
"""
|
|
||||||
|
|
||||||
capture_obj = self.microscope.camera.image_from_id(capture_id)
|
|
||||||
|
|
||||||
if not capture_obj or not capture_obj.state["available"]:
|
|
||||||
return abort(404) # 404 Not Found
|
|
||||||
|
|
||||||
data_dict = JsonResponse(request).json
|
|
||||||
|
|
||||||
if type(data_dict) != list:
|
|
||||||
return abort(400)
|
|
||||||
|
|
||||||
capture_obj.put_tags(data_dict)
|
|
||||||
|
|
||||||
metadata_tags = filter_dict(capture_obj.state, ["metadata", "tags"])
|
|
||||||
|
|
||||||
return jsonify(metadata_tags)
|
|
||||||
|
|
||||||
def delete(self, capture_id):
|
|
||||||
"""
|
|
||||||
Delete tags from the capture
|
|
||||||
|
|
||||||
.. :quickref: Capture; Delete tags.
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
DELETE /camera/capture/d0b2067abbb946f19351e075c5e7cd5b/tags HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
["tests", "mytag"]
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:<header Content-Type: application/json
|
|
||||||
:status 200: metadata updated
|
|
||||||
"""
|
|
||||||
capture_obj = self.microscope.camera.image_from_id(capture_id)
|
|
||||||
|
|
||||||
if not capture_obj:
|
|
||||||
return abort(404) # 404 Not Found
|
|
||||||
|
|
||||||
data_dict = JsonResponse(request).json
|
|
||||||
|
|
||||||
if type(data_dict) != list:
|
|
||||||
return abort(400)
|
|
||||||
|
|
||||||
for tag in data_dict:
|
|
||||||
capture_obj.delete_tag(str(tag))
|
|
||||||
|
|
||||||
metadata_tags = filter_dict(capture_obj.state, ["metadata", "tags"])
|
|
||||||
|
|
||||||
return jsonify(metadata_tags)
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
from openflexure_microscope.api.views import MicroscopeView
|
|
||||||
from openflexure_microscope.api.utilities import JsonResponse
|
|
||||||
|
|
||||||
from flask import jsonify, request
|
|
||||||
|
|
||||||
|
|
||||||
class ZoomAPI(MicroscopeView):
|
|
||||||
def get(self):
|
|
||||||
"""
|
|
||||||
Get the current zoom value
|
|
||||||
|
|
||||||
.. :quickref: Zoom; Get the zoom value
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:<header Content-Type: application/json
|
|
||||||
:status 200: preview started/stopped
|
|
||||||
"""
|
|
||||||
zoom_value = self.microscope.camera.status["zoom_value"]
|
|
||||||
|
|
||||||
return jsonify({"zoom_value": zoom_value})
|
|
||||||
|
|
||||||
def post(self):
|
|
||||||
"""
|
|
||||||
Change the current zoom value
|
|
||||||
|
|
||||||
.. :quickref: Zoom; Set the zoom value
|
|
||||||
|
|
||||||
**Example requests**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
POST /camera/zoom HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"zoom_value": 2.5,
|
|
||||||
}
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:<header Content-Type: application/json
|
|
||||||
:status 200: preview started/stopped
|
|
||||||
"""
|
|
||||||
payload = JsonResponse(request)
|
|
||||||
zoom_value = payload.param("zoom_value", default=1.0, convert=float)
|
|
||||||
|
|
||||||
self.microscope.camera.set_zoom(zoom_value)
|
|
||||||
|
|
||||||
return jsonify(self.microscope.camera.status)
|
|
||||||
|
|
||||||
|
|
||||||
class OverlayAPI(MicroscopeView):
|
|
||||||
def get(self):
|
|
||||||
"""
|
|
||||||
Get overlay text
|
|
||||||
|
|
||||||
.. :quickref: Overlay; Get camera overlay text
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:<header Content-Type: application/json
|
|
||||||
:status 200: preview started/stopped
|
|
||||||
"""
|
|
||||||
text = self.microscope.camera.camera.annotate_text
|
|
||||||
size = self.microscope.camera.camera.annotate_text_size
|
|
||||||
|
|
||||||
return jsonify({"text": text, "size": size})
|
|
||||||
|
|
||||||
def post(self):
|
|
||||||
"""
|
|
||||||
Set overlay text
|
|
||||||
|
|
||||||
.. :quickref: Overlay; Set camera overlay text
|
|
||||||
|
|
||||||
**Example requests**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
POST /camera/overlay HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"text": "2019/01/15 14:48",
|
|
||||||
"size": 50
|
|
||||||
}
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:<header Content-Type: application/json
|
|
||||||
:status 200: preview started/stopped
|
|
||||||
"""
|
|
||||||
|
|
||||||
payload = JsonResponse(request)
|
|
||||||
text = payload.param("text", default="", convert=str)
|
|
||||||
size = payload.param("size", default=50, convert=int)
|
|
||||||
|
|
||||||
self.microscope.camera.camera.annotate_text = text
|
|
||||||
self.microscope.camera.camera.annotate_text_size = size
|
|
||||||
|
|
||||||
return jsonify({"text": text, "size": size})
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
from openflexure_microscope.api.utilities import JsonResponse
|
|
||||||
from openflexure_microscope.api.views import MicroscopeView
|
|
||||||
|
|
||||||
from flask import jsonify, request
|
|
||||||
import logging
|
|
||||||
|
|
||||||
|
|
||||||
class GPUPreviewAPI(MicroscopeView):
|
|
||||||
def post(self, operation):
|
|
||||||
"""
|
|
||||||
Start or stop the onboard GPU preview.
|
|
||||||
Optional "window" parameter can be passed to control the position and size of the preview window,
|
|
||||||
in the format ``[x, y, width, height]``.
|
|
||||||
|
|
||||||
.. :quickref: GPU Preview; Start/stop preview
|
|
||||||
|
|
||||||
**Example requests**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
POST /camera/preview/start HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"window": [0, 0, 480, 320],
|
|
||||||
}
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
POST /camera/preview/stop HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:<header Content-Type: application/json
|
|
||||||
:status 200: preview started/stopped
|
|
||||||
"""
|
|
||||||
if operation == "start":
|
|
||||||
payload = JsonResponse(request)
|
|
||||||
|
|
||||||
window = payload.param("window", default=[])
|
|
||||||
logging.debug(window)
|
|
||||||
|
|
||||||
if len(window) != 4:
|
|
||||||
fullscreen = True
|
|
||||||
window = None
|
|
||||||
else:
|
|
||||||
fullscreen = False
|
|
||||||
window = [int(w) for w in window]
|
|
||||||
|
|
||||||
self.microscope.camera.start_preview(fullscreen=fullscreen, window=window)
|
|
||||||
elif operation == "stop":
|
|
||||||
self.microscope.camera.stop_preview()
|
|
||||||
return jsonify(self.microscope.state)
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
from openflexure_microscope.api.views import MicroscopeViewPlugin
|
|
||||||
|
|
||||||
from flask import Blueprint, jsonify
|
|
||||||
from openflexure_microscope.api.views import MicroscopeView
|
|
||||||
|
|
||||||
import copy
|
|
||||||
import logging
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
|
|
||||||
class PluginFormAPI(MicroscopeView):
|
|
||||||
def get(self):
|
|
||||||
"""
|
|
||||||
Return the current plugin forms
|
|
||||||
|
|
||||||
.. :quickref: Plugin; Get forms
|
|
||||||
|
|
||||||
Returns an array of present plugin forms (describing plugin user interfaces.)
|
|
||||||
Please note, this is *not* a list of all enabled plugins, only those with associated
|
|
||||||
user interface forms.
|
|
||||||
|
|
||||||
A complete list of enabled plugins can be found in the microscope state.
|
|
||||||
|
|
||||||
"""
|
|
||||||
out = self.microscope.plugins.forms
|
|
||||||
return jsonify(out)
|
|
||||||
|
|
||||||
|
|
||||||
def construct_blueprint(microscope_obj):
|
|
||||||
|
|
||||||
blueprint = Blueprint("plugin_blueprint", __name__)
|
|
||||||
|
|
||||||
# Create a base route to return plugin API forms, if any exist
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/",
|
|
||||||
view_func=PluginFormAPI.as_view("plugin_api_form", microscope=microscope_obj),
|
|
||||||
)
|
|
||||||
|
|
||||||
all_routes = []
|
|
||||||
|
|
||||||
# For each plugin attached to the microscope object
|
|
||||||
for plugin_name, plugin_obj in microscope_obj.plugins._legacy_plugins.items():
|
|
||||||
|
|
||||||
# If plugin contains valid endpoints
|
|
||||||
if hasattr(plugin_obj, "api_views") and isinstance(plugin_obj.api_views, dict):
|
|
||||||
|
|
||||||
# We'll keep a record of how each route was expanded
|
|
||||||
expanded_routes = {}
|
|
||||||
|
|
||||||
# For each defined endpoint
|
|
||||||
for view_route, view_class in plugin_obj.api_views.items():
|
|
||||||
|
|
||||||
# Remove all leading slashes from view route
|
|
||||||
cleaned_route = view_route
|
|
||||||
while cleaned_route[0] == "/":
|
|
||||||
cleaned_route = cleaned_route[1:]
|
|
||||||
|
|
||||||
# Construct a full view route from the plugin name
|
|
||||||
full_view_route = "/{}/{}".format(plugin_name, cleaned_route)
|
|
||||||
logging.debug(full_view_route)
|
|
||||||
|
|
||||||
# Record how the view_route got expanded
|
|
||||||
expanded_routes[view_route] = full_view_route
|
|
||||||
|
|
||||||
# Check if endpoint name clashes
|
|
||||||
if full_view_route not in all_routes and issubclass(
|
|
||||||
view_class, MicroscopeViewPlugin
|
|
||||||
):
|
|
||||||
# Add route to main route dictionary
|
|
||||||
all_routes.append(full_view_route)
|
|
||||||
|
|
||||||
# Create a Python-safe name for the route
|
|
||||||
plugin_route_id = "plugin{}".format(full_view_route).replace(
|
|
||||||
"/", "_"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add route to the plugins blueprint
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
full_view_route,
|
|
||||||
view_func=view_class.as_view(
|
|
||||||
plugin_route_id,
|
|
||||||
microscope=microscope_obj,
|
|
||||||
plugin=plugin_obj,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
warnings.warn(
|
|
||||||
"An endpoint /{} has already been loaded. Skipping {}.".format(
|
|
||||||
full_view_route, view_class
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# If plugin includes an API form
|
|
||||||
if hasattr(plugin_obj, "api_form") and isinstance(
|
|
||||||
plugin_obj.api_form, dict
|
|
||||||
):
|
|
||||||
api_form_info = copy.deepcopy(plugin_obj.api_form)
|
|
||||||
api_form_info["id"] = plugin_name
|
|
||||||
if "forms" in api_form_info and isinstance(
|
|
||||||
api_form_info["forms"], list
|
|
||||||
):
|
|
||||||
for form in api_form_info["forms"]:
|
|
||||||
if "route" in form and form["route"] in expanded_routes.keys():
|
|
||||||
form["route"] = expanded_routes[form["route"]]
|
|
||||||
else:
|
|
||||||
logging.warn(
|
|
||||||
"No valid expandable route found for {}".format(
|
|
||||||
form["route"]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Store the complete form in Microscope().plugin.form
|
|
||||||
microscope_obj.plugins.forms.append(api_form_info)
|
|
||||||
|
|
||||||
else:
|
|
||||||
warnings.warn(
|
|
||||||
"No valid 'api_views' dictionary found in {}".format(plugin_obj)
|
|
||||||
)
|
|
||||||
return blueprint
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
from openflexure_microscope.api.utilities import JsonResponse
|
|
||||||
from openflexure_microscope.api.views import MicroscopeView
|
|
||||||
from openflexure_microscope.utilities import axes_to_array, filter_dict
|
|
||||||
|
|
||||||
from flask import Blueprint, jsonify, request
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
|
|
||||||
class PositionAPI(MicroscopeView):
|
|
||||||
def get(self):
|
|
||||||
"""
|
|
||||||
Return current x, y and z positions of the stage.
|
|
||||||
The response is formatted as a sub-section of the general microscope state.
|
|
||||||
|
|
||||||
.. :quickref: Position; Get current position
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
GET /stage/position/ HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
**Example response**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
HTTP/1.1 200 OK
|
|
||||||
Vary: Accept
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"stage": {
|
|
||||||
"position": {
|
|
||||||
"x": -6629,
|
|
||||||
"y": 7489,
|
|
||||||
"z": -3844
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
out = filter_dict(self.microscope.state, ["stage", "position"])
|
|
||||||
return jsonify(out)
|
|
||||||
|
|
||||||
def post(self):
|
|
||||||
"""
|
|
||||||
Set x, y and z positions of the stage.
|
|
||||||
|
|
||||||
.. :quickref: Position; Update current position
|
|
||||||
|
|
||||||
:reqheader Accept: application/json
|
|
||||||
:<json boolean absolute: (true) move to absolute position, (false) move by relative amount
|
|
||||||
:<json boolean force: allow moving by more than programmed limit
|
|
||||||
:<json int x: x steps
|
|
||||||
:<json int y: y steps
|
|
||||||
:<json int z: z steps
|
|
||||||
|
|
||||||
"""
|
|
||||||
# Create response object
|
|
||||||
payload = JsonResponse(request)
|
|
||||||
logging.debug(payload.json)
|
|
||||||
|
|
||||||
# Construct position array
|
|
||||||
position = [0, 0, 0]
|
|
||||||
|
|
||||||
# Handle absolute positioning (calculate a relative move from current position and target)
|
|
||||||
if (payload.param("absolute") is True) and (
|
|
||||||
self.microscope.stage
|
|
||||||
): # Only if stage exists
|
|
||||||
target_position = axes_to_array(payload.json, ["x", "y", "z"])
|
|
||||||
logging.debug("TARGET: {}".format(target_position))
|
|
||||||
position = [
|
|
||||||
target_position[i] - self.microscope.stage.position[i] for i in range(3)
|
|
||||||
]
|
|
||||||
logging.debug("DELTA: {}".format(position))
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Get coordinates from payload
|
|
||||||
position = axes_to_array(payload.json, ["x", "y", "z"], [0, 0, 0])
|
|
||||||
|
|
||||||
logging.debug(position)
|
|
||||||
|
|
||||||
# Move if stage exists
|
|
||||||
if self.microscope.stage:
|
|
||||||
# Explicitally acquire lock
|
|
||||||
with self.microscope.stage.lock:
|
|
||||||
self.microscope.stage.move_rel(position)
|
|
||||||
|
|
||||||
out = filter_dict(self.microscope.state, ["stage", "position"])
|
|
||||||
|
|
||||||
return jsonify(out)
|
|
||||||
|
|
||||||
|
|
||||||
def construct_blueprint(microscope_obj):
|
|
||||||
|
|
||||||
blueprint = Blueprint("stage_blueprint", __name__)
|
|
||||||
|
|
||||||
blueprint.add_url_rule(
|
|
||||||
"/position",
|
|
||||||
view_func=PositionAPI.as_view("position", microscope=microscope_obj),
|
|
||||||
)
|
|
||||||
|
|
||||||
return blueprint
|
|
||||||
|
|
@ -1,141 +0,0 @@
|
||||||
from openflexure_microscope.api.views import MethodView
|
|
||||||
from flask import jsonify, abort, Blueprint
|
|
||||||
|
|
||||||
from openflexure_microscope.common import tasks
|
|
||||||
|
|
||||||
|
|
||||||
class TaskListAPI(MethodView):
|
|
||||||
def get(self):
|
|
||||||
"""
|
|
||||||
Get list of long-running tasks.
|
|
||||||
|
|
||||||
.. :quickref: Tasks; Get collection of tasks
|
|
||||||
|
|
||||||
**Example response**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
HTTP/1.1 200 OK
|
|
||||||
Vary: Accept
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"end_time": "2019-01-23 16-33-33",
|
|
||||||
"id": "db13a66787e1419bb06b1504e4d80b0c",
|
|
||||||
"return": [
|
|
||||||
0.848622546386467,
|
|
||||||
0.6106785018091292,
|
|
||||||
],
|
|
||||||
"start_time": "2019-01-23 16-33-13",
|
|
||||||
"status": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"end_time": null,
|
|
||||||
"id": "df46558cc8844924821bd0181881871e",
|
|
||||||
"return": null,
|
|
||||||
"start_time": "2019-01-23 16-34-54",
|
|
||||||
"status": "running"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
:query include_unavailable: return json representations of captures that have been completely deleted
|
|
||||||
|
|
||||||
:>header Content-Type: application/json
|
|
||||||
"""
|
|
||||||
|
|
||||||
data = tasks.states()
|
|
||||||
|
|
||||||
return jsonify(data)
|
|
||||||
|
|
||||||
def delete(self):
|
|
||||||
"""
|
|
||||||
Clean list of long-running tasks (running tasks persist).
|
|
||||||
|
|
||||||
.. :quickref: Tasks; Clean collection of tasks
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:>header Content-Type: application/json
|
|
||||||
"""
|
|
||||||
|
|
||||||
tasks.cleanup_tasks()
|
|
||||||
data = tasks.states()
|
|
||||||
|
|
||||||
return jsonify(data)
|
|
||||||
|
|
||||||
|
|
||||||
class TaskAPI(MethodView):
|
|
||||||
def get(self, task_id):
|
|
||||||
"""
|
|
||||||
Get JSON representation of a task
|
|
||||||
|
|
||||||
.. :quickref: Tasks; Get task
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
GET /task/db13a66787e1419bb06b1504e4d80b0c/ HTTP/1.1
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
**Example response**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
HTTP/1.1 200 OK
|
|
||||||
Vary: Accept
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"end_time": "2019-01-23 16-33-33",
|
|
||||||
"id": "db13a66787e1419bb06b1504e4d80b0c",
|
|
||||||
"return": [
|
|
||||||
0.848622546386467,
|
|
||||||
0.6106785018091292,
|
|
||||||
],
|
|
||||||
"start_time": "2019-01-23 16-33-13",
|
|
||||||
"status": "success"
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
task = tasks.tasks()[task_id]
|
|
||||||
except KeyError:
|
|
||||||
return abort(404) # 404 Not Found
|
|
||||||
|
|
||||||
# Return task state
|
|
||||||
return jsonify(task.state)
|
|
||||||
|
|
||||||
def delete(self, task_id):
|
|
||||||
"""
|
|
||||||
Terminate a particular task.
|
|
||||||
|
|
||||||
.. :quickref: Tasks; Terminate a task
|
|
||||||
|
|
||||||
:>header Accept: application/json
|
|
||||||
|
|
||||||
:>header Content-Type: application/json
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
task = tasks.tasks()[task_id]
|
|
||||||
except KeyError:
|
|
||||||
return abort(404) # 404 Not Found
|
|
||||||
|
|
||||||
task.terminate()
|
|
||||||
|
|
||||||
return jsonify(task.state)
|
|
||||||
|
|
||||||
|
|
||||||
def construct_blueprint(microscope_obj):
|
|
||||||
|
|
||||||
blueprint = Blueprint("task_blueprint", __name__)
|
|
||||||
|
|
||||||
blueprint.add_url_rule("/", view_func=TaskListAPI.as_view("task_list"))
|
|
||||||
|
|
||||||
blueprint.add_url_rule("/<task_id>/", view_func=TaskAPI.as_view("task"))
|
|
||||||
|
|
||||||
return blueprint
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue