mirror of
https://github.com/gradio-app/gradio.git
synced 2025-02-11 11:19:58 +08:00
multiple inputs & outputs
This commit is contained in:
parent
ce9d444088
commit
54eb9def99
@ -150,7 +150,7 @@ class Webcam(AbstractInput):
|
||||
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))
|
||||
array = np.array(im).flatten().reshape(1, self.image_width, self.image_height, self.num_channels)
|
||||
array = np.array(im).flatten().reshape(self.image_width, self.image_height, self.num_channels)
|
||||
return array
|
||||
|
||||
def rebuild_flagged(self, dir, msg):
|
||||
|
@ -28,38 +28,52 @@ class Interface:
|
||||
the appropriate inputs and outputs
|
||||
"""
|
||||
|
||||
def __init__(self, fn, inputs, outputs, verbose=False, live=False):
|
||||
def __init__(self, fn, inputs, outputs, verbose=False, live=False, show_input=True, show_output=True):
|
||||
"""
|
||||
: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.
|
||||
"""
|
||||
if isinstance(inputs, str):
|
||||
self.input_interface = gradio.inputs.registry[inputs.lower()]()
|
||||
elif isinstance(inputs, gradio.inputs.AbstractInput):
|
||||
self.input_interface = inputs
|
||||
def get_input_instance(iface):
|
||||
if isinstance(iface, str):
|
||||
return gradio.inputs.registry[iface.lower()]()
|
||||
elif isinstance(iface, gradio.inputs.AbstractInput):
|
||||
return iface
|
||||
else:
|
||||
raise ValueError("Input interface must be of type `str` or `AbstractInput`")
|
||||
def get_output_instance(iface):
|
||||
if isinstance(iface, str):
|
||||
return gradio.outputs.registry[iface.lower()]()
|
||||
elif isinstance(iface, gradio.outputs.AbstractOutput):
|
||||
return iface
|
||||
else:
|
||||
raise ValueError(
|
||||
"Output interface must be of type `str` or `AbstractOutput`"
|
||||
)
|
||||
if isinstance(inputs, list):
|
||||
self.input_interfaces = [get_input_instance(i) for i in inputs]
|
||||
else:
|
||||
raise ValueError("Input interface must be of type `str` or `AbstractInput`")
|
||||
if isinstance(outputs, str):
|
||||
self.output_interface = gradio.outputs.registry[outputs.lower()]()
|
||||
elif isinstance(outputs, gradio.outputs.AbstractOutput):
|
||||
self.output_interface = outputs
|
||||
self.input_interfaces = [get_input_instance(inputs)]
|
||||
if isinstance(outputs, list):
|
||||
self.output_interfaces = [get_output_instance(i) for i in outputs]
|
||||
else:
|
||||
raise ValueError(
|
||||
"Output interface must be of type `str` or `AbstractOutput`"
|
||||
)
|
||||
self.output_interfaces = [get_output_instance(outputs)]
|
||||
self.predict = fn
|
||||
self.verbose = verbose
|
||||
self.status = "OFF"
|
||||
self.saliency = None
|
||||
self.live = live
|
||||
self.show_input = show_input
|
||||
self.show_output = show_output
|
||||
|
||||
|
||||
def update_config_file(self, output_directory):
|
||||
config = {
|
||||
"input_interface_type": self.input_interface.__class__.__name__.lower(),
|
||||
"output_interface_type": self.output_interface.__class__.__name__.lower(),
|
||||
"live": self.live
|
||||
"input_interfaces": [iface.__class__.__name__.lower() for iface in self.input_interfaces],
|
||||
"output_interfaces": [iface.__class__.__name__.lower() for iface in self.output_interfaces],
|
||||
"live": self.live,
|
||||
"show_input": self.show_input,
|
||||
"show_output": self.show_output,
|
||||
}
|
||||
networking.set_config(config, output_directory)
|
||||
|
||||
@ -140,9 +154,7 @@ class Interface:
|
||||
# Set up a port to serve the directory containing the static files with interface.
|
||||
server_port, httpd = networking.start_simple_server(self, output_directory)
|
||||
path_to_local_server = "http://localhost:{}/".format(server_port)
|
||||
networking.build_template(
|
||||
output_directory, self.input_interface, self.output_interface
|
||||
)
|
||||
networking.build_template(output_directory)
|
||||
|
||||
self.update_config_file(output_directory)
|
||||
|
||||
|
@ -37,7 +37,7 @@ FLAGGING_DIRECTORY = 'static/flagged/'
|
||||
FLAGGING_FILENAME = 'data.txt'
|
||||
|
||||
|
||||
def build_template(temp_dir, input_interface, output_interface):
|
||||
def build_template(temp_dir):
|
||||
"""
|
||||
Create HTML file with supporting JS and CSS files in a given directory.
|
||||
:param temp_dir: string with path to temp directory in which the html file should be built
|
||||
@ -49,21 +49,6 @@ def build_template(temp_dir, input_interface, output_interface):
|
||||
copyfile(os.path.join(temp_dir, ASSOCIATION_PATH_IN_STATIC),
|
||||
os.path.join(temp_dir, ASSOCIATION_PATH_IN_ROOT))
|
||||
|
||||
render_template_with_tags(
|
||||
os.path.join(
|
||||
temp_dir,
|
||||
inputs.BASE_INPUT_INTERFACE_JS_PATH.format(input_interface.get_name()),
|
||||
),
|
||||
input_interface.get_js_context(),
|
||||
)
|
||||
render_template_with_tags(
|
||||
os.path.join(
|
||||
temp_dir,
|
||||
outputs.BASE_OUTPUT_INTERFACE_JS_PATH.format(output_interface.get_name()),
|
||||
),
|
||||
output_interface.get_js_context(),
|
||||
)
|
||||
|
||||
|
||||
def render_template_with_tags(template_path, context):
|
||||
"""
|
||||
@ -151,9 +136,11 @@ def serve_files_in_background(interface, port, directory_to_serve=None):
|
||||
data_string = self.rfile.read(int(self.headers["Content-Length"]))
|
||||
msg = json.loads(data_string)
|
||||
raw_input = msg["data"]
|
||||
processed_input = interface.input_interface.preprocess(raw_input)
|
||||
prediction = interface.predict(processed_input)
|
||||
processed_output = interface.output_interface.postprocess(prediction)
|
||||
processed_input = [input_interface.preprocess(raw_input[i]) for i, input_interface in enumerate(interface.input_interfaces)]
|
||||
prediction = interface.predict(*processed_input)
|
||||
if len(interface.input_interfaces) == 1:
|
||||
prediction = [prediction]
|
||||
processed_output = [output_interface.postprocess(prediction[i]) for i, output_interface in enumerate(interface.output_interfaces)]
|
||||
output = {"action": "output", "data": processed_output}
|
||||
if interface.saliency is not None:
|
||||
import numpy as np
|
||||
|
20
build/lib/gradio/static/css/interfaces/input/webcam.css
Normal file
20
build/lib/gradio/static/css/interfaces/input/webcam.css
Normal file
@ -0,0 +1,20 @@
|
||||
.webcam_box {
|
||||
width: 100% !important;
|
||||
flex-grow: 1;
|
||||
background-color: #BBBBBB;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.webcam_box canvas {
|
||||
border: none;
|
||||
}
|
||||
.take_photo {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.snapped {
|
||||
display: none;
|
||||
}
|
@ -1,15 +1,30 @@
|
||||
var io_master = {
|
||||
gather: function() {
|
||||
this.clear();
|
||||
for (let iface of this.input_interfaces) {
|
||||
iface.submit();
|
||||
}
|
||||
},
|
||||
clear: function() {
|
||||
this.last_input = new Array(this.input_interfaces.length);
|
||||
this.input_count = 0;
|
||||
},
|
||||
input: function(interface_id, data) {
|
||||
this.last_input = data;
|
||||
this.last_output = null;
|
||||
this.last_input[interface_id] = data;
|
||||
this.input_count += 1;
|
||||
if (this.input_count == this.input_interfaces.length) {
|
||||
this.submit();
|
||||
}
|
||||
},
|
||||
submit: function() {
|
||||
var post_data = {
|
||||
'data': data
|
||||
'data': this.last_input
|
||||
};
|
||||
if (!config.live) {
|
||||
$("#loading").removeClass("invisible");
|
||||
$("#loading_in_progress").show();
|
||||
$("#loading_failed").hide();
|
||||
$("#output_interface").addClass("invisible");
|
||||
$(".output_interface").addClass("invisible");
|
||||
}
|
||||
$.ajax({type: "POST",
|
||||
url: "/api/predict/",
|
||||
@ -30,15 +45,17 @@ var io_master = {
|
||||
},
|
||||
output: function(data) {
|
||||
this.last_output = data["data"];
|
||||
this.output_interface.output(data["data"]);
|
||||
if (this.input_interface.output && data["saliency"]) {
|
||||
this.input_interface.output(data["saliency"]);
|
||||
for (let i = 0; i < this.output_interfaces.length; i++) {
|
||||
this.output_interfaces[i].output(data["data"][i]);
|
||||
}
|
||||
// if (this.input_interface.output && data["saliency"]) {
|
||||
// this.input_interface.output(data["saliency"]);
|
||||
// }
|
||||
if (config.live) {
|
||||
io_master.input_interface.submit();
|
||||
this.gather();
|
||||
} else {
|
||||
$("#loading").addClass("invisible");
|
||||
$("#output_interface").removeClass("invisible");
|
||||
$(".output_interface").removeClass("invisible");
|
||||
}
|
||||
},
|
||||
flag: function(message) {
|
||||
|
@ -89,9 +89,10 @@ const image_input = {
|
||||
})
|
||||
},
|
||||
submit: function() {
|
||||
var io = this;
|
||||
if (this.state == "IMAGE_LOADED") {
|
||||
resizeImage.call(this, this.image_data, 300, 300, function(image_data) {
|
||||
this.io_master.input(this.id, image_data);
|
||||
this.io_master.input(io.id, image_data);
|
||||
})
|
||||
}
|
||||
},
|
||||
|
79
build/lib/gradio/static/js/interfaces/input/webcam.js
Normal file
79
build/lib/gradio/static/js/interfaces/input/webcam.js
Normal file
@ -0,0 +1,79 @@
|
||||
const webcam = {
|
||||
html: `
|
||||
<div class="webcam_box"></div>
|
||||
<button class="take_photo">
|
||||
<span class="camera_on">Click here to take a photo!</span>
|
||||
<span class="snapped">Snapped!</span>
|
||||
</button>
|
||||
`,
|
||||
init: function() {
|
||||
var io = this;
|
||||
// this.target.find(".webcam_box").width(this.target.find(".webcam_box").width);
|
||||
let w = this.target.find(".webcam_box").width();
|
||||
let h = this.target.find(".webcam_box").height();
|
||||
if (config.live) {
|
||||
this.target.find(".take_photo").hide();
|
||||
}
|
||||
let RATIO = 4/3;
|
||||
let dim = Math.min(h, w / RATIO);
|
||||
Webcam.set({
|
||||
image_format: 'jpeg',
|
||||
width: dim * RATIO,
|
||||
height: dim,
|
||||
dest_width: dim * RATIO,
|
||||
dest_height: dim,
|
||||
})
|
||||
Webcam.attach(this.target.find(".webcam_box")[0]);
|
||||
window.setTimeout(function() {
|
||||
io.state = "CAMERA_ON";
|
||||
}, 1000);
|
||||
this.target.find(".webcam_box, .take_photo").click(function() {
|
||||
if (io.state != "CAMERA_ON" || config.live) {
|
||||
return;
|
||||
}
|
||||
Webcam.snap(function(image_data) {
|
||||
io.image_data = image_data;
|
||||
});
|
||||
|
||||
io.state = "SNAPPED";
|
||||
Webcam.freeze();
|
||||
io.target.find(".webcam_box video").hide();
|
||||
io.target.find(".camera_on").hide();
|
||||
io.target.find(".snapped").show();
|
||||
|
||||
})
|
||||
},
|
||||
submit: function() {
|
||||
var io = this;
|
||||
if (config.live) {
|
||||
if (this.state == "CAMERA_ON") {
|
||||
Webcam.snap(function(image_data) {
|
||||
this.io_master.input(io.id, image_data);
|
||||
});
|
||||
} else {
|
||||
window.setTimeout(function() {
|
||||
io.submit();
|
||||
}, 500);
|
||||
}
|
||||
} else if (this.state == "SNAPPED") {
|
||||
this.io_master.input(this.id, this.image_data);
|
||||
}
|
||||
},
|
||||
clear: function() {
|
||||
if (this.state == "SNAPPED") {
|
||||
this.state = "CAMERA_ON";
|
||||
this.target.find(".camera_on").show();
|
||||
this.target.find(".snapped").hide();
|
||||
Webcam.unfreeze();
|
||||
this.target.find(".webcam_box video").show();
|
||||
}
|
||||
},
|
||||
state: "NOT_STARTED",
|
||||
image_data: null,
|
||||
renderFeatured: function(data) {
|
||||
return `<img src=${data}>`;
|
||||
},
|
||||
loadFeatured: function(data) {
|
||||
return `<img src=${data}>`;
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
input_to_object_map = {
|
||||
"csv" : {},
|
||||
"image" : image_input,
|
||||
"imagein" : image_input,
|
||||
"sketchpad" : sketchpad_input,
|
||||
"textbox" : textbox_input,
|
||||
"webcam" : webcam,
|
||||
"microphone" : microphone
|
||||
}
|
||||
output_to_object_map = {
|
||||
@ -16,39 +17,60 @@ id_to_interface_map = {}
|
||||
function set_interface_id(interface, id) {
|
||||
interface.id = id;
|
||||
id_to_interface_map[id] = interface;
|
||||
interface.target.attr("interface_id", id);
|
||||
}
|
||||
|
||||
var config;
|
||||
$.getJSON("static/config.json", function(data) {
|
||||
config = data;
|
||||
input_interface = Object.create(input_to_object_map[
|
||||
config["input_interface_type"]]);
|
||||
output_interface = Object.create(output_to_object_map[
|
||||
config["output_interface_type"]]);
|
||||
$("#input_interface").html(config.disabled ?
|
||||
input_interface.disabled_html : input_interface.html);
|
||||
input_interface.target = $("#input_interface");
|
||||
set_interface_id(input_interface, 1)
|
||||
input_interface.init();
|
||||
$("#output_interface").html(output_interface.html);
|
||||
output_interface.target = $("#output_interface");
|
||||
set_interface_id(output_interface, 2)
|
||||
output_interface.init();
|
||||
_id = 0;
|
||||
let input_interfaces = [];
|
||||
let output_interfaces = [];
|
||||
for (let i = 0; i < config["input_interfaces"].length; i++) {
|
||||
input_interface = Object.create(input_to_object_map[
|
||||
config["input_interfaces"][i]]);
|
||||
$(".input_interfaces").append(`
|
||||
<div class="input_interface interface" interface_id=${_id}>
|
||||
${input_interface.html}
|
||||
</div>
|
||||
`);
|
||||
input_interface.target = $(`.input_interface[interface_id=${_id}]`);
|
||||
set_interface_id(input_interface, _id);
|
||||
input_interface.init();
|
||||
input_interfaces.push(input_interface);
|
||||
input_interface.io_master = io_master;
|
||||
_id++;
|
||||
}
|
||||
for (let i = 0; i < config["output_interfaces"].length; i++) {
|
||||
output_interface = Object.create(output_to_object_map[
|
||||
config["output_interfaces"][i]]);
|
||||
$(".output_interfaces").append(`
|
||||
<div class="output_interface interface" interface_id=${_id}>
|
||||
${output_interface.html}
|
||||
</div>
|
||||
`);
|
||||
output_interface.target = $(`.output_interface[interface_id=${_id}]`);
|
||||
set_interface_id(output_interface, _id);
|
||||
output_interface.init();
|
||||
output_interfaces.push(output_interface);
|
||||
output_interface.io_master = io_master;
|
||||
_id++;
|
||||
}
|
||||
io_master.input_interfaces = input_interfaces;
|
||||
io_master.output_interfaces = output_interfaces;
|
||||
$(".clear").click(function() {
|
||||
input_interface.clear();
|
||||
output_interface.clear();
|
||||
for (let input_interface of input_interfaces) {
|
||||
input_interface.clear();
|
||||
}
|
||||
for (let output_interface of output_interfaces) {
|
||||
output_interface.clear();
|
||||
}
|
||||
$(".flag").removeClass("flagged");
|
||||
$(".flag_message").empty();
|
||||
$("#loading").addClass("invisible");
|
||||
$("#output_interface").removeClass("invisible");
|
||||
$(".output_interface").removeClass("invisible");
|
||||
io_master.last_input = null;
|
||||
io_master.last_output = null;
|
||||
})
|
||||
input_interface.io_master = io_master;
|
||||
io_master.input_interface = input_interface;
|
||||
output_interface.io_master = io_master;
|
||||
io_master.output_interface = output_interface;
|
||||
if (config["share_url"] != "None") {
|
||||
$("#share_row").css('display', 'flex');
|
||||
}
|
||||
@ -57,14 +79,17 @@ $.getJSON("static/config.json", function(data) {
|
||||
$("#featured_history").hide();
|
||||
}
|
||||
if (config.live) {
|
||||
input_interface.submit();
|
||||
io_master.gather();
|
||||
} else {
|
||||
$(".submit").show();
|
||||
$(".submit").click(function() {
|
||||
input_interface.submit();
|
||||
io_master.gather();
|
||||
$(".flag").removeClass("flagged");
|
||||
})
|
||||
}
|
||||
if (!config.show_input) {
|
||||
$(".input_panel").hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('click', '.flag', function(e) {
|
||||
|
2
build/lib/gradio/static/js/vendor/webcam.min.js
vendored
Normal file
2
build/lib/gradio/static/js/vendor/webcam.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -10,6 +10,7 @@
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/sketchpad.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/textbox.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">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/output/label.css">
|
||||
@ -37,15 +38,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="panels">
|
||||
<div class="panel">
|
||||
<div class="panel input_panel">
|
||||
<div class="panel_header">Input</div>
|
||||
<div id="input_interface" class="interface"></div>
|
||||
<div class="input_interfaces">
|
||||
</div>
|
||||
<div class="panel_buttons">
|
||||
<input class="submit" type="submit" value="submit"/>
|
||||
<input class="clear" type="reset" value="clear">
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel output_panel">
|
||||
<div class="panel_header">
|
||||
Output
|
||||
</div>
|
||||
@ -53,7 +55,8 @@
|
||||
<img id="loading_in_progress" src="../static/img/logo_loading.gif">
|
||||
<img id="loading_failed" src="../static/img/logo_error.png">
|
||||
</div>
|
||||
<div id="output_interface" class="interface"></div>
|
||||
<div class="output_interfaces">
|
||||
</div>
|
||||
<div class="panel_buttons">
|
||||
<input type="text" class="flag_message" placeholder="(Optional message for flagging)"/>
|
||||
<input type="button" class="panel_button flag" value="flag"/>
|
||||
@ -83,6 +86,8 @@
|
||||
<script src="../static/js/interfaces/input/sketchpad.js"></script>
|
||||
<script src="../static/js/interfaces/input/textbox.js"></script>
|
||||
<script src="../static/js/interfaces/input/csv.js"></script>
|
||||
<script src="../static/js/vendor/webcam.min.js"></script>
|
||||
<script src="../static/js/interfaces/input/webcam.js"></script>
|
||||
<script src="../static/js/interfaces/input/microphone.js"></script>
|
||||
<script src="../static/js/vendor/wavesurfer.min.js"></script>
|
||||
<script src="../static/js/vendor/p5.min.js"></script>
|
||||
|
@ -1,6 +1,11 @@
|
||||
import gradio as gr
|
||||
|
||||
def upper(sentence):
|
||||
return sentence.upper()
|
||||
|
||||
gr.Interface(upper, "textbox", "textbox", live=True).launch()
|
||||
def upper(sentence, sentence2):
|
||||
return sentence2.upper(), sentence[::-1]
|
||||
|
||||
|
||||
gr.Interface(upper,
|
||||
["textbox", "textbox"],
|
||||
["textbox", "textbox"],
|
||||
live=True).launch()
|
||||
|
@ -4,4 +4,4 @@ import numpy as np
|
||||
def flip(image):
|
||||
return np.flipud(image)
|
||||
|
||||
gr.Interface(flip, "image", "image").launch()
|
||||
gr.Interface(flip, "imagein", "image").launch()
|
7
demo/webcam.py
Normal file
7
demo/webcam.py
Normal file
@ -0,0 +1,7 @@
|
||||
import gradio as gr
|
||||
import numpy as np
|
||||
|
||||
def snap(image):
|
||||
return np.flipud(image)
|
||||
|
||||
gr.Interface(snap, "webcam", "image", live=True, show_input=False).launch()
|
BIN
dist/gradio-0.9.0-py3.7.egg
vendored
Normal file
BIN
dist/gradio-0.9.0-py3.7.egg
vendored
Normal file
Binary file not shown.
@ -25,6 +25,7 @@ gradio/static/css/interfaces/input/image.css
|
||||
gradio/static/css/interfaces/input/microphone.css
|
||||
gradio/static/css/interfaces/input/sketchpad.css
|
||||
gradio/static/css/interfaces/input/textbox.css
|
||||
gradio/static/css/interfaces/input/webcam.css
|
||||
gradio/static/css/interfaces/output/image.css
|
||||
gradio/static/css/interfaces/output/label.css
|
||||
gradio/static/css/interfaces/output/textbox.css
|
||||
@ -54,6 +55,7 @@ gradio/static/js/interfaces/input/image.js
|
||||
gradio/static/js/interfaces/input/microphone.js
|
||||
gradio/static/js/interfaces/input/sketchpad.js
|
||||
gradio/static/js/interfaces/input/textbox.js
|
||||
gradio/static/js/interfaces/input/webcam.js
|
||||
gradio/static/js/interfaces/output/image.js
|
||||
gradio/static/js/interfaces/output/label.js
|
||||
gradio/static/js/interfaces/output/textbox.js
|
||||
@ -70,6 +72,7 @@ gradio/static/js/vendor/tui-code-snippet.min.js
|
||||
gradio/static/js/vendor/tui-color-picker.js
|
||||
gradio/static/js/vendor/tui-image-editor.js
|
||||
gradio/static/js/vendor/wavesurfer.min.js
|
||||
gradio/static/js/vendor/webcam.min.js
|
||||
gradio/static/js/vendor/white-theme.js
|
||||
gradio/templates/bulk_data.html
|
||||
gradio/templates/index.html
|
||||
|
@ -150,7 +150,7 @@ class Webcam(AbstractInput):
|
||||
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))
|
||||
array = np.array(im).flatten().reshape(1, self.image_width, self.image_height, self.num_channels)
|
||||
array = np.array(im).flatten().reshape(self.image_width, self.image_height, self.num_channels)
|
||||
return array
|
||||
|
||||
def rebuild_flagged(self, dir, msg):
|
||||
|
@ -28,38 +28,52 @@ class Interface:
|
||||
the appropriate inputs and outputs
|
||||
"""
|
||||
|
||||
def __init__(self, fn, inputs, outputs, verbose=False, live=False):
|
||||
def __init__(self, fn, inputs, outputs, verbose=False, live=False, show_input=True, show_output=True):
|
||||
"""
|
||||
: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.
|
||||
"""
|
||||
if isinstance(inputs, str):
|
||||
self.input_interface = gradio.inputs.registry[inputs.lower()]()
|
||||
elif isinstance(inputs, gradio.inputs.AbstractInput):
|
||||
self.input_interface = inputs
|
||||
def get_input_instance(iface):
|
||||
if isinstance(iface, str):
|
||||
return gradio.inputs.registry[iface.lower()]()
|
||||
elif isinstance(iface, gradio.inputs.AbstractInput):
|
||||
return iface
|
||||
else:
|
||||
raise ValueError("Input interface must be of type `str` or `AbstractInput`")
|
||||
def get_output_instance(iface):
|
||||
if isinstance(iface, str):
|
||||
return gradio.outputs.registry[iface.lower()]()
|
||||
elif isinstance(iface, gradio.outputs.AbstractOutput):
|
||||
return iface
|
||||
else:
|
||||
raise ValueError(
|
||||
"Output interface must be of type `str` or `AbstractOutput`"
|
||||
)
|
||||
if isinstance(inputs, list):
|
||||
self.input_interfaces = [get_input_instance(i) for i in inputs]
|
||||
else:
|
||||
raise ValueError("Input interface must be of type `str` or `AbstractInput`")
|
||||
if isinstance(outputs, str):
|
||||
self.output_interface = gradio.outputs.registry[outputs.lower()]()
|
||||
elif isinstance(outputs, gradio.outputs.AbstractOutput):
|
||||
self.output_interface = outputs
|
||||
self.input_interfaces = [get_input_instance(inputs)]
|
||||
if isinstance(outputs, list):
|
||||
self.output_interfaces = [get_output_instance(i) for i in outputs]
|
||||
else:
|
||||
raise ValueError(
|
||||
"Output interface must be of type `str` or `AbstractOutput`"
|
||||
)
|
||||
self.output_interfaces = [get_output_instance(outputs)]
|
||||
self.predict = fn
|
||||
self.verbose = verbose
|
||||
self.status = "OFF"
|
||||
self.saliency = None
|
||||
self.live = live
|
||||
self.show_input = show_input
|
||||
self.show_output = show_output
|
||||
|
||||
|
||||
def update_config_file(self, output_directory):
|
||||
config = {
|
||||
"input_interface_type": self.input_interface.__class__.__name__.lower(),
|
||||
"output_interface_type": self.output_interface.__class__.__name__.lower(),
|
||||
"live": self.live
|
||||
"input_interfaces": [iface.__class__.__name__.lower() for iface in self.input_interfaces],
|
||||
"output_interfaces": [iface.__class__.__name__.lower() for iface in self.output_interfaces],
|
||||
"live": self.live,
|
||||
"show_input": self.show_input,
|
||||
"show_output": self.show_output,
|
||||
}
|
||||
networking.set_config(config, output_directory)
|
||||
|
||||
@ -140,9 +154,7 @@ class Interface:
|
||||
# Set up a port to serve the directory containing the static files with interface.
|
||||
server_port, httpd = networking.start_simple_server(self, output_directory)
|
||||
path_to_local_server = "http://localhost:{}/".format(server_port)
|
||||
networking.build_template(
|
||||
output_directory, self.input_interface, self.output_interface
|
||||
)
|
||||
networking.build_template(output_directory)
|
||||
|
||||
self.update_config_file(output_directory)
|
||||
|
||||
|
@ -37,7 +37,7 @@ FLAGGING_DIRECTORY = 'static/flagged/'
|
||||
FLAGGING_FILENAME = 'data.txt'
|
||||
|
||||
|
||||
def build_template(temp_dir, input_interface, output_interface):
|
||||
def build_template(temp_dir):
|
||||
"""
|
||||
Create HTML file with supporting JS and CSS files in a given directory.
|
||||
:param temp_dir: string with path to temp directory in which the html file should be built
|
||||
@ -49,21 +49,6 @@ def build_template(temp_dir, input_interface, output_interface):
|
||||
copyfile(os.path.join(temp_dir, ASSOCIATION_PATH_IN_STATIC),
|
||||
os.path.join(temp_dir, ASSOCIATION_PATH_IN_ROOT))
|
||||
|
||||
render_template_with_tags(
|
||||
os.path.join(
|
||||
temp_dir,
|
||||
inputs.BASE_INPUT_INTERFACE_JS_PATH.format(input_interface.get_name()),
|
||||
),
|
||||
input_interface.get_js_context(),
|
||||
)
|
||||
render_template_with_tags(
|
||||
os.path.join(
|
||||
temp_dir,
|
||||
outputs.BASE_OUTPUT_INTERFACE_JS_PATH.format(output_interface.get_name()),
|
||||
),
|
||||
output_interface.get_js_context(),
|
||||
)
|
||||
|
||||
|
||||
def render_template_with_tags(template_path, context):
|
||||
"""
|
||||
@ -151,9 +136,11 @@ def serve_files_in_background(interface, port, directory_to_serve=None):
|
||||
data_string = self.rfile.read(int(self.headers["Content-Length"]))
|
||||
msg = json.loads(data_string)
|
||||
raw_input = msg["data"]
|
||||
processed_input = interface.input_interface.preprocess(raw_input)
|
||||
prediction = interface.predict(processed_input)
|
||||
processed_output = interface.output_interface.postprocess(prediction)
|
||||
processed_input = [input_interface.preprocess(raw_input[i]) for i, input_interface in enumerate(interface.input_interfaces)]
|
||||
prediction = interface.predict(*processed_input)
|
||||
if len(interface.input_interfaces) == 1:
|
||||
prediction = [prediction]
|
||||
processed_output = [output_interface.postprocess(prediction[i]) for i, output_interface in enumerate(interface.output_interfaces)]
|
||||
output = {"action": "output", "data": processed_output}
|
||||
if interface.saliency is not None:
|
||||
import numpy as np
|
||||
|
20
gradio/static/css/interfaces/input/webcam.css
Normal file
20
gradio/static/css/interfaces/input/webcam.css
Normal file
@ -0,0 +1,20 @@
|
||||
.webcam_box {
|
||||
width: 100% !important;
|
||||
flex-grow: 1;
|
||||
background-color: #BBBBBB;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.webcam_box canvas {
|
||||
border: none;
|
||||
}
|
||||
.take_photo {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.snapped {
|
||||
display: none;
|
||||
}
|
@ -1,14 +1,31 @@
|
||||
var io_master = {
|
||||
gather: function() {
|
||||
this.clear();
|
||||
for (let iface of this.input_interfaces) {
|
||||
iface.submit();
|
||||
}
|
||||
},
|
||||
clear: function() {
|
||||
this.last_input = new Array(this.input_interfaces.length);
|
||||
this.input_count = 0;
|
||||
},
|
||||
input: function(interface_id, data) {
|
||||
this.last_input = data;
|
||||
this.last_output = null;
|
||||
this.last_input[interface_id] = data;
|
||||
this.input_count += 1;
|
||||
if (this.input_count == this.input_interfaces.length) {
|
||||
this.submit();
|
||||
}
|
||||
},
|
||||
submit: function() {
|
||||
var post_data = {
|
||||
'data': data
|
||||
'data': this.last_input
|
||||
};
|
||||
$("#loading").removeClass("invisible");
|
||||
$("#loading_in_progress").show();
|
||||
$("#loading_failed").hide();
|
||||
$("#output_interface").addClass("invisible");
|
||||
if (!config.live) {
|
||||
$("#loading").removeClass("invisible");
|
||||
$("#loading_in_progress").show();
|
||||
$("#loading_failed").hide();
|
||||
$(".output_interface").addClass("invisible");
|
||||
}
|
||||
$.ajax({type: "POST",
|
||||
url: "/api/predict/",
|
||||
data: JSON.stringify(post_data),
|
||||
@ -28,14 +45,17 @@ var io_master = {
|
||||
},
|
||||
output: function(data) {
|
||||
this.last_output = data["data"];
|
||||
this.output_interface.output(data["data"]);
|
||||
if (this.input_interface.output && data["saliency"]) {
|
||||
this.input_interface.output(data["saliency"]);
|
||||
for (let i = 0; i < this.output_interfaces.length; i++) {
|
||||
this.output_interfaces[i].output(data["data"][i]);
|
||||
}
|
||||
$("#loading").addClass("invisible");
|
||||
$("#output_interface").removeClass("invisible");
|
||||
// if (this.input_interface.output && data["saliency"]) {
|
||||
// this.input_interface.output(data["saliency"]);
|
||||
// }
|
||||
if (config.live) {
|
||||
io_master.input_interface.submit();
|
||||
this.gather();
|
||||
} else {
|
||||
$("#loading").addClass("invisible");
|
||||
$(".output_interface").removeClass("invisible");
|
||||
}
|
||||
},
|
||||
flag: function(message) {
|
||||
|
@ -89,9 +89,10 @@ const image_input = {
|
||||
})
|
||||
},
|
||||
submit: function() {
|
||||
var io = this;
|
||||
if (this.state == "IMAGE_LOADED") {
|
||||
resizeImage.call(this, this.image_data, 300, 300, function(image_data) {
|
||||
this.io_master.input(this.id, image_data);
|
||||
this.io_master.input(io.id, image_data);
|
||||
})
|
||||
}
|
||||
},
|
||||
|
79
gradio/static/js/interfaces/input/webcam.js
Normal file
79
gradio/static/js/interfaces/input/webcam.js
Normal file
@ -0,0 +1,79 @@
|
||||
const webcam = {
|
||||
html: `
|
||||
<div class="webcam_box"></div>
|
||||
<button class="take_photo">
|
||||
<span class="camera_on">Click here to take a photo!</span>
|
||||
<span class="snapped">Snapped!</span>
|
||||
</button>
|
||||
`,
|
||||
init: function() {
|
||||
var io = this;
|
||||
// this.target.find(".webcam_box").width(this.target.find(".webcam_box").width);
|
||||
let w = this.target.find(".webcam_box").width();
|
||||
let h = this.target.find(".webcam_box").height();
|
||||
if (config.live) {
|
||||
this.target.find(".take_photo").hide();
|
||||
}
|
||||
let RATIO = 4/3;
|
||||
let dim = Math.min(h, w / RATIO);
|
||||
Webcam.set({
|
||||
image_format: 'jpeg',
|
||||
width: dim * RATIO,
|
||||
height: dim,
|
||||
dest_width: dim * RATIO,
|
||||
dest_height: dim,
|
||||
})
|
||||
Webcam.attach(this.target.find(".webcam_box")[0]);
|
||||
window.setTimeout(function() {
|
||||
io.state = "CAMERA_ON";
|
||||
}, 1000);
|
||||
this.target.find(".webcam_box, .take_photo").click(function() {
|
||||
if (io.state != "CAMERA_ON" || config.live) {
|
||||
return;
|
||||
}
|
||||
Webcam.snap(function(image_data) {
|
||||
io.image_data = image_data;
|
||||
});
|
||||
|
||||
io.state = "SNAPPED";
|
||||
Webcam.freeze();
|
||||
io.target.find(".webcam_box video").hide();
|
||||
io.target.find(".camera_on").hide();
|
||||
io.target.find(".snapped").show();
|
||||
|
||||
})
|
||||
},
|
||||
submit: function() {
|
||||
var io = this;
|
||||
if (config.live) {
|
||||
if (this.state == "CAMERA_ON") {
|
||||
Webcam.snap(function(image_data) {
|
||||
this.io_master.input(io.id, image_data);
|
||||
});
|
||||
} else {
|
||||
window.setTimeout(function() {
|
||||
io.submit();
|
||||
}, 500);
|
||||
}
|
||||
} else if (this.state == "SNAPPED") {
|
||||
this.io_master.input(this.id, this.image_data);
|
||||
}
|
||||
},
|
||||
clear: function() {
|
||||
if (this.state == "SNAPPED") {
|
||||
this.state = "CAMERA_ON";
|
||||
this.target.find(".camera_on").show();
|
||||
this.target.find(".snapped").hide();
|
||||
Webcam.unfreeze();
|
||||
this.target.find(".webcam_box video").show();
|
||||
}
|
||||
},
|
||||
state: "NOT_STARTED",
|
||||
image_data: null,
|
||||
renderFeatured: function(data) {
|
||||
return `<img src=${data}>`;
|
||||
},
|
||||
loadFeatured: function(data) {
|
||||
return `<img src=${data}>`;
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
input_to_object_map = {
|
||||
"csv" : {},
|
||||
"image" : image_input,
|
||||
"imagein" : image_input,
|
||||
"sketchpad" : sketchpad_input,
|
||||
"textbox" : textbox_input,
|
||||
"webcam" : webcam,
|
||||
"microphone" : microphone
|
||||
}
|
||||
output_to_object_map = {
|
||||
@ -16,39 +17,60 @@ id_to_interface_map = {}
|
||||
function set_interface_id(interface, id) {
|
||||
interface.id = id;
|
||||
id_to_interface_map[id] = interface;
|
||||
interface.target.attr("interface_id", id);
|
||||
}
|
||||
|
||||
var config;
|
||||
$.getJSON("static/config.json", function(data) {
|
||||
config = data;
|
||||
input_interface = Object.create(input_to_object_map[
|
||||
config["input_interface_type"]]);
|
||||
output_interface = Object.create(output_to_object_map[
|
||||
config["output_interface_type"]]);
|
||||
$("#input_interface").html(config.disabled ?
|
||||
input_interface.disabled_html : input_interface.html);
|
||||
input_interface.target = $("#input_interface");
|
||||
set_interface_id(input_interface, 1)
|
||||
input_interface.init();
|
||||
$("#output_interface").html(output_interface.html);
|
||||
output_interface.target = $("#output_interface");
|
||||
set_interface_id(output_interface, 2)
|
||||
output_interface.init();
|
||||
_id = 0;
|
||||
let input_interfaces = [];
|
||||
let output_interfaces = [];
|
||||
for (let i = 0; i < config["input_interfaces"].length; i++) {
|
||||
input_interface = Object.create(input_to_object_map[
|
||||
config["input_interfaces"][i]]);
|
||||
$(".input_interfaces").append(`
|
||||
<div class="input_interface interface" interface_id=${_id}>
|
||||
${input_interface.html}
|
||||
</div>
|
||||
`);
|
||||
input_interface.target = $(`.input_interface[interface_id=${_id}]`);
|
||||
set_interface_id(input_interface, _id);
|
||||
input_interface.init();
|
||||
input_interfaces.push(input_interface);
|
||||
input_interface.io_master = io_master;
|
||||
_id++;
|
||||
}
|
||||
for (let i = 0; i < config["output_interfaces"].length; i++) {
|
||||
output_interface = Object.create(output_to_object_map[
|
||||
config["output_interfaces"][i]]);
|
||||
$(".output_interfaces").append(`
|
||||
<div class="output_interface interface" interface_id=${_id}>
|
||||
${output_interface.html}
|
||||
</div>
|
||||
`);
|
||||
output_interface.target = $(`.output_interface[interface_id=${_id}]`);
|
||||
set_interface_id(output_interface, _id);
|
||||
output_interface.init();
|
||||
output_interfaces.push(output_interface);
|
||||
output_interface.io_master = io_master;
|
||||
_id++;
|
||||
}
|
||||
io_master.input_interfaces = input_interfaces;
|
||||
io_master.output_interfaces = output_interfaces;
|
||||
$(".clear").click(function() {
|
||||
input_interface.clear();
|
||||
output_interface.clear();
|
||||
for (let input_interface of input_interfaces) {
|
||||
input_interface.clear();
|
||||
}
|
||||
for (let output_interface of output_interfaces) {
|
||||
output_interface.clear();
|
||||
}
|
||||
$(".flag").removeClass("flagged");
|
||||
$(".flag_message").empty();
|
||||
$("#loading").addClass("invisible");
|
||||
$("#output_interface").removeClass("invisible");
|
||||
$(".output_interface").removeClass("invisible");
|
||||
io_master.last_input = null;
|
||||
io_master.last_output = null;
|
||||
})
|
||||
input_interface.io_master = io_master;
|
||||
io_master.input_interface = input_interface;
|
||||
output_interface.io_master = io_master;
|
||||
io_master.output_interface = output_interface;
|
||||
if (config["share_url"] != "None") {
|
||||
$("#share_row").css('display', 'flex');
|
||||
}
|
||||
@ -57,14 +79,17 @@ $.getJSON("static/config.json", function(data) {
|
||||
$("#featured_history").hide();
|
||||
}
|
||||
if (config.live) {
|
||||
input_interface.submit();
|
||||
io_master.gather();
|
||||
} else {
|
||||
$(".submit").show();
|
||||
$(".submit").click(function() {
|
||||
input_interface.submit();
|
||||
io_master.gather();
|
||||
$(".flag").removeClass("flagged");
|
||||
})
|
||||
}
|
||||
if (!config.show_input) {
|
||||
$(".input_panel").hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('click', '.flag', function(e) {
|
||||
|
2
gradio/static/js/vendor/webcam.min.js
vendored
Normal file
2
gradio/static/js/vendor/webcam.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -10,6 +10,7 @@
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/sketchpad.css">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/input/textbox.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">
|
||||
<link rel="stylesheet" href="../static/css/interfaces/output/label.css">
|
||||
@ -37,15 +38,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="panels">
|
||||
<div class="panel">
|
||||
<div class="panel input_panel">
|
||||
<div class="panel_header">Input</div>
|
||||
<div id="input_interface" class="interface"></div>
|
||||
<div class="input_interfaces">
|
||||
</div>
|
||||
<div class="panel_buttons">
|
||||
<input class="submit" type="submit" value="submit"/>
|
||||
<input class="clear" type="reset" value="clear">
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel output_panel">
|
||||
<div class="panel_header">
|
||||
Output
|
||||
</div>
|
||||
@ -53,7 +55,8 @@
|
||||
<img id="loading_in_progress" src="../static/img/logo_loading.gif">
|
||||
<img id="loading_failed" src="../static/img/logo_error.png">
|
||||
</div>
|
||||
<div id="output_interface" class="interface"></div>
|
||||
<div class="output_interfaces">
|
||||
</div>
|
||||
<div class="panel_buttons">
|
||||
<input type="text" class="flag_message" placeholder="(Optional message for flagging)"/>
|
||||
<input type="button" class="panel_button flag" value="flag"/>
|
||||
@ -83,6 +86,8 @@
|
||||
<script src="../static/js/interfaces/input/sketchpad.js"></script>
|
||||
<script src="../static/js/interfaces/input/textbox.js"></script>
|
||||
<script src="../static/js/interfaces/input/csv.js"></script>
|
||||
<script src="../static/js/vendor/webcam.min.js"></script>
|
||||
<script src="../static/js/interfaces/input/webcam.js"></script>
|
||||
<script src="../static/js/interfaces/input/microphone.js"></script>
|
||||
<script src="../static/js/vendor/wavesurfer.min.js"></script>
|
||||
<script src="../static/js/vendor/p5.min.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user