odonata / app /server.py
Theivaprakasham Hari
first push
e05e237
from starlette.applications import Starlette
from starlette.responses import HTMLResponse, JSONResponse
from starlette.staticfiles import StaticFiles
from starlette.middleware.cors import CORSMiddleware
import uvicorn, aiohttp, asyncio
from io import BytesIO
from PIL import Image
import PIL
from datetime import datetime
import random
import torch
import boto3
BUCKET_NAME = "odonet-images-uploads"
s3 = boto3.resource('s3', aws_access_key_id = "AKIA6OMEZ3Q6NHLH47CG", aws_secret_access_key="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" )
from fastai.vision.all import *
export_file_url = 'https://dl.dropboxusercontent.com/s/vekzhkaspnkf2l4/odonates_res_256_19june2021_88.pkl'
export_file_name = 'odonates_res_256_19june2021_88.pkl'
classes = ['Aciagrion approximans', 'Aciagrion hisopa', 'Aciagrion occidentale', 'Aciagrion pallidum', 'Acisoma panorpoides', 'Aeshna mixta', 'Aeshna petalura', 'Aethriamanta brevipennis', 'Agriocnemis clauseni', 'Agriocnemis femina', 'Agriocnemis kalinga', 'Agriocnemis keralensis', 'Agriocnemis lacteola', 'Agriocnemis pieris', 'Agriocnemis pygmaea', 'Agriocnemis splendidissima', 'Agrionoptera insignis', 'Amphiallagma parvum', 'Amphithemis vacillans', 'Anaciaeschna jaspidea', 'Anax ephippiger', 'Anax guttatus', 'Anax immaculifrons', 'Anax indicus', 'Anax nigrofasciatus', 'Anax parthenope', 'Anisogomphus occipitalis', 'Anisopleura comes', 'Anisopleura lestoides', 'Anisopleura subplatystyla', 'Anisopleura vallei', 'Anotogaster nipalensis', 'Archibasis oscillans', 'Archilestes grandis', 'Argiocnemis rubescens', 'Aristocypha cuneata', 'Aristocypha fenestrella', 'Aristocypha quadrimaculata', 'Aristocypha trifasciata', 'Bayadera indica', 'Brachydiplax chalybea', 'Brachydiplax farinosa', 'Brachydiplax sobrina', 'Brachythemis contaminata', 'Bradinopyga geminata', 'Bradinopyga konkanensis', 'Burmagomphus divaricatus', 'Burmagomphus laidlawi', 'Caconeura ramburi', 'Caconeura risi', 'Calicnemia eximia', 'Calicnemia imitans', 'Calicnemia miniata', 'Calicnemia mortoni', 'Calicnemia nipalica', 'Caliphaea confusa', 'Calocypha laidlawi', 'Camacinia gigantea', 'Cephalaeschna acanthifrons', 'Ceriagrion aeruginosum', 'Ceriagrion auranticum', 'Ceriagrion azureum', 'Ceriagrion cerinorubellum', 'Ceriagrion chromothorax', 'Ceriagrion coromandelianum', 'Ceriagrion fallax', 'Ceriagrion olivaceum', 'Ceriagrion rubiae', 'Coeliccia bimaculata', 'Coeliccia cyanomelas', 'Coeliccia didyma', 'Coeliccia schmidti', 'Copera ciliata', 'Copera marginipes', 'Copera vittata', 'Cratilla lineata', 'Cratilla metallica', 'Crocothemis erythraea', 'Crocothemis servilia', 'Cyclogomphus flavoannulatus', 'Cyclogomphus ypsilon', 'Diplacodes lefebvrii', 'Diplacodes nebulosa', 'Diplacodes trivialis', 'Disparoneura quadrimaculata', 'Drepanosticta carmichaeli', 'Dysphaea ethela', 'Dysphaea gloriosa', 'Dysphaea walli', 'Dythemis nigrescens', 'Echo margarita', 'Elattoneura campioni', 'Elattoneura nigerrima', 'Elattoneura tetrica', 'Elattonuera souteri', 'Enallagma cyathigerum', 'Enallagma signatum', 'Epithemis mariae', 'Epophthalmia vittata', 'Esme longistyla', 'Esme mudiensis', 'Euphaea cardinalis', 'Euphaea dispar', 'Euphaea fraseri', 'Euphaea masoni', 'Euphaea ochracea', 'Gomphidia kodaguensis', 'Gomphidia t nigrum', 'Gynacantha bayadera', 'Gynacantha dravida', 'Gynacantha khasiaca', 'Gynacantha millardi', 'Gynacantha subinterrupta', 'Heliocypha biforata', 'Heliocypha bisignata', 'Heliocypha perforata', 'Heliogomphus promelas', 'Hemianax ephippiger', 'Hemicordulia asiatica', 'Hydrobasileus croceus', 'Hylaeothemis apicalis', 'Hylaeothemis indica', 'Ictinogomphus decoratus', 'Ictinogomphus distinctus', 'Ictinogomphus pertinax', 'Ictinogomphus rapax', 'Indocnemis orang', 'Indolestes cyaneus', 'Indolestes gracilis', 'Indolestes indicus', 'Indosticta deccanensis', 'Indothemis carnatica', 'Indothemis limbata', 'Ischnura elegans', 'Ischnura forcipata', 'Ischnura inarmata', 'Ischnura mildredae', 'Ischnura nursei', 'Ischnura rubilio', 'Ischnura rufostigma', 'Ischnura senegalensis', 'Lamelligomphus nilgiriensis', 'Lathrecista asiatica', 'Lestes barbarus', 'Lestes concinnus', 'Lestes dorothea', 'Lestes dryas', 'Lestes elatus', 'Lestes garoensis', 'Lestes nodalis', 'Lestes praemorsus', 'Lestes umbrinus', 'Lestes viridulus', 'Libellago andamanensis', 'Libellago indica', 'Libellago lineata', 'Libellula quadrimaculata', 'Lyriothemis acigastra', 'Lyriothemis bivittata', 'Lyriothemis tricolor', 'Macrodiplax cora', 'Macrogomphus annulatus', 'Macrogomphus montanus', 'Macromia moorei', 'Matrona basilaris', 'Matrona nigripectus', 'Megalestes major', 'Merogomphus longistigma', 'Merogomphus tamaracherriensis', 'Microgomphus souteri', 'Microgomphus torquatus', 'Mortonagrion aborense', 'Mortonagrion varralli', 'Nannophyopsis clara', 'Nehalennia irene', 'Nepogomphus modestus', 'Neurobasis chinensis', 'Neurothemis fluctuans', 'Neurothemis fulvia', 'Neurothemis intermedia', 'Neurothemis ramburii', 'Neurothemis tullia', 'Onychargia atrocyana', 'Onychogomphus acinaces', 'Onychogomphus duaricus', 'Onychogomphus nilgiriensis', 'Onychothemis testacea', 'Orthetrum brunneum', 'Orthetrum chrysis', 'Orthetrum glaucum', 'Orthetrum japonicum', 'Orthetrum luzonicum', 'Orthetrum pruinosum', 'Orthetrum sabina', 'Orthetrum taeniolatum', 'Orthetrum testaceum', 'Orthetrum triangulare', 'Palpopleura sexmaculata', 'Pantala flavescens', 'Paracercion calamorum', 'Paracercion malayanum', 'Paracypha unimaculata', 'Paragomphus lineatus', 'Perissogomphus stevensi', 'Phylloneura westermanni', 'Planaeschna poumai', 'Platygomphus dolabratus', 'Platylestes kirani', 'Platylestes platystylus', 'Potamarcha congener', 'Prodasineura verticalis', 'Protosticta davenporti', 'Protosticta gravelyi', 'Protosticta hearseyi', 'Protosticta ponmudiensis', 'Protosticta sanguinostigma', 'Pseudagrion australasiae', 'Pseudagrion decorum', 'Pseudagrion hypermelas', 'Pseudagrion indicum', 'Pseudagrion malabaricum', 'Pseudagrion microcephalum', 'Pseudagrion pilidorsum', 'Pseudagrion rubriceps', 'Pseudagrion spencei', 'Pseudocopera ciliata', 'Pseudothemis zonata', 'Rhinocypha trifasciata', 'Rhinocypha unimaculata', 'Rhodothemis rufa', 'Rhyothemis plutonia', 'Rhyothemis triangularis', 'Rhyothemis variegata', 'Schmidtiphaea chittaranjani', 'Stylogomphus inglisi', 'Sympecma paedisca', 'Sympetrum fonscolombii', 'Sympetrum hypomelas', 'Sympetrum orientale', 'Sympetrum striolatum', 'Tetracanthagyna waterhousei', 'Tetrathemis platyptera', 'Tholymis tillarga', 'Tramea basilaris', 'Tramea limbata', 'Tramea transmarina', 'Trithemis arteriosa', 'Trithemis aurora', 'Trithemis festiva', 'Trithemis kirbyi', 'Trithemis pallidinervis', 'Urothemis signata', 'Vestalis apicalis', 'Vestalis gracilis', 'Zygonyx iris', 'Zyxomma petiolatum']
path = Path(__file__).parent
app = Starlette()
app.add_middleware(CORSMiddleware, allow_origins=['*'], allow_headers=['X-Requested-With', 'Content-Type'])
app.mount('/css', StaticFiles(directory='app/css'))
app.mount('/fonts', StaticFiles(directory='app/fonts'))
app.mount('/images', StaticFiles(directory='app/images'))
app.mount('/js', StaticFiles(directory='app/js'))
@app.route('/terms')
def index(request):
html = path/'terms.html'
return HTMLResponse(html.open().read())
@app.route('/privacy')
def index(request):
html = path/'privacy.html'
return HTMLResponse(html.open().read())
async def download_file(url, dest):
if dest.exists(): return
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
data = await response.read()
with open(dest, 'wb') as f: f.write(data)
async def setup_learner():
await download_file(export_file_url, path/export_file_name)
try:
learn = load_learner(path/export_file_name)
return learn
except RuntimeError as e:
if len(e.args) > 0 and 'CPU-only machine' in e.args[0]:
print(e)
message = ""
raise RuntimeError(message)
else:
raise
loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(setup_learner())]
learn = loop.run_until_complete(asyncio.gather(*tasks))[0]
loop.close()
@app.route('/')
def index(request):
html = path/'index.html'
return HTMLResponse(html.open(encoding='utf-8').read())
@app.route('/analyze', methods=['POST'])
async def analyze(request):
data = await request.form()
basename = "odo"
suffix = datetime.now().strftime("%d%m%y_%H%M%S")
filename = "_".join([basename, suffix,str(random.randrange(0,1000)),'.jpg']) # e.g. 'mylogfile_120508_171442'
img_bytes = await (data['avatar'].read())
img = Image.open(BytesIO(img_bytes)).convert('RGB')
img.save(path/'upload_odo'/filename)
s3.Bucket(BUCKET_NAME).upload_file(str(path/'upload_odo'/filename),str(filename))
img.close()
print(filename)
_, _, outputs = learn.predict(path/'upload_odo'/filename)
values, indices = torch.topk(outputs,5)
predictions = [{"class": classes[j], "output": round(i, 1), "prob": round(i*100,2)} for i, j in zip(values.tolist(), indices.tolist())]
if predictions[0]['prob'] < 25:
predictions = [{'class': 'either not clear or quite challenging to identify. Please upload a proper odonate picture.', 'output': 1.0, 'prob': ''},{'class': '', 'output': 0.0, 'prob':''},{'class': '', 'output': 0.0, 'prob': ''}]
return JSONResponse({"predictions": predictions})
else:
return JSONResponse({"predictions": predictions})
if __name__ == '__main__':
if 'serve' in sys.argv: uvicorn.run(app=app, host='0.0.0.0', port=5042)