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

[AI 부트캠프] DAY 20 - 파이썬 프로젝트 5

by HOHHOH 2023. 8. 12.

[오늘의 일지]

파이썬 프로젝트 - 마무리해서 제출하기, 다른 수강자들의 프로젝트 발표 감상하기

오늘 한 작업 - 끝말잇기 기능을 만들려고 노력했으나 실패했습니다.

[상세 내용]

파이썬 프로젝트

끝말잇기 게임 기능 만들기

- 끝말잇기 게임을 만드는 것이 가장 시간이 오래 걸린 거 같습니다. 처음에는 open API라 크롤링하는 게 더 쉽고 편할 거라 생각했습니다. 그런데 공공데이터포털에서 미세먼지 정보를 가져올 때와는 다르게 파라미터가 꽤 세부적이고 많아서 더 많은 에러에 봉착했던 거 같습니다. 기존에 수업시간에 사용하던 파라미터는 미리 딕셔너리 형태로 다음과 같이 만들어서 사용했습니다.

 

params = {    'serviceKey': 'API 키',
    	      'returnType': 'json',
              'numOfRows': '100',
              'pageNo': '1',
              'sidoName': sidoName,
              'ver': '1.0'         }

 

그런데 사이트에 나와있는 파라미터만 봐도 선택사항이 좀 많습니다. 특히 끝말잇기 같은 게임은 조건이 많았기 때문에 파라미터를 이용해서 원하는 정보만 얻어내기는 좋지만 요청해야 하는 데이터의 양도 많다는 장단점이 있습니다. 우선 아래의 이미지와 링크를 통해 파라미터 종류에 대해 자세하게 보면 좋습니다.

 

 

우리말샘 - 오픈 API 서비스 소개

1. 우리말샘 오픈 API 서비스 소개 우리말샘 오픈 API는 검색 플랫폼을 외부에 공개하여 다양하고 재미있는 서비스 및 애플리케이션을 개발할 수 있도록 외부 개발자와 사용자들이 공유하는 프로

opendict.korean.go.kr

우리말샘에 나와있는 파라미터

 

여기서 특히 좋은 점은 시작하는 단어로 검색이 가능하다는 것과 명사만 가져올 수 있다는 점에서 끝말잇기를 만들기에 좋다고 말할 수 있습니다. 어찌 됐든 저는 필요한 파라미터를 세세하게 보면서 적으면서 정보를 불러오기 위해서 파이썬에서 계속해서 실행을 시도했는데 어디에선가 계속해서 에러코드가 떴고 도무지 검색을 해도 해결하지 못하는 상황에 도달했던 거 같습니다. 여기서 시간이 엄청나게 많이 잡아먹혔던 거 같습니다. 파라미터를 수정도 해봤지만 해결법을 못 찾던 와중에 오픈 API 예시라는 곳이 있어서 예시를 실행시켜 봤습니다. 여기서 저는 파라미터를 딕셔너리 형식으로 만들려고 할 때 너무 한 가지만 고집하려 했던 거 같습니다. 실행 예시를 통해 보면 예시 주소에  url이 제공되는데 그걸 이용하면 생각했던 것보다 쉽게 정보를 받아올 수 있었던 것입니다. 예시에는 없는 파라미터도 &를 이용해서 추가할 수 있다는 것도 금방 확인할 수 있었습니다.

우리말샘에서 제공하는 오픈 API예시

 

실행예시(주소창에 url을 가지고 오면 파라미터를 입력하기 쉽습니다. )

사실 저는 여기서 정보를 받아서 제가 입력한 단어가 끝말잇기에 가능한 단어인지 확인받는 함수를 만드는 것까지밖에 완성하지 못했습니다. 다음에 시간 날 때 끝말잇기 기능은 꼭 완성시켜 보도록 하겠습니다.

def inout_fuc(x):
    response = requests.get(f'https://opendict.korean.go.kr/api/search?key={API키}&target_type=search&req_type=json&q={x}&sort=dict&start=1&num=100&advanced=y&target=1&method=start&type1=word&type2=native,chinese,hybrid&type3=general&type4=general&pos=1', verify=False )
    json_data = json.loads(response.text)
    if json_data['channel']['total'] != 0:
        return x
    else:
        print('다시 선택')

 

게임기능은 미완으로 남긴 최종 프로젝트 완성본

from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium import webdriver
from googletrans import Translator
from gtts import gTTS 

import speech_recognition as sr
import playsound
import requests
import random
import time
import json
import os
import re

# 켈빈온도를 섭씨온도로 변환
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
def speak(text): 
	tts = gTTS(text=text, lang='ko') 
	tts.save('voice.mp3') 
	playsound.playsound('voice.mp3')
	os.remove('voice.mp3')
