본문 바로가기
가이드/Python

[Python] 파이썬으로 음성인식비서 만들기

by 루엔_vivid 2023. 8. 26.

소개

우리 주변에는 인공지능 기술을 활용한 음성인식 비서가 많이 나와 있습니다. 애플의 시리, 삼성의 빅스비, 아마존의 알렉사 등 다양한 음성인식 비서들이 우리의 일상생활에 큰 도움을 주고 있습니다.

이러한 음성인식 비서들은 사용자가 일상에서 언어로 입력한 명령이나 질문 등을 인식하여 그에 맞는 대화를 소리를 통해 알려주게 됩니다

따라서 음성인식 비서를 만들기 위해서는 위와 같은 기능들이 필요하게 되는데 해당 기능을 파이썬을 통해 구현하여 음성인식 비서를 만들어보는 과정에 대해 소개하겠습니다.


Speech Recognition으로 STT 구현

먼저 음성인식 비서를 만들기 위해서는 Speech-To-Text (STT) 기술이 필요합니다.

STT는 음성을 텍스트로 변환하는 기술로 파이썬에서 사용 가능한 라이브러리로는 Speech Recognition가 있는데 해당 라이브러리에서 원하는 음성인식 API를 선택하여 사용할 수 있습니다.

해당 라이브러리에는 음성인식 모델을 선택하여 사용할 수 있는데 그 중 몇가지 모델들의 장단점에 대해 소개해드리겠습니다.

 

CMU Sphinx

  • 장점 : 프리웨어, 오프라인 환경에서 사용 가능
  • 단점 : 한국어 지원 불가, 낮은 정확도

Google

  • 장점 : key값 없이도 사용 가능. 한국어 지원, 높은 정확도
  • 단점 : 기본 key로 하루 사용 횟수 제한

DeepSpeech

  • 장점 : 최신 딥러닝 모델을 사용하여 높은 정확도
  • 단점 : 무거우며 GPU 또는 TPU를 사용, 모델 학습에 시간 필요

이 이외에도 여러 가지 모델이 있지만 종합적으로 평가한 결과 Google이 가장 적절하다고 판단이 되어 해당 모델을 이용하여 구현하기로 하였습니다.

아래는 파이썬에서 Speech Recognition 라이브러리를 활용하여 음성을 텍스트로 변환하는 예제 코드입니다.

# STT.py

import speech_recognition as sr

text = STT.GetSpeechText()
print("음성 : " + text)

def GetSpeechText():
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("음성 인식 중...")
        audio = r.listen(source)
    try:
        return r.recognize_google(audio, language='ko-KR')
    except sr.UnknownValueError:
        print("음성 인식 불가")
    except sr.RequestError as e:
        print("Google Web Speech API 에러 발생: {0}".format(e))

위 코드를 실행하면 마이크로부터 입력된 음성을 API를 통해 인식하고 그 결과를 텍스트로 변환하여 출력하게 됩니다.

language 부분을 수정하게 되면 한국어 뿐만이 아니라 다양한 언어의 인식이 가능합니다.

 

본 문서의 질문 음성은 클로바더빙을 사용하였습니다

Google Text-to-Speech로 TTS 구현

음성인식 비서를 만들기 위해서는 듣는 것뿐만이 아니라 말하기 위한 Text-To-Speech (TTS) 기술도 필요합니다.

TTS 기술은 텍스트를 음성으로 변환하는 기술로, STT와 마찬가지로 Google에서 개발한 Text-to-Speech API를 활용하여 TTS를 구현할 수 있습니다.

위에서 소개 드린 STT와 달리 무료로 제한 없이 사용할 수 있으며 한국어를 지원한다는 점이 가장 큰 장점인 것 같습니다.

네이버 개발자 사이트에서 Clova Speech Synthesis를 사용할 수도 있지만 결제 수단 등록 및 글자 수 제한 등 여러 제약이 존재하여 선정하지는 않고 예시 영상에서 질문을 발음하는 용도로 사용하였습니다.

아래는 파이썬에서 Google Text-to-Speech API를 활용하여 텍스트를 음성으로 변환하는 예제 코드입니다.

# TTS.py

from gtts import gTTS
import playsound

fileName = "ttsFole.mp3"

