multiple inputs & outputs

This commit is contained in:
Ali Abid 2020-06-10 23:04:14 -07:00
parent ce9d444088
commit 54eb9def99
25 changed files with 476 additions and 162 deletions

View File

@ -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):

View File

@ -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)

View File

@ -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

View 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;
}

View File

@ -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) {

View File

@ -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);
})
}
},

View 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}>`;
}
}

View File

@ -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) {

File diff suppressed because one or more lines are too long

View File

@ -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>

View File

@ -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()

View File

@ -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
View 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

Binary file not shown.

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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

View 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;
}

View File

@ -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) {

View File

@ -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);
})
}
},

View 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}>`;
}
}

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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>