본문 바로가기
AI/AI 부트캠프

[AI 부트캠프] DAY 17 - 파이썬 프로젝트 2

by HOHHOH 2023. 8. 9.

[오늘의 일지]

파이썬 프로젝트 - 어제 만든 1차 완성 프로젝트 코드에 여러 가지 기능 첨가하기

오늘 한 작업 - 어제 만든 음성 인식 기능 추가하기, 명령받는 주체가 말하게 하기, 계산 기능 만들기

[상세 내용]

파이썬 프로젝트

1차 완성본에 검색, 날씨 음성 인식 기능 추가하기

- 우선 음성인식 기능을 추가해야 되는 이 기능의 이름은 STT로 란 Speech To Text의 약자로, 음성을 글자로 바꾸는 것을 의미합니다. 구글, 네이버 등에서는 음성을 인식해서 글자로 바꿔주는 STT API를 제공하고 있습니다. 저는 수업 시간에 구글의 API를 기반으로 개발된 라이브러리를 사용했습니다.

- window환경에서 STT 설치 방법

pip install pyaudio

 

- 위에서 나온 설치 시 오류가 발생할 때 해결방법

pip install pipwin

pipwin install pyaudio

- STT 사용 방법 예시

import speech_recognition as sr

# 인식을 위한 객체 생성
r = sr.Recognizer()

# 마이크 사용을 위한 객체 생성
mic = sr.Microphone()
with mic as source: # 마이크에 담긴 소리를 토대로 아래 코드 실행
    r.adjust_for_ambient_noise(source) # 잡음 제거 코드 (없어도 무방)
    print('인식 중...')
    audio = r.listen(source, timeout=5, phrase_time_limit=5) # 해당 소리를 오디오 파일 형태로 변환

try:
    result = r.recognize_google(audio, language = "ko-KR") # 오디오를 토대로 음성 인식
    print('결과: ' + result) # 인식 결과 출력
except sr.UnknownValueError:
    print("음성 인식 실패")
except sr.RequestError:
    print("서버 에러 발생")
except sr.WaitTimeoutError:
    print("인식 실패")

 

- 위에서 나온 사용방법을 활용하면 1차 완성본에 검색과 날씨 기능을 넣는 것은 크게 어렵지 않았습니다. 어제 두 개의 기능을 만들 때 함수의 형태로 만들었기 때문에 클래스 안에 함수를 넣고 def 다음에 함수 이름 뒤에 ()를 (self)만 변경해 주면 아무 무리 없이 기능이 실행되는 것을 확인할 수 있었습니다. 그리고 어제는 처음 명령을 받는 주체가 처음 입력을 받는 부분에서 문자로 입력을 받았던 것까지 음성으로 입력을 받는 것으로 모두 변경을 시켰습니다. 일단 어제 어디까지 진행되었는지 링크로 확인해 보셔도 됩니다.

 

[AI 부트캠프] DAY 16 - 파이썬 프로젝트 1

[오늘의 일지] 파이썬 프로젝트 - 음성인식으로 여러 가지 프로그램을 수행하는 코드 짜기 오늘 한 작업 - 일단은 채팅으로 명령받을 주체 설정하고 검색, 날씨 기능 설정하기, 음성인식 가능한

odds-endz.com

- 1차 완성본에 STT기능만 추가한 코드(어제와 다르게 검색엔진도 네이버에서 구글로 변경했습니다.)

import speech_recognition as sr
import time
import requests
import json
from googletrans import Translator
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 켈빈온도를 섭씨온도로 변환
def k_to_c(x):
    return round(x - 273)
# 단어 번역 함수
def trans_ko_en(x):
    translator = Translator()
    return translator.translate(x, src='ko', dest='en').text
def trans_en_ko(x):
    translator = Translator()
    return translator.translate(x, src='en', dest='ko').text

# 인식을 위한 객체 생성
r = sr.Recognizer()
# 마이크 사용을 위한 객체 생성
mic = sr.Microphone()

class project():
    def __init__(self) -> None:
        pass
    def command(self):
        while True:
            with mic as source: # 마이크에 담긴 소리를 토대로 아래 코드 실행
                print('프로그램을 시작합니다. 시리를 불러주세요.')
                print('인식 중...')
                audio = r.listen(source, timeout=3, phrase_time_limit=5) 
            try:
                command_1 = r.recognize_google(audio, language = "ko-KR") 
                print('명령어 인식 완료 : ' + command_1) # 인식 결과 출력
                if command_1 == '시리야' or command_1 == '시리':
                    print('안녕하세요. 시리입니다. 부르셨습니까?')             
                    with mic as source: # 마이크에 담긴 소리를 토대로 아래 코드 실행
                        print('명령어를 말해주세요.(검색,날씨,종료)')
                        print('인식 중...')
                        audio = r.listen(source, timeout=5, phrase_time_limit=5)   
                    try:
                        command_2 = r.recognize_google(audio, language = "ko-KR")
                        print('명령어 인식 완료 : ' + command_2)                                         
                        if command_2 == '검색':
                            print('검색 기능을 시작합니다.')
                            project().search_voice()
                        elif command_2 == '날씨':
                            print('날씨 기능을 시작합니다.')
                            project().weather_voice()
                        elif command_2 == '종료':
                            return print('프로그램을 종료합니다.')
                        else:
                            print('제대로 명령어를 말해주세요. 다시 처음으로 돌아갑니다.')
                    except sr.UnknownValueError:
                        print("음성 인식 실패")
                    except sr.RequestError:
                        print("서버 에러 발생")
                    except sr.WaitTimeoutError:
                        print("인식 실패")
                    except TypeError:
                        print("호출 에러 발생")                        
                else:
                    print('시리의 이름을 제대로 불러주세요')
                pass
            except sr.UnknownValueError:
                print("음성 인식 실패")
            except sr.RequestError:
                print("서버 에러 발생")
            except sr.WaitTimeoutError:
                print("인식 실패")
            except TypeError:
                print("호출 에러 발생")     

    def search_voice(self):
        with mic as source: # 마이크에 담긴 소리를 토대로 아래 코드 실행
            print('원하는 검색어를 말해주세요.')
            print('인식 중...')
            audio = r.listen(source, timeout=5, phrase_time_limit=5) # 해당 소리를 오디오 파일 형태로 변환

        try:
            result = r.recognize_google(audio, language = "ko-KR") # 오디오를 토대로 음성 인식
            print('명령어 인식 완료 : ' + result) # 인식 결과 출력
            print('검색을 시작합니다.')
            # 인식이 됐으니 검색 시작 (지난 시간 selenium 부분 코드와 동일)
            driver = webdriver.Chrome()
            driver.get('https://www.google.com/')
            WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#APjFqb')))
            search_input = driver.find_element(By.CSS_SELECTOR, '#APjFqb')
            search_input.send_keys(result)
            search_button = driver.find_element(By.CSS_SELECTOR, '.FPdoLc.lJ9FBc > center > input.gNO89b')
            search_button.click()
            time.sleep(5)
            driver.quit()
            print('검색 기능을 종료합니다.')
        except sr.UnknownValueError:
            print("음성 인식 실패")
        except sr.RequestError:
            print("서버 에러 발생")
        except sr.WaitTimeoutError:
            print("인식 실패")
        except TypeError:
            print("호출 에러 발생")     

    def weather_voice(self):
        with mic as source: # 마이크에 담긴 소리를 토대로 아래 코드 실행
            print('원하는 도시를 말해주세요.')
            print('인식 중...')
            audio = r.listen(source, timeout=5, phrase_time_limit=5) # 해당 소리를 오디오 파일 형태로 변환

        try:
            result = r.recognize_google(audio, language = "ko-KR") # 오디오를 토대로 음성 인식
            result_trans = trans_ko_en(result)
            url = f'https://api.openweathermap.org/data/2.5/weather?q={result_trans}&appid={API key}'
            response = requests.get(url)
            json_data = json.loads(response.text)
            print('도시명' + result + '인식 완료')
            print(f'''
                날씨정보를 말해드립니다.
                오늘 {result} 날씨정보입니다.
                전체적인 날씨의 특징은 {trans_en_ko(json_data['weather'][0]['description'])} 입니다.
                현재 온도는 {k_to_c(json_data['main']['temp'])}°C 입니다.
                현재 습도는 {json_data['main']['humidity']}% 입니다.
                현재 풍속은 {json_data['wind']['speed']}m/s 입니다.
                날씨정보였습니다.
                날씨 기능을 종료합니다.
                ''')
        except sr.UnknownValueError:
            print("음성 인식 실패")
        except sr.RequestError:
            print("서버 에러 발생")
        except sr.WaitTimeoutError:
            print("인식 실패")
        except TypeError:
            print("호출 에러 발생")             
        except KeyError:
            print("죄송합니다. 도시명을 풀네임으로 제대로 말해주세요")

 

명령받는 주체가 말하는 기능 추가하기

- 여기서는 TTS라는 기능을 사용하게 되는데 TTS는 STT 와는 반대로 Text to Speech, 즉 글을 음성으로 변환시키는 기술을 말합니다. 이 기술 또한 마찬가지로 구글에서 API 형태로 제공하고 있고, 저는 수업 시간에 해당 API를 쉽게 이용할 수 있도록 만들어진 패키지를 사용했습니다. 

- window환경에서 TTS 설치 방법

