version 0.7.8

This commit is contained in:
Abubakar Abid 2019-06-22 00:29:43 -07:00
parent 772416f3c0
commit 84b9bf548c
25 changed files with 676 additions and 92 deletions

View File

@ -45,6 +45,7 @@ class Interface:
preprocessing_fns=None,
postprocessing_fns=None,
verbose=True,
saliency=None,
):
"""
:param inputs: a string or `AbstractInput` representing the input interface.
@ -54,6 +55,8 @@ class Interface:
provided.
:param preprocessing_fns: an optional function that overrides the preprocessing function of the input interface.
:param postprocessing_fns: an optional function that overrides the postprocessing fn of the output interface.
:param saliency: an optional function that takes the model and the processed input and returns a 2-d array
"""
if isinstance(inputs, str):
self.input_interface = gradio.inputs.registry[inputs.lower()](
@ -94,6 +97,7 @@ class Interface:
self.validate_flag = False
self.simple_server = None
self.hash = random.getrandbits(32)
self.saliency = saliency
@staticmethod
def _infer_model_type(model):
@ -132,6 +136,7 @@ class Interface:
Method that calls the relevant method of the model object to make a prediction.
:param preprocessed_input: the preprocessed input returned by the input interface
"""
print(preprocessed_input.shape)
if self.model_type == "sklearn":
return self.model_obj.predict(preprocessed_input)
elif self.model_type == "keras":

View File

@ -7,7 +7,6 @@ import socket
import threading
from http.server import HTTPServer as BaseHTTPServer, SimpleHTTPRequestHandler
import pkg_resources
from bs4 import BeautifulSoup
from distutils import dir_util
from gradio import inputs, outputs
import json
@ -15,7 +14,6 @@ from gradio.tunneling import create_tunnel
import urllib.request
from shutil import copyfile
INITIAL_PORT_VALUE = (
7860
) # The http server will try to open on port 7860. If not available, 7861, 7862, etc.
@ -25,9 +23,7 @@ TRY_NUM_PORTS = (
LOCALHOST_NAME = "localhost"
GRADIO_API_SERVER = "https://api.gradio.app/v1/tunnel-request"
BASE_TEMPLATE = pkg_resources.resource_filename(
"gradio", "templates/base_template.html"
)
STATIC_TEMPLATE_LIB = pkg_resources.resource_filename("gradio", "templates/")
STATIC_PATH_LIB = pkg_resources.resource_filename("gradio", "static/")
STATIC_PATH_TEMP = "static/"
TEMPLATE_TEMP = "index.html"
@ -37,52 +33,18 @@ CONFIG_FILE = "static/config.json"
ASSOCIATION_PATH_IN_STATIC = "static/apple-app-site-association"
ASSOCIATION_PATH_IN_ROOT = "apple-app-site-association"
FLAGGING_DIRECTORY = 'gradio-flagged/{}'
FLAGGING_FILENAME = 'gradio-flagged.txt'
FLAGGING_DIRECTORY = 'static/flagged/'
FLAGGING_FILENAME = 'data.txt'
def build_template(temp_dir, input_interface, output_interface):
"""
Builds a complete HTML template with supporting JS and CSS files in a given directory.
:param temp_dir: string with path to temp directory in which the template should be built
:param input_interface: an AbstractInput object which includes is used to get the input template
:param output_interface: an AbstractInput object which includes is used to get the input template
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
"""
input_template_path = pkg_resources.resource_filename(
"gradio",
inputs.BASE_INPUT_INTERFACE_TEMPLATE_PATH.format(input_interface.get_name()),
)
output_template_path = pkg_resources.resource_filename(
"gradio",
outputs.BASE_OUTPUT_INTERFACE_TEMPLATE_PATH.format(output_interface.get_name()),
)
input_page = open(input_template_path)
output_page = open(output_template_path)
input_soup = BeautifulSoup(
render_string_or_list_with_tags(
input_page.read(), input_interface.get_template_context()
),
features="html.parser",
)
output_soup = BeautifulSoup(
render_string_or_list_with_tags(
output_page.read(), output_interface.get_template_context()
),
features="html.parser",
)
dir_util.copy_tree(STATIC_TEMPLATE_LIB, temp_dir)
dir_util.copy_tree(STATIC_PATH_LIB, os.path.join(temp_dir, STATIC_PATH_TEMP))
all_io_page = open(BASE_TEMPLATE)
all_io_soup = BeautifulSoup(all_io_page.read(), features="html.parser")
input_tag = all_io_soup.find("div", {"id": "input"})
output_tag = all_io_soup.find("div", {"id": "output"})
# input_tag.replace_with(input_soup)
# output_tag.replace_with(output_soup)
f = open(os.path.join(temp_dir, TEMPLATE_TEMP), "w")
f.write(str(all_io_soup))
copy_files(STATIC_PATH_LIB, os.path.join(temp_dir, STATIC_PATH_TEMP))
# Move association file to root of temporary directory.
copyfile(os.path.join(temp_dir, ASSOCIATION_PATH_IN_STATIC),
os.path.join(temp_dir, ASSOCIATION_PATH_IN_ROOT))
@ -103,15 +65,6 @@ def build_template(temp_dir, input_interface, output_interface):
)
def copy_files(src_dir, dest_dir):
"""
Copies all the files from one directory to another
:param src_dir: string path to source directory
:param dest_dir: string path to destination directory
"""
dir_util.copy_tree(src_dir, dest_dir)
def render_template_with_tags(template_path, context):
"""
Combines the given template with a given context dictionary by replacing all of the occurrences of tags (enclosed
@ -216,6 +169,10 @@ def serve_files_in_background(interface, port, directory_to_serve=None):
prediction = interface.predict(processed_input)
processed_output = interface.output_interface.postprocess(prediction)
output = {"action": "output", "data": processed_output}
if interface.saliency is not None:
import numpy as np
saliency = interface.saliency(interface.model_obj, processed_input, prediction)
output['saliency'] = saliency.tolist()
# Prepare return json dictionary.
self.wfile.write(json.dumps(output).encode())
@ -224,15 +181,80 @@ def serve_files_in_background(interface, port, directory_to_serve=None):
self._set_headers()
data_string = self.rfile.read(int(self.headers["Content-Length"]))
msg = json.loads(data_string)
flag_dir = FLAGGING_DIRECTORY.format(interface.hash)
flag_dir = os.path.join(directory_to_serve, FLAGGING_DIRECTORY)
os.makedirs(flag_dir, exist_ok=True)
dict = {'input': interface.input_interface.rebuild_flagged(flag_dir, msg),
'output': interface.output_interface.rebuild_flagged(flag_dir, msg),
'message': msg['data']['message']}
output = {'input': interface.input_interface.rebuild_flagged(flag_dir, msg),
'output': interface.output_interface.rebuild_flagged(flag_dir, msg),
'message': msg['data']['message']}
with open(os.path.join(flag_dir, FLAGGING_FILENAME), 'a+') as f:
f.write(json.dumps(dict))
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': f'rotation by {deg} degrees'}
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': f'brighting adjustment by a factor of {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: %s' % self.path)

View File

@ -1,13 +1,21 @@
from PIL import Image
from io import BytesIO
import base64
import tempfile
import scipy.io.wavfile
from scipy.fftpack import dct
import numpy as np
def encoding_to_image(encoding):
#########################
# IMAGE PRE-PROCESSING
#########################
def decode_base64_to_image(encoding):
content = encoding.split(';')[1]
image_encoded = content.split(',')[1]
return Image.open(BytesIO(base64.b64decode(image_encoded)))
def resize_and_crop(img, size, crop_type='top'):
"""
Resize and crop an image to fit the specified size.
@ -58,3 +66,89 @@ def resize_and_crop(img, size, crop_type='top'):
Image.ANTIALIAS)
# If the scale is the same, we do not need to crop
return img
##################
# AUDIO FILES
##################
def decode_base64_to_wav_file(encoding):
inp = encoding.split(';')[1].split(',')[1]
wav_obj = base64.b64decode(inp)
file_obj = tempfile.NamedTemporaryFile()
file_obj.close()
with open(file_obj.name, 'wb') as f:
f.write(wav_obj)
return file_obj
def generate_mfcc_features_from_audio_file(wav_filename,
pre_emphasis=0.95,
frame_size= 0.025,
frame_stride=0.01,
NFFT=512,
nfilt=40,
num_ceps=12,
cep_lifter=22):
"""
Loads and preprocesses a .wav audio file into mfcc coefficients, the typical inputs to models.
Adapted from: https://haythamfayek.com/2016/04/21/speech-processing-for-machine-learning.html
:param wav_filename: string name of audio file to process.
:param pre_emphasis: a float factor, typically 0.95 or 0.97, which amplifies high frequencies.
:param frame_size: a float that is the length, in seconds, of time frame over which to take the fft.
:param frame_stride: a float that is the offset, in seconds, between consecutive time frames.
:param NFFT: The number of points in the short-time fft for each time frame.
:param nfilt: The number of filters on the Mel-scale to extract frequency bands.
:param num_ceps: the number of cepstral coefficients to retrain.
:param cep_lifter: the int factor, by which to de-emphasize higher-frequency.
:return: a numpy array of mfcc coefficients.
"""
sample_rate, signal = scipy.io.wavfile.read(wav_filename)
emphasized_signal = np.append(signal[0], signal[1:] - pre_emphasis * signal[:-1])
frame_length, frame_step = frame_size * sample_rate, frame_stride * sample_rate # Convert from seconds to samples
signal_length = len(emphasized_signal)
frame_length = int(round(frame_length))
frame_step = int(round(frame_step))
num_frames = int(np.ceil(float(np.abs(signal_length - frame_length)) / frame_step)) # Make sure that we have at least 1 frame
pad_signal_length = num_frames * frame_step + frame_length
z = np.zeros((pad_signal_length - signal_length))
pad_signal = np.append(emphasized_signal, z) # Pad Signal to make sure that all frames have equal number of samples without truncating any samples from the original signal
indices = np.tile(np.arange(0, frame_length), (num_frames, 1)) + np.tile(np.arange(0, num_frames * frame_step, frame_step), (frame_length, 1)).T
frames = pad_signal[indices.astype(np.int32, copy=False)]
frames *= np.hamming(frame_length)
mag_frames = np.absolute(np.fft.rfft(frames, NFFT)) # Magnitude of the FFT
pow_frames = ((1.0 / NFFT) * ((mag_frames) ** 2)) # Power Spectrum
low_freq_mel = 0
high_freq_mel = (2595 * np.log10(1 + (sample_rate / 2) / 700)) # Convert Hz to Mel
mel_points = np.linspace(low_freq_mel, high_freq_mel, nfilt + 2) # Equally spaced in Mel scale
hz_points = (700 * (10**(mel_points / 2595) - 1)) # Convert Mel to Hz
bin = np.floor((NFFT + 1) * hz_points / sample_rate)
fbank = np.zeros((nfilt, int(np.floor(NFFT / 2 + 1))))
for m in range(1, nfilt + 1):
f_m_minus = int(bin[m - 1]) # left
f_m = int(bin[m]) # center
f_m_plus = int(bin[m + 1]) # right
for k in range(f_m_minus, f_m):
fbank[m - 1, k] = (k - bin[m - 1]) / (bin[m] - bin[m - 1])
for k in range(f_m, f_m_plus):
fbank[m - 1, k] = (bin[m + 1] - k) / (bin[m + 1] - bin[m])
filter_banks = np.dot(pow_frames, fbank.T)
filter_banks = np.where(filter_banks == 0, np.finfo(float).eps, filter_banks) # Numerical Stability
filter_banks = 20 * np.log10(filter_banks) # dB
mfcc = dct(filter_banks, type=2, axis=1, norm='ortho')[:, 0: (num_ceps + 1)] # Keep filters 1-13 by default.
(nframes, ncoeff) = mfcc.shape
n = np.arange(ncoeff)
lift = 1 + (cep_lifter / 2) * np.sin(np.pi * n / cep_lifter)
mfcc *= lift
filter_banks -= (np.mean(filter_banks, axis=0) + 1e-8)
mfcc -= (np.mean(mfcc, axis=0) + 1e-8)
return mfcc[np.newaxis, :, :] # Create a batch dimension.

View File

@ -0,0 +1,30 @@
body {
font-family: 'Open Sans', sans-serif;
font-size: 12px;
margin: 0;
}
nav {
text-align: center;
padding: 16px 0 4px;
}
nav img {
margin-right: auto;
height: 32px;
}
#bulk_rows td {
text-align: center;
height: 60px;
}
#bulk_rows tr:nth-child(even) {
background: #DDD
}
#bulk_rows img {
text-align: center;
height: 100%;
}
#bulk_rows {
margin: 0 auto;
width: 70%;
border-spacing: 0;
border-collapse: collapse;
}

View File

@ -36,7 +36,7 @@
.panel_buttons {
display: flex;
}
.submit, .clear, .flag {
.submit, .clear, .panel_button {
background-color: #F6F6F6 !important;
flex-grow: 1;
padding: 8px !important;
@ -74,6 +74,11 @@
justify-content: center;
text-align: center;
line-height: 1.5em;
flex-flow: column;
}
.upload_zone img {
height: 120px;
}
.drop_zone {
border: dashed 8px #DDD;
@ -102,3 +107,20 @@
.flag.flagged {
background-color: pink !important;
}
.test_panel {
margin-top: 5px;
padding:10px;
background-color: #eea45d6b !important;
border: 1px solid #EEA45D;
justify-content: space-between;
align-items: center;
}
.tests {
margin-top: 10px;
}
.test_panel > input[type="button"] {
max-width: 100px;
}

View File

@ -4,13 +4,36 @@
.image_display {
height: 100%;
}
.image_preview_holder {
.view_holders {
flex-grow: 1;
height: calc(100% - 36px);
background-color: #CCCCCC;
position: relative;
}
.image_preview_holder, .saliency_holder {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: #CCCCCC;
}
.saliency_holder {
position: absolute;
top: 0;
}
.saliency {
display: flex;
flex-direction: column;
border: none;
opacity: 1;
}
.saliency > div {
display: flex;
flex-grow: 1;
}
.saliency > div > div {
flex-grow: 1;
background-color: #EEA45D;
}
.image_preview {
max-width: 100%;

View File

@ -0,0 +1,52 @@
.hidden {
display: none !important;
}
.recording.input_caption {
color: #C00000;
}
.volume_display {
width: 100%;
display: flex;
}
.volume {
flex-grow: 1;
display: flex;
align-items: center;
}
.volume_left {
justify-content: flex-end;
}
.volume_bar {
height: 12px;
background-color: #C00000;
transition: width 0.1s;
}
.volume_left .volume_bar {
border-radius: 4px 0 0 4px;
}
.volume_right .volume_bar {
border-radius: 0 4px 4px 0;
}
.player {
display: flex;
width: 100%;
height: 100%;
flex-flow: column;
align-items: center;
justify-content: center;
}
.waveform {
width: 100%;
}
.waveform > wave {
overflow: visible !important;
}
.waveform canvas {
border: none !important;
}
.playpause {
margin-top: 26px;
font-size: 20px;
padding: 4px;
border-radius: 2px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -10,7 +10,7 @@ var io_master = {
data: JSON.stringify(post_data),
success: function(output){
if (output['action'] == 'output') {
io_master.output(output['data']);
io_master.output(output);
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
@ -21,8 +21,27 @@ var io_master = {
});
},
output: function(data) {
this.last_output = data;
this.output_interface.output(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"]);
}
},
test: function(type, data) {
var post_data = {
'data': data
};
if (type == "rotation") {
$.ajax({type: "POST",
url: "/api/auto/rotation",
data: JSON.stringify(post_data)
});
} else if (type == "lighting") {
$.ajax({type: "POST",
url: "/api/auto/lighting",
data: JSON.stringify(post_data)
});
}
},
flag: function(message) {
var post_data = {

View File

@ -7,8 +7,13 @@ const image_input = {
<div class="edit_holder">
<button class="edit_image interface_button primary">Edit</button>
</div>
<div class="image_preview_holder">
<img class="image_preview" />
<div class="view_holders">
<div class="image_preview_holder">
<img class="image_preview" />
</div>
<div class="saliency_holder hide">
<canvas class="saliency"></canvas>
</div>
</div>
</div>
<input class="hidden_upload" type="file" accept="image/x-png,image/gif,image/jpeg" />`
@ -20,11 +25,22 @@ const image_input = {
</div>
</div>
`,
test_html: `
<div class="panel_buttons test_panel">
<div><strong>Rotation</strong>: (rotates between -180 and 180 degrees)</div>
<input type="button" class="panel_button rotate_test" value="Run"/>
</div>
<div class="panel_buttons test_panel">
<div><strong>Lighting</strong>: (adjusts the lighting to 9 different levels)</div>
<input type="button" class="panel_button light_test" value="Run"/>
</div>
<a href="bulk_data.html"><input type="button" class="panel_button" value="Bulk Data" style="margin-top: 10px;"/></a>
`,
init: function() {
var io = this;
$('body').append(this.overlay_html.format(this.id));
this.overlay_target = $(`.overlay[interface_id=${this.id}]`);
this.target.find(".upload_zone").click(function (e) {
let io = get_interface(e.target)
io.target.find(".hidden_upload").click();
});
this.target.on('drag dragstart dragend dragover dragenter dragleave drop',
@ -33,19 +49,17 @@ const image_input = {
e.stopPropagation();
})
this.target.on('drop', '.drop_zone', function(e) {
let io = get_interface(e.target)
files = e.originalEvent.dataTransfer.files;
io.load_preview_from_files(files)
});
this.target.find('.hidden_upload').on('change', function (e) {
if (this.files) {
let io = get_interface(e.target);
io.load_preview_from_files(this.files);
}
})
this.target.find('.edit_image').click(function (e) {
let io = get_interface(e.target);
io.overlay_target.removeClass("hide");
io.target.find(".saliency_holder").addClass("hide");
})
this.tui_editor = new tui.ImageEditor(this.overlay_target.
find(".image_editor")[0], {
@ -65,7 +79,6 @@ const image_input = {
<button class="tui_cancel tui_close interface_button secondary">Cancel</button>
`)
this.overlay_target.find('.tui_close').click(function (e) {
let io = get_interface(e.target);
io.overlay_target.addClass("hide");
if ($(e.target).hasClass('tui_save')) {
// if (io.tui_editor.ui.submenu == "crop") {
@ -73,6 +86,17 @@ const image_input = {
// }
io.set_image_data(io.tui_editor.toDataURL(), /*update_editor=*/false);
}
});
$(".tests").html(this.test_html);
$(".rotate_test").click(function () {
if (io.image_data) {
io.io_master.test("rotation", io.image_data);
}
})
$(".light_test").click(function () {
if (io.image_data) {
io.io_master.test("lighting", io.image_data);
}
})
},
submit: function() {
@ -89,6 +113,37 @@ const image_input = {
this.target.find(".hidden_upload").prop("value", "")
this.state = "NO_IMAGE";
this.image_data = null;
this.target.find(".saliency_holder").addClass("hide");
},
output: function(data) {
if (this.target.find(".image_preview").attr("src")) {
var image = this.target.find(".image_preview");
var width = image.width();
var height = image.height();
this.target.find(".saliency_holder").removeClass("hide").html(`
<canvas class="saliency" width=${width} height=${height}></canvas>`);
var ctx = this.target.find(".saliency")[0].getContext('2d');
var cell_width = width / data[0].length
var cell_height = height / data.length
var r = 0
data.forEach(function(row) {
var c = 0
row.forEach(function(cell) {
if (cell < 0.25) {
ctx.fillStyle = "white";
} else if (cell < 0.5) {
ctx.fillStyle = "yellow";
} else if (cell < 0.75) {
ctx.fillStyle = "orange";
} else {
ctx.fillStyle = "red";
}
ctx.fillRect(c * cell_width, r * cell_height, cell_width, cell_height);
c++;
})
r++;
})
}
},
state: "NO_IMAGE",
image_data: null,

View File

@ -0,0 +1,95 @@
const microphone = {
html: `
<div class="upload_zone">
<img class="not_recording" src="/static/img/mic.png" />
<div class="recording hidden volume_display">
<div class="volume volume_left">
<div class="volume_bar"></div>
</div>
<img src="/static/img/mic_recording.png" />
<div class="volume volume_right">
<div class="volume_bar"></div>
</div>
</div>
<div class="not_recording input_caption">Click to Record from Microphone</div>
<div class="recording hidden input_caption">Click to Stop Recording</div>
</div>
<div class="player hidden">
<div class="waveform"></div>
<button class="playpause primary">Play / Pause</button>
</div>
`,
state: "NO_AUDIO",
init: function() {
var io = this;
this.wavesurfer = WaveSurfer.create({
container: '.waveform',
waveColor: '#888888',
progressColor: '#EEA45D',
barWidth: 3,
hideScrollbar: true
});
this.target.find(".upload_zone").click(function() {
if (io.state == "NO_AUDIO") {
if (!has_audio_loaded) {
loadAudio();
io.mic = new p5.AudioIn();
}
io.recorder = new p5.SoundRecorder();
io.soundFile = new p5.SoundFile();
io.recorder.setInput(io.mic);
io.target.find(".recording").removeClass("hidden");
io.target.find(".not_recording").hide();
io.state = "RECORDING";
io.mic.start();
io.recorder.record(io.soundFile);
var interval_id = window.setInterval(function () {
var volume = Math.floor(100 * io.mic.getLevel());
io.target.find(".volume_bar").width(`${(volume > 0 ? 10 : 0) + Math.round(2 * Math.sqrt(10 * volume))}px`)
}, 100)
}
});
this.target.find(".upload_zone").mousedown(function() {
if (io.state == "RECORDING" || io.state == "STOP_RECORDING") {
io.target.find(".upload_zone").hide();
io.recorder.stop();
var blob = io.soundFile.getBlob();
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
io.audio_data = reader.result;
io.target.find(".player").removeClass("hidden");
io.wavesurfer.load(io.audio_data);
if (io.state == "STOP_RECORDING") {
io.state = "RECORDED";
io.submit();
}
io.state = "RECORDED";
}
window.clearInterval(interval_id);
}
})
this.target.find(".playpause").click(function () {
io.wavesurfer.playPause();
})
},
submit: function() {
if (this.state == "RECORDED") {
this.io_master.input(this.id, this.audio_data);
} else if (this.state == "RECORDING") {
this.target.find(".upload_zone").mousedown();
}
},
clear: function() {
this.audio_data = null;
this.state = "NO_AUDIO";
this.target.find(".not_recording").show();
this.target.find(".recording").addClass("hidden");
this.target.find(".player").addClass("hidden");
this.target.find(".upload_zone").show();
if (this.wavesurfer) {
this.wavesurfer.stop();
}
}
}

View File

@ -9,6 +9,7 @@ const sketchpad_input = {
<canvas id="canvas"></canvas>
</div>`,
init: function() {
var io = this;
var dimension = Math.min(this.target.find(".canvas_holder").width(),
this.target.find(".canvas_holder").height()) - 2 // dimension - border
var id = this.id;
@ -21,7 +22,6 @@ const sketchpad_input = {
this.canvas = this.target.find('.canvas_holder canvas')[0];
this.context = this.canvas.getContext("2d");
this.target.find(".brush").click(function (e) {
let io = get_interface(e.target)
io.target.find(".brush").removeClass("selected");
$(this).addClass("selected");
io.sketchpad.penSize = $(this).attr("size");

View File

@ -2,7 +2,8 @@ input_to_object_map = {
"csv" : {},
"imageupload" : image_input,
"sketchpad" : sketchpad_input,
"textbox" : textbox_input
"textbox" : textbox_input,
"microphone" : microphone
}
output_to_object_map = {
"csv" : {},
@ -18,11 +19,6 @@ function set_interface_id(interface, id) {
interface.target.attr("interface_id", id);
}
function get_interface(target) {
return id_to_interface_map[$(target).closest(".interface, .interface_extension").
attr("interface_id")];
}
var config;
$.getJSON("static/config.json", function(data) {
config = data;

View File

@ -13,7 +13,7 @@ $("#send_link").click(function(evt) {
"type": "POST",
"crossDomain": true,
"data": {
"url": config["ngrok_socket_url"],
"url": config["share_url"],
"name": name,
"email": email
},

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,6 @@ en = {
"restarting python interpreter.",
"COLAB_NO_LOCAL": "Cannot display local interface on google colab, public link created.",
"PUBLIC_SHARE_TRUE": "To create a public link, set `share=True` in the argument to `launch()`.",
"MODEL_PUBLICLY_AVAILABLE_URL": "Model available publicly at: {}",
"MODEL_PUBLICLY_AVAILABLE_URL": "Model available publicly at: {} (may take up to a minute for link to be usable)",
"GENERATING_PUBLIC_LINK": "Generating public link (may take a few seconds...):",
}

View File

@ -0,0 +1,33 @@
<html lang="en">
<head>
<title>Gradio</title>
<link rel="stylesheet" href="../static/css/bulk_style.css">
</head>
<body>
<nav>
<a href="https://gradio.app"><img src="../static/img/logo_inline.png" /></a>
</nav>
<table id="bulk_rows">
<thead>
<th>Image</th>
<th>Label</th>
</thead>
</table>
<script src="../static/js/vendor/jquery.min.js"></script>
<script>
$.get("/static/flagged/data.txt", function(data) {
let lines = data.split("\n");
lines.forEach((line) => {
let row_data = JSON.parse(line);
let output = row_data["output"];
$("#bulk_rows").append(`
<tr class="bulk_row">
<td><img src="/static/flagged/${row_data["input"]}" /></td>
<td class="label">${output["label"] + (output["confidences"] ? ": " + Math.round(100 * output["confidences"][0]["confidence"]) + "%" : "")}</td>
</tr>
`)
})
});
</script>
</body>
</html>

View File

@ -0,0 +1,93 @@
<html lang="en">
<head>
<!-- <iframe src=""></iframe> -->
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Gradio</title>
<link rel="stylesheet" href="../static/css/style.css">
<link rel="stylesheet" href="../static/css/gradio.css">
<link rel="stylesheet" href="../static/css/interfaces/input/csv.css">
<link rel="stylesheet" href="../static/css/interfaces/input/image_upload.css">
<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/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/textbox.css">
<link rel="stylesheet" href="../static/css/loading.css"/>
<!-- TUI EDITOR -->
<link type="text/css" href="../static/css/vendor/tui-color-picker.css" rel="stylesheet">
<link type="text/css" href="../static/css/vendor/tui-image-editor.css" rel="stylesheet">
</head>
<body>
<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>
<div id="panels">
<div class="panel">
<div class="panel_header">Input</div>
<div id="input_interface" class="interface"></div>
<div class="panel_buttons">
<input class="submit" type="submit" value="submit"/>
<input class="clear" type="reset" value="clear">
</div>
<div class="tests"></div>
</div>
<div class="panel">
<div class="panel_header">
Output
<div class="loading">
<img src="../static/img/logo_mini.png" class="ld ld-skew"/>
<span class="loading_time"></span>
</div>
</div>
<div id="output_interface" class="interface"></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"/>
</div>
</div>
</div>
<script src="../static/js/vendor/jquery.min.js"></script>
<!-- TUI EDITOR -->
<script src="../static/js/vendor/fabric.js"></script>
<script src="../static/js/vendor/tui-code-snippet.min.js"></script>
<script src="../static/js/vendor/FileSaver.min.js"></script>
<script src="../static/js/vendor/tui-color-picker.js"></script>
<script src="../static/js/vendor/tui-image-editor.js"></script>
<script src="../static/js/vendor/white-theme.js"></script>
<script src="../static/js/vendor/black-theme.js"></script>
<script src="../static/js/utils.js"></script>
<script src="../static/js/all_io.js"></script>
<script src="../static/js/interfaces/input/csv.js"></script>
<script src="../static/js/interfaces/input/image_upload.js"></script>
<script src="../static/js/vendor/sketchpad.js"></script>
<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/interfaces/input/microphone.js"></script>
<script src="../static/js/vendor/wavesurfer.min.js"></script>
<script src="../static/js/vendor/p5.min.js"></script>
<script src="../static/js/vendor/p5.sound.min.js"></script>
<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/textbox.js"></script>
<script src="../static/js/share.js"></script>
<script src="../static/js/load_interfaces.js"></script>
</body>
</html>

View File

@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: gradio
Version: 0.7.7
Version: 0.7.8
Summary: Python library for easily interacting with trained machine learning models
Home-page: https://github.com/abidlabs/gradio
Author: Abubakar Abid

View File

@ -19,12 +19,14 @@ gradio.egg-info/top_level.txt
gradio/static/apple-app-site-association
gradio/static/config.json
gradio/static/css/.DS_Store
gradio/static/css/bulk_style.css
gradio/static/css/font-awesome.min.css
gradio/static/css/gradio.css
gradio/static/css/loading.css
gradio/static/css/style.css
gradio/static/css/interfaces/input/csv.css
gradio/static/css/interfaces/input/image_upload.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/output/image.css
@ -38,6 +40,7 @@ gradio/static/img/logo_loading.gif
gradio/static/img/logo_mini.png
gradio/static/img/logo_only.png
gradio/static/img/mic.png
gradio/static/img/mic_recording.png
gradio/static/img/table.png
gradio/static/img/webcam.png
gradio/static/img/vendor/icon-a.svg
@ -50,6 +53,7 @@ gradio/static/js/share.js
gradio/static/js/utils.js
gradio/static/js/interfaces/input/csv.js
gradio/static/js/interfaces/input/image_upload.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/output/image.js
@ -59,20 +63,18 @@ gradio/static/js/vendor/FileSaver.min.js
gradio/static/js/vendor/black-theme.js
gradio/static/js/vendor/fabric.js
gradio/static/js/vendor/jquery.min.js
gradio/static/js/vendor/p5.dom.min.js
gradio/static/js/vendor/p5.min.js
gradio/static/js/vendor/p5.sound.min.js
gradio/static/js/vendor/papaparse.min.js
gradio/static/js/vendor/sketchpad.js
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/white-theme.js
gradio/templates/base_template.html
gradio/templates/input/csv.html
gradio/templates/input/image_upload.html
gradio/templates/input/sketchpad.html
gradio/templates/input/textbox.html
gradio/templates/output/image.html
gradio/templates/output/label.html
gradio/templates/output/textbox.html
gradio/templates/bulk_data.html
gradio/templates/index.html
test/test_inputs.py
test/test_interface.py
test/test_networking.py

View File

@ -4,3 +4,4 @@ Pillow
requests
psutil
paramiko
scipy

View File

@ -5,7 +5,7 @@ except ImportError:
setup(
name='gradio',
version='0.7.7',
version='0.7.8',
include_package_data=True,
description='Python library for easily interacting with trained machine learning models',
author='Abubakar Abid',