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

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

by HOHHOH 2023. 8. 8.

[오늘의 일지]

파이썬 프로젝트 - 음성인식으로 여러 가지 프로그램을 수행하는 코드 짜기

오늘 한 작업 - 일단은 채팅으로 명령받을 주체 설정하고 검색, 날씨 기능 설정하기, 음성인식 가능한 검색, 날씨 가능 만들기

[상세 내용]

파이썬 프로젝트

음성인식으로 여러 가지 프로그램을 수행하는 코드 짜기

- 우선 여러 가지 기능을 넣기 전에 큰 틀을 짜고 우선 적으로 키보드 명령으로 수행하는 프로그램을 짜고 그 후에 음성인식을 넣는 것으로 큰 틀을 짜고 시작했습니다. 

 

클래스와 함수를 이용해서 큰 틀 설정하기

- 기존 수업에서 클래스와 함수를 이용한 연습문제들 중에서 은행 ATM 시스템에서 사용했던 코드들을 복습하면서 틀을 짜 보았습니다. 기존 ATM 시스템 연습문제는 아래의 글에 있습니다.

 

[AI 부트캠프] DAY 12 - 파이썬 6

[오늘의 일지] 파이썬 익숙해지기 - 다양한 매개변수, 람다함수, map과 filter 함수, 클래스, 모듈 [상세 내용] 파이썬 익숙해지기 다양한 매개변수 - 위치 매개변수 # 가장 기본적인 매개변수 def my_fu

odds-endz.com

- 검색 기능 넣기

더보기
  • 요소 하나 찾기 - driver.find_element(By.CSS_SELECTOR, '태그, 선택자')
  • 요소 여러개 찾기 - driver.find_elements(By.CSS_SELECTOR, '태그, 선택자')
  • 글자 입력하기 - 요소.send_keys(’단어’)
  • 요소 클릭하기 - 요소.click()
  • 특정한 요소가 로딩될 때까지 기다리기 - WebDriverWait(driver, 초).until(EC.presence_of_element_located((By.CSS_SELECTOR, ‘태그, 선택자’)))
  • 그냥 기다리기 - time.sleep(초)
  • 현재 페이지의 HTML 다 가져오기 - driver.page_source

위에 selenium 문법을 이용해서 네이버에 접근해서 검색창을 클릭하는 것을 구현할 수 있습니다. 그런 뒤 원하는 단어를 input으로 받고 다시 클릭하여 검색결과를 얻을 수 있습니다. 코드는 다음과 같이 나타 낼 수 있습니다.

def search(self):
    search_1 = input('검색하고 싶은 단어를 말해주세요. : ')
    driver = webdriver.Chrome()
    # 어떤 주소로 크롬 브라우저가 접속할 건지 지정
    driver.get('https://naver.com')
    # #query 라는 요소가 로딩되어서 나타날때까지 최대 '5초'까지 대기 
    # (우리가 찾고자 하는 요소가 나타나면 바로 대기를 중단하고 다음 코드 실행)
    # 로딩이 완료되기 전에 요소를 클릭하거나 글을 입력하면 오작동할 수 있으므로, 이를 방지하기 위함
    WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#query')))
    # 검색창 요소 특정
    search_input = driver.find_element(By.CSS_SELECTOR, '#query')
    search_input.send_keys(search_1) # 검색하도록 지시
    # 검색 버튼 특정
    search_button = driver.find_element(By.CSS_SELECTOR, '#search-btn')
    search_button.click() # 클릭하도록 지시
    # 잠시 종료전에 멈추고 검색 잘됐는지 확인
    time.sleep(5)
    # 브라우저 종료
    driver.quit()

 

- 날씨 정보 받기

기존에 수업시간에는 https://open-meteo.com/en/docs#api_form 이곳을 무료 API로 알려 주셨는데 찾아보니까 날씨 API 사이트 중에서 도시이름을 url에 사용하면서 간편하게 정보를 얻을 수 있는 사이트가 있어서 소개드리겠습니다. 비록 아이디 가입을 하고 API key를 받아 사용해야 하는 점은 있지만 기존 사이트보다 url 측면에서 사용하기 좋고 정보도 잘 나오는 것 같습니다. 사이트 링크는 아래입니다.

 

Сurrent weather and forecast - OpenWeatherMap

