This commit is contained in:
Abubakar Abid 2020-06-26 18:23:55 -05:00
commit b000f86261
32 changed files with 257 additions and 388 deletions

View File

@ -2,6 +2,8 @@
# Gradio UI
![alt text](https://i.ibb.co/GHRk2JP/header-2.png)
At Gradio, we often try to understand what inputs that a model is particularly sensitive to. To help facilitate this, we've developed and open-sourced `gradio`, a python library that allows you to easily create input and output interfaces over trained models to make it easy for you to "play around" with your model in your browser by dragging-and-dropping in your own images (or pasting your own text, recording your own voice, etc.) and seeing what the model outputs. We are working on making creating a shareable, public link to your model so you can share the interface with others (e.g. your client, your advisor, or your dad), who can use the model without writing any code.
Gradio is useful for:
@ -54,7 +56,7 @@ label = gradio.outputs.Label(num_top_classes=3)
gr.Interface(classify_image, imagein, label).launch();
```
![alt text](https://raw.githubusercontent.com/abidlabs/gradio/master/image_interface.png)
![alt text](https://i.ibb.co/nM97z2B/image-interface.png)
You can supply your own model instead of the pretrained model above, as well as use different kinds of models or functions. Changing the `input` and `output` parameters in the `Interface` face object allow you to create different interfaces, depending on the needs of your model. Take a look at the python notebooks for more examples. The currently supported interfaces are as follows:
@ -82,7 +84,7 @@ label = Label(num_top_classes=4)
gradio.Interface(predict, sketchpad, label).launch();
```
![alt text](https://raw.githubusercontent.com/abidlabs/gradio/master/sketchpad_interface.png)
![alt text](https://i.ibb.co/CV8Kk3D/sketchpad-interface.png)
#### Human DNA Variant Effect Prediction (Input: Textbox, Output: Label)
@ -90,7 +92,7 @@ gradio.Interface(predict, sketchpad, label).launch();
gradio.Interface(predict, 'textbox', 'label').launch()
```
![alt text](https://raw.githubusercontent.com/abidlabs/gradio/master/label_interface.png)
![alt text](https://i.ibb.co/C7GXDDQ/label-interface.png)
### Contributing:
If you would like to contribute and your contribution is small, you can directly open a pull request (PR). If you would like to contribute a larger feature, we recommend first creating an issue with a proposed design for discussion. Please see our contributing guidelines for more info.

View File

@ -332,9 +332,9 @@ class ImageIn(AbstractInput):
im = np.array(im).flatten()
im = im * self.scale + self.shift
if self.num_channels is None:
array = im.reshape(1, self.image_width, self.image_height)
array = im.reshape(self.image_width, self.image_height)
else:
array = im.reshape(1, self.image_width, self.image_height, \
array = im.reshape(self.image_width, self.image_height, \
self.num_channels)
return array

View File

@ -180,7 +180,7 @@ class Interface:
return
raise RuntimeError("Validation did not pass")
def launch(self, inline=None, inbrowser=None, share=True, validate=True):
def launch(self, inline=None, inbrowser=None, share=False, validate=True):
"""
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)
@ -212,7 +212,6 @@ class Interface:
server_port, httpd = networking.start_simple_server(self, output_directory, self.server_name)
path_to_local_server = "http://{}:{}/".format(self.server_name, server_port)
networking.build_template(output_directory)
networking.set_config(self.get_config_file(), output_directory)
self.status = "RUNNING"
self.simple_server = httpd
@ -243,6 +242,7 @@ class Interface:
if share:
try:
share_url = networking.setup_tunnel(server_port)
print(share_url)
except RuntimeError:
share_url = None
if self.verbose:
@ -288,5 +288,8 @@ class Interface:
else:
display(IFrame(path_to_local_server, width=1000, height=500))
config = self.get_config_file()
config["share_url"] = share_url
networking.set_config(config, output_directory)
return httpd, path_to_local_server, share_url

View File

@ -139,7 +139,7 @@ def serve_files_in_background(interface, port, directory_to_serve=None, server_n
int(self.headers["Content-Length"]))
msg = json.loads(data_string)
raw_input = msg["data"]
output = {"action": "output", "data": interface.process(raw_input)}
output = {"data": interface.process(raw_input)}
if interface.saliency is not None:
saliency = interface.saliency(raw_input, prediction)
output['saliency'] = saliency.tolist()
@ -179,81 +179,6 @@ def serve_files_in_background(interface, port, directory_to_serve=None, server_n
f.write(json.dumps(output))
f.write("\n")
# TODO(abidlabs): clean this up
elif self.path == "/api/auto/rotation":
from gradio import validation_data, preprocessing_utils
import numpy as np
self._set_headers()
data_string = self.rfile.read(
int(self.headers["Content-Length"]))
msg = json.loads(data_string)
img_orig = preprocessing_utils.decode_base64_to_image(
msg["data"])
img_orig = img_orig.convert('RGB')
img_orig = img_orig.resize((224, 224))
flag_dir = os.path.join(directory_to_serve, FLAGGING_DIRECTORY)
os.makedirs(flag_dir, exist_ok=True)
for deg in range(-180, 180+45, 45):
img = img_orig.rotate(deg)
img_array = np.array(img) / 127.5 - 1
prediction = interface.predict(
np.expand_dims(img_array, axis=0))
processed_output = interface.output_interface.postprocess(
prediction)
output = {'input': interface.input_interface.save_to_file(flag_dir, img),
'output': interface.output_interface.rebuild_flagged(
flag_dir, {'data': {'output': processed_output}}),
'message': 'rotation by {} degrees'.format(
deg)}
with open(os.path.join(flag_dir, FLAGGING_FILENAME), 'a+') as f:
f.write(json.dumps(output))
f.write("\n")
# Prepare return json dictionary.
self.wfile.write(json.dumps({}).encode())
elif self.path == "/api/auto/lighting":
from gradio import validation_data, preprocessing_utils
import numpy as np
from PIL import ImageEnhance
self._set_headers()
data_string = self.rfile.read(
int(self.headers["Content-Length"]))
msg = json.loads(data_string)
img_orig = preprocessing_utils.decode_base64_to_image(
msg["data"])
img_orig = img_orig.convert('RGB')
img_orig = img_orig.resize((224, 224))
enhancer = ImageEnhance.Brightness(img_orig)
flag_dir = os.path.join(directory_to_serve, FLAGGING_DIRECTORY)
os.makedirs(flag_dir, exist_ok=True)
for i in range(9):
img = enhancer.enhance(i/4)
img_array = np.array(img) / 127.5 - 1
prediction = interface.predict(
np.expand_dims(img_array, axis=0))
processed_output = interface.output_interface.postprocess(
prediction)
output = {'input': interface.input_interface.save_to_file(flag_dir, img),
'output': interface.output_interface.rebuild_flagged(
flag_dir, {'data': {'output': processed_output}}),
'message': 'brighting adjustment by a factor '
'of {}'.format(i)}
with open(os.path.join(flag_dir, FLAGGING_FILENAME), 'a+') as f:
f.write(json.dumps(output))
f.write("\n")
# Prepare return json dictionary.
self.wfile.write(json.dumps({}).encode())
else:
self.send_error(404, 'Path not found: {}'.format(self.path))

View File

@ -9,6 +9,7 @@ import numpy as np
import json
from gradio import preprocessing_utils
import datetime
import operator
# Where to find the static resources associated with each template.
BASE_OUTPUT_INTERFACE_JS_PATH = 'static/js/interfaces/output/{}.js'
@ -41,14 +42,6 @@ class AbstractOutput(ABC):
"""
return {}
@abstractmethod
def rebuild_flagged(self, inp):
"""
All interfaces should define a method that rebuilds the flagged output when it's passed back (i.e. rebuilds image from base64)
"""
pass
import operator
class Label(AbstractOutput):
def __init__(self, num_top_classes=None, label=None):
self.num_top_classes = num_top_classes
@ -90,6 +83,17 @@ class Label(AbstractOutput):
return json.loads(msg)
class KeyValues(AbstractOutput):
def __init__(self, label=None):
super().__init__(label)
@classmethod
def get_shortcut_implementations(cls):
return {
"key_values": {},
}
class Textbox(AbstractOutput):
def __init__(self, lines=None, placeholder=None, label=None):
self.lines = lines

View File

@ -0,0 +1,13 @@
.key_values th {
text-align: left;
}
.key_values tr {
padding: 4px;
}
.key_values {
font-family: monospace;
font-size: 16px;
}
.key_values tbody tr:nth-child(odd) {
background-color: white;
}

View File

@ -0,0 +1,3 @@
.key_values {
width: 100%;
}

View File

@ -21,28 +21,15 @@ nav img {
margin-right: auto;
height: 32px;
}
#share_row {
justify-content: center;
#share {
text-align: center;
margin-bottom: 10px;
font-size: 14px;
}
#share_form {
flex-grow: 1;
justify-content: center;
align-items: center;
}
#share_row button, #share_row input[type=text] {
padding: 6px 4px;
margin-left: 5px;
}
#share_row input[type=text] {
background-color: #F6F6F6;
}
#share_email {
flex-grow: 1;
max-width: 400px;
}
#share_row, #share_complete, #share_form {
display: none;
#share-copy {
background-color: whitesmoke;
padding: 4px;
border-radius: 2px;
}
.panels {
display: flex;

View File

@ -12,14 +12,14 @@ function gradio(config, fn, target) {
</div>
<div class="panel output_panel">
<div class="loading interface invisible">
<img class="loading_in_progress" src="../static/img/logo_loading.gif">
<img class="loading_failed" src="../static/img/logo_error.png">
<img class="loading_in_progress" src="static/img/logo_loading.gif">
<img class="loading_failed" src="static/img/logo_error.png">
</div>
<div class="output_interfaces">
</div>
</div>
</div>`);
io_master = Object.create(io_master_template);
let io_master = Object.create(io_master_template);
io_master.fn = fn
io_master.target = target;
io_master.config = config;
@ -41,6 +41,7 @@ function gradio(config, fn, target) {
"csv" : {},
"image" : image_output,
"label" : label_output,
"keyvalues" : key_values,
"textbox" : textbox_output
}
let id_to_interface_map = {}

View File

@ -92,7 +92,7 @@ const image_input = {
var io = this;
if (this.state == "IMAGE_LOADED") {
resizeImage.call(this, this.image_data, 300, 300, function(image_data) {
this.io_master.input(io.id, image_data);
io.io_master.input(io.id, image_data);
})
}
},

View File

@ -1,19 +1,12 @@
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(opts) {
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 (this.io_master.config.live) {
this.target.find(".take_photo").hide();
}
let RATIO = 4/3;
let dim = Math.min(h, w / RATIO);
Webcam.set({
@ -24,48 +17,19 @@ const webcam = {
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 (this.io_master.config.live) {
if (this.state == "CAMERA_ON") {
Webcam.freeze();
Webcam.snap(function(image_data) {
this.io_master.input(io.id, image_data);
io.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);
}
this.state = "SNAPPED";
},
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",

View File

@ -0,0 +1,25 @@
const key_values = {
html: `
<table class="key_values">
<thead>
<th>Property</th>
<th>Value</th>
</thead>
<tbody></tbody>
</table>
`,
init: function(opts) {},
output: function(data) {
let html = ""
for (let row of data) {
html += `<tr>
<td>${row[0]}</td>
<td>${row[1]}</td>
</tr>`;
}
this.target.find("tbody").html(html);
},
clear: function() {
this.target.find("tbody").empty();
}
}

View File

@ -18,6 +18,7 @@
<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">
<link rel="stylesheet" href="../static/css/interfaces/output/key_values.css">
<link rel="stylesheet" href="../static/css/interfaces/output/textbox.css">
<link rel="stylesheet" href="../static/css/loading.css"/>
<!-- TUI EDITOR -->
@ -29,17 +30,9 @@
<nav>
<a href="https://gradio.app"><img src="../static/img/logo_inline.png" /></a>
</nav>
<div id="share_row">
<button id="share" class="primary">Share this Interface</button>
<div id="share_form">
<input type="text" id="share_name" placeholder="sender name (you)"></input>
<input type="text" id="share_email" placeholder="emails (comma-separated if multiple)"></input>
<button class="primary" id="send_link">Send Link</button>
</div>
<div id="share_complete">
<span id="share_message"></span>
<button class="secondary" id="share_more"></button>
</div>
<div id="share" class="invisible">
Live at <a id="share-link"></a>.
<button id="share-copy">Copy Link</button>
</div>
<div id="interface_target"></div>
<script src="../static/js/vendor/jquery.min.js"></script>
@ -74,8 +67,8 @@
<script src="../static/js/vendor/p5.dom.min.js"></script>
<script src="../static/js/interfaces/output/image.js"></script>
<script src="../static/js/interfaces/output/label.js"></script>
<script src="../static/js/interfaces/output/key_values.js"></script>
<script src="../static/js/interfaces/output/textbox.js"></script>
<script src="../static/js/share.js"></script>
<script src="../static/js/gradio.js"></script>
<script>
$.getJSON("static/config.json", function(config) {
@ -89,7 +82,23 @@
});
});
}, "#interface_target");
if (config["share_url"]) {
let share_url = config["share_url"];
$("#share").removeClass("invisible");
$("#share-link").text(share_url).attr("href", share_url);
$("#share-copy").click(function() {
copyToClipboard(share_url);
})
}
});
const copyToClipboard = str => {
const el = document.createElement('textarea');
el.value = str;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
};
</script>
</body>
</html>

View File

@ -1,14 +1,21 @@
import gradio as gr
from time import sleep
def answer_question(text1, text2):
return text1, text2, {"plagiarism": 0.62, "original": 0.38}
sleep(2)
return text1[::-1], [
("Value 1", 12.3),
("Section", "DF3"),
("Confidence", 100),
]
gr.Interface(answer_question,
[
gr.inputs.Microphone(label="speech"),
gr.inputs.Dropdown(["Deepspeech", "Sphynx", "Wav2Text"], label="model"),
gr.inputs.Textbox(label="text 1", lines=4),
gr.inputs.Textbox(label="text 2", lines=4),
], [
gr.outputs.Textbox(label="text 1", lines=8),
gr.outputs.Textbox(label="out", lines=8),
"key_values"
]
).launch()
).launch(share=True)

