为了让之后的项目能够专注于算法,于是打算先在近几日解决一定的应用层面的内容。因此也就诞生了这篇文章。
背景
这个Web应用说来其实应该是很简单的,但是由于没有前后端开发经验,对我来说也算是一个挑战。这个应用旨在实现能够通过前端上传录音文件,通过后端的处理将文本返回给前端页面以及能够调用本地的麦克风进行录音最后通过这段录音能够返回文本内容。项目不大,也应该不会太过华丽,所以选用了Flask框架处理。
基本文件上传表单
从客户端的角度来讲,上传文件和提交表单数据一样,因此我们需要定义一个包含文件字段的HTML表单。一个简单的HTML表单如下。这个表单可以接收一个文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>语音识别站点</title>
</head>
<body>
<h1>录音文件上传</h1>
<form method="post" action="" enctype="multipart/form-data">
<p><input type="file" name="file" accept=".wav"></p>
<p><input type="submit" value="提交"></p>
</form>
</body>
</html>
这里需要注意的是,<form>
元素的method
属性可以是get
或post
。使用get
时,数据将在请求URL的查询字符串中提交,而使用post
时,数据将进入请求主体。当一个HTML表单中包含文件时,必须使用post
方法,因为我们不可能在请求URL字符串中处理提交的文件数据。采用multipart/form-data
字段则是因为这个字段可以适用于提交文件。accept
属性则是可以限制表单可以接受的文件类型。如上使用了.wav
进行限制,当点击选择文件时,系统的资源管理器会帮你过滤类型不匹配的文件。
使用Flask进行文件接收
对于常规表单,Flask提供了对提交表单字段的访问。其中文件字段就包含在 request.files
字典中,可以通过键值 file
来访问文件列表,从中得出文件名,再用save保存文件。
@app.route('/upload', methods=['post'])
def upload_file():
upload_file = request.files['file']
if upload_file.filename != "":
upload_file.save(upload_file.filename)
return redirect(url_for('upload_file'))
这样,每当提交一次文件时,就会将文件保存到你的工程目录中。如下图所示
添加一些限制
文件大小限制
为了防止上传十分大的文件,我们在后端中添加对文件大小进行限制的配置。
app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024
添加了如上的配置之后,文件大小将会被限制在1MB,超过此大小的文件将会被拒收。这样在一定程度上也可以防止客户端采用上传大文件的方式过多的占用服务器资源以及,通过大容量文件对服务器进行攻击。
可接收文件类型限制
在前面的HTML表单中提到了accept
属性,通过这个属性系统资源管理器会对文件的扩展名进行筛选。在发现了Flask框架可以对文件类型进行限制的时候我决定转到后台进行文件类型的限制。
app.config['UPLOAD_EXTENSIONS'] = ['.wav']
上传路径的限制
由于之后需要使用到这个录音文件,所以我将这个录音文件保存在相应的工程路径中,便于之后的获取。据此添加了相关配置
app.config['UPLOAD_PATH'] = 'uploads'
这样当文件上传之后,你就可以看到文件在uploads的文件夹下出现
综合以上几点限制之后我们可以得到后端接收录音文件的完整代码如下。
@app.route('/upload', methods=['post'])
def upload_file():
upload_file = request.files['file']
filename = secure_filename(upload_file.filename)
if filename != "":
file_ext = os.path.splitext(filename)[1]
if file_ext not in app.config['UPLOAD_EXTENSIONS']:
abort(400)
upload_file.save(os.path.join(app.config['UPLOAD_PATH'], filename))
return redirect(url_for('upload_file'))
使用dropzone的css框架
当采用HTML自带的表单文件上传时,生成的页面显示的更像是一个登录的文本框,在我看来如果要提交一个文件的话这样的文本框未免太小气了,因此在查阅相关资料后,发现了dropzone这个css框架,通过这个框架可以得到一个范围较大且可拖拽上传的文本框以及一个上传动画(虽然HTML表单也可以拖拽)。
要使用这个框架我们只需要在前端页面中添加如下的代码即可
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.7.1/min/dropzone.min.css">
<form action="{{ url_for('upload_file') }}" class="dropzone"></form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.7.1/min/dropzone.min.js"></script>
此处的action
属性即是Flask后端中用来接收上传文件的处理函数。这样一个简单的录音文件上传的前后端应用就已经初具模样了。