# 인식을 위한 객체 생성
r = sr.Recognizer()
# 마이크 사용을 위한 객체 생성
mic = sr.Microphone()

class project():
    def __init__(self) -> None:
        pass
    def command(self):
        while True:
            try:
                with mic as source:
                    speak('프로그램을 시작합니다. 시리를 불러주세요.')
                    print('인식 중...')
                    audio = r.listen(source, timeout=3, phrase_time_limit=3) 
                try:
                    command_1 = r.recognize_google(audio, language = "ko-KR")
                    print('명령어 인식 완료 : ' + command_1) 
                    if command_1 == '시리야' or command_1 == '시리':
                        speak('안녕하세요. 시리입니다. 부르셨습니까?')
                        while True:
                            try:
                                with mic as source: 
                                    speak('명령어를 말해주세요.(검색, 날씨, 미세먼지, 계산, 번역, 종료)')
                                    print('인식 중...')
                                    audio = r.listen(source, timeout=3, phrase_time_limit=3)   
                                try:
                                    command_2 = r.recognize_google(audio, language = "ko-KR") 
                                    print('명령어 인식 완료 : ' + command_2)                                        
                                    if command_2 == '검색':
                                        speak('검색 기능을 시작합니다.')
                                        search().search_voice()
                                    elif command_2 == '날씨':
                                        speak('날씨 기능을 시작합니다.')
                                        weather().weather_voice()
                                    elif command_2 == '미세먼지':
                                        speak('미세먼지 기능을 시작합니다.')
                                        airinfo().airinfo_voice()                                        
                                    elif command_2 == '계산':
                                        speak('계산 기능을 시작합니다.')
                                        calcurator().cal_voice()
                                    elif command_2 == '번역':
                                        speak('번역 기능을 시작합니다.')
                                        translator().tran_voice()                                      
                                    elif command_2 == '종료':
                                        return speak('프로그램을 종료합니다.')
                                    else:
                                        speak('잘못된 명령어 입니다.')
                                except sr.UnknownValueError:
                                    speak("음성 인식 실패!")
                                    continue
                                except sr.RequestError:
                                    speak("서버 에러 발생!")
                                    continue
                                except sr.WaitTimeoutError:
                                    speak("인식 실패!")
                                    continue
                                except TypeError:
                                    speak("호출 에러 발생!")
                                    continue
                            except sr.exceptions.WaitTimeoutError:
                                speak("시간 초과!")
                                continue                             
                    elif command_1 == '종료':
                        return speak('프로그램을 종료합니다.')                                                 
                    else:
                        speak('시리의 이름을 제대로 불러주세요')
                except sr.UnknownValueError:
                    speak("음성 인식 실패!")
                except sr.RequestError:
                    speak("서버 에러 발생!")
                except sr.WaitTimeoutError:
                    speak("인식 실패!")
                except TypeError:
                    speak("호출 에러 발생!")  
            except sr.exceptions.WaitTimeoutError:
                speak("시간 초과!")                    

class search():
    def __init__(self) -> None:
        pass
    def search_voice(self):
        while True:
            try:
                with mic as source:
                    speak('원하는 검색어를 말해주세요.')
                    print('인식 중...')
                    audio = r.listen(source, timeout=4, phrase_time_limit=4)
                try:
                    result = r.recognize_google(audio, language = "ko-KR") 
                    print('명령어 인식 완료 : ' + result)
                    speak('검색어' +result + '인식 완료')
                    speak('검색을 시작합니다.')
                    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()
                    return speak('검색 기능을 종료합니다.')
                except sr.UnknownValueError:
                    speak("음성 인식 실패!")
                except sr.RequestError:
                    speak("서버 에러 발생!")
                except sr.WaitTimeoutError:
                    speak("인식 실패!")
                except TypeError:
                    speak("호출 에러 발생!")
            except sr.exceptions.WaitTimeoutError:
                speak("시간 초과!")     

