개인 대시보드에 "말로 물어보면 말로 답하는" 기능을 붙였다. 텍스트·이미지·음성을 한 모델이 다루는 멀티모달이 흔해지면서 이런 기능의 문턱이 많이 낮아졌다. 다만 만들고 보니 모델보다 브라우저와 기기 쪽에서 배운 것이 더 많았다.
구성
마이크 녹음 ──▶ 서버 ──▶ 받아쓰기(멀티모달 모델) ──▶ 답변 생성(가벼운 모델) ──▶ 음성 합성 ──▶ 재생
받아쓰기를 브라우저에 맡기지 않은 이유
브라우저에는 음성 인식 API 가 있다. 무료이고 코드도 짧다. 그런데 기기와 브라우저에 따라 지원 여부가 제각각이고, 앱 안에 내장된 브라우저에서는 아예 없는 경우가 많았다. 그래서 녹음한 오디오를 서버로 보내 멀티모달 모델에게 "이 음성을 받아 적어 줘"라고 시키는 방식을 택했다.
- 어느 브라우저에서나 똑같이 동작한다. 필요한 것은 녹음 기능뿐이다.
- 오디오를 요청 본문에 직접 실어 보내면 되므로 별도의 음성 인식 서비스를 붙일 필요가 없다.
- 개발할 때 편하다. 녹음 파일을 코드로 직접 넣어 볼 수 있어서 마이크가 막힌 환경에서도 시험할 수 있었다.
답변은 가벼운 모델로
질문에 답할 때는 대시보드가 이미 모아 둔 데이터의 요약을 맥락으로 준다. 긴 추론이 필요 없는 일이라 가벼운 모델로 충분했고 1~2초면 답이 나왔다. 전체 대기 시간의 대부분은 오히려 마지막의 음성 합성이었다. 60자 정도의 답을 소리로 만드는 데 5초쯤 걸렸다. 그 사이의 침묵을 줄이려고 "확인해 볼게요" 같은 짧은 음성을 먼저 틀어 준다.
겪은 문제들
- 말이 끝난 시점 알아내기. 녹음 버튼을 다시 누르게 하는 것은 불편해서, 소리 크기가 일정 시간 이상 작으면 끝난 것으로 본다. 기준값을 고정하면 시끄러운 곳에서는 영영 끝나지 않으므로, 시작할 때 잰 배경 소음의 몇 배를 기준으로 삼고 최솟값을 두었다.
- 대기 음성이 답변을 지워 버렸다. 재생 목록에 이전 항목이 남은 상태에서 대기 음성을 틀었더니, 그 음성이 끝나면서 "다음 항목 재생"이 호출되고, 그 과정에서 재생 상태가 초기화돼 정작 도착한 답변이 버려졌다. 대기 음성을 틀기 전에 재생 목록을 먼저 비워야 했다. 비동기 재생이 얽힌 코드에서는 "누가 언제 상태를 초기화하는가"를 한 번은 그려 봐야 한다.
- 서버에 본문 읽는 코드가 없었다. 조회만 하던 서버라 요청 본문을 읽는 부분이 아예 없었다. 오디오를 받으려고 추가하면서 크기 상한(몇 메가바이트)을 함께 넣었다. 상한 없는 업로드 경로는 그 자체로 약점이다.
- 차에서 쓰면 "통화 중"이 된다. 가장 예상하지 못한 문제였다. 안드로이드의 브라우저에서 마이크를 여는 순간 운영체제가 블루투스를 통화용 연결로 전환한다. 차량 화면에 통화 표시가 뜨고 듣던 음악의 음질이 떨어진다. 마이크의 음성 처리 옵션을 모두 끄면 피할 수 있다는 기기도 있지만 확실한 방법은 찾지 못했다.
그래서 바꾼 것
- 질문 입력의 기본을 글로 바꾸고, 마이크는 입력창 옆의 선택 기능으로 내렸다. 음성 입력이 필요하면 키보드 앱의 받아쓰기를 쓰는 것도 방법이다. 그쪽은 통화 모드로 전환하지 않는다.
- 화면이 가려지면 녹음을 즉시 취소하고, 20초가 넘으면 강제로 끝낸다. 마이크가 켜진 채 남는 일은 없어야 한다.
정리
멀티모달 모델 덕분에 "음성을 받아 적고, 답하고, 읽어 주는" 흐름은 며칠이면 만든다. 시간이 드는 곳은 그 앞뒤다. 언제 말이 끝났는지, 소리가 어디로 나가는지, 기기가 마이크를 어떻게 취급하는지. 음성 기능은 모델 데모가 아니라 실제로 쓸 장소에서 시험해 봐야 한다.
댓글 없음:
댓글 쓰기