Access current weather data for any location on Earth including over 200,000 cities! The data is frequently updated based on the global and local weather models, satellites, radars and a vast network of weather stations. how to obtain APIs (subscriptions w

openweathermap.org

https://api.openweathermap.org/data/2.5/weather?q={도시 이름}&appid={API key}

온도 같은 경우는 사이트에서 켈빈온도를 사용하므로 섭씨온도로 변화할 수 있는 -273를 함수로 만들어서 나타냈습니다.

def k_to_c(x):
    return round(x - 273)

 

- 얻은 날씨 정보의 영문명과 url에 사용되는 도시의 영문명의 문제점 해결하기

위에 url을 사용하여 도시의 날씨 정보를 얻어서 json.loads를 이용하면 딕셔너리 형태로 변영하여 나타낼 수 있는데 여기서 문제점이 몇 가지 있습니다. 우선 url에 입력해야 되는 도시 이름이 영문 명인데 모든 도시의 영문명 스펠링을 다 잘 알지 못한다는 점과 딕셔너리로 받은 날씨 정보가 영문명으로 다시 한글로 출력해서 사용해야 된다는 두 가지 문제점이 있습니다. 이 문제점은 번역기 함수를 만들어서 상황마다 사용하면 해결될 거 같았습니다. 그래서 googletrans 패키지를 사용해서 해결해 보았습니다.

 

- googletrans 패키지 설치 오류 문제 해결하기

아래의 방법을 통해서 googletrans를 설치하게 되면 번역 기능을 실행할 때 다음 에러가 발생할 수도 있고 그냥 실행될 수도 있는데 저는 에러가 발생했습니다.

# 일반적으로 설치 할때
pip install googletrans
# 에러 코드
AttributeError: 'NoneType' object has no attribute 'group'

 

- 해결방법

# 아래와 같이 따로 cmd에 입력하여 재설치  하면 됩니다.
pip uninstall googletrans
pip install googletrans==3.1.0a0

 

- googletrans 사용방법

# 한국어를 영어로 번역
from googletrans import Translator
translator = Translator()
result = '원하는 단어'
result_trans = translator.translate(result, src='ko', dest='en')
print(result_trans)
print(result_trans.text)
>>>
Translated(src=ko, dest=en, text=word, pronunciation=None, extra_data="{'translat...")
word # 이걸 .text를 붙여야 단어만 쓸수 있다

저는 위에 사용방법을 이용해서 함수를 만들었습니다. 함수를 만들어서 필요할 때마다 사용하니 편리했던 거 같습니다.

# 영어을 한글로
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

그런데 제가 위에 코드에서 마지막에 .text를 붙인 이유가 있습니다. 그 이유는 .text를 붙이지 않으면 위에 사용방법에 나와 있는 것처럼 Translated(src=ko, dest=en, text=word, pronunciation=None, extra_data="{'translat...") 이런 식의 번역 정보가 포함되어 실행이 되기 때문입니다.

 

1차적으로 완성한 프로젝트 코드

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


class project():
    def __init__(self) -> None:
        pass
    def command(self):
        while True:
            command_1 = input('프로그램 시작 : ')
            if command_1 == '시리야' or command_1 == '시리':
                print('안녕하세요 시리입니다. 부르셨습니까?')             
                command_2 = input('명령을 말해주세요. : ')
                if command_2 == '검색':
                    project().search()
                elif command_2 == '날씨':
                    project().weather()
                elif command_2 == '종료':
                    return print('프로그램을 종료합니다.')
                else:
                    print('제대로 명령해주세요. 다시 처음으로 돌아갑니다.')
            else:
                print('이름을 제대로 불러주세요')
                pass
                
    def search(self):
        search_1 = input('검색하고 싶은 단어를 말해주세요. : ')
        driver = webdriver.Chrome()
        # 어떤 주소로 크롬 브라우저가 접속할 건지 지정
        driver.get('https://naver.com')
        # #query 라는 요소가 로딩되어서 나타날때까지 최대 '5초'까지 대기 
        # (우리가 찾고자 하는 요소가 나타나면 바로 대기를 중단하고 다음 코드 실행)
        # 로딩이 완료되기 전에 요소를 클릭하거나 글을 입력하면 오작동할 수 있으므로, 이를 방지하기 위함
        WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#query')))
        # 검색창 요소 특정
        search_input = driver.find_element(By.CSS_SELECTOR, '#query')
        search_input.send_keys(search_1) # 검색하도록 지시
        # 검색 버튼 특정
        search_button = driver.find_element(By.CSS_SELECTOR, '#search-btn')
        search_button.click() # 클릭하도록 지시
        # 잠시 종료전에 멈추고 검색 잘됐는지 확인
        time.sleep(5)
        # 브라우저 종료
        driver.quit()


    def weather(self):
        try:
            result = input('날씨를 알고 싶은 도시를 말해주세요. : ')
            result_trans = trans_ko_en(result) # 한글로 받은 날씨를 url에 넣기 위해 영어로 번역
            url = f'https://api.openweathermap.org/data/2.5/weather?q={result_trans}&appid={API key}
            response = requests.get(url) # url에서 정보 받기
            json_data = json.loads(response.text) # 받은 정보를 json을 통해 딕션너리로 전환
            print(f'''
            오늘 {trans_en_ko(json_data['name'])} 날씨정보입니다. 
            전체적인 날씨의 특징은 {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 KeyError: 
            print('도시 이름을 확인해 주시고 한글로 적어주세요')

 

- 실행결과

project().command()
>>>
프로그램 시작 : 잘못된 입력
이름을 제대로 불러주세요
프로그램 시작 : 시리
안녕하세요 시리입니다. 부르셨습니까?
명령을 말해주세요. : 잘못된 입력
제대로 명령해주세요. 다시 처음으로 돌아갑니다.
프로그램 시작 : 시리야
안녕하세요 시리입니다. 부르셨습니까?
명령을 말해주세요. : 검색
검색하고 싶은 단어를 말해주세요. : 안녕
The chromedriver version (114.0.5735.90) detected in PATH at C:\Coding\chromedriver.exe might not be compatible with the detected chrome version (115.0.5790.171); currently, chromedriver 115.0.5790.170 is recommended for chrome 115.*, so it is advised to delete the driver in PATH and retry

DevTools listening on ws://127.0.0.1:65105/devtools/browser/6931d5c6-31df-40f5-91f2-c1d3dc55e950
프로그램 시작 : 시리
안녕하세요 시리입니다. 부르셨습니까?
명령을 말해주세요. : 날씨
날씨를 알고 싶은 도시를 말해주세요. : 런던

            오늘 런던 날씨정보입니다. 
            전체적인 날씨의 특징은 흐린 구름 입니다.
            현재 온도는 22°C 입니다.
            현재 습도는 47% 입니다.
            현재 풍속은 5.14m/s 입니다.
            감사합니다.

프로그램 시작 : 시리야
안녕하세요 시리입니다. 부르셨습니까?
명령을 말해주세요. : 종료
프로그램을 종료합니다.

 

1차적으로 완성한 오디오로 실행하는 검색과 날씨 정보 받는 코드 만들기(내일은 프로젝트 코드와 병합할 예정)

- 검색 기능

import speech_recognition as sr
import time
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

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

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

try:
    result = r.recognize_google(audio, language = "ko-KR") # 오디오를 토대로 음성 인식
    print('결과: ' + result) # 인식 결과 출력
    # 인식이 됐으니 검색 시작 (지난 시간 selenium 부분 코드와 동일)
    driver = webdriver.Chrome()
    driver.get('https://naver.com')
    WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#query')))
    search_input = driver.find_element(By.CSS_SELECTOR, '#query')
    search_input.send_keys(result)
    search_button = driver.find_element(By.CSS_SELECTOR, '#search-btn')
    search_button.click()
    time.sleep(5)
    driver.quit()
except sr.UnknownValueError:
    print("음성 인식 실패")
except sr.RequestError:
    print("서버 에러 발생")
except sr.WaitTimeoutError:
    print("인식 실패")

 

- 날씨 기능

날씨 기능은 위에서 만든 번역 함수를 이용해서 한글로 도시 이름을 받아서 번역해서 url에 사용한 뒤 사이트에서 얻은 영문 자료를 json 패키지를 이용해 딕셔너리 자료로 바꾼 뒤 다시 함수를 이용해서 한글로 번역해서 출력시켰습니다.

import speech_recognition as sr
import time
import requests
import json
from googletrans import Translator


# 인식을 위한 객체 생성
r = sr.Recognizer()
# 켈빈온도를 섭씨온도로 변환
def k_to_c(x):
    return round(x - 273)
# 단어 번역 함수
def trans_ko_en(x):
    translator = Translator()
    return translator.translate(x, src='ko', dest='en')
def trans_en_ko(x):
    translator = Translator()
    return translator.translate(x, src='en', dest='ko')    

# 마이크 사용을 위한 객체 생성
mic = sr.Microphone()
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).text
    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(f'''
          오늘 {trans_en_ko(json_data['name']).text} 날씨정보입니다.
          전체적인 날씨의 특징은 {trans_en_ko(json_data['weather'][0]['description']).text} 입니다.
          현재 온도는 {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("인식 실패")

 

[마무리]

 오늘은 드디어 지난 거의 2주간 수업에서 배운 파이썬 지식들을 전반적으로 이용해서 프로젝트를 수행하는 날이었습니다. 기간은 넉넉하게 4일 정도를 줬기 때문에 오늘은 우선 기존에 많이 연습했던 클래스와 함수를 이용한 큰 틀을 잡아 1차적인 코드를 완성해서 실행도 되는 것까지 확인했습니다. 그리고 음성을 인식해서 검색하는 기능과 날씨 정보를 주는 기능까지 완성시켜 놨습니다. 그러므로 내일의 큰 목표는 저 두 가지 음성 인식 기능을 큰 틀에 주입시키는 것입니다. 그런 다음 시간이 남는다면 명령을 받는 주체가 소리로 대답을 하는 것을 주입까지 하면 좋을 것 같습니다.

반응형

댓글