This commit is contained in:
Ali Abid 2021-01-19 09:15:09 -08:00
parent f888d2b637
commit e7454cb150
4 changed files with 14 additions and 4 deletions

View File

@ -3,6 +3,7 @@ requests
Flask>=1.1.1
Flask-Cors>=3.0.8
flask-cachebuster
Flask-BasicAuth
paramiko
scipy
IPython

View File

@ -44,7 +44,7 @@ class Interface:
Interface.instances)
def __init__(self, fn, inputs, outputs, verbose=False, examples=None,
examples_per_page=10, live=False,
examples_per_page=10, live=False, auth=None,
layout="horizontal", show_input=True, show_output=True,
capture_session=False, interpretation=None,
title=None, description=None, article=None, thumbnail=None,
@ -61,6 +61,7 @@ class Interface:
examples (List[List[Any]]): sample inputs for the function; if provided, appears below the UI components and can be used to populate the interface. Should be nested list, in which the outer list consists of samples and each inner list consists of an input corresponding to each input component.
examples_per_page (int): If examples are provided, how many to display per page.
live (bool): whether the interface should automatically reload on change.
auth (Tuple[str, str]): If provided, username and password required to access interface.
layout (str): Layout of input and output panels. "horizontal" arranges them as two columns of equal height, "unaligned" arranges them as two columns of unequal height, and "vertical" arranges them vertically.
capture_session (bool): if True, captures the default graph and session (needed for Tensorflow 1.x)
interpretation (Union[Callable, str]): function that provides interpretation explaining prediction output. Pass "default" to use built-in interpreter.
@ -113,6 +114,7 @@ class Interface:
self.verbose = verbose
self.status = "OFF"
self.live = live
self.auth = auth
self.layout = layout
self.show_input = show_input
self.show_output = show_output
@ -384,7 +386,7 @@ class Interface:
networking.set_meta_tags(self.title, self.description, self.thumbnail)
server_port, app, thread = networking.start_server(
self, self.server_name, self.server_port)
self, self.server_name, self.server_port, self.auth)
path_to_local_server = "http://{}:{}/".format(self.server_name, server_port)
self.server_port = server_port
self.status = "RUNNING"

View File

@ -7,6 +7,7 @@ import socket
import threading
from flask import Flask, request, jsonify, abort, send_file, render_template
from flask_cachebuster import CacheBuster
from flask_basicauth import BasicAuth
from flask_cors import CORS
import threading
import pkg_resources
@ -256,12 +257,17 @@ def interpret():
def file(path):
return send_file(os.path.join(app.cwd, path))
def start_server(interface, server_name, server_port=None):
def start_server(interface, server_name, server_port=None, auth=None):
if server_port is None:
server_port = INITIAL_PORT_VALUE
port = get_first_available_port(
server_port, server_port + TRY_NUM_PORTS
)
if auth is not None:
app.config['BASIC_AUTH_USERNAME'] = auth[0]
app.config['BASIC_AUTH_PASSWORD'] = auth[1]
app.config['BASIC_AUTH_FORCE'] = True
basic_auth = BasicAuth(app)
app.interface = interface
app.cwd = os.getcwd()
log = logging.getLogger('werkzeug')
@ -304,6 +310,6 @@ def setup_tunnel(local_server_port):
def url_ok(url):
try:
r = requests.head(url)
return r.status_code == 200
return r.status_code == 200 or r.status_code == 401
except ConnectionError:
return False

View File

@ -19,6 +19,7 @@ setup(
'Flask>=1.1.1',
'Flask-Cors>=3.0.8',
'flask-cachebuster',
'Flask-BasicAuth',
'paramiko',
'scipy',
'IPython',