运行时错误:打开<文件存储:'audio_file.wav'("音频/wav")时出错>:文件包含未知格式的数据。Flask, JS, Librosa



我试图通过web浏览器记录音频6秒,并将其发送到flask。然后音频文件被转换成频谱图。之后,它应该被转换成Numpy数组来处理模型。

我不知道问题是我的上传功能还是librosa

我尝试了几个不同的版本和选项,但都不行。

这是JS代码:
function lDUp(){
var formData = new FormData();
const startButton = document.getElementById("startLungBtn");
startButton.addEventListener("click", function() {
if (!navigator.mediaDevices) {
console.error("getUserMedia not supported.")
return;
}

const constraints = { audio: true };
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
var chunks = [];
const recorder = new MediaRecorder(stream);
recorder.ondataavailable = event => {
// Collect all the chunks of the recording in an array.
chunks.push(event.data);
};
const audioContext = new AudioContext();
const audioStreamSource = audioContext.createMediaStreamSource(stream);


recorder.onstop = event => {
console.log("Recording stopped.")
// Create a blob with all the chunks of the recording.
let blob = new Blob(chunks, { type: "audio/wav" }); 
// let blob = new Blob(chunks, { type: recorder.mimeType }); 
chunks = [];
startButton.disabled = false;

// Create form data that contain the recording.
formData.append("audio_file", blob, "audio_file.wav");
$.ajax({

type: "POST",
url: "http://127.0.0.1:5000/LungUploader",
processData: false,
contentType: false,
cache: false,
data: formData,
success: function(response) {
console.log(response);
console.log("This is class: ", response)
},
error: function(err) {
console.log(err);
}
});   

};
recorder.onstart = event => {
console.log("Recording started.");
startButton.disabled = true;
// Stop recording when the time is up.
setTimeout(function() { recorder.stop(); }, 6000);


};
recorder.start();
})
.catch(function(err) {
console.error(err);
});
});


}

这是flask的代码:

@app.route('/LUploader', methods=["GET", 'POST'])
def lUploader():
if request.method == "POST":
f = request.files["audio_file.wav"]
with open('audio.wav', 'wb') as audio:
f.save(audio)

print("Checkpoint1")
y, sr = lb.load(f)
print("Checkpoint")
#Plot signal in
plt.figure(figsize=(10,3))
src_ft = lb.stft(y)
src_db = lb.amplitude_to_db(abs(src_ft))
specshow(src_db, sr=sr, x_axis='time', y_axis='hz')  
plt.ylim(0, 5000)        
plt.close()
}

提前感谢您的帮助:)

您试图通过文件名获取文件。为了在表单中接收文件,输入字段的名称是必需的。在您的示例中,这是"audio_file"

f = request.files['audio_file']

您将得到一个类型为werkzeug.datastructures.FileStorage的类文件对象,它可以通过save函数保存。

f.save(f.filename)

