Извлечение характеристик из блоба с помощью Librosa
Я пытаюсь записать голосовое сообщение во фронтенде и отправить его в бэкенд Django, чтобы проверить его на соответствие ML-алгоритму распознавания пола по голосу. Во фронтенде я записываю голос с помощью videojs-record и использую AJAX для отправки блоба в бэкенд следующим образом:
На бэкенде я пытаюсь использовать wave, чтобы сохранить файл как правильный .wav, например так:
def post(self, request):
f = request.FILES['file']
with open('file.wav', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
with open('file.wav', 'rb') as file:
file_content = file.read()
audio = wave.open('test.wav', 'wb')
audio.setnchannels(1)
audio.setnframes(1)
audio.setsampwidth(1)
audio.setframerate(8000)
audio.writeframes(file_content)
audio.close()
(prediction, probability) = predict('test.wav')
context["prediction"] = prediction
context["probability"] = probability*100
os.remove(file_name)
return render(request, self.template_name, context=context)
Здесь я попробовал две вещи. Первая попытка заключалась в том, чтобы сохранить блоб непосредственно в файл, используя open with 'wb'. Проблема с этим подходом в том, что librosa жалуется, что тип файла не распознан. Другая попытка была с помощью wave, но что бы я ни пробовал, файл, сохраненный с помощью wave, дает шум, и алгоритм предсказания не работает. Вот как я хотел бы использовать файл с записанным голосом для предсказания:
def predict(file_name):
# construct the model
model = create_model()
# load the saved/trained weights
model.load_weights('model.h5')
# extract features and reshape it
features = extract_feature(file_name, mel=True).reshape(1, -1)
# predict the gender!
male_prob = model.predict(features)[0][0]
female_prob = 1 - male_prob
gender = "male" if male_prob > female_prob else "female"
if gender == "male":
return (gender, male_prob)
return (gender, female_prob)
А вот функция extract_feature, в которой я загружаю файл и обрабатываю его:
def extract_feature(file_name, **kwargs):
mfcc = kwargs.get("mfcc")
chroma = kwargs.get("chroma")
mel = kwargs.get("mel")
contrast = kwargs.get("contrast")
tonnetz = kwargs.get("tonnetz")
X, sample_rate = librosa.core.load(file_name)
if chroma or contrast:
stft = np.abs(librosa.stft(X))
result = np.array([])
if mfcc:
mfccs = np.mean(librosa.feature.mfcc(y=X, sr=sample_rate, n_mfcc=40).T, axis=0)
result = np.hstack((result, mfccs))
if chroma:
chroma = np.mean(librosa.feature.chroma_stft(S=stft, sr=sample_rate).T,axis=0)
result = np.hstack((result, chroma))
if mel:
mel = np.mean(librosa.feature.melspectrogram(X, sr=sample_rate).T,axis=0)
result = np.hstack((result, mel))
if contrast:
contrast = np.mean(librosa.feature.spectral_contrast(S=stft, sr=sample_rate).T,axis=0)
result = np.hstack((result, contrast))
if tonnetz:
tonnetz = np.mean(librosa.feature.tonnetz(y=librosa.effects.harmonic(X), sr=sample_rate).T,axis=0)
result = np.hstack((result, tonnetz))
return result
Что я делаю неправильно? Есть ли способ создать правильный WAV-файл с тем же содержимым, что и блоб, который я записываю на фронтенде? Или есть способ напрямую использовать блоб, который я получаю с фронтенда?
После некоторого копания я обнаружил инструмент ffmpeg в Linux и использовал его в python для преобразования файла из формата WebM в WAV. Вот решение:
def post(self, request):
webm_file = str(datetime.datetime.now()) + ".webm"
wav_file = str(datetime.datetime.now()) + ".wav"
f = request.FILES['file']
with open(webm_file, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
destination.close()
# convert file from WebM to WAV format
subprocess.run(["ffmpeg", "-i", webm_file, "-vn", wav_file])
(prediction, probability) = predict(wav_file)
context["prediction"] = prediction
context["probability"] = probability*100
os.remove(webm_file)
os.remove(wav_file)
return render(request, self.template_name, context=context)