from flask import Flask, render_template
from flask import request, jsonify, Markup, send_file
import lazy_loader as lazy
from PIL import Image
import datetime,requests, subprocess,shlex,os,json,io,bokeh
import numpy as np
from distutils.util import strtobool
import bokeh.plotting,bokeh.models
pyFAI = lazy.load("pyFAI", require="AFL-automation[scattering-processing]")
from .AreaDetectorLive import AreaDetectorLive
import matplotlib as mpl
from matplotlib import cm
#app = Flask('NistoRoboto') #okay this breaks the templating apparently
app = Flask(__name__)
app.config['ENV'] = 'development'
experiment = 'Development'
contactinfo = '[email protected]'
# app.config['ENV'] = 'production'
# initialize auth module
from flask_jwt_extended import JWTManager, jwt_required
from flask_jwt_extended import create_access_token, get_jwt_identity
app.config['JWT_SECRET_KEY'] = '03570' #hide the secret?
jwt = JWTManager(app)
import logging
app.logger.setLevel(level=logging.DEBUG)
# this is necessary to use the default debug reloading functionality
if app.config['ENV']=='production' or os.environ.get("WERKZEUG_RUN_MAIN") =='true':
#import queue
results = []
from EpicsADLiveProcessDaemon import EpicsADLiveProcessDaemon
EADLP_daemon = EpicsADLiveProcessDaemon(app,results)
EADLP_daemon.start()# start server thread
# @app.route('/')
# def index():
# '''Live, status page of the robot'''
# kw = status_dict()
#
# return render_template('index.html',**kw),200
[docs]
@app.route('/results')
def results():
response = "<ul>"
for num,res in enumerate(EADLP_daemon.results):
response += f'<li>#{num} | {res[0]} | exp {res[1]} | '
response += f'<a href="raw_image?n={num}&log=1&max=25" target="_blank">raw img</a> |'
response += f'<a href="unwrapped_image?n={num}&log=1&max=25" target="_blank">unwrapped img</a> |'
response += f'<a href="1d_plot?n={num}" target="_blank">reduced data</a></li>'
response += "</ul>"
return Markup(response)
[docs]
@app.route('/clear_results')
def clear_results():
EADLP_daemon.results.clear()
return 'Success',200
[docs]
@app.route('/raw_image',methods=['GET'])
def raw_image():
itemnum = int(request.args['n'])
if 'log' in request.args:
log_image = strtobool(request.args['log'])
else:
log_image = True
if 'max' in request.args:
maxv = int(request.args['max'])
else:
maxv = None
# convert numpy array to PIL Image
npa = EADLP_daemon.results[itemnum][2]
return send_array_as_jpg(npa,log_image=log_image,max_val=maxv)
[docs]
@app.route('/unwrapped_image',methods=['GET'])
def unwrapped_image():
itemnum = int(request.args['n'])
if 'log' in request.args:
log_image = strtobool(request.args['log'])
else:
log_image = True
if 'max' in request.args:
maxv = int(request.args['max'])
else:
maxv = None
# convert numpy array to PIL Image
npa = EADLP_daemon.results[itemnum][4].intensity
return send_array_as_jpg(npa,log_image=log_image,max_val=maxv)
[docs]
def send_array_as_jpg(array,log_image=False,max_val=None):
if(log_image):
array = np.log(array)
#img = Image.fromarray(array.astype('uint8'))
if max_val == None:
max_val = np.amax(array)
array = array/max_val
img = Image.fromarray(np.uint8(cm.plasma(array)*255)).convert('RGB')
# create file-object in memory
file_object = io.BytesIO()
# write PNG in file-object
img.save(file_object, 'jpeg')
# move to beginning of file so `send_file()` it will read from start
file_object.seek(0)
return send_file(file_object, mimetype='image/jpeg')
[docs]
@app.route('/1d_plot',methods=['GET'])
def oned_plot():
items = request.args['n'].split(",")
if 'xlin' in request.args:
xlin = strtobool(request.args['xlin'])
xmode = 'linear' if xlin else 'log'
else:
xmode = 'log'
if 'ylin' in request.args:
ylin = strtobool(request.args['ylin'])
ymode = 'linear' if xlin else 'log'
else:
ymode = 'log'
TOOLS = 'pan,wheel_zoom,box_zoom,reset,save'
title = EADLP_daemon.results[int(items[0])][0]
p = bokeh.plotting.figure(title=title,tools=TOOLS,x_axis_type=xmode,y_axis_type=ymode)
p.xaxis.axis_label = 'q (A^-1)'
p.yaxis.axis_label = 'Intensity (AU)'
for item in items:
res = EADLP_daemon.results[int(item)][3]
p.scatter(res[0],res[1],marker='circle', size=2,
line_color='navy', fill_color='orange', alpha=0.5)
#errors = bokeh.models.Band(base=res[1],upper=res[1]+res[2],lower=res[1]-res[2], level='underlay',
# fill_alpha=1.0, line_width=1, line_color='black')
#p.add_layout(band)
script,div = bokeh.embed.components(p)
return render_template('simple-bokeh.html',script=script,div=div,title=title)
[docs]
@app.route('/3up',methods=['GET'])
def threeup():
items = request.args['n'].split(",")
if 'xlin' in request.args:
xlin = strtobool(request.args['xlin'])
xmode = 'linear' if xlin else 'log'
else:
xmode = 'log'
if 'ylin' in request.args:
ylin = strtobool(request.args['ylin'])
ymode = 'linear' if xlin else 'log'
else:
ymode = 'log'
TOOLS = 'pan,wheel_zoom,box_zoom,reset,save'
title = EADLP_daemon.results[int(items[0])][0]
p = bokeh.plotting.figure(title=title,tools=TOOLS,x_axis_type=xmode,y_axis_type=ymode)
p.xaxis.axis_label = 'q (A^-1)'
p.yaxis.axis_label = 'Intensity (AU)'
for item in items:
res = EADLP_daemon.results[int(item)][3]
p.scatter(res[0],res[1],marker='circle', size=2,
line_color='navy', fill_color='orange', alpha=0.5)
#errors = bokeh.models.Band(base=res[1],upper=res[1]+res[2],lower=res[1]-res[2], level='underlay',
# fill_alpha=1.0, line_width=1, line_color='black')
#p.add_layout(band)
script,div = bokeh.embed.components(p)
return render_template('threeup.html',script=script,div=div,title=title,n=request.args['n'])
[docs]
@app.route('/mostrecent',methods=['GET'])
def mostrecent():
items = request.args['n'].split(",")
if 'xlin' in request.args:
xlin = strtobool(request.args['xlin'])
xmode = 'linear' if xlin else 'log'
else:
xmode = 'log'
if 'ylin' in request.args:
ylin = strtobool(request.args['ylin'])
ymode = 'linear' if xlin else 'log'
else:
ymode = 'log'
TOOLS = 'pan,wheel_zoom,box_zoom,reset,save'
title = EADLP_daemon.results[int(items[0])][0]
p = bokeh.plotting.figure(title=title,tools=TOOLS,x_axis_type=xmode,y_axis_type=ymode)
p.xaxis.axis_label = 'q (A^-1)'
p.yaxis.axis_label = 'Intensity (AU)'
res = EADLP_daemon.results[-1][3]
p.scatter(res[0],res[1],marker='circle', size=2,
line_color='navy', fill_color='orange', alpha=0.5)
#errors = bokeh.models.Band(base=res[1],upper=res[1]+res[2],lower=res[1]-res[2], level='underlay',
# fill_alpha=1.0, line_width=1, line_color='black')
#p.add_layout(band)
script,div = bokeh.embed.components(p)
return render_template('threeup.html',script=script,div=div,title=title,n="-1")
[docs]
@app.route('/reconfig_integrator',methods=['POST'])
def reconfig_integrator():
poni1 = request.args['poni1']
poni2 = request.args['poni2']
rot1 = request.args['rot1']
rot2 = request.args['rot2']
rot3 = request.args['rot3']
distance = request.args['distance']
wavelength = request.args['wavelength']
det_type = request.args['det_type']
pixel1 = request.args['pixel1']
pixel2 = request.args['pixel2']
npts = request.args['npts']
#sanity check for integrator integrity goes here...
if(det_type != ''):
EADLP_daemon.detector = pyFAI.detector_factory(name=det_type)
else:
EADLP_daemon.detector = pyFAI.detector_factory()
EADLP_daemon.integrator = pyFAI.azimuthalIntegrator.AzimuthalIntegrator(detector = EADLP_daemon.detector,
wavelength = wavelength,poni1 = poni1, poni2 = poni2, rot1 = rot1, rot2 = rot2,
rot3 = rot3, distance = distance)
EADLP_daemon.reduceDaemon.npts = npts
[docs]
@app.route('/reconfig_detector',methods=['POST'])
def reconfig_detector():
basepv= request.args['basepv']
if 'cam' in request.args:
cam = request.args['cam']
else:
cam = "cam1:"
if 'filewriter' in request.args:
filewriter = request.args['filewriter']
else:
filewriter="TIFF1:"
if 'image' in request.args:
image = request.args['image']
else:
image="image1:"
EADLP_daemon.collateDaemon.detector = AreaDetectorLive(basepv = basepv,cam=cam,filewriter=filewriter,image=image)
return 'Success',200
@app.route('/login_test',methods=['POST'])
@jwt_required
def login_test():
username = get_jwt_identity()
app.logger.info(f'Login test for {username} successful')
return 'Success',200
if __name__ == '__main__':
if app.config['ENV'] == 'development':
debug = True
else:
debug = False
app.run(host='0.0.0.0',debug=debug,port=5050)