소공 과제를 하면서 음성인식을 위해, 녹음한 파일을 바로 서버로 전송시키는 방법이 뭐가 있을까 생각해보았다.
그러다 든 생각이, body에 파일을 담아서 보내자 였다. 그런데, 그 큰 파일을 어떻게 body에 담을 수 있을까?
계속 검색하고, ChatGPT한테 물어보아 해결하게 되었다.
https://ko.javascript.info/formdata
이 글을 많이 참고하였다.
프론트를 맡은 친구가 녹음하는 부분까지 구현하였던 코드를 샅샅히 살펴보았다. 녹음한 파일은 webm파일로 저장되고, Blob객체에 담겨져있었다.
그렇다면 Blob(Binary Large Object)은 무엇인가?
https://developer.mozilla.org/ko/docs/Web/API/Blob
위 글을 참고하였다.
"Blob 객체는 파일류의 불변하는 미가공 데이터를 나타냅니다. 텍스트와 이진 데이터의 형태로 읽을 수 있으며, ReadableStream으로 변환한 후 스트림 메서드를 사용해 데이터를 처리할 수도 있습니다." 라고 나와있다.
보통 Blob은 파일의 크기를 알아내거나, 데이터를 송수신할 때 이용할 수 있다고 한다. 그렇다면 이 Blob 객체를 전송만 할 수 있으면 된다.
과정은 힘들었지만 방법은 간단했다.
FormData를 만들고, 그 안에 Blob을 넣어주면 된다.
아래 코드를 보면 쉽게 이해가 갈 것이다.
const formData = new FormData();
formData.append('file', blob);
fetch('http://127.0.0.1:5000/voice-recognization', {
method: 'POST',
body: formData,
})
.then(response => response.text())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
FormData는 데이터를 묶어놓은 하나의 폼이라고 생각하면 된다. 딕셔너리와 비슷한 형태로 키, 밸류가 존재한다. file이라는 키에 blob이라는 Blob객체 밸류를 넣은 코드이고, 이것을 통째로 body에 담아서 api를 호출해주면 된다.
개발자도구를 이용해서 network에서 방금 호출한 api를 보자.
payload를 보면 Form Data 안에, file: (binary)가 저장되어있는 것을 볼 수 있다.
방금 넣은 키, 밸류값이 저장되어있는 것이다.
그러면, 서버에서는 어떻게 이를 활용할 수 있을까?
원래는 request.get_data()를 사용하면 바디에 담겨진 정보를 가져올 수 있다. 하지만 이번 같은 경우에는 파일이 저장된 것이므로, request.files를 이용하는 것이 편하다.
get_data() 는 이진문자열이 반환되지만, files는 이를 파싱해서 구조화시킨 것을 리턴해준다.
@app.route('/voice-recognization', methods=['POST'])
def voice_recognization():
data = request.files
file_stream = data.get('file').stream
ret = ctr.voice_recognization(id, api_key, file_stream)
return jsonify(ret), 200
request.files는 <FileStorage: 'blob' ('audio/webm;codecs=opus')>를 리턴하였다.
키값인 'file'에 접근하여 객체를 출력해보니 아래와 같았다(print(data.get('file').__dict__))
{
"name":"file",
"stream":<tempfile.SpooledTemporaryFile object at 0x106025e40>,
"filename":"blob",
"headers":"Headers("[
"(""Content-Disposition",
"form-data; name=\"file\"; filename=\"blob\""")",
"(""Content-Type",
"audio/webm;codecs=opus"")"
]")"
}
이름과 stream이 저장되어있는 것을 볼 수 있다. 위 stream은 흔히 특정 개발 언어에서 파일을 open한 것과 같다. 즉, 이 스트림을 read하면 파일 안에 들어있는 정보들을 다룰 수 있다는 의미이다.
audio_data = file_stream.read()
response = requests.post(url, headers=headers, data=audio_data)
위 코드는 다른 부분에서 이 스트림을 read한 후, 다른 api의 body로 전송시킨 코드이다.
(녹음한 파일 스트림을 이용해서 음성인식 api를 호출하는 부분이다.)
'개발' 카테고리의 다른 글
[Git] 로컬에서 git url 세팅하는 법 (0) | 2024.03.20 |
---|---|
파이썬 대화형으로 실행하기 (0) | 2023.12.26 |
CORS 에러, 무엇일까? (5) | 2023.11.29 |
post api 간단하게 테스트 (1) | 2023.11.24 |
Facade pattern (1) | 2023.11.23 |