๊ฐ์
- ํ๋ก์ ํธ๋ช : ์ธ๊ณต์ง๋ฅ ์คํผ์ปค ๋ง๋ค๊ธฐ
- ์ ์ ๊ธฐ๊ฐ: 2022.09.19 ~ 2022.09.22
- ๋ชฉํ: ์์ฑ์ธ์ ๊ธฐ์ (STT, TTS) ๊ตฌํ, ์น ์คํฌ๋ํ ์ตํ๊ธฐ
- ๊ฐ๋ฐ ํ๊ฒฝ
- OS: MacOS M1
- IDE: VSCode
๋ง๋ ๊ณ๊ธฐ
์ ํ๋ธ๋ฅผ ๋ณด๋ค๊ฐ ๋๋์ฝ๋ฉ
๋์ ์ธ๊ณต์ง๋ฅ ์คํผ์ปค ๋ง๋ค๊ธฐ ใํ์ด์ฌใ ์์์ ๋ดค๋๋ฐ ์ธํธ๋ก 20์ด ๋ณด๊ณ ๋ฐ๋ก ๋๋ ๋ง๋ค์ด ๋ณด๊ณ ์ถ๋ค๋ ์๊ฐ์ด ๋ค์๋ค. ์์ฑ์ธ์ ์ฑ๋ฅ์ด ๊ต์ฅํ ์ ๋์์ ์ ๋ฐ๋ผ ํด ๋ณผ ์๊ฐ ์์์!
๊ทธ๋ฆฌ๊ณ ์ง๋ ๋ฌ์ ์ง์ํ์๋ <2022 ํ๊ตญ์ด AI ๊ฒฝ์ง๋ํ> ์ฌ์ ๊ณผ์ ๋ก wav ํ์ผ์ ๋ค๋ค ๋ณผ ์ผ์ด ์์๋๋ฐ ๋น์ ์์ฑ ๋ฐ์ดํฐ๋ ์ฒ์ ๋ค๋ค๋ณด๋ ๊ฑฐ๋ผ ๋๋ฌด ์ด๋ ต๊ฒ ๋๊ปด์ก์๋ค. ๊ทธ๋ ์์ฌ์์ด ์ข ๋จ์์ ์ด๋ฒ์ ์์์ ๋ฐ๋ผ ํ๋ฉด์ ๊ฐ๋จํ๊ฒ ์ธ๊ณต์ง๋ฅ ์คํผ์ปค๋ฅผ ๋ง๋ค์ด๋ณด๋ฉด ์ข ๋ ์ฝ๊ฒ ์ดํดํ ์ ์์ ๊ฒ ๊ฐ์ ๋์ ํ๋ค.
์ฌ์ฉ ๊ธฐ์
TTS(Text To Speech)
- gTTS
- playsound
- PyObjC
STT(Speech To Text)
- SpeechRecognition
- PyAudio
์น ์คํฌ๋ํ
- beautifulsoup4
๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ
๐ฆAI_Speaker
โฃ ๐myenv
โ โฃ ๐bin
โ โฃ ๐include
โ โฃ ๐lib
โฃ ๐scrape
โ โฃ ๐__pycache__
โ โฃ ๐naver_exchange_rate.py
โ โ ๐naver_weather.py
โฃ ๐TTS_STT
โ โฃ ๐sample.txt
โ โฃ ๐sample_fr.txt
โ โฃ ๐speech_to_text.py
โ โ ๐text_to_speech.py
โฃ ๐reqirements.txt
โ ๐speaker.py
์ฐธ๊ณ
์ธ๊ณต์ง๋ฅ ์คํผ์ปค ๋ง๋ค๊ธฐ ใํ์ด์ฌใ
ํ์ด์ฌ ๊ฐ์ํ๊ฒฝ ์ฌ์ฉ ๋ฐฉ๋ฒ | venv
ํ์ด์ฌ ์ฝ๋ฉ ๋ฌด๋ฃ ๊ฐ์ (ํ์ฉํธ3) - ์น ํฌ๋กค๋ง/์น ์คํฌ๋ํ
34.2 ํด๋์ค ์์ฑ ์ฌ์ฉํ๊ธฐ
์ ์ ๊ณผ์
TTS ์ค์ต
TTS ์ค์ต์ ์์ฃผ ์ค๋ฌด์คํ๊ฒ ์งํ๋๋ค.
์งง์ ๋ฌธ์ฅ ๋ฟ๋ง ์๋๋ผ 3์ค ์ด์์ ๊ธด ๋ฌธ์ฅ๋ค๋ ์์ฑ์ผ๋ก ์ ์ฌ์๋๋ค.
from gtts import gTTS
from playsound import playsound
# ํ๊ตญ์ด ์งง์ ๋ฌธ์ฅ ํ
์คํธ
text = '์ ๋ ๊ธฐ๊ณ์
๋๋ค. ํ์ง๋ง ๊ด์ฐฎ์ ๋ณด์ด์ฃ ?'
file_name = 'sample.mp3'
tts_ko = gTTS(text=text, lang='ko') # gTTS(text=, lang=) -> text: gTTSํ ํ
์คํธ, lang: ์ธ์ด (ํ๊ธ = 'ko')
tts_ko.save(file_name)
playsound(file_name) # .mp3 ํ์ผ ์ฌ์
# ํ๊ตญ์ด ๊ธด ๋ฌธ์ฅ ํ
์คํธ (ํ์ผ ๋ถ๋ฌ์์ ์ฒ๋ฆฌํ๊ธฐ)
# sample.txt -> ํ๊ตญ์ด ๋ฌธ์ฅ์ด ๋ค์ด์๋ ํ
์คํธ ํ์ผ
with open('TTS_STT/sample.txt', 'r', encoding='utf8') as f: # ํ์ผ์ ํ๊ธ๋ก ์ฝ์ด์ฌ ๊ฑฐ๋๊น encoding='utf8'
text = f.read()
file_name = 'sample.mp3'
tts_ko = gTTS(text=text, lang='ko')
tts_ko.save(file_name)
playsound(file_name)
- gTTS()์์๋ ์ธ์ด๋ฅผ ์ ๋ ฅํ ๋ 'lang'์ผ๋ก ์์ฑ
โ๏ธ์๋ฌ
์ค์ตํ ๋๋ text_to_speech.py
ํ์ผ ์์ฒด๋ฅผ ๋ฐ๋ก ํด๋์ ๋ฃ์ง ์์์ ๋ฌธ์ ๊ฐ ์์๋๋ฐ
๋ค ๋ง๋ค๊ณ ๋ ํ์ ์ค์ตํ๋ ํ์ผ๋ค์ TTS_STT ํด๋๋ก ์ด๋ํ๋ฉด์ sample.txt
ํ์ผ์ ๊ฒฝ๋ก๋ฅผ ๋ค์ ์ค์ ํด์ค์ผ ํ๋ค.
sample.txt
ํ์ผ์ด๋ text_to_speech.py
ํ์ผ์ ๊ฐ์ ํด๋์ ์์ด์
๊ทธ๋ฅ '/'๋ง ์ถ๊ฐํด์ with open('/sample.txt',
์ด๋ผ๊ณ ํ๋๋ ๊ฒฝ๋ก๋ฅผ ์ฐพ์ ์ ์๋ค๊ณ ์๋ฌ๊ฐ ๋ฌ๋ค.
์ฐพ์๋ณด๋ ๊ทธ๋ฅ ํด๋ ์ด๋ฆ์ ์จ์ฃผ๋ฉด ํด๊ฒฐ๋๋ ๊ฐ๋จํ ์๋ฌ์์. with open('TTS_STT/sample.txt',
๋ผ๊ณ ํด์ฃผ๋ฉด ํด๊ฒฐ!
์ ์๋ ์ด ์๋ฌ๋ฅผ ์์ฃผ ๋ง๋ฌ์๋๋ฐ ํ๋ก์ ํธ๋ฅผ ์ค๋๋ง์ ํด์ ๊ทธ๋ฐ์ง ๊ธฐ์ต์ด ์ ์ ๋ฌ๋ค...
์ด์ ๋ฐฉ๋ฒ์ ์์์ผ๋๊น ์์ผ๋ก๋ ์ ๊น๋จน์ ๊ฒ์ด๋ค!
STT ์ค์ต
๋ชจ๋ ๊ณผ์ ์ด ๋ค ์ค๋ฌด์คํ๊ฒ ์ ์งํ๋ผ์ ๊ธฐ๋ปํ๋ ์ค, ๋๋์ด ๊ณ ๋์ด ์์๋๋ค.
STT๋ฅผ ๊ตฌํํ๊ธฐ ์ํด ํ์ํ ๋ชจ๋์ธ PyAudio
๋ฅผ ์ค์นํ๋ ๊ณผ์ ์์ ์๋ฌ๊ฐ ๋ฌ๋ค.
โ๏ธ์๋ฌ
์ฐพ์๋ณด๋ ํ์ด์ฌ ์์ฒด๋ฅผ ์ฌ์ค์นํด๋ณด๋ผ๋ ์ด์ผ๊ธฐ๊ฐ ๋ง์๋๋ฐ ์๋ชป ๊ฑด๋๋ ธ๋ค๊ฐ๋ ๋๋๋ฆด ์ ์์ ๊ฒ ๊ฐ์์ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๋ ์ค
๋๋์ฝ๋ฉ๋ ์์ ๋๊ธ์ ๋๋ ๊ฐ์ ์๋ฌ๊ฐ ๋์ จ๋ค๋ ๋ถ์ ๋ฐ๊ฒฌํ๋ค.
๊ทธ๋ถ๋ ๊ฒฐ๊ตญ brew install python3
๋ก ํ์ด์ฌ ์์ฒด๋ฅผ ์ฌ์ค์นํ์ ๋ค์์ venv ๊ฐ์ํ๊ฒฝ๋ ๋ค์ ์ธํ
ํ์
์ ํด๊ฒฐํ์
จ๋ค๊ณ ํ๋ค...
๋๋ python์ด anaconda์ ์ค์น๋์ด ์์ด์ ์ญ์ ํ์ง๋ ๋ชปํ๊ณ ๊ทธ๋ฅ brew install python3
๋ก ํ์ด์ฌ์ ์ค์นํ ๋ค์์ ๊ฐ์ํ๊ฒฝ์ ๋ค์ ์ธํ
ํ๊ณ ๋๋ PyAudio
๊ฐ ์ ๋๋ก ์ค์น๋๋ค!
์๊ฐ๋ณด๋ค ๊ฐ๋จํ๊ฒ ํด๊ฒฐ๋ผ์ ๋คํ์ด์๋ค.
์๋ฌ๋ฅผ ํด๊ฒฐํ๊ณ ๋๋์ด ๋ง์ดํฌ๋ก ์์ฑ์ธ์์ ์ง์ ์๋ํ๋ค!
import speech_recognition as sr
# ๋ง์ดํฌ๋ก๋ถํฐ ์์ฑ ๋ฃ๊ธฐ
r = sr.Recognizer()
with sr.Microphone() as source:
print('๋ฃ๊ณ ์์ด์') # ์ด ๋ฌธ์ฅ์ด ๋จ๊ณ ๋๋ฉด ๊ทธ๋๋ถํฐ ๋งํ๋ฉด ๋จ
audio = r.listen(source) # ๋ง์ดํฌ๋ก๋ถํฐ ์์ฑ ๋ฃ๊ธฐ
# ์์ธ์ฒ๋ฆฌ
try:
# ๊ตฌ๊ธ API๋ก ์ธ์ (ํ๋ฃจ 50ํ ๊น์ง๋ก ์ ํ)
# ์์ด ๋ฌธ์ฅ ํ
์คํธ
text = r.recognize_google(audio, language='en-US')
print(text)
except sr.UnknownValueError:
print('์ธ์ ์คํจ') # ์์ฑ ์ธ์์ ์คํจํ ๊ฒฝ์ฐ
except sr.RequestError as e:
print('์์ฒญ ์คํจ : {0}'.format(e)) # ์์ฒญ ์คํจํ ์ด์ ๊ฐ์ด ์ถ๋ ฅ -> API key ์ค๋ฅ, ๋คํธ์ํฌ ๋จ์ ๋ฑ
- sr.Recognizer()์์๋ ์ธ์ด๋ฅผ ์ ๋ ฅํ ๋ 'language'๋ก ์์ฑ
๋จผ์ ์์ด๋ก ํด๋ดค๋ค.
๋นจ๊ฐ์ ํ์ดํ ๋ถ๋ถ์ด ๋ด๊ฐ ๋งํ ๋ด์ฉ์ด ํ ์คํธ๋ก ๋ณํ๋ผ์ ์ถ๋ ฅ๋ ๋ถ๋ถ!
ํ๊ตญ์ด๋ ๊ต์ฅํ ์ ์ธ์ํ๋ค.
ํ์ง๋ง ์ฌํฌ๋ฆฌ๋ ์ด์ํ๊ฒ ์ธ์ํ๋ค. (๋ด ๋ฐ์์ด ์ ์ข์๋ ๊ฒ์ผ ์๋...)
๊ถ๊ธํด์ ํ๋์ค์ด๋ก๋ ํด๋ดค๋๋ฐ ์ธ์์ด ์ ๋ผ์ ๋ ๋๋๋ค!
์ฌ์ฑํ, ๋จ์ฑํ๋ ๋ฐ์์ผ๋ก ๊ตฌ๋ถํด์ ํ
์คํธ๋ก ์ ๋์จ๋ค. ์ญ์ ๊ตฌ๊ธ ๐
์ด๊ฑธ๋ก ๋ด ๋ถ์ด ๋ฐ์์ ์ธ์ ๋ฐ์ ๊ฒ ๊ฐ์์ ์ข ๋ ๊ธฐ๋ปค๋ค
์ธ๊ณต์ง๋ฅ ์คํผ์ปค ๊ตฌํ
์์์ ์ค์ตํ TTS, STT๋ฅผ ๊ฐ์ง๊ณ ์ด์ ๋๋ง์ ์ธ๊ณต์ง๋ฅ ์คํผ์ปค๋ฅผ ๊ตฌํํ๋ค.
๊ฐ๊ฒฉ์ค๋ฌ์ด ์ฒซ ๋ํ..!
์๋ ํ๋ก์ฐ๋
1) TTS๋ฅผ ์ด์ฉํด์ ์ธ๊ณต์ง๋ฅ์ด '๋ฌด์์ ๋์๋๋ฆด๊น์?'๋ฅผ ๋งํ๋ค.
2) ์ฌ๋์ด ๋ง์ ํ๋ฉด STT๋ก ๋งํ ๋ด์ฉ์ ํ
์คํธ๋ก ๋ณด์ฌ์ค๋ค.
3) ์ฌ๋์ด ๋งํ ๋ด์ฉ ์ค์ answer()
ํจ์์์ ์ ์ํด๋ ๋จ์ด๊ฐ ๋ค์ด๊ฐ๋ฉด ์ธ๊ณต์ง๋ฅ์ด ๊ทธ์ ๋ง๋ ๋๋ต์ ๋ค์ TTS๋ก ๋งํด์ฃผ๋ ํ์.
์ด๋๋ ๋๋์ฝ๋ฉ๋์ ์์์ ๋์จ ๋๋ก ์ธ๊ณต์ง๋ฅ์ด ๋ตํ ๋ด์ฉ์ ์ง์ str์ผ๋ก ๋ฏธ๋ฆฌ ์ง์ ํด๋๋ค.
๋ง๋ค๋ค ๋ณด๋ ์ธ๊ณต์ง๋ฅ์ด ๋๋ตํ ๋ด์ฉ์ ์ด๋ ๊ฒ ์ง์ ์ง์ ํด๋๋ ๊ฒ ์๋๋ผ API๋ ํฌ๋กค๋ง์ ์ฌ์ฉํด์ ์ง์ง ์ธ๊ณต์ง๋ฅ ์คํผ์ปค์ฒ๋ผ ์ค์๊ฐ ์ ๋ณด๋ฅผ ๋ตํ๊ฒ ํ๊ณ ์ถ์๋ค.
๊ทธ๋์ ๋ ์จ์ ํ์จ์ ๋ํ ๋ต์ ๋ค์ด๋ฒ ์คํฌ๋ํ์ ํตํด ๊ฐ์ ธ์ค๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค!
๋ค์ด๋ฒ ๋ ์จ, ํ์จ ์ ๋ณด ์น ์คํฌ๋ํ
์ฒ์์ ์คํฌ๋ํํ ๊ฒฐ๊ณผ๋ฅผ ํจ์ ํํ๋ก ๋ฐ์์์ answer()
ํจ์ ๋ด answer_text
์ ๋ฃ์๋๋ฐ
์ด๋ ๊ฒ ํ๋ answer_text
์ TTS๊ฐ ์ ์ฉ๋์ง ๋ชปํ๋ค.
์ธ๊ณต์ง๋ฅ์ด ๋ตํ๋ ๊ฒ ํ ์คํธ๋ก๋ ์ถ๋ ฅ๋์ง๋ง ์๋ฆฌ ๋ด์ ์ฝ๋ ๊ฒ์ ์๋ฌ๊ฐ ๋ฌ๋ค.
๊ทธ๋์ class์ ์์ฑ์ผ๋ก ๋ฐ์์ค๋๋ก ์์ ํ๋ค.
# ๋ค์ด๋ฒ ํ์จ ์คํฌ๋ํ
import requests
from bs4 import BeautifulSoup
# ์๋ฌ๋ฌ ํ์จ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
class Exchange:
def __init__(self, url=None, res=None, soup=None):
self.url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%ED%99%98%EC%9C%A8"
self.res = requests.get(self.url)
self.soup = BeautifulSoup(self.res.text, "lxml")
# ํ์ฌ ์๋ฌ๋ฌ ํ์จ
self.curr_exchange = self.soup.find("span", attrs={"class":"recite _recite result"}).get_text()
# ๋ฑ๋ฝ๋ฅ
self.ex_rate = self.soup.find("td", attrs={"class":"flu_pct"}).get_text()
# ๋ค์ด๋ฒ ์์ธ ๋ ์จ ์คํฌ๋ํ
import requests
from bs4 import BeautifulSoup
# ์ค๋์ ์์ธ ๋ ์จ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
class Weather:
def __init__(self, url=None, res=None, soup=None):
self.url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EC%84%9C%EC%9A%B8+%EB%82%A0%EC%94%A8"
self.res = requests.get(self.url)
self.soup = BeautifulSoup(self.res.text, "lxml")
# ํ์ฌ ์จ๋
self.curr_temp = self.soup.find("div", attrs={"class":"temperature_text"}).get_text().replace("ํ์ฌ ์จ๋", "ํ์ฌ ์์ธ์ ์จ๋๋ ").strip() # ๊ณต๋ฐฑ ์ ๊ฑฐ
# ๋ ์จ ์ํ
self.weather_con = self.soup.find("span", attrs={"class":"weather before_slash"}).get_text()
# ์ด์ ๋ณด๋ค
self.yester_temp = self.soup.find("p", attrs={"class":"summary"}).get_text().split('์์')[0] # ์ถ๋ ฅ ์ ๋ค์ '์ต๋๋ค.' ๋ถ์ด๊ธฐ
# ์ต์ ๊ธฐ์จ
self.min_temp = self.soup.find("span", attrs={"class":"lowest"}).get_text().replace("์ต์ ๊ธฐ์จ", "์ต์ ๊ธฐ์จ์ ")
# ์ต๊ณ ๊ธฐ์จ
self.max_temp = self.soup.find("span", attrs={"class":"highest"}).get_text().replace("์ต๊ณ ๊ธฐ์จ", "์ต๊ณ ๊ธฐ์จ์ ")
โ๏ธ์๋ฌ
์ด ๊ธ์ ์์ฑํ๋ฉด์ ๋ค์ ์คํ์์ผ๋ณด๋ ์ ์ฝ๋์ yester_temp
๊ฐ ์๋ฌ๊ฐ ๋ฌ๋ค.
- ์์ ํ๊ธฐ ์ ์ฝ๋
self.yester_temp = self.soup.find("span", attrs={"class":"temperature down"}).get_text()
๋ถ๋ช
๊ทธ์ ๊ป ์คํํ์ ๋๋ ์ ์๋ํ๋๋ฐ ๊ฐ์๊ธฐ ์ ์๋ฌ๊ฐ ๋๋์ง ์ดํด๋ณด๋ "temperature down"
๋๋ฌธ์ด์๋ค.
๋ด๊ฐ ์ฒ์์ ์ฝ๋๋ฅผ ์งค ๋๋ ๋ฌผ๊ฒฐ ํ์๋ ์ ๋ถ๋ถ์ด "temperature down"
์ด๋ผ๊ณ ๋์ด ์์๋๋ฐ ์ค๋์ ์ด์ ๋ณด๋ค ๊ธฐ์จ์ด ์ฌ๋ผ์ "temperature up"
์ผ๋ก ๋ฐ๋ ๊ฒ.
์์ ์ ์ฝ๋๋ '์ด์ ๋ณด๋ค' ๋ค์ ์จ๋๋ง ๊ฐ์ ธ์์๋๋ฐ ์จ๋๊ฐ ๋์์ง๊ณ ๋ฎ์์ง๋ ๊ฒ์ ๋ฐ๋ผ ๊ณ์ ๋ฐ๋๋๊น
์์ ๊ทธ ์์ <p class="summary">
๋ถ๋ถ์ ๋ค ๋ฐ์์์ '์ด์ ๋ณด๋ค 00° ๋/๋ฎ'๊น์ง๋ง ๋ฐ์์ค๋๋ก ์์ ํ๋ค.
- ์์ ํ ์ฝ๋
self.yester_temp = self.soup.find("p", attrs={"class":"summary"}).get_text().split('์์')[0]
# ์คํฌ๋ํ ํด๋์ค ๋ถ๋ฌ์ค๊ธฐ
import scrape.naver_exchange_rate as nex
import scrape.naver_weather as nwh
# (๋ ์จ)
# ์ธ์คํด์ค ์ ์ธ
wh = nwh.Weather()
# ์์ฑ ๋ฐ๊ธฐ
wh.curr_temp # ํ์ฌ ์์ธ์ ์จ๋
wh.weather_con # ๋ ์จ ์ํ (ex. ๋ง์, ํ๋ฆผ, ...)
# (ํ์จ)
# ์ธ์คํด์ค ์ ์ธ
ex = nex.Exchange()
# ์์ฑ ๋ฐ๊ธฐ
ex.curr_exchange # ํ์ฌ ์๋ฌ๋ฌ ํ์จ
ex.ex_rate # ๋ฑ๋ฝ๋ฅ
๊ฒฐ๊ณผ ์์ฐ
- 9์ 20์ผ
- 9์ 22์ผ
์น ์คํฌ๋ํ์ผ๋ก ์ค์๊ฐ ๋ ์จ, ํ์จ ์ ๋ณด๋ฅผ ๋ฐ์์ ๋งค๋ฒ ๋ค๋ฅด๊ฒ ์ ๋๋ตํ๋ค.
9์ 22์ผ ๋ํ์์ ๋ง์ง๋ง์ "์ด์ ์ข ๋ฃํ๋ค"๋ ์ฌ์ค "์ด์ ์ข ๋ฃํ์"๋ผ๊ณ ๋งํ ๊ฑฐ์๋๋ฐ '์'๋ฅผ '๋ค'๋ผ๊ณ ์๋ชป ์ธ์๋ ๋ชจ์ต๋ ๋ณด์ธ๋ค.
์๋ฌ ๋ชจ์์ง
1) [bs4 ์๋ฌ] ImportError: cannot import name 'BeautifulSoup'
- ํ์ผ๋ช ์ด 'bs4.py'๋ก ๋์ด ์์ด์ ๋ชจ๋์ ๋ถ๋ฌ์ค์ง ๋ชปํจ
- -> ํ์ผ๋ช ์ ์์ ํ๋ฉด ํด๊ฒฐ
2) [bs4 lxml ์๋ฌ] bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml.
- ์๋ฌ ๋ฌธ: bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?
- lxml์ ์ค์นํ๋ฉด ํด๊ฒฐ
- ->
pip install lxml
3) [git ์๋ฌ] ! [rejected] main -> main (fetch first)
- ์๊ฒฉ ์ ์ฅ์์ ํ์ฌ ์์ ์ค์ธ ๋ก์ปฌ ์ ์ฅ์๊ฐ ๋๊ธฐํ๋์ง ์์์ ๋ฐ์
- ๋๊ธฐํ๋์ง ์์ ์ํ์์ ๋ค์ push ํ๋ฉด ๋ฐ์ดํฐ๊ฐ ์์ค๋ ์ ์๋ค๊ณ ๊ฒฝ๊ณ
- ๋๊ธฐํ๋ฅผ ์ํด pull ํ ํ push ํ๋ฉด ํด๊ฒฐ
- ->
git pull --rebase origin main
๋๋ ์ ๋ฐ ํฅํ ๊ฐ์ ๋ฐฉ์
- ๋๋ ์
๊ฐ๋จํ๊ฒ ๋ฐ๋ผ ํด๋ณด๋ ๋ฏธ๋ ํ ์ด ํ๋ก์ ํธ์์ง๋ง ์ฝ๋๋ฅผ ์ง์ ๋ฌด์ธ๊ฐ๋ฅผ ๋ง๋ค์ด ๋ณด๋ ๊ฒ ์ ๋ง ์ค๋๋ง์ด๋ผ ๋ง๋ค๋ฉด์ ๋๋ฌด ๊ธฐ๋ปค๋ค.
๊ตฌ๊ธ API๋ฅผ ์ด์ฉํด์ ์ธ๊ณต์ง๋ฅ ์คํผ์ปค๋ฅผ ์ ๋ง ๊ฐ๋จํ๊ฒ ๋ง๋ค ์ ์๋ค๋ ๊ฒ์ ๋๋๊ณ , ์๊ฐ๋ณด๋ค ์์ฑ์ ๊ต์ฅํ ์ ์ธ์ํด์ ํ๋ฒ ๋ ๋๋๋ค. (๊ฐ ๊ตฌ๊ธ!)
- ํฅํ ๊ฐ์ ๋ฐฉ์
๋ค์์๋ ๊ตฌ๊ธ API๊ฐ ์๋๋ผ ๋ค์ด๋ฒ ๋ฒ์ญ API๋ฅผ ์ฌ์ฉํด์ ๋ค์ ํ๋ฒ ๋ง๋ค์ด ๋ณผ ๊ฒ์ด๋ค.
๊ทธ๋ฆฌ๊ณ API๋ฅผ ์ฌ์ฉํ์ง ์๊ณ TTS์ STT๋ฅผ ์ง์ ๊ตฌํํ๋ ๊ฒ์๋ ๋์ ํ ๊ฒ์ด๋ค.
์์คํ ๊ณต๊ฐ ๊ฐ์ฌํฉ๋๋ค :)