text = STT.GetSpeechText()
print("음성 : " + text)
TTS.SpeakText(text)

def SpeakText(text):
    SaveMp3File(text)
    playsound.playsound(fileName)
    print(text)

def SaveMp3File(text):
    tts = gTTS(text=text, lang='ko')
    tts.save(fileName)

앞선 코드와 함께 위 코드를 실행하면 받아온 텍스트를 gtts를 통해 원하는 언어로 변환을 하여 저장을 하게 되고 저장된 mp3 파일을 가지고 playsound로 실행을 하게 되어 소리를 재생을 하게 됩니다.

(playsound 최신 버전 사용시 에러가 발생하여 1.2.2 사용 필요)

 


Chat GPT와의 연동

지금까지 구현한 STT와 TTS를 통해 음성 인식과 음성 출력을 할 수 있도록 구현하였지만 아직 질문에 대한 답변을 할 수는 없습니다.

음성 인식 비서이기 때문에 우리가 하는 질문에 대해 원하는 답변을 하도록 하여야 하는데 예전 같았으면 질문 내용을 위키에 검색을 하거나 하는 방식으로 일차원적인 답변만 제공할 수 있었지만 최근 Chat GPT의 추가로 해당 기능을 활용하여 대부분의 원하는 대답을 하도록 할 수 있습니다.

 

 

Introducing ChatGPT

We’ve trained a model called ChatGPT which interacts in a conversational way. The dialogue format makes it possible for ChatGPT to answer followup questions, admit its mistakes, challenge incorrect premises, and reject inappropriate requests.

openai.com

Chat GPT에서 파이썬에서 사용할 수 있도록 API를 제공하고 있어 위 ChatGPT 공식 사이트에 로그인 후 API key를 발급받아 사용할 수 있습니다.

openai 라이브러리를 통해 API와 모델 엔진을 설정하게 되면 약간의 시간이 걸린 후 웹사이트로 ChatGPT를 이용한 것과 같은 결과를 얻을 수 있습니다.

 

# ChartGpt.py

import openai

openai.api_key = "발급 받은 API키"
model_engine = "text-davinci-003"


def SearchChatGPT(prompt):
    completion = openai.Completion.create(
        engine=model_engine,
        prompt=prompt,
        max_tokens=1024,
        n=1,
        stop=None,
        temperature=0.5,
    )

    return completion.choices[0].text
# Main.py

import STT
import TTS
import ChatGpt

text = STT.GetSpeechText()
print("음성 : " + text)

if text.find('GPT') != -1:
    answer = ChatGpt.SearchChatGPT(text[text.find(' ')+1:])
    TTS.SpeakText(answer)

첫 번째 코드는 받아온 질문을 토대로 ChatGPT를 활용하여 답변을 얻어내는 코드이며

두 번째 코드는 GPT라는 단어가 질문에 들어있을 경우 ChatGPT 답변 함수를 실행하도록 합니다.

 

위 영상에서 영어를 질문과 답변에서 사용되고 있는데 STT나 TTS 언어를 ko로 설정을 하여도 영어의 경우 문제 없이 인식이 가능합니다.

원하는 상황에서 호출하도록 세팅

Chat GPT까지 더해져서 음성 인식 비서의 간단한 틀은 갖추어진 것처럼 보이지만 실행을 하고 한 가지 질문만 가능할 뿐 계속해서 대화를 할 수 있는 구조가 아닙니다.

따라서 항상 실행 중이며 음성이 감지될 때만 작동을 하도록 해야 하는데 Speech Recognition의 경우 음성 인식 전까지는 무한 대기를 하기 때문에 간단히 반복문만 추가를 하여 구현할 수 있습니다.

또한 시리나 빅스비를 부를 때처럼 특정 키워드를 통해 호출하도록 구현을면 주위 음성에 따른 불필요한 호출 또한 막을 수 있습니다.

 

# Main.py

import STT
import TTS
import ChatGpt
import playsound

isActive = False

while True:
    text = STT.GetSpeechText()
    print("음성 : " + text)

    if isActive:
        if text == '중지':
            isActive = False
            TTS.SpeakText("휴먼모드로 진입합니다")
        elif text.find('GPT') != -1:
            answer = ChatGpt.SearchChatGPT(text[text.find(' ') + 1:])
            TTS.SpeakText(answer)
    elif text == '안녕':
        isActive = True
		playsound.playsound('sound.mp3')