View File

@ -4,16 +4,17 @@ from time import time
def flip(image):
start = time()
return np.flipud(image), time() - start
return image, {
"1": 0.2,
"2": 0.8
}
def flip2(image):
start = time()
return np.fliplr(image), time() - start
gr.Interface([flip, flip2],
"imagein",
[
gr.Interface(flip,
"image",
gr.outputs.Textbox(lines=1)
["image", "label"
]).launch()

View File

@ -4,4 +4,4 @@ import numpy as np
def snap(image):
return np.flipud(image)
gr.Interface(snap, "webcam", "image", live=True, show_input=False).launch()
gr.Interface(snap, "webcam", "image").launch()

View File

@ -31,6 +31,7 @@ gradio/static/css/interfaces/input/slider.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/key_values.css
gradio/static/css/interfaces/output/label.css
gradio/static/css/interfaces/output/textbox.css
gradio/static/css/vendor/tui-color-picker.css
@ -51,7 +52,6 @@ gradio/static/img/vendor/icon-c.svg
gradio/static/img/vendor/icon-d.svg
gradio/static/js/all_io.js
gradio/static/js/gradio.js
gradio/static/js/share.js
gradio/static/js/utils.js
gradio/static/js/interfaces/input/checkbox.js
gradio/static/js/interfaces/input/checkbox_group.js
@ -65,6 +65,7 @@ gradio/static/js/interfaces/input/slider.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/key_values.js
gradio/static/js/interfaces/output/label.js
gradio/static/js/interfaces/output/textbox.js
gradio/static/js/vendor/FileSaver.min.js

View File

@ -332,9 +332,9 @@ class ImageIn(AbstractInput):
im = np.array(im).flatten()
im = im * self.scale + self.shift
if self.num_channels is None:
array = im.reshape(1, self.image_width, self.image_height)
array = im.reshape(self.image_width, self.image_height)
else:
array = im.reshape(1, self.image_width, self.image_height, \
array = im.reshape(self.image_width, self.image_height, \
self.num_channels)
return array

View File

@ -179,7 +179,7 @@ class Interface:
return
raise RuntimeError("Validation did not pass")
def launch(self, inline=None, inbrowser=None, share=True, validate=True):
def launch(self, inline=None, inbrowser=None, share=False, validate=True):
"""
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)
@ -212,7 +212,6 @@ class Interface:
server_port, httpd = networking.start_simple_server(self, output_directory, self.server_name)
path_to_local_server = "http://{}:{}/".format(self.server_name, server_port)
networking.build_template(output_directory)
networking.set_config(self.get_config_file(), output_directory)
self.status = "RUNNING"
self.simple_server = httpd
@ -243,6 +242,7 @@ class Interface:
if share:
try:
share_url = networking.setup_tunnel(server_port)
print(share_url)
except RuntimeError:
share_url = None
if self.verbose:
@ -288,5 +288,8 @@ class Interface:
else:
display(IFrame(path_to_local_server, width=1000, height=500))
config = self.get_config_file()
config["share_url"] = share_url
networking.set_config(config, output_directory)
return httpd, path_to_local_server, share_url

View File

@ -139,7 +139,7 @@ def serve_files_in_background(interface, port, directory_to_serve=None, server_n
int(self.headers["Content-Length"]))
msg = json.loads(data_string)
raw_input = msg["data"]
output = {"action": "output", "data": interface.process(raw_input)}
output = {"data": interface.process(raw_input)}
if interface.saliency is not None:
saliency = interface.saliency(raw_input, prediction)
output['saliency'] = saliency.tolist()
@ -179,81 +179,6 @@ def serve_files_in_background(interface, port, directory_to_serve=None, server_n
f.write(json.dumps(output))
f.write("\n")
# TODO(abidlabs): clean this up
elif self.path == "/api/auto/rotation":
from gradio import validation_data, preprocessing_utils
import numpy as np
self._set_headers()
data_string = self.rfile.read(
int(self.headers["Content-Length"]))
msg = json.loads(data_string)
img_orig = preprocessing_utils.decode_base64_to_image(
msg["data"])
img_orig = img_orig.convert('RGB')
img_orig = img_orig.resize((224, 224))
flag_dir = os.path.join(directory_to_serve, FLAGGING_DIRECTORY)
os.makedirs(flag_dir, exist_ok=True)
for deg in range(-180, 180+45, 45):
img = img_orig.rotate(deg)
img_array = np.array(img) / 127.5 - 1
prediction = interface.predict(
np.expand_dims(img_array, axis=0))
processed_output = interface.output_interface.postprocess(
prediction)
output = {'input': interface.input_interface.save_to_file(flag_dir, img),
'output': interface.output_interface.rebuild_flagged(
flag_dir, {'data': {'output': processed_output}}),
'message': 'rotation by {} degrees'.format(
deg)}
with open(os.path.join(flag_dir, FLAGGING_FILENAME), 'a+') as f:
f.write(json.dumps(output))
f.write("\n")
# Prepare return json dictionary.
self.wfile.write(json.dumps({}).encode())
elif self.path == "/api/auto/lighting":
from gradio import validation_data, preprocessing_utils
import numpy as np
from PIL import ImageEnhance
self._set_headers()
data_string = self.rfile.read(
int(self.headers["Content-Length"]))
msg = json.loads(data_string)
img_orig = preprocessing_utils.decode_base64_to_image(
msg["data"])
img_orig = img_orig.convert('RGB')
img_orig = img_orig.resize((224, 224))
enhancer = ImageEnhance.Brightness(img_orig)
flag_dir = os.path.join(directory_to_serve, FLAGGING_DIRECTORY)
os.makedirs(flag_dir, exist_ok=True)
for i in range(9):
img = enhancer.enhance(i/4)
img_array = np.array(img) / 127.5 - 1
prediction = interface.predict(
np.expand_dims(img_array, axis=0))
processed_output = interface.output_interface.postprocess(
prediction)
output = {'input': interface.input_interface.save_to_file(flag_dir, img),
'output': interface.output_interface.rebuild_flagged(
flag_dir, {'data': {'output': processed_output}}),
'message': 'brighting adjustment by a factor '
'of {}'.format(i)}
with open(os.path.join(flag_dir, FLAGGING_FILENAME), 'a+') as f:
f.write(json.dumps(output))
f.write("\n")
# Prepare return json dictionary.
self.wfile.write(json.dumps({}).encode())
else:
self.send_error(404, 'Path not found: {}'.format(self.path))

View File

@ -9,6 +9,7 @@ import numpy as np
import json
from gradio import preprocessing_utils
import datetime
import operator
# Where to find the static resources associated with each template.
BASE_OUTPUT_INTERFACE_JS_PATH = 'static/js/interfaces/output/{}.js'
@ -41,14 +42,6 @@ class AbstractOutput(ABC):
"""
return {}
@abstractmethod
def rebuild_flagged(self, inp):
"""
All interfaces should define a method that rebuilds the flagged output when it's passed back (i.e. rebuilds image from base64)
"""
pass
import operator
class Label(AbstractOutput):
def __init__(self, num_top_classes=None, label=None):
self.num_top_classes = num_top_classes
@ -90,6 +83,17 @@ class Label(AbstractOutput):
return json.loads(msg)
class KeyValues(AbstractOutput):
def __init__(self, label=None):
super().__init__(label)
@classmethod
def get_shortcut_implementations(cls):
return {
"key_values": {},
}
class Textbox(AbstractOutput):
def __init__(self, lines=None, placeholder=None, label=None):
self.lines = lines

View File

@ -0,0 +1,13 @@
.key_values th {
text-align: left;
}
.key_values tr {
padding: 4px;
}
.key_values {
font-family: monospace;
font-size: 16px;
}
.key_values tbody tr:nth-child(odd) {
background-color: white;
}

View File

@ -21,28 +21,15 @@ nav img {
margin-right: auto;
height: 32px;
}
#share_row {
justify-content: center;
#share {
text-align: center;
margin-bottom: 10px;
font-size: 14px;
}
#share_form {
flex-grow: 1;
justify-content: center;
align-items: center;
}
#share_row button, #share_row input[type=text] {
padding: 6px 4px;
margin-left: 5px;
}
#share_row input[type=text] {
background-color: #F6F6F6;
}
#share_email {
flex-grow: 1;
max-width: 400px;
}
#share_row, #share_complete, #share_form {
display: none;
#share-copy {
background-color: whitesmoke;
padding: 4px;
border-radius: 2px;
}
.panels {
display: flex;

View File

@ -12,14 +12,14 @@ function gradio(config, fn, target) {
</div>
<div class="panel output_panel">
<div class="loading interface invisible">
<img class="loading_in_progress" src="../static/img/logo_loading.gif">
<img class="loading_failed" src="../static/img/logo_error.png">
<img class="loading_in_progress" src="static/img/logo_loading.gif">
<img class="loading_failed" src="static/img/logo_error.png">
</div>
<div class="output_interfaces">
</div>
</div>
</div>`);
io_master = Object.create(io_master_template);
let io_master = Object.create(io_master_template);
io_master.fn = fn
io_master.target = target;
io_master.config = config;
@ -41,6 +41,7 @@ function gradio(config, fn, target) {
"csv" : {},
"image" : image_output,
"label" : label_output,
"keyvalues" : key_values,
"textbox" : textbox_output
}
let id_to_interface_map = {}

View File

@ -92,7 +92,7 @@ const image_input = {
var io = this;
if (this.state == "IMAGE_LOADED") {
resizeImage.call(this, this.image_data, 300, 300, function(image_data) {
this.io_master.input(io.id, image_data);
io.io_master.input(io.id, image_data);
})
}
},

View File

@ -1,19 +1,12 @@
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(opts) {
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 (this.io_master.config.live) {
this.target.find(".take_photo").hide();
}
let RATIO = 4/3;
let dim = Math.min(h, w / RATIO);
Webcam.set({
@ -24,48 +17,19 @@ const webcam = {
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 (this.io_master.config.live) {
if (this.state == "CAMERA_ON") {
Webcam.snap(function(image_data) {
this.io_master.input(io.id, image_data);
io.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);
}
// Webcam.freeze();
this.state = "SNAPPED";
},
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();
// Webcam.unfreeze();
}
},
state: "NOT_STARTED",

View File

@ -0,0 +1,25 @@
const key_values = {
html: `
<table class="key_values">
<thead>
<th>Property</th>
<th>Value</th>
</thead>
<tbody></tbody>
</table>
`,
init: function(opts) {},
output: function(data) {
let html = ""
for (let row of data) {
html += `<tr>
<td>${row[0]}</td>
<td>${row[1]}</td>
</tr>`;
}
this.target.find("tbody").html(html);
},
clear: function() {
this.target.find("tbody").empty();
}
}

View File

@ -1,41 +0,0 @@
$("#share").click(function() {
$("#share").hide()
$("#share_form").css('display', 'flex')
})
$("#send_link").click(function(evt) {
let name = $("#share_name").val()
let email = $("#share_email").val()
if (name && email) {
$("#send_link").attr('disabled', true);
$.ajax({
"url" : "https://gradio.app/api/send-email/",
"type": "POST",
"crossDomain": true,
"data": {
"url": config["share_url"],
"name": name,
"email": email
},
"success": function() {
$("#share_message").text("Shared successfully.");
$("#share_more").text("Share more");
},
"error": function() {
$("#share_message").text("Failed to share.");
$("#share_more").text("Try again");
},
"complete": function() {
$("#share_form").hide();
$("#share_complete").show();
$("#send_link").attr('disabled', false);
}
})
}
})
$("#share_more").click(function (evt) {
$("#share_email").val("");
$("#share_form").show();
$("#share_complete").hide();
})

View File

@ -18,6 +18,7 @@
<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">
<link rel="stylesheet" href="../static/css/interfaces/output/key_values.css">
<link rel="stylesheet" href="../static/css/interfaces/output/textbox.css">
<link rel="stylesheet" href="../static/css/loading.css"/>
<!-- TUI EDITOR -->
@ -29,17 +30,9 @@
<nav>
<a href="https://gradio.app"><img src="../static/img/logo_inline.png" /></a>
</nav>
<div id="share_row">
<button id="share" class="primary">Share this Interface</button>
<div id="share_form">
<input type="text" id="share_name" placeholder="sender name (you)"></input>
<input type="text" id="share_email" placeholder="emails (comma-separated if multiple)"></input>
<button class="primary" id="send_link">Send Link</button>
</div>
<div id="share_complete">
<span id="share_message"></span>
<button class="secondary" id="share_more"></button>
</div>
<div id="share" class="invisible">
Live at <a id="share-link"></a>.
<button id="share-copy">Copy Link</button>
</div>
<div id="interface_target"></div>
<script src="../static/js/vendor/jquery.min.js"></script>
@ -74,8 +67,8 @@
<script src="../static/js/vendor/p5.dom.min.js"></script>
<script src="../static/js/interfaces/output/image.js"></script>
<script src="../static/js/interfaces/output/label.js"></script>
<script src="../static/js/interfaces/output/key_values.js"></script>
<script src="../static/js/interfaces/output/textbox.js"></script>
<script src="../static/js/share.js"></script>
<script src="../static/js/gradio.js"></script>
<script>
$.getJSON("static/config.json", function(config) {
@ -89,7 +82,23 @@
});
});
}, "#interface_target");
if (config["share_url"]) {
let share_url = config["share_url"];
$("#share").removeClass("invisible");
$("#share-link").text(share_url).attr("href", share_url);
$("#share-copy").click(function() {
copyToClipboard(share_url);
})
}
});
const copyToClipboard = str => {
const el = document.createElement('textarea');
el.value = str;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
};
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

34
size.sh Normal file
View File

@ -0,0 +1,34 @@
#!/bin/bash
#set -x
# Shows you the largest objects in your repo's pack file.
# Written for osx.
#
# @see https://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/
# @author Antony Stubbs
# set the internal field separator to line break, so that we can iterate easily over the verify-pack output
IFS=$'\n';
# list all objects including their size, sort by size, take top 10
objects=`git verify-pack -v .git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head`
echo "All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file."
output="size,pack,SHA,location"
allObjects=`git rev-list --all --objects`
for y in $objects
do
# extract the size in bytes
size=$((`echo $y | cut -f 5 -d ' '`/1024))
# extract the compressed size in bytes
compressedSize=$((`echo $y | cut -f 6 -d ' '`/1024))
# extract the SHA
sha=`echo $y | cut -f 1 -d ' '`
# find the objects location in the repository tree
other=`echo "${allObjects}" | grep $sha`
#lineBreak=`echo -e "\n"`
output="${output}\n${size},${compressedSize},${other}"
done
echo -e $output | column -t -s ', '

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB