[Raspberry Pi] Azure Speech Service 사용해보기 + alsa

heering·2023년 11월 12일
0

Azure

목록 보기
1/4

시작

오랜만에 글을 써본다. 하루 종일 삽질하고 쓰는 후기

Azure Student 구독을 사용하면 Azure Speech Service를 무료로 사용해볼 수 있다.

프로젝트에서 목표가 STT -> GPT -> TTS 였는데, API 최초 탐색 후 선정은 아래와 같았다.

STT: ETRI 음성인식 OPEN API
TTS: 네이버 클라우드 CLOVA Voice - Premium

그런데 ㅋㅋ ETRI 음성인식 API를 써봤더니 "나 오늘 학교에서 그림 잘 그렸다고 칭찬 받았다?"를 말했더니 외계어를 쏟아낸다... 성능이 아쉽다. 🤨

그리고 아무 생각 없이 네이버 클라우드 가입하고 십만 원 크레딧 받았더니, 정작 내가 쓰고 싶은 TTS 서비스는 크레딧 적용이 안되는 항목이었다.. ㅋㅋ? 그래도 언젠가는 쓸 날이 올 거야~

내가 Azure를 쓰는 이유

그래서 Azure 서비스를 찾다가 Speech Service는 써보니까 성능도 좋고, 반응 속도도 빠르고, 무엇보다 무료라... STT뿐만 아니라 TTS도 할 수 있어서 그냥 한꺼번에 하면 된다.

나는 Azure의 Document만 보면 겁이 나던데, 뭐랄까 번역이 덜 된 부분도 가끔가다 있고, 여기저기 이동하면서 다시 찾아야 하는 내용도 많고,, 무엇보다 인지도가 그렇게 높지 않아서 한글 자료도 별로 없다.

그럼에도 불구하고 내가 Azure를 좋아하는 이유는 유용한 무료 서비스가 정말 많다는 것. 특정 사용량까지는 무료고, 그 이상으로 넘어가면 그때부터 무료 크레딧에서 까이는 서비스들이 많아서 고맙다. (단 하나 아쉬운 점은 Azure Students 구독으로 GPU는 쓸 수 없다는 것)

그리고 특히 이 Speech Service는 굉장히 편리하다. 나는 당연히 텍스트를 주면 음성 파일로 저장하거나, 음성 파일이 존재하는 걸 불러와서 텍스트로 변환하는 건가 했는데. 그게 아니라 파일 없이 실시간으로 해준다.

  1. STT: 최대 30초까지 말할 수 있고, 알아서 침묵이 느껴지면 듣기를 종료한다. 😮
  2. TTS: 그냥 자기 할 일 끝나면 바로 스피커 쪽으로 소리 출력해버린다. 😎

어떻게 하는가

무료 F0 요금제로 인스턴스를 만들고, speech key, service region, 성우 이름만 알면 된다.

여기에 보이는 키1이 speech key이고, 위치/지역이 service region이다. 나는 한국말하는 성우 중에 어린이 목소리에 가까운 서현을 골랐다.

Azure에 언어별 샘플 코드가 웬만하면 다 있으므로 확인해보시고,, ! Python 코드를 Class로 짰는데 그중에 일부만 가져왔다.

import azure.cognitiveservices.speech as speechsdk

# ...

def tts(self):
    """
    Azure Speech Service를 이용해 Text-to-Speech
    """
    speech_key = self.azure_speech_key
    service_region = self.azure_service_region

    speech_config = speechsdk.SpeechConfig(subscription=speech_key, region=service_region)

    speech_config.speech_synthesis_voice_name = "ko-KR-SeoHyeonNeural"

    if self.answer_text == "":
        text = "오류가 발생했어요. 문제가 계속된다면 관리자에게 문의하세요."
        logging.error("TTS API 실행 전 Answer Text Result가 비어있습니다.")

    text = self.answer_text

    speech_synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config)

    result = speech_synthesizer.speak_text_async(text).get()

    if result.reason == speechsdk.ResultReason.SynthesizingAudioCompleted:
        logging.info("TTS Speech synthesized for text [{}]".format(text))
    elif result.reason == speechsdk.ResultReason.Canceled:
        cancellation_details = result.cancellation_details
        logging.error("Speech synthesis canceled: {}".format(cancellation_details.reason))
        if cancellation_details.reason == speechsdk.CancellationReason.Error:
            logging.error("TTS Error details: {}".format(cancellation_details.error_details))

alsa

ㅎㅎ 이렇게 생각보다 API 적용은 금방 했지만, 정작 라즈베리파이에 연결된 스피커와 마이크가 말썽이었다.
python3 test.py 이런 식으로 실행하면 아무런 문제 없이 되던 프로그램이, systemd에 올린 뒤 실행하니 마이크랑 스피커를 인식하지 못한다... 🙃 너 갑자기 왜 그래

또 열심히 구글링 해보니 나랑 똑같은 사례가 존재했다.

cat /proc/asound/cards를 통해 스피커와 마이크가 연결된 id를 알아내고, 그 id에 맞게 /etc/asound.conf에 아래와 같이 입력해 주면 해결된다. 나의 경우 pcm은 마이크였다. 아직도 ctl이 스피커인지는 모르겠다. 잘 돼서 따로 확인을 안 해봤다.

defaults.pcm.card 3
defaults.ctl.card 0

.wav 효과음 스피커로 출력하기

이거도 예상외로 굉장히 시간을 많이 잡아먹었는데.. 단순히 .mp3 또는 .wav 파일을 pygame으로 소리 출력하면 되지 않을까? 싶어서 했는데 ALSA 관련 오류가 나면서 계속 실패했다. 솔루션을 찾아봐도 안 나와서 포기할까 했지만, 이건 비정석적인 방법을 동원해서라도 해결해야겠다 싶었다.

os.system을 사용해서 코드가 안 예쁘긴 하지만.. 이렇게라도 해야만 했다. cat /proc/asound/cards를 해서 나오는 오디오 잭 id를 0으로 알아냈고, 그 결과 아래처럼 코드를 작성해 해결했다.

import os
os.system(f"/usr/bin/aplay -D hw:0,0 {파일명.wav}")

끄읕

0개의 댓글