import numpy as np
import librosa
import tensorflow as tf
from flask_cors import CORS, cross_origin
from flask import Flask, request, jsonify
import ffmpeg
import warnings
import speech_recognition as sr
warnings.filterwarnings('ignore')
r=sr.Recognizer()
app = Flask(__name__)
app.config['DEBUG'] = True
CORS(app)
# 리턴값 딕셔너리
checkDict = { 0 : "응",
1 : "아니",
}
wordDict = { 0 : "냠냠",
1 : "드르륵",
2 : "보글보글",
3 : "사각사각",
4 : "송송",
5 : "주르륵",
6 : "탁탁",
7 : "툭툭",
8 : "팔팔",
9 : "풀풀",
10 : "휘휘" }
birdDict = { 0 : "까마귀",
1 : "꿩",
2 : "뱁새",
3 : "오리",
4 : "참새",
5 : "황새" }
사용자의 음성이 들어오고 Flask 환경에 올라와있는 모델은 그것을 판단하여 진행되고 있는 게임에 따라 그에 맞는 값을 돌려준다. 앞선 글에서 새 이름 분류 모델에 관해 다뤘으므로 그의 연장선에 있는 코드를 다뤄보겠다.
@app.route('/api/ai/sky/bird', methods=["POST"])
@cross_origin()
def sky_bird():
model = tf.keras.models.load_model('../bird_determine_model220928.h5')
# 받아온 오디오 데이터
file = request.files['audio_data']
path='./audio.wav'
file.save(path)
audio_input = ffmpeg.input('./audio.wav')
audio_cut = audio_input.audio.filter('atrim', duration=1)
audio_output = ffmpeg.output(audio_cut, './audio_output.wav')
ffmpeg.run(audio_output)
path='./audio_output.wav'
들어오는 음성 데이터를 모델에 통과 시키기 위한 적절한 길이인 1초로 자른다.
wav, sr = librosa.load(path, sr=16000)
mfcc = librosa.feature.mfcc(wav, sr=16000, n_mfcc=100, n_fft=400, hop_length=160)
# mfcc = sklearn.preprocessing.scale(mfcc, axis=1)
pad2d = lambda a, i: a[:, 0:i] if a.shape[1] > i else np.hstack((a, np.zeros((a.shape[0], i-a.shape[1]))))
padded_mfcc = pad2d(mfcc, 110)
padded_mfcc = np.expand_dims(padded_mfcc, 0)
result = model.predict(padded_mfcc)
# 판별 완료된 음성 파일 삭제
os.remove('./audio.wav')
os.remove('./audio_output.wav')
# 어떤 결과를 리턴시켜야 하나(까마귀 : 0, 꿩 : 1, 뱁새 : 2, 오리 : 3, 참새 : 4, 황새 : 5)
for key, val in birdDict.items():
if key == np.argmax(result) :
return jsonify(answer = val)
앞선 시리즈에서 다룬 분류 예측 확인 과정 코드와 동일하다.
파이썬 음성 인식 라이브러리인 SpeechRecognition을 이용하였다.
그리고 Google Speech Recognition을 활용하여 speech를 text로 바꾼다.
@app.route("/api/ai/stt", methods=["POST"])
def sttcheck():
r = sr.Recognizer()
file = request.files['audio_data']
path='./audio.wav'
file.save(path)
audio_input = ffmpeg.input('./audio.wav')
audio_cut = audio_input.audio.filter('atrim', duration=5)
audio_output = ffmpeg.output(audio_cut, './audio_output.wav')
ffmpeg.run(audio_output)
path='./audio_output.wav'
stt도 들어온 음성 데이터를 검증을 위해 5초 길이로 자른다.
try:
transcript = ''
while not transcript:
with sr.AudioFile(path) as source:
audio = r.record(source)
transcript=r.recognize_google(audio, language="ko-KR")
os.remove('./audio.wav')
os.remove('./audio_output.wav')
return jsonify(answer=transcript)
except:
os.remove('./audio.wav')
os.remove('./audio_output.wav')
return jsonify(answer='failed')
if __name__ == '__main__':
app.run(host="0.0.0.0", port="5678", debug=True)
아무 데이터도 들어오지 않았을 때 recognizer을 계속 작동시키고, 정상적으로 음성을 인식했을 경우 audio를 text로 변환한 내용을 transcript에 담고, 그것을 정답과 비교한 결과를 반환한다.
한국어를 말할 것이기 때문에 language="ko-KR"로 설정하였고 try, except를 이용하여 예외 처리도 해줬다. 제대로 인식하지 못했을 시 다시 말해달라고 하기 위함이다.