#!/usr/bin/env python import gunicorn.app.base import sys from predictor import Predictor, Prediction class CustomUnicornApp(gunicorn.app.base.BaseApplication): """ This gunicorn app class provides create and exit callbacks for workers, and runs gunicorn with a single worker and multiple gthreads """ def __init__(self, create_app_callback, exit_app_callback, host_port): self._configBind = host_port self._createAppCallback = create_app_callback self._exitAppCallback = exit_app_callback super().__init__() @staticmethod def exitWorker(arbiter, worker): # worker.app provides us with a reference to "self", and we can call the # exit callback with the object created by the createAppCallback: self = worker.app self._exitAppCallback(self._createdApp) def load_config(self): self.cfg.set("bind", self._configBind) self.cfg.set("worker_class", "gthread") self.cfg.set("workers", 1) self.cfg.set("threads", 4) self.cfg.set("worker_exit", CustomUnicornApp.exitWorker) # Try to uncomment and make 10 requests, to test correct restart of worker: # self.cfg.set("max_requests", 10) def load(self): # This function is invoked when a worker is booted self._createdApp = self._createAppCallback() return self._createdApp # --- index.html contents html = """ Cell Growth Classifier

Cell Growth Classifier

""" # ---- from PIL import Image from bottle import Bottle, request, response import threading import io def startServer(index_html:str, predictor:Predictor, host_port:str): def create(): app = Bottle() lock = threading.Lock() @app.route("/") def getIndex(): # Serve static content, no lock protection necessary: return index_html @app.route('/upload', method='POST') def upload_image(): uploads = request.files.getall('images') results = {} for upload in uploads: # Read the image file in bytes and open it with Pillow image_bytes = io.BytesIO(upload.file.read()) try: with Image.open(image_bytes) as img: pred:Prediction = app.predictor.predict(img) results[upload.filename] = pred.getDict() except IOError: response.status = 400 return "Invalid image file" return {"model": app.predictor.modelName, "results": results} # Store predictor in the bottle app object app.predictor = predictor return app def exit(app): # Get the service through the app object and save state pass CustomUnicornApp(create, exit, host_port).run() def usage(): print("""Usage: server.py modelfile host_port Example: ./server.py cells_2.pth localhost:8001 """) if __name__ == "__main__": if len(sys.argv) != 3: usage() else: p = Predictor(sys.argv[1]) startServer(html, p, sys.argv[2])