pip install gtts
# 그 다음은 음성이 만들어지고 나면, 이를 파이썬에서 재생시키기 위한 playsound 를 설치해주세요.
# (그 아래의 PyObjC 는 playsound 의 원활한 실행을 위해서 필요한 패키지입니다.)
pip install playsound

pip install PyObjC

 

- TTS 사용 방법 예시 (. py로 저장해서 모듈로 사용해도 편합니다.) : TTS는 확실히 사용하기 편했습니다. 기존에 만들었던 코드에서 print() 함수 대신에 speak()로만 변경시켜 주면 되는 상황이었습니다.

from gtts import gTTS 
import playsound
import os

def speak(text): 
	tts = gTTS(text=text, lang='ko') # 함수 인자로 들어온 text 를 음성으로 변환
	tts.save('voice.mp3') # 변환된 음성을 voice.mp3 라는 이름으로 저장
	playsound.playsound('voice.mp3') # 저장한 음성 파일을 재생
	os.remove('voice.mp3') # 재생 후에는 해당 파일 삭제

speak('안녕하세요') # 코드가 실행되면, 컴퓨터가 안녕하세요 라고 말하는 것을 들을 수 있습니다!

 

-  speak 함수 사용 시 다음과 같은 에러 발생 (Error 259,  Error 263)

    Error 259 for command:
        play voice.mp3 wait
    지정한 명령 매개 변수를 드라이버가 인식할 수 없습니다.

    Error 263 for command:
        close voice.mp3
    지정한 장치가 열려 있지 않거나 MCI에서 인식되지 않습니다.

 

- 해결 방법(버전을 다운그레이드하면 해결이 되는 것 같습니다.)

pip install playsound==1.2.2

 

STT와 TTS 기능까지 추가한 2차 완성 프로젝트 코드

import speech_recognition as sr
import time
import requests
import json
from tts import speak
from googletrans import Translator
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 켈빈온도를 섭씨온도로 변환
def k_to_c(x):
    return round(x - 273)
# 단어 번역 함수
def trans_ko_en(x):
    translator = Translator()
    return translator.translate(x, src='ko', dest='en').text
def trans_en_ko(x):
    translator = Translator()
    return translator.translate(x, src='en', dest='ko').text

# 인식을 위한 객체 생성
r = sr.Recognizer()
# 마이크 사용을 위한 객체 생성
mic = sr.Microphone()