您应该区分表单字段的名称和发送的文件的文件名。从表单请求文件需要输入字段的名称(例如:"audio_file"。文件名是文件在服务器上保存和加载的名称(例如:"audio_file. wave ")。

代码应该是这样的:

from flask import (
Flask, 
request, 
# ...
)
from werkzeug.utils import secure_filename
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = os.path.join(
app.instance_path, 
'uploads'
)
try: 
os.makedirs(app.config['UPLOAD_FOLDER'])
except: 
pass 
# ...
@app.post('/upload')
def upload():
# Get the FileStorage object with the name of the form's input field.
file = request.files.get('audio_file')
if file and file.filename != '': 
dest = os.path.join(
app.config['UPLOAD_FOLDER'], 
secure_filename(file.filename)
)
# Save the file on the server.
f.save(dest)

# Load the file by filename using librosa.
y,sr = librosa.load(dest)

# ...

上传文件的详细说明可以在这里找到。


我写了一个示例应用程序,用于上传,播放音频文件和显示这里的频谱图。请注意,使用的音频格式取决于平台和浏览器。

<编辑>瓶
'''
pip install flask librosa numpy scikit-image
'''
from flask import (
Flask,
Response,
abort,
current_app,
render_template,
redirect,
request,
send_from_directory,
stream_with_context,
url_for
)
from collections import namedtuple
from glob import glob
from mimetypes import add_type, guess_extension, guess_type
from werkzeug.utils import secure_filename
import librosa
import numpy
import os
import skimage.io

add_type('audio/aac', '.m4a', strict=True)
Record = namedtuple('Record', ('filename', 'specimage', 'created_at'))
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
try:
os.makedirs(os.path.join(
app.instance_path,
app.config.get('UPLOAD_FOLDER', 'uploads')
))
except:
pass
@app.route('/')
def audio_index():
patterns = [
'*.m4a',
'*.wav',
'*.weba'
]
path = os.path.join(
current_app.instance_path,
current_app.config.get('UPLOAD_FOLDER', 'uploads')
)
records = [
Record(fn[len(path)+1:], f'{fn[len(path)+1:]}.png', os.path.getctime(fn)) 
for ptrn in patterns for fn in glob(os.path.join(path, ptrn))
]
return render_template('index.html', records=records)
@app.route('/audio-upload', methods=['POST'])
def audio_upload():
if 'audio_file' in request.files:
file = request.files['audio_file']
extname = guess_extension(file.mimetype)
if not extname:
abort(400)
# WARNING: Check for allowed file extensions.
i = 1
while True:
dst = os.path.join(
current_app.instance_path,
current_app.config.get('UPLOAD_FOLDER', 'uploads'),
secure_filename(f'audio_record_{i}{extname}'))
if not os.path.exists(dst): break
i += 1
file.save(dst)
img = os.path.join(
current_app.instance_path,
current_app.config.get('UPLOAD_FOLDER', 'uploads'),
secure_filename(f'{os.path.basename(dst)}.png')
)
hop_length = 512
n_mels = 128
time_steps = 384
y, sr = librosa.load(dst)
spectrogram_image(y, sr=sr, out=img, hop_length=hop_length, n_mels=n_mels)
return redirect(url_for('audio_index'))
def spectrogram_image(y, sr, out, hop_length, n_mels):
mels = librosa.feature.melspectrogram(
y=y, sr=sr, n_mels=n_mels,
n_fft=hop_length*2, hop_length=hop_length
)
mels = numpy.log(mels + 1e-9)
img = scale_minmax(mels, 0, 255).astype(numpy.uint8)
img = numpy.flip(img, axis=0)
img = 255-img
skimage.io.imsave(out, img)
def scale_minmax(X, min=0.0, max=1.0):
X_std = (X - X.min()) / (X.max() - X.min())
X_scaled = X_std * (max - min) + min
return X_scaled
@app.route('/audio/stream/<path:fn>', methods=['GET'])
def audio_download(fn):
@stream_with_context
def generator(src):
CHUNK_SIZE = 1024
with open(src, 'rb') as fp:
while True:
data = fp.read(CHUNK_SIZE)
if not data: break
yield data
src = os.path.join(
current_app.instance_path,
current_app.config.get('UPLOAD_FOLDER', 'uploads'),
fn
)
if not os.path.exists(src):
return abort(404)
mime,_ = guess_type(src)
return Response(generator(src), mimetype=mime)
@app.route('/audio/spec/<path:fn>')
def audio_spec(fn):
path = os.path.join(
current_app.instance_path,
current_app.config.get('UPLOAD_FOLDER', 'uploads')
)
return send_from_directory(path, fn)
<编辑>HTML(模板/index . HTML)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Audio Index</title>
</head>
<body>
<div class="rec-container">
<div class="rec-column rec-column-1">
<button class="rec-btn" id="toggle-rec-btn">Record</button>
</div>
<div class="rec-column rec-column-2">
{% for record in records|sort(attribute='created_at', reverse=True) -%}
<div class="rec-item">
<div class="content">
<span class="rec-title">{{ record.filename }}</span>
<audio
controls
src="{{ url_for('audio_download', fn=record.filename) }}"
></audio>
</div>
<div class="spec">
<img src="{{ url_for('audio_spec', fn=record.specimage) }}" />
</div>
</div>
{% endfor -%}
</div>
</div>
<script type="text/javascript">
(function() {
const uploadURL = {{ url_for('audio_upload') | tojson }};
const startButton = document.getElementById("toggle-rec-btn");
startButton.addEventListener("click", function() {
if (!navigator.mediaDevices) {
console.error("getUserMedia not supported.")
return;
}
const constraints = { audio: true };
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
let chunks = []
let recorder = new MediaRecorder(stream);
recorder.ondataavailable = event => {
chunks.push(event.data);
};
recorder.onstop = event => {
console.log("Recording stopped.")
let blob = new Blob(chunks, { type: recorder.mimeType });
chunks = [];
startButton.disabled = false;
let formData = new FormData();
formData.append("audio_file", blob);
fetch(uploadURL, {
method: "POST",
cache: "no-cache",
body: formData
}).then(resp => {
if (resp.status === 200) {
window.location.reload(true);
} else {
console.error("Error:", resp)
}
}).catch(err => {
console.error(err);
});
};
recorder.onstart = event => {
console.log("Recording started.");
startButton.disabled = true;
setTimeout(function() { recorder.stop(); }, 10000);
};
recorder.start();
})
.catch(function(err) {
console.error(err);
});
});
})();
</script>
</body>
</html>

最新更新