mirror of
https://github.com/gradio-app/gradio.git
synced 2024-12-21 02:19:59 +08:00
docs and new UI
This commit is contained in:
parent
066b16fa42
commit
32f2d96c63
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,3 +19,4 @@ __pycache__/
|
||||
demo/models/*
|
||||
dist/*
|
||||
*.h5
|
||||
docs.json
|
68
build/lib/gradio/generate_docs.py
Normal file
68
build/lib/gradio/generate_docs.py
Normal file
@ -0,0 +1,68 @@
|
||||
import json
|
||||
from gradio.inputs import AbstractInput
|
||||
from gradio.outputs import AbstractOutput
|
||||
from gradio.interface import Interface
|
||||
import inspect
|
||||
|
||||
def get_params(func):
|
||||
params_str = inspect.getdoc(func)
|
||||
params_doc = []
|
||||
documented_params = {"self"}
|
||||
for param_line in params_str.split("\n")[1:]:
|
||||
space_index = param_line.index(" ")
|
||||
colon_index = param_line.index(":")
|
||||
name = param_line[:space_index]
|
||||
documented_params.add(name)
|
||||
params_doc.append((name, param_line[space_index+2:colon_index-1], param_line[colon_index+2:]))
|
||||
params = inspect.getfullargspec(func)
|
||||
param_set = []
|
||||
for i in range(len(params.args)):
|
||||
neg_index = -1 - i
|
||||
if params.args[neg_index] not in documented_params:
|
||||
continue
|
||||
if i < len(params.defaults):
|
||||
default = params.defaults[neg_index]
|
||||
if type(default) == str:
|
||||
default = '"' + default + '"'
|
||||
else:
|
||||
default = str(default)
|
||||
param_set.insert(0, (params.args[neg_index], default))
|
||||
else:
|
||||
param_set.insert(0, (params.args[neg_index],))
|
||||
return param_set, params_doc
|
||||
|
||||
def document(cls_set):
|
||||
docset = []
|
||||
for cls in cls_set:
|
||||
inp = {}
|
||||
inp["name"] = cls.__name__
|
||||
doc = inspect.getdoc(cls)
|
||||
inp["doc"] = "\n".join(doc.split("\n")[:-1])
|
||||
inp["type"] = doc.split("\n")[-1].split("type: ")[-1]
|
||||
inp["params"], inp["params_doc"] = get_params(cls.__init__)
|
||||
inp["shortcuts"] = list(cls.get_shortcut_implementations().items())
|
||||
docset.append(inp)
|
||||
return docset
|
||||
|
||||
inputs = document(AbstractInput.__subclasses__())
|
||||
outputs = document(AbstractOutput.__subclasses__())
|
||||
interface_params = get_params(Interface.__init__)
|
||||
interface = {
|
||||
"doc": inspect.getdoc(Interface),
|
||||
"params": interface_params[0],
|
||||
"params_doc": interface_params[1],
|
||||
}
|
||||
launch_params = get_params(Interface.launch)
|
||||
launch = {
|
||||
"params": launch_params[0],
|
||||
"params_doc": launch_params[1],
|
||||
}
|
||||
|
||||
with open("docs.json", "w") as docs:
|
||||
json.dump({
|
||||
"inputs": inputs,
|
||||
"outputs": outputs,
|
||||
"interface": interface,
|
||||
"launch": launch
|
||||
}, docs)
|
||||
|
@ -4,15 +4,18 @@ This module defines various classes that can serve as the `input` to an interfac
|
||||
automatically added to a registry, which allows them to be easily referenced in other parts of the code.
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from gradio import preprocessing_utils, validation_data
|
||||
import numpy as np
|
||||
import PIL.Image, PIL.ImageOps
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import warnings
|
||||
import json
|
||||
import datetime
|
||||
import os
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
import numpy as np
|
||||
import PIL.Image
|
||||
import PIL.ImageOps
|
||||
import scipy.io.wavfile
|
||||
from gradio import preprocessing_utils, validation_data
|
||||
|
||||
# Where to find the static resources associated with each template.
|
||||
# BASE_INPUT_INTERFACE_TEMPLATE_PATH = 'static/js/interfaces/input/{}.js'
|
||||
@ -24,6 +27,7 @@ class AbstractInput(ABC):
|
||||
An abstract class for defining the methods that all gradio inputs should have.
|
||||
When this is subclassed, it is automatically added to the registry
|
||||
"""
|
||||
|
||||
def __init__(self, label):
|
||||
self.label = label
|
||||
|
||||
@ -60,79 +64,27 @@ class AbstractInput(ABC):
|
||||
return {}
|
||||
|
||||
|
||||
class Sketchpad(AbstractInput):
|
||||
def __init__(self, shape=(28, 28), invert_colors=True,
|
||||
flatten=False, label=None):
|
||||
self.image_width = shape[0]
|
||||
self.image_height = shape[1]
|
||||
self.invert_colors = invert_colors
|
||||
self.flatten = flatten
|
||||
super().__init__(label)
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"sketchpad": {},
|
||||
}
|
||||
|
||||
def preprocess(self, inp):
|
||||
"""
|
||||
Default preprocessing method for the SketchPad is to convert the sketch to black and white and resize 28x28
|
||||
"""
|
||||
im_transparent = preprocessing_utils.decode_base64_to_image(inp)
|
||||
im = PIL.Image.new("RGBA", im_transparent.size, "WHITE") # Create a white background for the alpha channel
|
||||
im.paste(im_transparent, (0, 0), im_transparent)
|
||||
im = im.convert('L')
|
||||
if self.invert_colors:
|
||||
im = PIL.ImageOps.invert(im)
|
||||
im = im.resize((self.image_width, self.image_height))
|
||||
if self.flatten:
|
||||
array = np.array(im).flatten().reshape(1, self.image_width * self.image_height)
|
||||
else:
|
||||
array = np.array(im).flatten().reshape(1, self.image_width, self.image_height)
|
||||
return array
|
||||
|
||||
def process_example(self, example):
|
||||
return preprocessing_utils.convert_file_to_base64(example)
|
||||
|
||||
|
||||
class Webcam(AbstractInput):
|
||||
def __init__(self, shape=(224, 224), label=None):
|
||||
self.image_width = shape[0]
|
||||
self.image_height = shape[1]
|
||||
self.num_channels = 3
|
||||
super().__init__(label)
|
||||
|
||||
def get_validation_inputs(self):
|
||||
return validation_data.BASE64_COLOR_IMAGES
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"webcam": {},
|
||||
}
|
||||
|
||||
def preprocess(self, inp):
|
||||
"""
|
||||
Default preprocessing method for is to convert the picture to black and white and resize to be 48x48
|
||||
"""
|
||||
im = preprocessing_utils.decode_base64_to_image(inp)
|
||||
im = im.convert('RGB')
|
||||
im = preprocessing_utils.resize_and_crop(im, (self.image_width, self.image_height))
|
||||
return np.array(im)
|
||||
|
||||
|
||||
class Textbox(AbstractInput):
|
||||
"""
|
||||
Component creates a textbox for user to enter input. Provides a string (or number is `is_numeric` is true) as an argument to the wrapped function.
|
||||
Input type: str
|
||||
"""
|
||||
|
||||
def __init__(self, lines=1, placeholder=None, default=None, numeric=False, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
lines (int): number of line rows to provide in textarea.
|
||||
placeholder (str): placeholder hint to provide behind textarea.
|
||||
default (str): default text to provide in textarea.
|
||||
numeric (bool): whether the input should be parsed as a number instead of a string.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.lines = lines
|
||||
self.placeholder = placeholder
|
||||
self.default = default
|
||||
self.numeric = numeric
|
||||
super().__init__(label)
|
||||
|
||||
def get_validation_inputs(self):
|
||||
return validation_data.ENGLISH_TEXTS
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"lines": self.lines,
|
||||
@ -159,44 +111,21 @@ class Textbox(AbstractInput):
|
||||
return inp
|
||||
|
||||
|
||||
class Radio(AbstractInput):
|
||||
def __init__(self, choices, label=None):
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class Dropdown(AbstractInput):
|
||||
def __init__(self, choices, label=None):
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class CheckboxGroup(AbstractInput):
|
||||
def __init__(self, choices, label=None):
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class Slider(AbstractInput):
|
||||
def __init__(self, minimum=0, maximum=100, default=None, label=None):
|
||||
"""
|
||||
Component creates a slider that ranges from `minimum` to `maximum`. Provides a number as an argument to the wrapped function.
|
||||
Input type: float
|
||||
"""
|
||||
|
||||
def __init__(self, minimum=0, maximum=100, step=None, default=None, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
minimum (float): minimum value for slider.
|
||||
maximum (float): maximum value for slider.
|
||||
step (float): increment between slider values.
|
||||
default (float): default value.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.minimum = minimum
|
||||
self.maximum = maximum
|
||||
self.default = minimum if default is None else default
|
||||
@ -218,7 +147,16 @@ class Slider(AbstractInput):
|
||||
|
||||
|
||||
class Checkbox(AbstractInput):
|
||||
"""
|
||||
Component creates a checkbox that can be set to `True` or `False`. Provides a boolean as an argument to the wrapped function.
|
||||
Input type: bool
|
||||
"""
|
||||
|
||||
def __init__(self, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
super().__init__(label)
|
||||
|
||||
@classmethod
|
||||
@ -228,8 +166,85 @@ class Checkbox(AbstractInput):
|
||||
}
|
||||
|
||||
|
||||
class CheckboxGroup(AbstractInput):
|
||||
"""
|
||||
Component creates a set of checkboxes of which a subset can be selected. Provides a list of strings representing the selected choices as an argument to the wrapped function.
|
||||
Input type: List[str]
|
||||
"""
|
||||
|
||||
def __init__(self, choices, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
choices (List[str]): list of options to select from.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class Radio(AbstractInput):
|
||||
"""
|
||||
Component creates a set of radio buttons of which only one can be selected. Provides string representing selected choice as an argument to the wrapped function.
|
||||
Input type: str
|
||||
"""
|
||||
|
||||
def __init__(self, choices, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
choices (List[str]): list of options to select from.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class Dropdown(AbstractInput):
|
||||
"""
|
||||
Component creates a dropdown of which only one can be selected. Provides string representing selected choice as an argument to the wrapped function.
|
||||
Input type: str
|
||||
"""
|
||||
|
||||
def __init__(self, choices, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
choices (List[str]): list of options to select from.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class Image(AbstractInput):
|
||||
"""
|
||||
Component creates an image upload box with editing capabilities. Provides numpy array of shape `(width, height, 3)` if `image_mode` is "RGB" as an argument to the wrapped function. Provides numpy array of shape `(width, height)` if `image_mode` is "L" as an argument to the wrapped function.
|
||||
Input type: numpy.array
|
||||
"""
|
||||
|
||||
def __init__(self, shape=(224, 224), image_mode='RGB', label=None):
|
||||
'''
|
||||
Parameters:
|
||||
shape (Tuple[int, int]): shape to crop and resize image to.
|
||||
image_mode (str): "RGB" if color, or "L" if black and white.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.image_width = shape[0]
|
||||
self.image_height = shape[1]
|
||||
self.image_mode = image_mode
|
||||
@ -258,7 +273,8 @@ class Image(AbstractInput):
|
||||
warnings.simplefilter("ignore")
|
||||
im = im.convert(self.image_mode)
|
||||
|
||||
im = preprocessing_utils.resize_and_crop(im, (self.image_width, self.image_height))
|
||||
im = preprocessing_utils.resize_and_crop(
|
||||
im, (self.image_width, self.image_height))
|
||||
return np.array(im)
|
||||
|
||||
def process_example(self, example):
|
||||
@ -268,21 +284,132 @@ class Image(AbstractInput):
|
||||
return example
|
||||
|
||||
|
||||
class Microphone(AbstractInput):
|
||||
def __init__(self, label=None):
|
||||
class Sketchpad(AbstractInput):
|
||||
"""
|
||||
Component creates a sketchpad for black and white illustration. Provides numpy array of shape `(width, height)` as an argument to the wrapped function.
|
||||
Input type: numpy.array
|
||||
"""
|
||||
|
||||
def __init__(self, shape=(28, 28), invert_colors=True,
|
||||
flatten=False, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
shape (Tuple[int, int]): shape to crop and resize image to.
|
||||
invert_colors (bool): whether to represent black as 1 and white as 0 in the numpy array.
|
||||
flatten (bool): whether to reshape the numpy array to a single dimension.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.image_width = shape[0]
|
||||
self.image_height = shape[1]
|
||||
self.invert_colors = invert_colors
|
||||
self.flatten = flatten
|
||||
super().__init__(label)
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"sketchpad": {},
|
||||
}
|
||||
|
||||
def preprocess(self, inp):
|
||||
"""
|
||||
Default preprocessing method for the SketchPad is to convert the sketch to black and white and resize 28x28
|
||||
"""
|
||||
im_transparent = preprocessing_utils.decode_base64_to_image(inp)
|
||||
# Create a white background for the alpha channel
|
||||
im = PIL.Image.new("RGBA", im_transparent.size, "WHITE")
|
||||
im.paste(im_transparent, (0, 0), im_transparent)
|
||||
im = im.convert('L')
|
||||
if self.invert_colors:
|
||||
im = PIL.ImageOps.invert(im)
|
||||
im = im.resize((self.image_width, self.image_height))
|
||||
if self.flatten:
|
||||
array = np.array(im).flatten().reshape(
|
||||
1, self.image_width * self.image_height)
|
||||
else:
|
||||
array = np.array(im).flatten().reshape(
|
||||
1, self.image_width, self.image_height)
|
||||
return array
|
||||
|
||||
def process_example(self, example):
|
||||
return preprocessing_utils.convert_file_to_base64(example)
|
||||
|
||||
|
||||
class Webcam(AbstractInput):
|
||||
"""
|
||||
Component creates a webcam for captured image input. Provides numpy array of shape `(width, height, 3)` as an argument to the wrapped function.
|
||||
Input type: numpy.array
|
||||
"""
|
||||
|
||||
def __init__(self, shape=(224, 224), label=None):
|
||||
'''
|
||||
Parameters:
|
||||
shape (Tuple[int, int]): shape to crop and resize image to.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.image_width = shape[0]
|
||||
self.image_height = shape[1]
|
||||
self.num_channels = 3
|
||||
super().__init__(label)
|
||||
|
||||
def get_validation_inputs(self):
|
||||
return validation_data.BASE64_COLOR_IMAGES
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"webcam": {},
|
||||
}
|
||||
|
||||
def preprocess(self, inp):
|
||||
"""
|
||||
Default preprocessing method for is to convert the picture to black and white and resize to be 48x48
|
||||
"""
|
||||
im = preprocessing_utils.decode_base64_to_image(inp)
|
||||
im = im.convert('RGB')
|
||||
im = preprocessing_utils.resize_and_crop(
|
||||
im, (self.image_width, self.image_height))
|
||||
return np.array(im)
|
||||
|
||||
|
||||
class Microphone(AbstractInput):
|
||||
"""
|
||||
Component creates a microphone element for audio inputs. Provides numpy array of shape `(samples, 2)` as an argument to the wrapped function.
|
||||
Input type: numpy.array
|
||||
"""
|
||||
|
||||
def __init__(self, preprocessing=None, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
preprocessing (Union[str, Callable]): preprocessing to apply to input
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
super().__init__(label)
|
||||
if preprocessing is None or preprocessing == "mfcc":
|
||||
self.preprocessing = preprocessing
|
||||
else:
|
||||
raise ValueError(
|
||||
"unexpected value for preprocessing", preprocessing)
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"microphone": {},
|
||||
}
|
||||
|
||||
def preprocess(self, inp):
|
||||
"""
|
||||
By default, no pre-processing is applied to a microphone input file
|
||||
"""
|
||||
file_obj = preprocessing_utils.decode_base64_to_wav_file(inp)
|
||||
mfcc_array = preprocessing_utils.generate_mfcc_features_from_audio_file(file_obj.name)
|
||||
return mfcc_array
|
||||
if self.preprocessing == "mfcc":
|
||||
return preprocessing_utils.generate_mfcc_features_from_audio_file(file_obj.name)
|
||||
_, signal = scipy.io.wavfile.read(file_obj.name)
|
||||
return signal
|
||||
|
||||
|
||||
# Automatically adds all shortcut implementations in AbstractInput into a dictionary.
|
||||
shortcuts = {}
|
||||
for cls in AbstractInput.__subclasses__():
|
||||
for shortcut, parameters in cls.get_shortcut_implementations().items():
|
||||
shortcuts[shortcut] = cls(**parameters)
|
||||
shortcuts[shortcut] = cls(**parameters)
|
||||
|
@ -33,8 +33,7 @@ except requests.ConnectionError:
|
||||
|
||||
class Interface:
|
||||
"""
|
||||
The Interface class represents a general input/output interface for a machine learning model. During construction,
|
||||
the appropriate inputs and outputs
|
||||
Interfaces are created with Gradio using the `gradio.Interface()` function.
|
||||
"""
|
||||
instances = weakref.WeakSet()
|
||||
|
||||
@ -43,9 +42,15 @@ class Interface:
|
||||
capture_session=False, title=None, description=None,
|
||||
thumbnail=None, server_name=networking.LOCALHOST_NAME):
|
||||
"""
|
||||
:param fn: a function that will process the input panel data from the interface and return the output panel data.
|
||||
:param inputs: a string or `AbstractInput` representing the input interface.
|
||||
:param outputs: a string or `AbstractOutput` representing the output interface.
|
||||
Parameters:
|
||||
fn (Callable): the function to wrap an interface around.
|
||||
inputs (Union[str, List[Union[str, AbstractInput]]]): a single Gradio input component, or list of Gradio input components. Components can either be passed as instantiated objects, or referred to by their string shortcuts. The number of input components should match the number of parameters in fn.
|
||||
outputs (Union[str, List[Union[str, AbstractOutput]]]): a single Gradio output component, or list of Gradio output components. Components can either be passed as instantiated objects, or referred to by their string shortcuts. The number of output components should match the number of values returned by fn.
|
||||
live (bool): whether the interface should automatically reload on change.
|
||||
capture_session (bool): if True, captures the default graph and session (needed for Tensorflow 1.x)
|
||||
title (str): a title for the interface; if provided, appears above the input and output components.
|
||||
description (str): a description for the interface; if provided, appears above the input and output components.
|
||||
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.
|
||||
"""
|
||||
def get_input_instance(iface):
|
||||
if isinstance(iface, str):
|
||||
@ -257,11 +262,8 @@ class Interface:
|
||||
|
||||
def launch(self, inline=None, inbrowser=None, share=False, validate=True, debug=False):
|
||||
"""
|
||||
Standard method shared by interfaces that creates the interface and sets up a websocket to communicate with it.
|
||||
:param inline: boolean. If True, then a gradio interface is created inline (e.g. in jupyter or colab notebook)
|
||||
:param inbrowser: boolean. If True, then a new browser window opens with the gradio interface.
|
||||
:param share: boolean. If True, then a share link is generated using ngrok is displayed to the user.
|
||||
:param validate: boolean. If True, then the validation is run if the interface has not already been validated.
|
||||
Parameters
|
||||
share (bool): whether to create a publicly shareable link from your computer for the interface.
|
||||
"""
|
||||
# if validate and not self.validate_flag:
|
||||
# self.validate()
|
||||
|
@ -116,6 +116,17 @@ def get_first_available_port(initial, final):
|
||||
)
|
||||
)
|
||||
|
||||
def send_prediction_analytics(interface):
|
||||
data = {'input_interface': interface.input_interfaces,
|
||||
'output_interface': interface.output_interfaces,
|
||||
}
|
||||
try:
|
||||
requests.post(
|
||||
analytics_url + 'gradio-prediction-analytics/',
|
||||
data=data)
|
||||
except requests.ConnectionError:
|
||||
pass # do not push analytics if no network
|
||||
|
||||
|
||||
def serve_files_in_background(interface, port, directory_to_serve=None, server_name=LOCALHOST_NAME):
|
||||
class HTTPHandler(SimpleHTTPRequestHandler):
|
||||
@ -160,17 +171,11 @@ def serve_files_in_background(interface, port, directory_to_serve=None, server_n
|
||||
# f.write(json.dumps(output_flag))
|
||||
# f.write("\n")
|
||||
|
||||
# Prepare return json dictionary.
|
||||
self.wfile.write(json.dumps(output).encode())
|
||||
data = {'input_interface': interface.input_interfaces,
|
||||
'output_interface': interface.output_interfaces,
|
||||
}
|
||||
try:
|
||||
requests.post(
|
||||
analytics_url + 'gradio-prediction-analytics/',
|
||||
data=data)
|
||||
except requests.ConnectionError:
|
||||
pass # do not push analytics if no network
|
||||
|
||||
analytics_thread = threading.Thread(
|
||||
target=send_prediction_analytics, args=[interface])
|
||||
analytics_thread.start()
|
||||
|
||||
elif self.path == "/api/flag/":
|
||||
self._set_headers()
|
||||
|
@ -21,6 +21,7 @@ class AbstractOutput(ABC):
|
||||
An abstract class for defining the methods that all gradio inputs should have.
|
||||
When this is subclassed, it is automatically added to the registry
|
||||
"""
|
||||
|
||||
def __init__(self, label):
|
||||
self.label = label
|
||||
|
||||
@ -44,12 +45,56 @@ class AbstractOutput(ABC):
|
||||
return {}
|
||||
|
||||
|
||||
class Textbox(AbstractOutput):
|
||||
'''
|
||||
Component creates a textbox to render output text or number.
|
||||
Output type: str
|
||||
'''
|
||||
|
||||
def __init__(self, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"text": {},
|
||||
"textbox": {},
|
||||
"number": {},
|
||||
}
|
||||
|
||||
def postprocess(self, prediction):
|
||||
if isinstance(prediction, str) or isinstance(prediction, int) or isinstance(prediction, float):
|
||||
return str(prediction)
|
||||
else:
|
||||
raise ValueError("The `Textbox` output interface expects an output that is one of: a string, or"
|
||||
"an int/float that can be converted to a string.")
|
||||
|
||||
|
||||
class Label(AbstractOutput):
|
||||
'''
|
||||
Component outputs a classification label, along with confidence scores of top categories if provided. Confidence scores are represented as a dictionary mapping labels to scores between 0 and 1.
|
||||
Output type: Union[Dict[str, float], str, int, float]
|
||||
'''
|
||||
|
||||
LABEL_KEY = "label"
|
||||
CONFIDENCE_KEY = "confidence"
|
||||
CONFIDENCES_KEY = "confidences"
|
||||
|
||||
def __init__(self, num_top_classes=None, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
num_top_classes (int): number of most confident classes to show.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.num_top_classes = num_top_classes
|
||||
super().__init__(label)
|
||||
|
||||
@ -58,7 +103,7 @@ class Label(AbstractOutput):
|
||||
return {"label": str(prediction)}
|
||||
elif isinstance(prediction, dict):
|
||||
sorted_pred = sorted(
|
||||
prediction.items(),
|
||||
prediction.items(),
|
||||
key=operator.itemgetter(1),
|
||||
reverse=True
|
||||
)
|
||||
@ -86,51 +131,18 @@ class Label(AbstractOutput):
|
||||
}
|
||||
|
||||
|
||||
class KeyValues(AbstractOutput):
|
||||
def __init__(self, label=None):
|
||||
super().__init__(label)
|
||||
|
||||
def postprocess(self, prediction):
|
||||
if isinstance(prediction, dict):
|
||||
return prediction
|
||||
else:
|
||||
raise ValueError("The `KeyValues` output interface expects an output that is a dictionary whose keys are "
|
||||
"labels and values are corresponding values.")
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"key_values": {},
|
||||
}
|
||||
|
||||
|
||||
class Textbox(AbstractOutput):
|
||||
def __init__(self, label=None):
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"text": {},
|
||||
"textbox": {},
|
||||
"number": {},
|
||||
}
|
||||
|
||||
def postprocess(self, prediction):
|
||||
if isinstance(prediction, str) or isinstance(prediction, int) or isinstance(prediction, float):
|
||||
return str(prediction)
|
||||
else:
|
||||
raise ValueError("The `Textbox` output interface expects an output that is one of: a string, or"
|
||||
"an int/float that can be converted to a string.")
|
||||
|
||||
|
||||
class Image(AbstractOutput):
|
||||
'''
|
||||
Component displays an image. Expects a numpy array of shape `(width, height, 3)` to be returned by the function, or a `matplotlib.pyplot` if `plot = True`.
|
||||
Output type: numpy.array
|
||||
'''
|
||||
|
||||
def __init__(self, plot=False, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
plot (bool): whether to expect a plot to be returned by the function.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.plot = plot
|
||||
super().__init__(label)
|
||||
|
||||
@ -154,7 +166,8 @@ class Image(AbstractOutput):
|
||||
try:
|
||||
return preprocessing_utils.encode_array_to_base64(prediction)
|
||||
except:
|
||||
raise ValueError("The `Image` output interface (with plt=False) expects a numpy array.")
|
||||
raise ValueError(
|
||||
"The `Image` output interface (with plt=False) expects a numpy array.")
|
||||
|
||||
def rebuild_flagged(self, dir, msg):
|
||||
"""
|
||||
@ -168,6 +181,33 @@ class Image(AbstractOutput):
|
||||
return filename
|
||||
|
||||
|
||||
class KeyValues(AbstractOutput):
|
||||
'''
|
||||
Component displays a table representing values for multiple fields.
|
||||
Output type: List[Tuple[str, value]]
|
||||
'''
|
||||
|
||||
def __init__(self, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
super().__init__(label)
|
||||
|
||||
def postprocess(self, prediction):
|
||||
if isinstance(prediction, dict):
|
||||
return prediction
|
||||
else:
|
||||
raise ValueError("The `KeyValues` output interface expects an output that is a dictionary whose keys are "
|
||||
"labels and values are corresponding values.")
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"key_values": {},
|
||||
}
|
||||
|
||||
|
||||
# Automatically adds all shortcut implementations in AbstractInput into a dictionary.
|
||||
shortcuts = {}
|
||||
for cls in AbstractOutput.__subclasses__():
|
||||
|
@ -60,11 +60,9 @@ input.panel_button {
|
||||
flex-grow: 1;
|
||||
padding: 12px;
|
||||
box-sizing: border-box;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
border: 0 none;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s ease;
|
||||
margin-left: 16px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
@ -78,11 +76,6 @@ input.submit {
|
||||
input.submit:hover {
|
||||
background-color: #f39c12;
|
||||
}
|
||||
label {
|
||||
transition: background-color 0.2s ease;
|
||||
padding: 2px 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
/* label:hover {
|
||||
background-color: lightgray;
|
||||
} */
|
||||
|
@ -13,30 +13,8 @@
|
||||
margin-top: 12px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.ui-icon-background, .ui-state-active .ui-icon-background {
|
||||
border: #f39c12;
|
||||
background-color: #ffffff;
|
||||
.checkbox_solo label {
|
||||
width: 27px !important;
|
||||
padding-left: 11px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
.ui-visual-focus {
|
||||
box-shadow: 0 0 3px 1px rgb(241, 171, 41);
|
||||
}
|
||||
.ui-button {
|
||||
padding: 0.25em 0.6em;
|
||||
}
|
||||
.ui-widget {
|
||||
font-family: inherit;
|
||||
}
|
||||
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, .ui-button, html .ui-button.ui-state-disabled:hover, html .ui-button.ui-state-disabled:active {
|
||||
border: 1px solid lightgray;
|
||||
background: lightgray;
|
||||
}
|
||||
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover {
|
||||
border: 1px solid #e67e22 !important;
|
||||
background: #e67e22 !important;
|
||||
font-weight: normal;
|
||||
color: #ffffff;
|
||||
}
|
||||
.ui-button {
|
||||
outline: none;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
.key_values {
|
||||
width: 100%;
|
||||
}
|
34
build/lib/gradio/static/css/vendor/jquery-ui.css
vendored
34
build/lib/gradio/static/css/vendor/jquery-ui.css
vendored
@ -1,7 +1,7 @@
|
||||
/*! jQuery UI - v1.12.1 - 2016-09-14
|
||||
* http://jqueryui.com
|
||||
* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&fwDefault=normal&cornerRadius=3px&bgColorHeader=e9e9e9&bgTextureHeader=flat&borderColorHeader=dddddd&fcHeader=333333&iconColorHeader=444444&bgColorContent=ffffff&bgTextureContent=flat&borderColorContent=dddddd&fcContent=333333&iconColorContent=444444&bgColorDefault=f6f6f6&bgTextureDefault=flat&borderColorDefault=c5c5c5&fcDefault=454545&iconColorDefault=777777&bgColorHover=ededed&bgTextureHover=flat&borderColorHover=cccccc&fcHover=2b2b2b&iconColorHover=555555&bgColorActive=007fff&bgTextureActive=flat&borderColorActive=003eff&fcActive=ffffff&iconColorActive=ffffff&bgColorHighlight=fffa90&bgTextureHighlight=flat&borderColorHighlight=dad55e&fcHighlight=777620&iconColorHighlight=777620&bgColorError=fddfdf&bgTextureError=flat&borderColorError=f1a899&fcError=5f3f3f&iconColorError=cc0000&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=666666&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=5px&offsetTopShadow=0px&offsetLeftShadow=0px&cornerRadiusShadow=8px
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6
|
||||
* Copyright jQuery Foundation and other contributors; Licensed MIT */
|
||||
|
||||
/* Layout helpers
|
||||
@ -164,7 +164,7 @@
|
||||
right: 0;
|
||||
}
|
||||
.ui-button {
|
||||
padding: .4em 1em;
|
||||
padding: 0.25em 0.6em;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
line-height: normal;
|
||||
@ -290,9 +290,7 @@ button.ui-button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.ui-checkboxradio-label .ui-icon-background {
|
||||
box-shadow: inset 1px 1px 1px #ccc;
|
||||
border-radius: .12em;
|
||||
border: none;
|
||||
}
|
||||
.ui-checkboxradio-radio-label .ui-icon-background {
|
||||
width: 16px;
|
||||
@ -301,12 +299,15 @@ button.ui-button::-moz-focus-inner {
|
||||
overflow: visible;
|
||||
border: none;
|
||||
}
|
||||
.ui-checkboxradio-label .ui-icon-background {
|
||||
border: solid 1px lightgray;
|
||||
}
|
||||
.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,
|
||||
.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon {
|
||||
background-image: none;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-width: 4px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
}
|
||||
.ui-checkboxradio-disabled {
|
||||
@ -880,10 +881,11 @@ button.ui-button::-moz-focus-inner {
|
||||
body .ui-tooltip {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
/* Component containers
|
||||
----------------------------------*/
|
||||
.ui-widget {
|
||||
font-family: Arial,Helvetica,sans-serif;
|
||||
font-family: inherit;
|
||||
font-size: 1em;
|
||||
}
|
||||
.ui-widget .ui-widget {
|
||||
@ -928,8 +930,8 @@ body .ui-tooltip {
|
||||
works properly when clicked or hovered */
|
||||
html .ui-button.ui-state-disabled:hover,
|
||||
html .ui-button.ui-state-disabled:active {
|
||||
border: 1px solid #c5c5c5;
|
||||
background: #f6f6f6;
|
||||
border: 1px solid lightgray;
|
||||
background: white;
|
||||
font-weight: normal;
|
||||
color: #454545;
|
||||
}
|
||||
@ -970,23 +972,25 @@ a.ui-button:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ui-visual-focus {
|
||||
box-shadow: 0 0 3px 1px rgb(94, 158, 214);
|
||||
.ui-checkboxradio-label {
|
||||
border: none !important;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.ui-state-active,
|
||||
.ui-widget-content .ui-state-active,
|
||||
.ui-widget-header .ui-state-active,
|
||||
a.ui-button:active,
|
||||
.ui-button:active,
|
||||
.ui-button.ui-state-active:hover {
|
||||
border: 1px solid #003eff;
|
||||
background: #007fff;
|
||||
border: 1px solid #e67e22;
|
||||
background: #e67e22;
|
||||
font-weight: normal;
|
||||
color: #ffffff;
|
||||
}
|
||||
.ui-icon-background,
|
||||
.ui-state-active .ui-icon-background {
|
||||
border: #003eff;
|
||||
border: solid 1px #f39c12;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.ui-state-active a,
|
||||
@ -1302,8 +1306,8 @@ a.ui-button:active,
|
||||
/* Overlays */
|
||||
.ui-widget-overlay {
|
||||
background: #aaaaaa;
|
||||
opacity: .3;
|
||||
filter: Alpha(Opacity=30); /* support: IE8 */
|
||||
opacity: .003;
|
||||
filter: Alpha(Opacity=.3); /* support: IE8 */
|
||||
}
|
||||
.ui-widget-shadow {
|
||||
-webkit-box-shadow: 0px 0px 5px #666666;
|
||||
|
@ -6,8 +6,8 @@ function gradio(config, fn, target) {
|
||||
<div class="input_interfaces">
|
||||
</div>
|
||||
<div class="panel_buttons">
|
||||
<input class="submit panel_button" type="submit" value="submit"/>
|
||||
<input class="clear panel_button" type="reset" value="clear">
|
||||
<input class="clear panel_button" type="reset" value="CLEAR">
|
||||
<input class="submit panel_button" type="submit" value="SUBMIT"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel output_panel">
|
||||
@ -18,8 +18,8 @@ function gradio(config, fn, target) {
|
||||
<div class="output_interfaces">
|
||||
</div>
|
||||
<div class="panel_buttons">
|
||||
<input class="screenshot panel_button" type="button" value="screenshot"/>
|
||||
<input class="flag panel_button" type="button" value="flag"/>
|
||||
<input class="screenshot panel_button" type="button" value="SCREENSHOT" style="visibility: hidden"/>
|
||||
<input class="flag panel_button" type="button" value="FLAG" style="visibility: hidden"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>`);
|
||||
|
@ -1,5 +1,7 @@
|
||||
const checkbox = {
|
||||
html: `<label><input class="checkbox" type="checkbox"> </label>`,
|
||||
html: `<div class="checkbox_solo">
|
||||
<label><input class="checkbox" type="checkbox"> </label>
|
||||
</div>`,
|
||||
init: function(opts) {
|
||||
this.target.css("height", "auto");
|
||||
this.target.find("input").checkboxradio();
|
||||
@ -11,6 +13,7 @@ const checkbox = {
|
||||
},
|
||||
clear: function() {
|
||||
this.target.find("input").prop("checked", false);
|
||||
this.target.find("input").button("refresh");
|
||||
},
|
||||
load_example: function(data) {
|
||||
if (data) {
|
||||
@ -18,5 +21,6 @@ const checkbox = {
|
||||
} else {
|
||||
this.target.find("input").prop("checked", false);
|
||||
}
|
||||
this.target.find("input").button("refresh");
|
||||
}
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
// var MAX_PREVIEW_ROWS = 100
|
||||
//
|
||||
// $('body').on('click', ".input_csv.drop_mode", function (e) {
|
||||
// $(this).parent().find(".hidden_upload").click();
|
||||
// })
|
||||
//
|
||||
// $('body').on('drag dragstart dragend dragover dragenter dragleave drop', ".input_csv.drop_mode", function(e) {
|
||||
// e.preventDefault();
|
||||
// e.stopPropagation();
|
||||
// })
|
||||
//
|
||||
// function loadTableFromFiles(files) {
|
||||
// Papa.parse(files[0], {
|
||||
// complete: function(results) {
|
||||
// $(".input_csv").hide()
|
||||
// $(".input_csv").removeClass("drop_mode")
|
||||
// var data_array = results.data
|
||||
// var table_html = ""
|
||||
// for (var i = 0; i < data_array.length && i <= MAX_PREVIEW_ROWS; i++) {
|
||||
// row = data_array[i]
|
||||
// if (i == 0) {
|
||||
// table_html += "<tr class='header'>"
|
||||
// } else {
|
||||
// table_html += "<tr>"
|
||||
// }
|
||||
// for (var c = 0; c < row.length; c++) {
|
||||
// table_html += "<td>" + row[c] + "</td>"
|
||||
// }
|
||||
// table_html += "</tr>"
|
||||
// }
|
||||
// table_html += ""
|
||||
// $(".csv_preview").html(table_html)
|
||||
// $(".table_holder").show()
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// $(".input_csv").on('drop', function(e) {
|
||||
// files = e.originalEvent.dataTransfer.files;
|
||||
// loadTableFromFiles(files)
|
||||
// });
|
||||
//
|
||||
// $(".hidden_upload").on("change", function() {
|
||||
// var files = !!this.files ? this.files : []
|
||||
// if (!files.length || !window.FileReader) {
|
||||
// return
|
||||
// }
|
||||
// loadTableFromFiles(files)
|
||||
// })
|
||||
//
|
||||
// $('body').on('click', '.clear', function(e) {
|
||||
// $(".hidden_upload").prop("value", "")
|
||||
// $(".input_csv").show()
|
||||
// $(".input_csv").addClass("drop_mode")
|
||||
// $(".table_holder").hide()
|
||||
// })
|
||||
// $('body').on('click', '.submit', function(e) {
|
||||
// loadStart();
|
||||
// })
|
@ -1,150 +0,0 @@
|
||||
const image_input = {
|
||||
html: `
|
||||
<div class="upload_zone drop_zone">
|
||||
<div class="input_caption">Drop Image Here<br>- or -<br>Click to Upload</div>
|
||||
</div>
|
||||
<div class="image_display hide">
|
||||
<div class="edit_holder">
|
||||
<button class="edit_image interface_button primary">Edit</button>
|
||||
</div>
|
||||
<div class="view_holders">
|
||||
<div class="image_preview_holder">
|
||||
<img class="image_preview" />
|
||||
</div>
|
||||
<div class="saliency_holder hide">
|
||||
<canvas class="saliency"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input class="hidden_upload" type="file" accept="image/x-png,image/gif,image/jpeg" />`
|
||||
,
|
||||
overlay_html: `
|
||||
<div class="overlay interface_extension image_editor_overlay hide" interface_id="{0}">
|
||||
<div class="image_editor_holder">
|
||||
<div class="image_editor"></div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
init: function() {
|
||||
var io = this;
|
||||
$('body').append(this.overlay_html.format(this.id));
|
||||
this.overlay_target = $(`.overlay[interface_id=${this.id}]`);
|
||||
this.target.find(".upload_zone").click(function (e) {
|
||||
io.target.find(".hidden_upload").click();
|
||||
});
|
||||
this.target.on('drag dragstart dragend dragover dragenter dragleave drop',
|
||||
".drop_zone", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
})
|
||||
this.target.on('drop', '.drop_zone', function(e) {
|
||||
files = e.originalEvent.dataTransfer.files;
|
||||
io.load_preview_from_files(files)
|
||||
});
|
||||
this.target.find('.hidden_upload').on('change', function (e) {
|
||||
if (this.files) {
|
||||
io.load_preview_from_files(this.files);
|
||||
}
|
||||
})
|
||||
this.target.find('.edit_image').click(function (e) {
|
||||
io.overlay_target.removeClass("hide");
|
||||
io.target.find(".saliency_holder").addClass("hide");
|
||||
})
|
||||
this.tui_editor = new tui.ImageEditor(this.overlay_target.
|
||||
find(".image_editor")[0], {
|
||||
includeUI: {
|
||||
menuBarPosition: 'left',
|
||||
menu: ['crop', 'flip', 'rotate', 'draw', 'filter']
|
||||
},
|
||||
cssMaxWidth: 700,
|
||||
cssMaxHeight: 500,
|
||||
selectionStyle: {
|
||||
cornerSize: 20,
|
||||
rotatingPointOffset: 70
|
||||
}
|
||||
})
|
||||
this.overlay_target.find(".tui-image-editor-header-buttons").html(`
|
||||
<button class="tui_save tui_close interface_button primary">Save</button>
|
||||
<button class="tui_cancel tui_close interface_button secondary">Cancel</button>
|
||||
`)
|
||||
this.overlay_target.find('.tui_close').click(function (e) {
|
||||
io.overlay_target.addClass("hide");
|
||||
if ($(e.target).hasClass('tui_save')) {
|
||||
// if (io.tui_editor.ui.submenu == "crop") {
|
||||
// io.tui_editor._cropAction().crop());
|
||||
// }
|
||||
io.set_image_data(io.tui_editor.toDataURL(), /*update_editor=*/false);
|
||||
}
|
||||
});
|
||||
$(".tests").html(this.test_html);
|
||||
$(".rotate_test").click(function () {
|
||||
if (io.image_data) {
|
||||
io.io_master.test("rotation", io.image_data);
|
||||
}
|
||||
})
|
||||
$(".light_test").click(function () {
|
||||
if (io.image_data) {
|
||||
io.io_master.test("lighting", io.image_data);
|
||||
}
|
||||
})
|
||||
},
|
||||
submit: function() {
|
||||
if (this.state == "IMAGE_LOADED") {
|
||||
resizeImage.call(this, this.image_data, 300, 300, function(image_data) {
|
||||
this.io_master.input(this.id, image_data);
|
||||
})
|
||||
}
|
||||
},
|
||||
clear: function() {
|
||||
this.target.find(".upload_zone").show();
|
||||
this.target.find(".image_preview").attr('src', '');
|
||||
this.target.find(".image_display").addClass("hide");
|
||||
this.target.find(".hidden_upload").prop("value", "")
|
||||
this.state = "NO_IMAGE";
|
||||
this.image_data = null;
|
||||
this.target.find(".saliency_holder").addClass("hide");
|
||||
},
|
||||
output: function(data) {
|
||||
if (this.target.find(".image_preview").attr("src")) {
|
||||
var image = this.target.find(".image_preview");
|
||||
var width = image.width();
|
||||
var height = image.height();
|
||||
this.target.find(".saliency_holder").removeClass("hide").html(`
|
||||
<canvas class="saliency" width=${width} height=${height}></canvas>`);
|
||||
var ctx = this.target.find(".saliency")[0].getContext('2d');
|
||||
paintSaliency(ctx, width, height);
|
||||
}
|
||||
},
|
||||
state: "NO_IMAGE",
|
||||
image_data: null,
|
||||
set_image_data: function(data, update_editor) {
|
||||
let io = this;
|
||||
resizeImage.call(this, data, 600, 600, function(image_data) {
|
||||
io.image_data = image_data
|
||||
io.target.find(".image_preview").attr('src', image_data);
|
||||
if (update_editor) {
|
||||
io.tui_editor.loadImageFromURL(io.image_data, 'input').then(function (sizeValue) {
|
||||
io.tui_editor.clearUndoStack();
|
||||
io.tui_editor.ui.activeMenuEvent();
|
||||
io.tui_editor.ui.resizeEditor({ imageSize: sizeValue });
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
load_preview_from_files: function(files) {
|
||||
if (!files.length || !window.FileReader || !/^image/.test(files[0].type)) {
|
||||
return
|
||||
}
|
||||
var ReaderObj = new FileReader()
|
||||
ReaderObj.readAsDataURL(files[0])
|
||||
ReaderObj.io = this;
|
||||
this.state = "IMAGE_LOADING"
|
||||
ReaderObj.onloadend = function() {
|
||||
let io = this.io;
|
||||
io.target.find(".upload_zone").hide();
|
||||
io.target.find(".image_display").removeClass("hide");
|
||||
io.set_image_data(this.result, /*update_editor=*/true);
|
||||
io.state = "IMAGE_LOADED"
|
||||
}
|
||||
}
|
||||
}
|
@ -34,7 +34,6 @@
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/dropdown.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/checkbox_group.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/slider.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/csv.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/webcam.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/microphone.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/output/image.css">
|
||||
@ -61,7 +60,9 @@
|
||||
</div>
|
||||
<div id="credit">Built with <a href="http://gradio.app" target="_blank">Gradio</a>.</div>
|
||||
<script src="../static/js/vendor/jquery.min.js"></script>
|
||||
<!-- TUI EDITOR -->
|
||||
<!-- VENDOR -->
|
||||
<script src="../static/js/vendor/html2canvas.min.js"></script>
|
||||
<script src="../static/js/vendor/jquery-ui.min.js"></script>
|
||||
<script src="../static/js/vendor/fabric.js"></script>
|
||||
<script src="../static/js/vendor/tui-code-snippet.min.js"></script>
|
||||
<script src="../static/js/vendor/FileSaver.min.js"></script>
|
||||
@ -70,9 +71,6 @@
|
||||
<script src="../static/js/vendor/white-theme.js"></script>
|
||||
<script src="../static/js/vendor/black-theme.js"></script>
|
||||
|
||||
<script src="../static/js/vendor/html2canvas.min.js"></script>
|
||||
<script src="../static/js/vendor/jquery-ui.min.js"></script>
|
||||
|
||||
<script src="../static/js/utils.js"></script>
|
||||
<script src="../static/js/all_io.js"></script>
|
||||
<script src="../static/js/interfaces/input/csv.js"></script>
|
||||
|
@ -5,20 +5,17 @@ from time import time
|
||||
|
||||
def flip(image):
|
||||
start = time()
|
||||
return image, {
|
||||
"1": 0.2,
|
||||
"2": 0.8
|
||||
}
|
||||
return image
|
||||
|
||||
|
||||
def flip2(image):
|
||||
start = time()
|
||||
return np.fliplr(image), "stuff"
|
||||
return np.fliplr(image)
|
||||
|
||||
|
||||
gr.Interface([flip, flip2],
|
||||
gr.inputs.Image(shape=(50, 50, 3)),
|
||||
["image", "label"],
|
||||
["image"],
|
||||
examples=[
|
||||
["images/cheetah1.jpg"],
|
||||
["images/cheetah2.jpg"],
|
||||
|
@ -2,6 +2,7 @@ MANIFEST.in
|
||||
README.md
|
||||
setup.py
|
||||
gradio/__init__.py
|
||||
gradio/generate_docs.py
|
||||
gradio/inputs.py
|
||||
gradio/interface.py
|
||||
gradio/networking.py
|
||||
|
68
gradio/generate_docs.py
Normal file
68
gradio/generate_docs.py
Normal file
@ -0,0 +1,68 @@
|
||||
import json
|
||||
from gradio.inputs import AbstractInput
|
||||
from gradio.outputs import AbstractOutput
|
||||
from gradio.interface import Interface
|
||||
import inspect
|
||||
|
||||
def get_params(func):
|
||||
params_str = inspect.getdoc(func)
|
||||
params_doc = []
|
||||
documented_params = {"self"}
|
||||
for param_line in params_str.split("\n")[1:]:
|
||||
space_index = param_line.index(" ")
|
||||
colon_index = param_line.index(":")
|
||||
name = param_line[:space_index]
|
||||
documented_params.add(name)
|
||||
params_doc.append((name, param_line[space_index+2:colon_index-1], param_line[colon_index+2:]))
|
||||
params = inspect.getfullargspec(func)
|
||||
param_set = []
|
||||
for i in range(len(params.args)):
|
||||
neg_index = -1 - i
|
||||
if params.args[neg_index] not in documented_params:
|
||||
continue
|
||||
if i < len(params.defaults):
|
||||
default = params.defaults[neg_index]
|
||||
if type(default) == str:
|
||||
default = '"' + default + '"'
|
||||
else:
|
||||
default = str(default)
|
||||
param_set.insert(0, (params.args[neg_index], default))
|
||||
else:
|
||||
param_set.insert(0, (params.args[neg_index],))
|
||||
return param_set, params_doc
|
||||
|
||||
def document(cls_set):
|
||||
docset = []
|
||||
for cls in cls_set:
|
||||
inp = {}
|
||||
inp["name"] = cls.__name__
|
||||
doc = inspect.getdoc(cls)
|
||||
inp["doc"] = "\n".join(doc.split("\n")[:-1])
|
||||
inp["type"] = doc.split("\n")[-1].split("type: ")[-1]
|
||||
inp["params"], inp["params_doc"] = get_params(cls.__init__)
|
||||
inp["shortcuts"] = list(cls.get_shortcut_implementations().items())
|
||||
docset.append(inp)
|
||||
return docset
|
||||
|
||||
inputs = document(AbstractInput.__subclasses__())
|
||||
outputs = document(AbstractOutput.__subclasses__())
|
||||
interface_params = get_params(Interface.__init__)
|
||||
interface = {
|
||||
"doc": inspect.getdoc(Interface),
|
||||
"params": interface_params[0],
|
||||
"params_doc": interface_params[1],
|
||||
}
|
||||
launch_params = get_params(Interface.launch)
|
||||
launch = {
|
||||
"params": launch_params[0],
|
||||
"params_doc": launch_params[1],
|
||||
}
|
||||
|
||||
with open("docs.json", "w") as docs:
|
||||
json.dump({
|
||||
"inputs": inputs,
|
||||
"outputs": outputs,
|
||||
"interface": interface,
|
||||
"launch": launch
|
||||
}, docs)
|
||||
|
320
gradio/inputs.py
320
gradio/inputs.py
@ -27,6 +27,7 @@ class AbstractInput(ABC):
|
||||
An abstract class for defining the methods that all gradio inputs should have.
|
||||
When this is subclassed, it is automatically added to the registry
|
||||
"""
|
||||
|
||||
def __init__(self, label):
|
||||
self.label = label
|
||||
|
||||
@ -63,79 +64,27 @@ class AbstractInput(ABC):
|
||||
return {}
|
||||
|
||||
|
||||
class Sketchpad(AbstractInput):
|
||||
def __init__(self, shape=(28, 28), invert_colors=True,
|
||||
flatten=False, label=None):
|
||||
self.image_width = shape[0]
|
||||
self.image_height = shape[1]
|
||||
self.invert_colors = invert_colors
|
||||
self.flatten = flatten
|
||||
super().__init__(label)
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"sketchpad": {},
|
||||
}
|
||||
|
||||
def preprocess(self, inp):
|
||||
"""
|
||||
Default preprocessing method for the SketchPad is to convert the sketch to black and white and resize 28x28
|
||||
"""
|
||||
im_transparent = preprocessing_utils.decode_base64_to_image(inp)
|
||||
im = PIL.Image.new("RGBA", im_transparent.size, "WHITE") # Create a white background for the alpha channel
|
||||
im.paste(im_transparent, (0, 0), im_transparent)
|
||||
im = im.convert('L')
|
||||
if self.invert_colors:
|
||||
im = PIL.ImageOps.invert(im)
|
||||
im = im.resize((self.image_width, self.image_height))
|
||||
if self.flatten:
|
||||
array = np.array(im).flatten().reshape(1, self.image_width * self.image_height)
|
||||
else:
|
||||
array = np.array(im).flatten().reshape(1, self.image_width, self.image_height)
|
||||
return array
|
||||
|
||||
def process_example(self, example):
|
||||
return preprocessing_utils.convert_file_to_base64(example)
|
||||
|
||||
|
||||
class Webcam(AbstractInput):
|
||||
def __init__(self, shape=(224, 224), label=None):
|
||||
self.image_width = shape[0]
|
||||
self.image_height = shape[1]
|
||||
self.num_channels = 3
|
||||
super().__init__(label)
|
||||
|
||||
def get_validation_inputs(self):
|
||||
return validation_data.BASE64_COLOR_IMAGES
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"webcam": {},
|
||||
}
|
||||
|
||||
def preprocess(self, inp):
|
||||
"""
|
||||
Default preprocessing method for is to convert the picture to black and white and resize to be 48x48
|
||||
"""
|
||||
im = preprocessing_utils.decode_base64_to_image(inp)
|
||||
im = im.convert('RGB')
|
||||
im = preprocessing_utils.resize_and_crop(im, (self.image_width, self.image_height))
|
||||
return np.array(im)
|
||||
|
||||
|
||||
class Textbox(AbstractInput):
|
||||
"""
|
||||
Component creates a textbox for user to enter input. Provides a string (or number is `is_numeric` is true) as an argument to the wrapped function.
|
||||
Input type: str
|
||||
"""
|
||||
|
||||
def __init__(self, lines=1, placeholder=None, default=None, numeric=False, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
lines (int): number of line rows to provide in textarea.
|
||||
placeholder (str): placeholder hint to provide behind textarea.
|
||||
default (str): default text to provide in textarea.
|
||||
numeric (bool): whether the input should be parsed as a number instead of a string.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.lines = lines
|
||||
self.placeholder = placeholder
|
||||
self.default = default
|
||||
self.numeric = numeric
|
||||
super().__init__(label)
|
||||
|
||||
def get_validation_inputs(self):
|
||||
return validation_data.ENGLISH_TEXTS
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"lines": self.lines,
|
||||
@ -162,44 +111,21 @@ class Textbox(AbstractInput):
|
||||
return inp
|
||||
|
||||
|
||||
class Radio(AbstractInput):
|
||||
def __init__(self, choices, label=None):
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class Dropdown(AbstractInput):
|
||||
def __init__(self, choices, label=None):
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class CheckboxGroup(AbstractInput):
|
||||
def __init__(self, choices, label=None):
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class Slider(AbstractInput):
|
||||
def __init__(self, minimum=0, maximum=100, default=None, label=None):
|
||||
"""
|
||||
Component creates a slider that ranges from `minimum` to `maximum`. Provides a number as an argument to the wrapped function.
|
||||
Input type: float
|
||||
"""
|
||||
|
||||
def __init__(self, minimum=0, maximum=100, step=None, default=None, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
minimum (float): minimum value for slider.
|
||||
maximum (float): maximum value for slider.
|
||||
step (float): increment between slider values.
|
||||
default (float): default value.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.minimum = minimum
|
||||
self.maximum = maximum
|
||||
self.default = minimum if default is None else default
|
||||
@ -221,7 +147,16 @@ class Slider(AbstractInput):
|
||||
|
||||
|
||||
class Checkbox(AbstractInput):
|
||||
"""
|
||||
Component creates a checkbox that can be set to `True` or `False`. Provides a boolean as an argument to the wrapped function.
|
||||
Input type: bool
|
||||
"""
|
||||
|
||||
def __init__(self, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
super().__init__(label)
|
||||
|
||||
@classmethod
|
||||
@ -231,8 +166,85 @@ class Checkbox(AbstractInput):
|
||||
}
|
||||
|
||||
|
||||
class CheckboxGroup(AbstractInput):
|
||||
"""
|
||||
Component creates a set of checkboxes of which a subset can be selected. Provides a list of strings representing the selected choices as an argument to the wrapped function.
|
||||
Input type: List[str]
|
||||
"""
|
||||
|
||||
def __init__(self, choices, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
choices (List[str]): list of options to select from.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class Radio(AbstractInput):
|
||||
"""
|
||||
Component creates a set of radio buttons of which only one can be selected. Provides string representing selected choice as an argument to the wrapped function.
|
||||
Input type: str
|
||||
"""
|
||||
|
||||
def __init__(self, choices, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
choices (List[str]): list of options to select from.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class Dropdown(AbstractInput):
|
||||
"""
|
||||
Component creates a dropdown of which only one can be selected. Provides string representing selected choice as an argument to the wrapped function.
|
||||
Input type: str
|
||||
"""
|
||||
|
||||
def __init__(self, choices, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
choices (List[str]): list of options to select from.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.choices = choices
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"choices": self.choices,
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
|
||||
class Image(AbstractInput):
|
||||
"""
|
||||
Component creates an image upload box with editing capabilities. Provides numpy array of shape `(width, height, 3)` if `image_mode` is "RGB" as an argument to the wrapped function. Provides numpy array of shape `(width, height)` if `image_mode` is "L" as an argument to the wrapped function.
|
||||
Input type: numpy.array
|
||||
"""
|
||||
|
||||
def __init__(self, shape=(224, 224), image_mode='RGB', label=None):
|
||||
'''
|
||||
Parameters:
|
||||
shape (Tuple[int, int]): shape to crop and resize image to.
|
||||
image_mode (str): "RGB" if color, or "L" if black and white.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.image_width = shape[0]
|
||||
self.image_height = shape[1]
|
||||
self.image_mode = image_mode
|
||||
@ -261,7 +273,8 @@ class Image(AbstractInput):
|
||||
warnings.simplefilter("ignore")
|
||||
im = im.convert(self.image_mode)
|
||||
|
||||
im = preprocessing_utils.resize_and_crop(im, (self.image_width, self.image_height))
|
||||
im = preprocessing_utils.resize_and_crop(
|
||||
im, (self.image_width, self.image_height))
|
||||
return np.array(im)
|
||||
|
||||
def process_example(self, example):
|
||||
@ -271,13 +284,112 @@ class Image(AbstractInput):
|
||||
return example
|
||||
|
||||
|
||||
class Sketchpad(AbstractInput):
|
||||
"""
|
||||
Component creates a sketchpad for black and white illustration. Provides numpy array of shape `(width, height)` as an argument to the wrapped function.
|
||||
Input type: numpy.array
|
||||
"""
|
||||
|
||||
def __init__(self, shape=(28, 28), invert_colors=True,
|
||||
flatten=False, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
shape (Tuple[int, int]): shape to crop and resize image to.
|
||||
invert_colors (bool): whether to represent black as 1 and white as 0 in the numpy array.
|
||||
flatten (bool): whether to reshape the numpy array to a single dimension.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.image_width = shape[0]
|
||||
self.image_height = shape[1]
|
||||
self.invert_colors = invert_colors
|
||||
self.flatten = flatten
|
||||
super().__init__(label)
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"sketchpad": {},
|
||||
}
|
||||
|
||||
def preprocess(self, inp):
|
||||
"""
|
||||
Default preprocessing method for the SketchPad is to convert the sketch to black and white and resize 28x28
|
||||
"""
|
||||
im_transparent = preprocessing_utils.decode_base64_to_image(inp)
|
||||
# Create a white background for the alpha channel
|
||||
im = PIL.Image.new("RGBA", im_transparent.size, "WHITE")
|
||||
im.paste(im_transparent, (0, 0), im_transparent)
|
||||
im = im.convert('L')
|
||||
if self.invert_colors:
|
||||
im = PIL.ImageOps.invert(im)
|
||||
im = im.resize((self.image_width, self.image_height))
|
||||
if self.flatten:
|
||||
array = np.array(im).flatten().reshape(
|
||||
1, self.image_width * self.image_height)
|
||||
else:
|
||||
array = np.array(im).flatten().reshape(
|
||||
1, self.image_width, self.image_height)
|
||||
return array
|
||||
|
||||
def process_example(self, example):
|
||||
return preprocessing_utils.convert_file_to_base64(example)
|
||||
|
||||
|
||||
class Webcam(AbstractInput):
|
||||
"""
|
||||
Component creates a webcam for captured image input. Provides numpy array of shape `(width, height, 3)` as an argument to the wrapped function.
|
||||
Input type: numpy.array
|
||||
"""
|
||||
|
||||
def __init__(self, shape=(224, 224), label=None):
|
||||
'''
|
||||
Parameters:
|
||||
shape (Tuple[int, int]): shape to crop and resize image to.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.image_width = shape[0]
|
||||
self.image_height = shape[1]
|
||||
self.num_channels = 3
|
||||
super().__init__(label)
|
||||
|
||||
def get_validation_inputs(self):
|
||||
return validation_data.BASE64_COLOR_IMAGES
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"webcam": {},
|
||||
}
|
||||
|
||||
def preprocess(self, inp):
|
||||
"""
|
||||
Default preprocessing method for is to convert the picture to black and white and resize to be 48x48
|
||||
"""
|
||||
im = preprocessing_utils.decode_base64_to_image(inp)
|
||||
im = im.convert('RGB')
|
||||
im = preprocessing_utils.resize_and_crop(
|
||||
im, (self.image_width, self.image_height))
|
||||
return np.array(im)
|
||||
|
||||
|
||||
class Microphone(AbstractInput):
|
||||
"""
|
||||
Component creates a microphone element for audio inputs. Provides numpy array of shape `(samples, 2)` as an argument to the wrapped function.
|
||||
Input type: numpy.array
|
||||
"""
|
||||
|
||||
def __init__(self, preprocessing=None, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
preprocessing (Union[str, Callable]): preprocessing to apply to input
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
super().__init__(label)
|
||||
if preprocessing is None or preprocessing == "mfcc":
|
||||
self.preprocessing = preprocessing
|
||||
else:
|
||||
raise ValueError("unexpected value for preprocessing", preprocessing)
|
||||
raise ValueError(
|
||||
"unexpected value for preprocessing", preprocessing)
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
|
@ -33,8 +33,7 @@ except requests.ConnectionError:
|
||||
|
||||
class Interface:
|
||||
"""
|
||||
The Interface class represents a general input/output interface for a machine learning model. During construction,
|
||||
the appropriate inputs and outputs
|
||||
Interfaces are created with Gradio using the `gradio.Interface()` function.
|
||||
"""
|
||||
instances = weakref.WeakSet()
|
||||
|
||||
@ -43,9 +42,15 @@ class Interface:
|
||||
capture_session=False, title=None, description=None,
|
||||
thumbnail=None, server_name=networking.LOCALHOST_NAME):
|
||||
"""
|
||||
:param fn: a function that will process the input panel data from the interface and return the output panel data.
|
||||
:param inputs: a string or `AbstractInput` representing the input interface.
|
||||
:param outputs: a string or `AbstractOutput` representing the output interface.
|
||||
Parameters:
|
||||
fn (Callable): the function to wrap an interface around.
|
||||
inputs (Union[str, List[Union[str, AbstractInput]]]): a single Gradio input component, or list of Gradio input components. Components can either be passed as instantiated objects, or referred to by their string shortcuts. The number of input components should match the number of parameters in fn.
|
||||
outputs (Union[str, List[Union[str, AbstractOutput]]]): a single Gradio output component, or list of Gradio output components. Components can either be passed as instantiated objects, or referred to by their string shortcuts. The number of output components should match the number of values returned by fn.
|
||||
live (bool): whether the interface should automatically reload on change.
|
||||
capture_session (bool): if True, captures the default graph and session (needed for Tensorflow 1.x)
|
||||
title (str): a title for the interface; if provided, appears above the input and output components.
|
||||
description (str): a description for the interface; if provided, appears above the input and output components.
|
||||
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.
|
||||
"""
|
||||
def get_input_instance(iface):
|
||||
if isinstance(iface, str):
|
||||
@ -257,11 +262,8 @@ class Interface:
|
||||
|
||||
def launch(self, inline=None, inbrowser=None, share=False, validate=True, debug=False):
|
||||
"""
|
||||
Standard method shared by interfaces that creates the interface and sets up a websocket to communicate with it.
|
||||
:param inline: boolean. If True, then a gradio interface is created inline (e.g. in jupyter or colab notebook)
|
||||
:param inbrowser: boolean. If True, then a new browser window opens with the gradio interface.
|
||||
:param share: boolean. If True, then a share link is generated using ngrok is displayed to the user.
|
||||
:param validate: boolean. If True, then the validation is run if the interface has not already been validated.
|
||||
Parameters
|
||||
share (bool): whether to create a publicly shareable link from your computer for the interface.
|
||||
"""
|
||||
# if validate and not self.validate_flag:
|
||||
# self.validate()
|
||||
|
@ -21,6 +21,7 @@ class AbstractOutput(ABC):
|
||||
An abstract class for defining the methods that all gradio inputs should have.
|
||||
When this is subclassed, it is automatically added to the registry
|
||||
"""
|
||||
|
||||
def __init__(self, label):
|
||||
self.label = label
|
||||
|
||||
@ -44,12 +45,56 @@ class AbstractOutput(ABC):
|
||||
return {}
|
||||
|
||||
|
||||
class Textbox(AbstractOutput):
|
||||
'''
|
||||
Component creates a textbox to render output text or number.
|
||||
Output type: str
|
||||
'''
|
||||
|
||||
def __init__(self, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"text": {},
|
||||
"textbox": {},
|
||||
"number": {},
|
||||
}
|
||||
|
||||
def postprocess(self, prediction):
|
||||
if isinstance(prediction, str) or isinstance(prediction, int) or isinstance(prediction, float):
|
||||
return str(prediction)
|
||||
else:
|
||||
raise ValueError("The `Textbox` output interface expects an output that is one of: a string, or"
|
||||
"an int/float that can be converted to a string.")
|
||||
|
||||
|
||||
class Label(AbstractOutput):
|
||||
'''
|
||||
Component outputs a classification label, along with confidence scores of top categories if provided. Confidence scores are represented as a dictionary mapping labels to scores between 0 and 1.
|
||||
Output type: Union[Dict[str, float], str, int, float]
|
||||
'''
|
||||
|
||||
LABEL_KEY = "label"
|
||||
CONFIDENCE_KEY = "confidence"
|
||||
CONFIDENCES_KEY = "confidences"
|
||||
|
||||
def __init__(self, num_top_classes=None, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
num_top_classes (int): number of most confident classes to show.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.num_top_classes = num_top_classes
|
||||
super().__init__(label)
|
||||
|
||||
@ -58,7 +103,7 @@ class Label(AbstractOutput):
|
||||
return {"label": str(prediction)}
|
||||
elif isinstance(prediction, dict):
|
||||
sorted_pred = sorted(
|
||||
prediction.items(),
|
||||
prediction.items(),
|
||||
key=operator.itemgetter(1),
|
||||
reverse=True
|
||||
)
|
||||
@ -86,51 +131,18 @@ class Label(AbstractOutput):
|
||||
}
|
||||
|
||||
|
||||
class KeyValues(AbstractOutput):
|
||||
def __init__(self, label=None):
|
||||
super().__init__(label)
|
||||
|
||||
def postprocess(self, prediction):
|
||||
if isinstance(prediction, dict):
|
||||
return prediction
|
||||
else:
|
||||
raise ValueError("The `KeyValues` output interface expects an output that is a dictionary whose keys are "
|
||||
"labels and values are corresponding values.")
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"key_values": {},
|
||||
}
|
||||
|
||||
|
||||
class Textbox(AbstractOutput):
|
||||
def __init__(self, label=None):
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
**super().get_template_context()
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"text": {},
|
||||
"textbox": {},
|
||||
"number": {},
|
||||
}
|
||||
|
||||
def postprocess(self, prediction):
|
||||
if isinstance(prediction, str) or isinstance(prediction, int) or isinstance(prediction, float):
|
||||
return str(prediction)
|
||||
else:
|
||||
raise ValueError("The `Textbox` output interface expects an output that is one of: a string, or"
|
||||
"an int/float that can be converted to a string.")
|
||||
|
||||
|
||||
class Image(AbstractOutput):
|
||||
'''
|
||||
Component displays an image. Expects a numpy array of shape `(width, height, 3)` to be returned by the function, or a `matplotlib.pyplot` if `plot = True`.
|
||||
Output type: numpy.array
|
||||
'''
|
||||
|
||||
def __init__(self, plot=False, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
plot (bool): whether to expect a plot to be returned by the function.
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
self.plot = plot
|
||||
super().__init__(label)
|
||||
|
||||
@ -154,7 +166,8 @@ class Image(AbstractOutput):
|
||||
try:
|
||||
return preprocessing_utils.encode_array_to_base64(prediction)
|
||||
except:
|
||||
raise ValueError("The `Image` output interface (with plt=False) expects a numpy array.")
|
||||
raise ValueError(
|
||||
"The `Image` output interface (with plt=False) expects a numpy array.")
|
||||
|
||||
def rebuild_flagged(self, dir, msg):
|
||||
"""
|
||||
@ -168,6 +181,33 @@ class Image(AbstractOutput):
|
||||
return filename
|
||||
|
||||
|
||||
class KeyValues(AbstractOutput):
|
||||
'''
|
||||
Component displays a table representing values for multiple fields.
|
||||
Output type: List[Tuple[str, value]]
|
||||
'''
|
||||
|
||||
def __init__(self, label=None):
|
||||
'''
|
||||
Parameters:
|
||||
label (str): component name in interface.
|
||||
'''
|
||||
super().__init__(label)
|
||||
|
||||
def postprocess(self, prediction):
|
||||
if isinstance(prediction, dict):
|
||||
return prediction
|
||||
else:
|
||||
raise ValueError("The `KeyValues` output interface expects an output that is a dictionary whose keys are "
|
||||
"labels and values are corresponding values.")
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"key_values": {},
|
||||
}
|
||||
|
||||
|
||||
# Automatically adds all shortcut implementations in AbstractInput into a dictionary.
|
||||
shortcuts = {}
|
||||
for cls in AbstractOutput.__subclasses__():
|
||||
|
@ -60,11 +60,9 @@ input.panel_button {
|
||||
flex-grow: 1;
|
||||
padding: 12px;
|
||||
box-sizing: border-box;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
border: 0 none;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s ease;
|
||||
margin-left: 16px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
@ -78,11 +76,6 @@ input.submit {
|
||||
input.submit:hover {
|
||||
background-color: #f39c12;
|
||||
}
|
||||
label {
|
||||
transition: background-color 0.2s ease;
|
||||
padding: 2px 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
/* label:hover {
|
||||
background-color: lightgray;
|
||||
} */
|
||||
|
@ -13,30 +13,8 @@
|
||||
margin-top: 12px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.ui-icon-background, .ui-state-active .ui-icon-background {
|
||||
border: #f39c12;
|
||||
background-color: #ffffff;
|
||||
.checkbox_solo label {
|
||||
width: 27px !important;
|
||||
padding-left: 11px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
.ui-visual-focus {
|
||||
box-shadow: 0 0 3px 1px rgb(241, 171, 41);
|
||||
}
|
||||
.ui-button {
|
||||
padding: 0.25em 0.6em;
|
||||
}
|
||||
.ui-widget {
|
||||
font-family: inherit;
|
||||
}
|
||||
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, .ui-button, html .ui-button.ui-state-disabled:hover, html .ui-button.ui-state-disabled:active {
|
||||
border: 1px solid lightgray;
|
||||
background: lightgray;
|
||||
}
|
||||
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover {
|
||||
border: 1px solid #e67e22 !important;
|
||||
background: #e67e22 !important;
|
||||
font-weight: normal;
|
||||
color: #ffffff;
|
||||
}
|
||||
.ui-button {
|
||||
outline: none;
|
||||
}
|
34
gradio/static/css/vendor/jquery-ui.css
vendored
34
gradio/static/css/vendor/jquery-ui.css
vendored
@ -1,7 +1,7 @@
|
||||
/*! jQuery UI - v1.12.1 - 2016-09-14
|
||||
* http://jqueryui.com
|
||||
* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&fwDefault=normal&cornerRadius=3px&bgColorHeader=e9e9e9&bgTextureHeader=flat&borderColorHeader=dddddd&fcHeader=333333&iconColorHeader=444444&bgColorContent=ffffff&bgTextureContent=flat&borderColorContent=dddddd&fcContent=333333&iconColorContent=444444&bgColorDefault=f6f6f6&bgTextureDefault=flat&borderColorDefault=c5c5c5&fcDefault=454545&iconColorDefault=777777&bgColorHover=ededed&bgTextureHover=flat&borderColorHover=cccccc&fcHover=2b2b2b&iconColorHover=555555&bgColorActive=007fff&bgTextureActive=flat&borderColorActive=003eff&fcActive=ffffff&iconColorActive=ffffff&bgColorHighlight=fffa90&bgTextureHighlight=flat&borderColorHighlight=dad55e&fcHighlight=777620&iconColorHighlight=777620&bgColorError=fddfdf&bgTextureError=flat&borderColorError=f1a899&fcError=5f3f3f&iconColorError=cc0000&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=666666&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=5px&offsetTopShadow=0px&offsetLeftShadow=0px&cornerRadiusShadow=8px
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6
|
||||
* Copyright jQuery Foundation and other contributors; Licensed MIT */
|
||||
|
||||
/* Layout helpers
|
||||
@ -164,7 +164,7 @@
|
||||
right: 0;
|
||||
}
|
||||
.ui-button {
|
||||
padding: .4em 1em;
|
||||
padding: 0.25em 0.6em;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
line-height: normal;
|
||||
@ -290,9 +290,7 @@ button.ui-button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.ui-checkboxradio-label .ui-icon-background {
|
||||
box-shadow: inset 1px 1px 1px #ccc;
|
||||
border-radius: .12em;
|
||||
border: none;
|
||||
}
|
||||
.ui-checkboxradio-radio-label .ui-icon-background {
|
||||
width: 16px;
|
||||
@ -301,12 +299,15 @@ button.ui-button::-moz-focus-inner {
|
||||
overflow: visible;
|
||||
border: none;
|
||||
}
|
||||
.ui-checkboxradio-label .ui-icon-background {
|
||||
border: solid 1px lightgray;
|
||||
}
|
||||
.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,
|
||||
.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon {
|
||||
background-image: none;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-width: 4px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
}
|
||||
.ui-checkboxradio-disabled {
|
||||
@ -880,10 +881,11 @@ button.ui-button::-moz-focus-inner {
|
||||
body .ui-tooltip {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
/* Component containers
|
||||
----------------------------------*/
|
||||
.ui-widget {
|
||||
font-family: Arial,Helvetica,sans-serif;
|
||||
font-family: inherit;
|
||||
font-size: 1em;
|
||||
}
|
||||
.ui-widget .ui-widget {
|
||||
@ -928,8 +930,8 @@ body .ui-tooltip {
|
||||
works properly when clicked or hovered */
|
||||
html .ui-button.ui-state-disabled:hover,
|
||||
html .ui-button.ui-state-disabled:active {
|
||||
border: 1px solid #c5c5c5;
|
||||
background: #f6f6f6;
|
||||
border: 1px solid lightgray;
|
||||
background: white;
|
||||
font-weight: normal;
|
||||
color: #454545;
|
||||
}
|
||||
@ -970,23 +972,25 @@ a.ui-button:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ui-visual-focus {
|
||||
box-shadow: 0 0 3px 1px rgb(94, 158, 214);
|
||||
.ui-checkboxradio-label {
|
||||
border: none !important;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.ui-state-active,
|
||||
.ui-widget-content .ui-state-active,
|
||||
.ui-widget-header .ui-state-active,
|
||||
a.ui-button:active,
|
||||
.ui-button:active,
|
||||
.ui-button.ui-state-active:hover {
|
||||
border: 1px solid #003eff;
|
||||
background: #007fff;
|
||||
border: 1px solid #e67e22;
|
||||
background: #e67e22;
|
||||
font-weight: normal;
|
||||
color: #ffffff;
|
||||
}
|
||||
.ui-icon-background,
|
||||
.ui-state-active .ui-icon-background {
|
||||
border: #003eff;
|
||||
border: solid 1px #f39c12;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.ui-state-active a,
|
||||
@ -1302,8 +1306,8 @@ a.ui-button:active,
|
||||
/* Overlays */
|
||||
.ui-widget-overlay {
|
||||
background: #aaaaaa;
|
||||
opacity: .3;
|
||||
filter: Alpha(Opacity=30); /* support: IE8 */
|
||||
opacity: .003;
|
||||
filter: Alpha(Opacity=.3); /* support: IE8 */
|
||||
}
|
||||
.ui-widget-shadow {
|
||||
-webkit-box-shadow: 0px 0px 5px #666666;
|
||||
|
@ -6,8 +6,8 @@ function gradio(config, fn, target) {
|
||||
<div class="input_interfaces">
|
||||
</div>
|
||||
<div class="panel_buttons">
|
||||
<input class="submit panel_button" type="submit" value="submit"/>
|
||||
<input class="clear panel_button" type="reset" value="clear">
|
||||
<input class="clear panel_button" type="reset" value="CLEAR">
|
||||
<input class="submit panel_button" type="submit" value="SUBMIT"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel output_panel">
|
||||
@ -18,8 +18,7 @@ function gradio(config, fn, target) {
|
||||
<div class="output_interfaces">
|
||||
</div>
|
||||
<div class="panel_buttons">
|
||||
<input class="screenshot panel_button" type="button" value="screenshot"/>
|
||||
<input class="flag panel_button" type="button" value="flag"/>
|
||||
<input class="screenshot panel_button" type="button" value="SCREENSHOT" style="visibility: hidden"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>`);
|
||||
|
@ -1,5 +1,7 @@
|
||||
const checkbox = {
|
||||
html: `<label><input class="checkbox" type="checkbox"> </label>`,
|
||||
html: `<div class="checkbox_solo">
|
||||
<label><input class="checkbox" type="checkbox"> </label>
|
||||
</div>`,
|
||||
init: function(opts) {
|
||||
this.target.css("height", "auto");
|
||||
this.target.find("input").checkboxradio();
|
||||
@ -11,6 +13,7 @@ const checkbox = {
|
||||
},
|
||||
clear: function() {
|
||||
this.target.find("input").prop("checked", false);
|
||||
this.target.find("input").button("refresh");
|
||||
},
|
||||
load_example: function(data) {
|
||||
if (data) {
|
||||
@ -18,5 +21,6 @@ const checkbox = {
|
||||
} else {
|
||||
this.target.find("input").prop("checked", false);
|
||||
}
|
||||
this.target.find("input").button("refresh");
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,6 @@
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/dropdown.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/checkbox_group.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/slider.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/csv.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/webcam.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/microphone.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/output/image.css">
|
||||
@ -61,7 +60,9 @@
|
||||
</div>
|
||||
<div id="credit">Built with <a href="http://gradio.app" target="_blank">Gradio</a>.</div>
|
||||
<script src="../static/js/vendor/jquery.min.js"></script>
|
||||
<!-- TUI EDITOR -->
|
||||
<!-- VENDOR -->
|
||||
<script src="../static/js/vendor/html2canvas.min.js"></script>
|
||||
<script src="../static/js/vendor/jquery-ui.min.js"></script>
|
||||
<script src="../static/js/vendor/fabric.js"></script>
|
||||
<script src="../static/js/vendor/tui-code-snippet.min.js"></script>
|
||||
<script src="../static/js/vendor/FileSaver.min.js"></script>
|
||||
@ -70,9 +71,6 @@
|
||||
<script src="../static/js/vendor/white-theme.js"></script>
|
||||
<script src="../static/js/vendor/black-theme.js"></script>
|
||||
|
||||
<script src="../static/js/vendor/html2canvas.min.js"></script>
|
||||
<script src="../static/js/vendor/jquery-ui.min.js"></script>
|
||||
|
||||
<script src="../static/js/utils.js"></script>
|
||||
<script src="../static/js/all_io.js"></script>
|
||||
<script src="../static/js/interfaces/input/csv.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user