class project():
    def __init__(self) -> None:
        pass
    def command(self):
        while True:
            with mic as source: # 마이크에 담긴 소리를 토대로 아래 코드 실행
                speak('프로그램을 시작합니다. 시리를 불러주세요.')
                print('인식 중...')
                audio = r.listen(source, timeout=3, phrase_time_limit=5) 
            try:
                command_1 = r.recognize_google(audio, language = "ko-KR") 
                print('명령어 인식 완료 : ' + command_1) # 인식 결과 출력
                if command_1 == '시리야' or command_1 == '시리':
                    speak('안녕하세요. 시리입니다. 부르셨습니까?')             
                    with mic as source: # 마이크에 담긴 소리를 토대로 아래 코드 실행
                        speak('명령어를 말해주세요.(검색,날씨,종료)')
                        print('인식 중...')
                        audio = r.listen(source, timeout=5, phrase_time_limit=5) 
                    try:
                        command_2 = r.recognize_google(audio, language = "ko-KR") 
                        print('명령어 인식 완료: ' + command_2) # 인식 결과 출력                                          
                        if command_2 == '검색':
                            speak('검색 기능을 시작합니다.')
                            project().search_voice()
                        elif command_2 == '날씨':
                            speak('날씨 기능을 시작합니다.')
                            project().weather_voice()
                        elif command_2 == '종료':
                            return speak('프로그램을 종료합니다.')
                        else:
                            speak('제대로 명령어를 말해주세요. 다시 처음으로 돌아갑니다.')
                    except sr.UnknownValueError:
                        speak("음성 인식 실패")
                    except sr.RequestError:
                        speak("서버 에러 발생")
                    except sr.WaitTimeoutError:
                        speak("인식 실패")
                    except TypeError:
                        speak("호출 에러 발생")                        
                else:
                    speak('시리의 이름을 제대로 불러주세요')
                pass
            except sr.UnknownValueError:
                speak("음성 인식 실패")
            except sr.RequestError:
                speak("서버 에러 발생")
            except sr.WaitTimeoutError:
                speak("인식 실패")
            except TypeError:
                speak("호출 에러 발생")     

    def search_voice(self):
        with mic as source: # 마이크에 담긴 소리를 토대로 아래 코드 실행
            speak('원하는 검색어를 말해주세요.')
            print('인식 중...')
            audio = r.listen(source, timeout=5, phrase_time_limit=5) # 해당 소리를 오디오 파일 형태로 변환

        try:
            result = r.recognize_google(audio, language = "ko-KR") # 오디오를 토대로 음성 인식
            print('명령어 인식 완료 : ' + result) # 인식 결과 출력
            speak('검색어' +result + '인식 완료')
            speak('검색을 시작합니다.')
            # 인식이 됐으니 검색 시작 (지난 시간 selenium 부분 코드와 동일)
            driver = webdriver.Chrome()
            driver.get('https://www.google.com/')
            WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#APjFqb')))
            search_input = driver.find_element(By.CSS_SELECTOR, '#APjFqb')
            search_input.send_keys(result)
            search_button = driver.find_element(By.CSS_SELECTOR, '.FPdoLc.lJ9FBc > center > input.gNO89b')
            search_button.click()
            time.sleep(5)
            driver.quit()
            speak('검색 기능을 종료합니다.')
        except sr.UnknownValueError:
            speak("음성 인식 실패")
        except sr.RequestError:
            speak("서버 에러 발생")
        except sr.WaitTimeoutError:
            speak("인식 실패")
        except TypeError:
            speak("호출 에러 발생")     

    def weather_voice(self):
        with mic as source: # 마이크에 담긴 소리를 토대로 아래 코드 실행
            speak('원하는 도시를 말해주세요.')
            print('인식 중...')
            audio = r.listen(source, timeout=5, phrase_time_limit=5) # 해당 소리를 오디오 파일 형태로 변환

        try:
            result = r.recognize_google(audio, language = "ko-KR") # 오디오를 토대로 음성 인식
            result_trans = trans_ko_en(result)
            url = f'https://api.openweathermap.org/data/2.5/weather?q={result_trans}&appid={API key}'
            response = requests.get(url)
            json_data = json.loads(response.text)
            speak('도시명' + result + '인식 완료')
            speak(f'''
                날씨정보를 말해드립니다.
                오늘 {result} 날씨정보입니다.
                전체적인 날씨의 특징은 {trans_en_ko(json_data['weather'][0]['description'])} 입니다.
                현재 온도는 {k_to_c(json_data['main']['temp'])}°C 입니다.
                현재 습도는 {json_data['main']['humidity']}% 입니다.
                현재 풍속은 {json_data['wind']['speed']}m/s 입니다.
                날씨정보였습니다.
                날씨 기능을 종료합니다.
                ''')
        except sr.UnknownValueError:
            speak("음성 인식 실패")
        except sr.RequestError:
            speak("서버 에러 발생")
        except sr.WaitTimeoutError:
            speak("인식 실패")
        except TypeError:
            speak("호출 에러 발생")             
        except KeyError:
            speak("죄송합니다. 도시명을 풀네임으로 제대로 말해주세요")


project().command()

 

계산 기능 만들기 

- 간단하게 두 개의 숫자를 이용해서 사칙연산 기능만 가능한 계산기 함수를 만들어 봤습니다. 여기서 일부러 연산자를 한글로 입력을 받도록 코드를 짰는데 그 이유는 어차피 STT를 사용해서 연산자를 한글로 받아야 되기 때문입니다.

def cal():
    try:
        first_num = float(input('첫번째 숫자를 입력 : '))
        secound_num = float(input('두번째 숫자를 입력 : '))        
    except ValueError:
        print('잘못된 숫자입니다.')
    operator = input('원하는 연산자 입력')  
    if operator == '더하기':
        return print(first_num + secound_num)
    elif operator == '빼기':
        return print(first_num - secound_num)
    elif operator == '곱하기':
        return print(first_num * secound_num)
    elif operator == '나누기':
        if secound_num == 0:
            return print('분모에 0을 넣을 수 없습니다.')
        else:
            return print(first_num / secound_num)
    else:
        print('잘못된 연산자 입니다.')

 

[마무리]

 오늘은 STT와 TTS 기능을 추가하고 계산기 기능까지 만들어 보았습니다. 결과적으로 작업한 것이 얼마 안 되는 것처럼 보입니다. 사실은 시간을 많이 잡아먹은 부분이 있는데 계산 기능을 어떻게 STT와 접목시킬지를 고민 많이 했습니다. 특히 숫자를 그냥 음성으로 입력받으면 1이나 0 같은 숫자는 '일', '영' 이런 식으로 텍스트화되기 때문에 방법을 찾는데 쫌 오래 결렸던 거 같습니다. 어찌 됐든 간에 어느 정도 해결책은 찾은 거 같습니다. 그 해결책은 내일 일지에 적어 보도록 하겠습니다. 또 내일은 번역 기능과 게임 기능을 만들어서 추가하는 것까지 하도록 노력해 보겠습니다.

반응형

댓글