近日在做毕设,需要搭建一个完整的平台,用来对外展示组里的语音相关模型(类似这种)。为了实现这种需求,最关键的是客户端(浏览器)和服务端(server)之间能正确地相互通信。如果你学过计算机网络的话,你会发现,承担这项任务的是HTTP request (浏览器-->服务器)和HTTP response (服务器-->浏览器)。对于后者,现在已经有很多成熟的开源后端框架(nginx+django)帮助你在服务器端接收request,处理request,然后生成response返回, 我就不做过多的介绍了,本文的目的主要是为了解决在客户端如何生成request的问题。
在客户端所看到的网页(html+css),实际上是静态的,他们只能用来展示页面,真正从页面中获取信息并制作request的是js文件。通过在html中插入javascript脚本,当某一事件发生时(比如点击某个button),就可以执行这个脚本 :
.html中对应按钮的部分
Browse files
source audio
对应的 .js部分
$("#browse-button").change(function() {
loadAudio($("#browse-button").prop("files")[0]);
});
这段的意思是:js通过id(browse-container)来定位html中的某个实体(input),当这个实体发生某种变化(.change)就会执行后面的function。具体到上面的需求中,function要做的就是1:找到音频数据,2:预加载到浏览器缓存中。
在upload之前,浏览器必须先读取出本地音频文件的内容到内存中(此时还没开始上传服务器),具体代码如下:
loadAudio = function(file) {
var reader = new FileReader();
reader.onload = function(event) {
$('#img-card').attr('src', event.target.result);
};
reader.readAsDataURL(file);
switchCard(1);
};
实际上file就是前面的$("#browse-button").prop("files")[0] 他传给loadaudio的是音频文件在本地的地址,然后js会创建一个reader以base64字节的方式读取出文件所有的信息,注意此时会把读取的信息赋给上面html中的
得到想上传的音频后,接下来要做的就是为它制作request并能接收服务器返回的response,在js中,ajax()可以完成这两项工作:
upload and detect audio按钮对应的.html
Upload and Detect Audio
相应的.js
$('#upload-button').click(function() {
$('.modal').modal('open');
});
$('.modal').modal({
dismissible: false,
ready: function(modal, trigger) {
$.ajax({
type: "POST",
url:'VC_api/',
data: {
'image64': $('#img-card').attr('src')
},
dataType: 'text',
success: function(data) {
modal.modal('close');
loadStats(data);
},
error: function(data) {
modal.modal('close');
loadStats(data);
},
}).always(function() {
modal.modal('close');
});
}
});
首先js检测到upload-button出现‘点击’事件(此时browse-button的读取音频和预览工作已经完成),开始调用ajax构造request,这个request属于POST请求(因为要向服务器发送数据,如果只是从服务器请求数据,则用GET),data就是之前的
{% load staticfiles %}
THU Audio
cloud_upload
Drag and drop audio here
or
source audio
Upload and Detect Audio
Go Back
Go Back
js
$(document).ready(function() {
var dropContainer = document.getElementById('drop-container');
dropContainer.ondragover = dropContainer.ondragend = function() {
return false;
};
dropContainer.ondrop = function(e) {
e.preventDefault();
loadAudio(e.dataTransfer.files[0])
};
$("#browse-button").change(function() {
loadAudio($("#browse-button").prop("files")[0]);
});
$('.modal').modal({
dismissible: false,
ready: function(modal, trigger) {
$.ajax({
type: "POST",
url:'VC_api/',
data: {
'image64': $('#img-card').attr('src')
},
dataType: 'text',
success: function(data) {
modal.modal('close');
loadStats(data);
},
error: function(data) {
modal.modal('close');
loadStats(data);
},
}).always(function() {
modal.modal('close');
});
}
});
$('#go-back, #go-start').click(function() {
$('#img-card').removeAttr("src");
$('#stat-table').html('');
switchCard(0);
});
$('#upload-button').click(function() {
$('.modal').modal('open');
});
});
switchCard = function(cardNo) {
var containers = [".dd-container", ".uf-container", ".dt-container"];
var visibleContainer = containers[cardNo];
for (var i = 0; i < containers.length; i++) {
var oz = (containers[i] === visibleContainer) ? '1' : '0';
$(containers[i]).animate({
opacity: oz
}, {
duration: 200,
queue: false,
}).css("z-index", oz);
}
};
loadAudio = function(file) {
var reader = new FileReader();
reader.onload = function(event) {
$('#img-card').attr('src', event.target.result);
};
reader.readAsDataURL(file);
switchCard(1);
};
loadStats = function(jsonData) {
switchCard(2);
var data = JSON.parse(jsonData);
if (data["success"] == true) {
var markup = `
source audio
target audio
`;
$("#stat-table").append(markup);
}
};