# STT.py

import speech_recognition as sr

def GetSpeechText():
    r = sr.Recognizer()
    try:
        with sr.Microphone() as source:
            print("음성 인식 중...")
            audio = r.listen(source, timeout=10)
            return r.recognize_google(audio, language='ko-KR')
    except sr.UnknownValueError:
        print("음성 인식 불가")
    except sr.WaitTimeoutError:
        return '중지'
    except sr.RequestError as e:
        print("Google Web Speech API 에러 발생: {0}".format(e))

while 문을 통해 종료되기 전까지는 반복해서 사용자의 음성을 인식할 수 있도록 하였습니다.

안녕라는 명령을 통해 음성을 인식하는 활성화 상태에 들어가고 타임아웃 설정을 통해 음성 임력 대기 시간이 10초가 넘어가거나 중지라는 명령을 말하면 휴먼 상태로 돌아가게 됩니다.

 

두 번째 tts.save(fileName) 코드 동작시 PermissionError: [Errno 13] Permission denied: 'ttsFole.mp3’ 에러가 발생하는데 재생 후 os.remove(fileName) 로 기존 음성 파일을 제거하면 문제없이 동작 가능합니다.

 


여러 정보 크롤링으로 취득

Chat GPT의 추가로 인해 이제 음성 인식 비서라고 부를 수 있는 첫걸음에 도달한 것 같습니다.

하지만 Chat GPT 만으로는 실시간으로 취득이 필요한 내용이나 원하는 정보에 대해 획득이 어려울 수 있는데 이러한 몇몇 질문의 경우 크롤링을 통해 원하는 내용을 가져올 수 있도록 구현할 수 있습니다.

 

# Crawling.py

from urllib.request import urlopen, Request
import urllib
import bs4

def Search(text):
    if text.find('날씨') != -1:
        return SearchWeather()
    elif text.find('기사') != -1:
        return SearchNews(text)
    else:
        return '잘 모르겠습니다.'

def SearchWeather():
    enc_location = urllib.parse.quote('날씨')
    url = "https://search.naver.com/search.naver?ie=utf8&query=" + enc_location
    soup = GetSoup(url)

    return '오늘 날씨는 ' + soup.find('i', class_='wt_icon ico_wt2').find('span', class_='blind').text + \
        '이고 ' + soup.find('div', class_='temperature_text').text + '입니다.'

def SearchNews(question):
    i = question.find('기사')
    question = question[:i - 1]

    enc_qu = urllib.parse.quote(question)
    url = "https://search.naver.com/search.naver?where=news&sm=tab_jum&query=" + enc_qu
    soup = GetSoup(url)

    return soup.find('div', class_='news_dsc').text

def GetSoup(url):
    user_agent = 'Mozilla/5.0'
    headers = {'referer': 'http://naver.com', 'User-Agent': user_agent}
    req = Request(url, headers=headers)
    html = urlopen(req).read()
    soup = bs4.BeautifulSoup(html, "html.parser")
    return soup

urllib 라이브러리를 통해 웹 페이지의 데이터를 가져오게 되고 Beautiful Soup 라이브러리를 통해 가져온 텍스트 형태의 html에서 원하는 태그를 추출하게 됩니다.

이를 통해 네이버 검색을 통한 날씨 정보, 뉴스 기사와 같이 실시간으로 확인이 필요한 정보 또한 가져올 수 있게 되었습니다.

 


마무리

지금까지 파이썬으로 음성 인식 비서를 만드는 법에 대해 소개를 드렸는데 상용화되어 있는 다른 인공지능 비서 대비 느린 속도와 횟수 제한만 감수한다면 원하는 대로 커스텀도 가능한 도움이 되는 비서인 것 같습니다.

위에서 설명한 내용으로는 PC에서만 사용이 가능하여 활용도가 떨어지지만 라이베이파이 등과 같은 소형 디바이스를 이용하게 된다면 여러 홈 인공지능 기기와 같이 설치해두고 사용할 수 있어 다양한 방식으로 활용도가 있을 것 같습니다.

반응형

댓글