class weather():
    def __init__(self) -> None:
        pass
    def weather_voice(self):
        speak('''
              날씨 기능은 국내 도시뿐만
              아니라 세계 도시의 
              날씨 정보도 알려줍니다.
              ''')
        while True:
            try:
                with mic as source: 
                    speak('원하는 도시를 말해주세요.')
                    print('인식 중...')
                    audio = r.listen(source, timeout=3, phrase_time_limit=3) 
                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키}'
                    response = requests.get(url)
                    json_data = json.loads(response.text)
                    print('명령어 인식 완료 : ' + result)   
                    speak('도시명' + 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 입니다.
                        ''')
                    return 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("죄송합니다. 잘못된 도시명입니다.")
            except sr.exceptions.WaitTimeoutError:
                speak("시간 초과!") 

class airinfo():
    def __init__(self) -> None:
        pass
    def airinfo_voice(self):		
        speak('''
            미세먼지 기능은 다음과 같습니다.
            한국에 있는 원하는 지역을 말하면 
            그 지역에 있는 모든 측정소에서 
            가장 최근에 측정한 미세먼지 수치와 등급을 출력합니다.
            ''')		
        while True:
            sido_all = ['전국', '서울', '부산', '대구', '인천', '광주', '대전', '울산', '경기',
                         '강원', '충북', '충남', '전북', '전남', '경북', '경남', '제주', '세종']            
            try:
                with mic as source: 
                    speak('원하는 지역를 말해주세요.')
                    print('인식 중...')
                    audio = r.listen(source, timeout=3, phrase_time_limit=3) 	
                try:
                    sidoName = r.recognize_google(audio, language = "ko-KR")	
                    print('명령어 인식 완료 : ' + sidoName)
                    params = {
                        'serviceKey': '{API키}',
                        'returnType': 'json',
                        'numOfRows': '100',
                        'pageNo': '1',
                        'sidoName': sidoName,
                        'ver': '1.0',
                    }
                    response = requests.get('http://apis.data.go.kr/B552584/ArpltnInforInqireSvc/getCtprvnRltmMesureDnsty', params=params)
                    json_data = json.loads(response.text)
                    airinfo_list = json_data['response']['body']['items']
                    result_list = []
                    for airinfo in airinfo_list:
                        result_list.append([airinfo['sidoName'],airinfo['stationName'],'미세먼지 수치 : '+ airinfo['pm25Value'],'미세먼지 등급 : '+ str(airinfo['pm25Grade'])])				
                    if sidoName in sido_all:                    
                        for i in result_list:
                            print(i)
                        return speak(f'''
                                현재 {sidoName}의 미세먼지 정보를 알려드립니다.
                                미세먼지 정보는 자료로 출력됩니다.
                                미세먼지 기능을 종료합니다.
                                ''')
                    else:
                        speak('죄송합니다. 잘못된 도시명 입니다.')
                        continue                    
                except sr.UnknownValueError:
                    speak("음성 인식 실패!")
                except sr.RequestError:
                    speak("서버 에러 발생!")
                except sr.WaitTimeoutError:
                    speak("인식 실패!")
                except TypeError:
                    speak("호출 에러 발생!")              
                except KeyError:
                    speak("죄송합니다. 잘못된 도시명 입니다.")
            except sr.exceptions.WaitTimeoutError:
                speak("시간 초과!") 

class calcurator():
    def __init__(self) -> None:
        pass
    def cal_voice(self):
        speak('''
            계산 기능은 다음과 같습니다.
            첫번째 숫자와 두번째 숫자의 사이에 원하는 사칙연산이 가능합니다.
            ''')
        while True:
            try:            
                speak('첫번째 숫자를 적어주세요')
                first_num = float(input('첫번째 숫자 입력 : '))
                speak(f'첫번째 숫자는 {first_num} 입니다')            
                speak('두번째 숫자를 적어주세요') 
                secound_num = float(input('두번째 숫자 입력 : '))
                speak(f'두번째 숫자는 {secound_num} 입니다')  
            except ValueError:
                speak('잘못된 숫자입니다. 다시 처음으로 돌아갑니다.')
                continue
            try:
                with mic as source: 
                    speak('원하는 연산자를 말해주세요.(더하기, 빼기, 곱하기, 나누기)') 
                    print('인식 중...')
                    audio = r.listen(source, timeout=3, phrase_time_limit=3)                        
                try:
                    operator = r.recognize_google(audio, language = "ko-KR")
                    print('명령어 인식 완료 : ' + operator)                                   
                    if operator == '더하기':
                        print(f'계산 결과 = {first_num + secound_num}')
                        return (f'계산 결과는 {first_num + secound_num} 입니다. 계산 기능을 종료합니다.')
                    elif operator == '빼기':
                        print(f'계산 결과 = {first_num - secound_num}')
                        return speak(f'계산 결과는 {first_num - secound_num} 입니다. 계산 기능을 종료합니다.')
                    elif operator == '곱하기':
                        print(f'계산 결과 = {first_num * secound_num}')
                        return speak(f'계산 결과는 {first_num * secound_num} 입니다. 계산 기능을 종료합니다.')
                    elif operator == '나누기' or operator == '=':
                        if secound_num == 0:
                            speak('분모에는 0을 넣을 수 없습니다. 다시 처음으로 돌아갑니다.')
                        else:
                            print(f'계산 결과 = {first_num / secound_num}')
                            return speak(f'계산 결과는 {first_num / secound_num} 입니다. 계산 기능을 종료합니다.')                  
                    else:
                        speak('잘못된 연산자 입니다. 다시 처음으로 돌아갑니다.')                
                except sr.UnknownValueError:
                    speak("음성 인식 실패! 다시 처음으로 돌아갑니다.")
                except sr.RequestError:
                    speak("서버 에러 발생! 다시 처음으로 돌아갑니다.")
                except sr.WaitTimeoutError:
                    speak("인식 실패! 다시 처음으로 돌아갑니다.")
                except TypeError:
                    speak("호출 에러 발생! 다시 처음으로 돌아갑니다.")
            except sr.exceptions.WaitTimeoutError:
                speak("시간 초과!")                     

class translator():
    def __init__(self) -> None:
        pass
    def tran_voice(self):
        speak('''
              번역 기능은 두 가지 선택이 있습니다.
              영한번역을 선택하려면 영한을 말하면 되고
              한영번역을 선택하려면 한영을 말하면 됩니다.
              ''')
        while True:
            try:
                with mic as source: 
                    speak('원하는 선택을 말해주세요(영한, 한영)')
                    print('인식 중...')
                    audio = r.listen(source, timeout=2, phrase_time_limit=2) 
                try:
                    trans = r.recognize_google(audio, language = "ko-KR") 
                    print('명령어 인식 완료 : ' + trans) 
                    if trans == '영한' or trans == '0 1':
                        speak('''
                            영한번역을 선택했습니다.
                            번역을 원하는 단어 또는 문장을 입력해주세요.
                            ''')
                        result = input('번역을 원하는 단어 또는 문장 입력 : ')
                        speak('번역을 시작합니다.')
                        print(f'번역된 내용 : {trans_en_ko(result)}')
                        return speak('번역이 완료되었습니다. 번역 기능을 종료합니다.')
                    elif trans == '한영' :
                        speak('''
                            한영번역을 선택했습니다.
                            번역을 원하는 단어 또는 문장을 입력해주세요.
                            ''')
                        result = input('번역을 원하는 단어 또는 문장 입력 : ')
                        speak('번역을 시작합니다.')
                        print(f'번역된 내용 : {trans_ko_en(result)}')
                        return speak('번역이 완료되었습니다. 번역 기능을 종료합니다.')
                    else:
                        speak('잘못된 선택입니다.')
                except sr.UnknownValueError:
                    speak("음성 인식 실패!")
                except sr.RequestError:
                    speak("서버 에러 발생!")
                except sr.WaitTimeoutError:
                    speak("인식 실패!")
                except TypeError:
                    speak("호출 에러 발생!") 
            except sr.exceptions.WaitTimeoutError:
                speak("시간 초과!")

 

다른 수강생들 프로젝트 발표 감상하기

- 사실 파이썬을 이번에 처음 배우는 입장에서 잘하는 분들의 완성본을 봤을 때 한없이 작아지는 느낌을 받았습니다. 아직 공부해야 할게 많다는 것도 깨닫게 된 거 같습니다. 그리고 한 가지 더 느낀 점은 역시 사람들은 모두가 각자 개성을 가지고 다른 생각을 하며 살기 때문에 단 한 사람도 똑같은 코드를 짜지 않았다는 것이 프로젝트 발표를 더 흥미롭게 지켜볼 수 있었던 감상 포인트였던 거 같습니다. 여러 사람들의 코드를 보면서 이것저것 많은 것을 생각할 수 있었던 좋은 시간이었습니다.

 

[마무리]

  오늘은 벌써 4주 차의 마지막 날이면서 이번 부트캠프의 첫 프로젝트를 마무리하는 날이었습니다. 파이썬 초보자의 입장에서는 이번 프로젝트가 통계 수업을 제외하면 약 2주 정도에 걸친 파이썬 수업에 대한 평가를 받을 수 있으면서 배운 것을 복습할 수 있는 좋은 계기였던 거 같습니다. 프로젝트를 하면서 밤늦게 까지 자발적으로 고민했을 만큼 열심히 수행했다는 점은 결과가 어찌 됐든 좋은 경험이었던 거 같습니다. 마지막으로 강사님이 조언해 준 것이 있는데 코드를 짜는 것에 있어서 중요한 것이 재사용성과 가독성이 라고 합니다. 앞으로 제가 나아가면서 꼭 지키리라는 다짐을 하면서 이번 프로젝트를 마무리하겠습니다.

반응형

댓글