[Gen AI] 영어 학습봇 만들기
행 내용
그라디오를 이용하여, 영어 한 문장씩 출력해주는 영어 학습봇을 만들어본다.
레이아웃 및 기능 설명
대략적인 레이아웃은 아래와 같다. (이는 작업하며 변경될 수 있다.)
[각 레이아웃에 대한 설명은 다음과 같다.]
- #1: 영어 문장 주제를 선택할 수 있으며, 드롭다운 형태로 생성
- #2: 출력된 영어 문장의 속도를 조절할 수 있으며, 슬라이더 형태로 생성
- #3: 목소리 설정 기능을 제공하며, 드롭다운 형태로 생성
- #4: 생성된 문장을 음성으로 들을 수 있으며, 버튼 형태로 생성
- #5: AI가 생성한 문장이 출력되는 화면. 텍스트 박스 형태로 생성
- #6: AI가 생성한 문장의 문법이나 뜻을 설명하는 화면. 텍스트 박스 형태로 생성
- #7: 다른 문장을 생성할 수 있는 기능. 버튼 형태로 생성
그라디오 사용을 위한 OpenAI import
import os
import openai
# 환경변수에서 OpenAI API 키를 읽어옴.
openai_api_key = os.getenv('OPENAI_API_KEY')
# API 키가 환경변수에 설정되어 있는지 확인.
if not openai_api_key:
raise ValueError("환경변수 'OPENAI_API_KEY'가 설정되지 않았습니다.")
# OpenAI API 키를 설정.
openai.api_key = openai_api_key
# OpenAI 클라이언트를 생성.
client = openai.OpenAI()
그라디오로 기본적인 레이아웃 짜기
그라디오를 import 하여 기본적인 레이아웃을 짜본다.
import gradio as gr
with gr.Blocks() as app:
with gr.Tab("영어 학습봇"): # 탭
with gr.Column():
gr.Markdown() # 제목
with gr.Row():
with gr.Column():
with gr.Column():
gr.Dropdown() #1
gr.Slider() #2
gr.Dropdown() #3
gr.Button() #4
gr.Textbox() #5
with gr.Row():
gr.Textbox() #6
gr.Button() #7
app.launch()
여러 부분들을 디테일하게 손봐야 할 듯하다.
레이아웃 다듬기
컴포넌트 추가하기
대략적인 레이아웃을 다듬었다.
물론, 이를 실행하기 위한 기능, 이벤트리스너 등을 추가해줘야 하는 중요한 과정이 남아있다.
import gradio as gr
with gr.Blocks() as app:
with gr.Tab("영어 학습봇"): # 탭
with gr.Column():
gr.Markdown(
value="""
# <center>영어 학습봇</center>
<center>인공지능 비서 DUDE 입니다.
영어 학습을 위한 영어 한 문장을 생성합니다.</center>
"""
) # 제목
with gr.Row():
with gr.Column():
with gr.Column():
en_type = gr.Dropdown( #1
label="타입 선택",
choices=["일반회화", "비즈니스", "명언", "시사"],
value = "일반회화",
interactive=True
)
gr.Slider( #2
label="속도",
info="숫자가 높을수록 속도 빠름",
minimum=0,
maximum=2,
step=0.2,
value=1,
interactive=True
)
en_voice = gr.Dropdown( #3
label="목소리 선택",
choices = ["alloy", "echo", "fable", "onyx", "nova", "shimmer"],
value = "alloy",
interactive=True
)
cb_submit_btn=gr.Button(
value="음성 듣기",
scale=1,
visible="primary",
icon="https://cdn-icons-png.flaticon.com/128/12439/12439334.png" # 재생버튼
) #4
gr.Textbox( #5
container=False,
placeholder="AI와 함께 영어 공부를!",
lines=3,
scale=4
)
with gr.Row():
gr.Textbox( #6
label="",
placeholder="AI가 생성한 문장을 해석 및 설명합니다.",
lines=5,
max_lines=20,
show_copy_button=True
)
en_create=gr.Button( #7
value="🔄️생성하기",
scale=0.3,
visible='primary'
)
app.launch()
이를 실행해보면
영어학습봇 기능구현하기
◆ 문장 생성하는 기능 (함수)
문장을 생성하는 기능을 추가하기 위해 generate_sentence 함수를 정의한다.
해당 함수는 영어 주제(en_type), 속도(speed), 목소리(en_voice)를 인자로 받는다.
# 문장을 생성하는 함수
def generate_sentence(en_type, speed, en_voice):
prompt = f"Generate an English sentence in the category of '{en_type}'."
try:
completion = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": prompt
}
],
max_tokens=60
)
generated_sentence = completion.choices[0].message.content
return generated_sentence
except Exception as e:
return f"문장 생성 중 오류 발생: {e}"
- prompt 에 영어 주제(en_type)에 맞게 영어 한 문장을 생성해줘 라고 입력하고,
- try-except 문을 사용하여
- 이상 없을 경우, openai가 메시지를 생성할 수 있도록 model, message, max_token을 설정해준 뒤
- 내용을 생성하고 return 하도록 하고,
- 문제가 있을 경우엔 오류 발생과 해당 오류가 뜨도록 설정하였다.
[completions.create & message.content]
- openai.chat.completions.create: OpenAI의 API를 호출하여 채팅 응답(Completions)을 생성하는 함수.
- completion.choices[0].message.content: API 호출의 결과로 반환된 completion 객체는 choices라는 리스트를 포함하고 있는데, 일반적으로 단일 응답의 경우 첫 번째 요소인 choices[0]가 사용된다.
.message는 선택된 응답 안의 메시지 객체를 나타내며, 그 안에는 role (예: "assistant")과 content (응답 문자열)의 필드가 포함된다.
.content는 해당 메시지의 실제 내용을 가진 부분으로, AI가 생성한 텍스트 응답을 나타낸다.
◆ TTS(Text to Speech, 텍스트 음성 변환) 기능 설정
먼저, 기존에 그라디오를 이용해 챗봇을 만들 때는 OpenAI의 Whipser 나 구글의 gTTS 등을 사용했었는데,
(관련 링크: https://puppy-foot-it.tistory.com/621)
찾아보니, whisper를 사용하게 되면 생성된 텍스트를 음성 파일로 변환하여 로컬 파일로 저장한 뒤, 재생을 위해 해당 파일을 불러와야 하는 작업이 추가돼야 한다고 했다.
따라서, 변환된 음성을 다운로드 없이 바로 재생할 수 있는 pyttsx3 엔진을 이용하여 작업을 진행했다.
(pyttsx3 사이트: https://pypi.org/project/pyttsx3)
우선, 목소리 목록을 드롭다운 목록으로 반환해야 하므로, 해당 목소리 리스트를 가져올 수 있도록 get_available_voices 함수를 정의한다.
그리고 재생을 위한 play_sentence 함수를 정의했다.
이 함수는 앞서 정의한 문장을 생성해주는 generated_sentence 함수와 속도(speed), 목소리(en_voice)를 입력값으로 받는다.
# 문장 발음을 위한 함수
# 사용 가능한 목소리 목록 가져오기
def get_available_voices():
# TTS 엔진 초기화
engine = pyttsx3.init()
# 사용 가능한 목소리 목록 가져오기
voices = engine.getProperty('voices')
voice_choices = []
for voice in voices:
voice_choices.append(voice.name) # 목소리 이름을 리스트에 추가
return voice_choices
# 음성 재생 함수
# 음성 파일 다운로드 없이 바로 재생될 수 있게 pyttsx3 엔진 사용
def play_sentence(generated_sentence, speed, en_voice):
# 텍스트 음성을 위한 pyttsx3 초기화
engine = pyttsx3.init()
# 속도 설정
engine.setProperty('rate', 150 + (speed * 50)) # 기본 속도 조절(기본속도 = 150)
# 목소리 설정
voices = engine.getProperty('voices')
for voice in voices:
if voice.name == en_voice:
engine.setProperty('voice', voice.id)
# 문장 읽기
engine.say(generated_sentence)
engine.runAndWait()
◆ 문장 해석과 설명을 위한 기능 설정
문장 해석 및 설명을 위한 explain_sentence 함수를 정의하고, 입력값으로 sentence를 받도록 한다.
또한, 문장 해석 및 설명은 한국어로 출력돼야 하므로, 프롬프트를 영어가 아닌 한국어로 작성하였다.
(영어로 작성하면 해석과 설명이 영어로 나온다.
explanation_prompt에 "Please translate and explain the {sentent} in Korean" 이라고 입력했더니 영어로 출력되어 한국어로 수정했더니 한국어로 잘 출력되었다.).
# 문장 해석 및 설명 함수
def explain_sentence(sentence):
# 문장을 해석하는 기본적인 설명
# 한국어로 출력되게 하기 위해 한국어로 프롬프트 작성
explanation_prompt = f"문장 '{sentence}'을(를) 한국어로 번역하고 해당 문장에 사용된 문법이나 단어를 설명해 주세요."
try:
completion = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": explanation_prompt
}
],
max_tokens=1000 # 보다 긴 설명을 위한 토큰 수 증가
)
generated_explanation = completion.choices[0].message.content # 생성된 설명 받
return generated_explanation
except Exception as e:
return f"문장 생성 중 오류 발생: {e}"
- 앞의 문장을 생성하는 generate_sentence 함수와 비슷하나, 보다 긴 설명을 위해 max_tokens를 늘렸다.
변수에 컴포넌트 바인딩하기
앞서 작성한 함수에 참조하기 위한 기능들을 변수에 바인딩한다.
import gradio as gr
with gr.Blocks() as app:
with gr.Tab("영어 학습봇"): # 탭
with gr.Column():
gr.Markdown(
value="""
# <center>영어 학습봇</center>
<center>인공지능 비서 DUDE 입니다.
영어 학습을 위한 영어 한 문장을 생성합니다.</center>
"""
) # 제목
with gr.Row():
with gr.Column():
with gr.Column():
en_type = gr.Dropdown( #1
label="타입 선택",
choices=["일반회화", "비즈니스", "명언", "시사"],
value = "일반회화",
interactive=True
)
speed = gr.Slider( #2
label="속도",
info="숫자가 높을수록 속도 빠름",
minimum=0,
maximum=2,
step=0.2,
value=1,
interactive=True
)
# 사용 가능한 목소리 리스트 가져오기
voice_choices = get_available_voices()
en_voice = gr.Dropdown( #3
label="목소리 선택",
choices = voice_choices,
value = "alloy",
interactive=True
)
play_btn=gr.Button(
value="음성 듣기",
scale=1,
visible="primary",
icon="https://cdn-icons-png.flaticon.com/128/12439/12439334.png" # 재생버튼
) #4
generated_sentence_box = gr.Textbox( #5
container=False,
placeholder="AI와 함께 영어 공부를!",
lines=3,
scale=4,
show_copy_button=True # 내용 복사 기능
)
with gr.Row():
explanation_box = gr.Textbox( #6
label="",
placeholder="AI가 생성한 문장을 해석 및 설명합니다.",
lines=10,
max_lines=100,
show_copy_button=True # 내용 복사 기능
)
en_create=gr.Button( #7
value="🔄️생성하기",
scale=0.3,
visible='primary'
)
- en_type: 영어 주제를 드롭다운으로 선택
- speed: 음성 재생 속도
- en_voice: 음성 재생 목소리
- play_btn: 음성 듣기 버튼
- generated_sentence_box: 문장이 생성되는 텍스트 박스
- explanation_box: 생성된 영어 문장을 해석 및 설명해주는 텍스트 박스
- en_create: 영어 문장 생성을 위한 버튼
마무리
이벤트 리스너 추가 및 설정
생성 및 정의한 기능(함수)들을 실행할 수 있도록 이벤트 리스너를 추가 및 설정한다.
# 이벤트 리스너
en_create.click(
fn=generate_sentence,
inputs=[en_type, speed, en_voice],
outputs=generated_sentence_box
)
play_btn.click(
fn=play_sentence,
inputs=[generated_sentence_box, speed, en_voice],
outputs=None
)
generated_sentence_box.change(
fn=explain_sentence,
inputs=generated_sentence_box,
outputs=explanation_box
)
[각 이벤트 리스너들과 그에 대한 설명]
1. en_create.click()
- 이벤트 리스너: 사용자가 en_create 버튼을 클릭할 때 generate_sentence 함수를 실행하도록 설정.
- fn=generate_sentence: 버튼 클릭 시 호출할 함수. 이 함수는 주어진 입력값을 바탕으로 문장을 생성하는 역할.
- inputs=[en_type, speed, en_voice]: 함수에 전달할 입력값.
- outputs=generated_sentence_box: 함수의 결과로 출력할 요소다. 생성된 문장이 표시될 텍스트 박스를 지정.
2. paly_btn.click()
- 이벤트 리스너: 사용자가 play_btn 버튼을 클릭할 때 play_sentence 함수를 실행하도록 설정.
- fn=play_sentence: 클릭 시 호출할 함수로, 사용자가 생성한 문장을 음성으로 재생하는 역할.
- inputs=[generated_sentence_box, speed, en_voice]: 함수에 전달할 입력값. 출력할 문장, 음성 속도 및 선택된 목소리 목록 포함.
- outputs=None: 출력 요소가 없음을 지정. 이 경우 음성이 재생되므로 추가적인 출력이 필요하지 않다.
3. generated_sentence_box.change()
- 이벤트 리스너: 사용자가 generated_sentence_box에서 텍스트를 변경할 때마다 explain_sentence 함수를 실행하도록 설정.
- fn=explain_sentence: 이 함수는 생성된 문장에 대한 설명을 제공하는 역할.
- inputs=generated_sentence_box: 변경된 문장이 입력으로 전달.
- outputs=explanation_box: 함수의 결과로 설명이 표시될 박스 지정.
코드 실행 및 테스트
◆ 레이아웃 체크
코드가 정상적으로 잘 실행된다.
물론, 처음에 구현한 레이아웃과는 조금 차이가 있긴 하나, 그라디오의 설정 상 어쩔 수 없는 부분들도 있어 최대한 기존에 기획한 레이아웃과 최대한 맞추도록 했다.
◆ 문장 생성 및 해석과 번역 기능 수행 체크
[생성하기] 버튼을 클릭해보면 선택한 주제인 '일반회화' 에 맞는 영어 문장과, 그에 대한 뜻과 설명이 잘 출력되는 것을 확인할 수 있다.
◆ 문장 주제 레이아웃 및 기능 수행 여부 체크
주제(타입)는 앞서 설정한 총 4개의 주제가 있으며, 드롭다운으로 선택할 수 있도록 잘 구현되었고,
이중에서 타입을 '명언'으로 바꾸고 실행을 해보면
해당 주제에 맞게 문장과 풀이가 잘 출력되는 것을 확인할 수 있다.
◆ 목소리 선택 레이아웃 및 기능 체크
pyttsx3의 아쉬운 점 중 하나인데, OpenAI의 Whisper와는 달리, 목소리가 언어에 따라 나뉘어져 있다.
※ Whisper 의 경우, "alloy", "echo", "fable", "onyx", "nova", "shimmer" 6가지의 목소리가 있다.
아무튼, 목소리 목록이 드롭다운으로 고를 수 있게 잘 구현되었고, (혹시 추후에 모델이 발전해 목소리 기능이 추가될 수 있으므로, 이 부분은 그대로 놔두기로 했다.) 선택한 목소리에 따라 문장이 다르게 들린다.
조금 킹 받는 건, 'Korean'을 선택해서 영어 문장을 들어보면 마치 한국인이 콩글리쉬 하는 것 같은 느낌이 든다.
AI가 콩글리쉬도 완벽히 구현해 내다니.... 놀라울 따름이다.
◆ 속도 레이아웃 및 기능 체크
속도는 슬라이더로 0부터 2사이에서 조절할 수 있도록 했는데, 설정된 속도에 따라 음성의 속도가 빨라지고 느려지고 하는 부분이 구현이 잘 되었다.
[음성 듣기] 부분의 경우, 버튼으로 레이아웃이 잘 구현되었고, 앞서 설명한 목소리와 속도가 설정한 대로 잘 나오는 것으로 보아, 기능이 잘 설정된 것으로 확인되어진다.
마찬가지로, [생성하기] 부분 역시 설정한 주제로 문장이 잘 설정되니, 기능이 잘 구현되었다. 버튼으로도 잘 보여지니 레이아웃도 잘 구현되었다.
전체 코드
전체 코드는 아래와 같다.
import os
import openai
import pyttsx3 # 텍스트 음성
# 환경변수에서 OpenAI API 키를 읽어옴.
openai_api_key = os.getenv('OPENAI_API_KEY')
# API 키가 환경변수에 설정되어 있는지 확인.
if not openai_api_key:
raise ValueError("환경변수 'OPENAI_API_KEY'가 설정되지 않았습니다.")
# OpenAI API 키를 설정.
openai.api_key = openai_api_key
# OpenAI 클라이언트를 생성.
client = openai.OpenAI()
# 문장을 생성하는 함수
def generate_sentence(en_type, speed, en_voice):
prompt = f"Generate an English sentence in the category of '{en_type}'."
try:
completion = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": prompt
}
],
max_tokens=60
)
generated_sentence = completion.choices[0].message.content
return generated_sentence
except Exception as e:
return f"문장 생성 중 오류 발생: {e}"
# 문장 발음을 위한 함수
# 사용 가능한 목소리 목록 가져오기
def get_available_voices():
# TTS 엔진 초기화
engine = pyttsx3.init()
# 사용 가능한 목소리 목록 가져오기
voices = engine.getProperty('voices')
voice_choices = []
for voice in voices:
voice_choices.append(voice.name) # 목소리 이름을 리스트에 추가
return voice_choices
# 음성 재생 함수
# 음성 파일 다운로드 없이 바로 재생될 수 있게 pyttsx3 엔진 사용
def play_sentence(generated_sentence, speed, en_voice):
# 텍스트 음성을 위한 pyttsx3 초기화
engine = pyttsx3.init()
# 속도 설정
engine.setProperty('rate', 150 + (speed * 50)) # 기본 속도 조절(기본속도 = 150)
# 목소리 설정
voices = engine.getProperty('voices')
for voice in voices:
if voice.name == en_voice:
engine.setProperty('voice', voice.id)
# 문장 읽기
engine.say(generated_sentence)
engine.runAndWait()
# 문장 해석 및 설명 함수
def explain_sentence(sentence):
# 문장을 해석하는 기본적인 설명
# 한국어로 출력되게 하기 위해 한국어로 프롬프트 작성
explanation_prompt = f"문장 '{sentence}'을(를) 한국어로 번역하고 해당 문장에 사용된 문법이나 단어를 설명해 주세요."
try:
completion = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": explanation_prompt
}
],
max_tokens=1000 # 보다 긴 설명을 위한 토큰 수 증가
)
generated_explanation = completion.choices[0].message.content # 생성된 설명 받
return generated_explanation
except Exception as e:
return f"문장 생성 중 오류 발생: {e}"
import gradio as gr
with gr.Blocks() as app:
with gr.Tab("영어 학습봇"): # 탭
with gr.Column():
gr.Markdown(
value="""
# <center>영어 학습봇</center>
<center>인공지능 비서 DUDE 입니다.
영어 학습을 위한 영어 한 문장을 생성합니다.</center>
"""
) # 제목
with gr.Row():
with gr.Column():
with gr.Column():
en_type = gr.Dropdown( #1
label="타입 선택",
choices=["일반회화", "비즈니스", "명언", "시사"],
value = "일반회화",
interactive=True
)
speed = gr.Slider( #2
label="속도",
info="숫자가 높을수록 속도 빠름",
minimum=0,
maximum=2,
step=0.2,
value=1,
interactive=True
)
# 사용 가능한 목소리 리스트 가져오기
voice_choices = get_available_voices()
en_voice = gr.Dropdown( #3
label="목소리 선택",
choices = voice_choices,
value = "alloy",
interactive=True
)
play_btn=gr.Button(
value="음성 듣기",
scale=1,
visible="primary",
icon="https://cdn-icons-png.flaticon.com/128/12439/12439334.png" # 재생버튼
) #4
generated_sentence_box = gr.Textbox( #5
container=False,
placeholder="AI와 함께 영어 공부를!",
lines=3,
scale=4,
show_copy_button=True # 내용 복사 기능
)
with gr.Row():
explanation_box = gr.Textbox( #6
label="",
placeholder="AI가 생성한 문장을 해석 및 설명합니다.",
lines=10,
max_lines=100,
show_copy_button=True # 내용 복사 기능
)
en_create=gr.Button( #7
value="🔄️생성하기",
scale=0.3,
visible='primary'
)
# 이벤트 리스너
en_create.click(
fn=generate_sentence,
inputs=[en_type, speed, en_voice],
outputs=generated_sentence_box
)
play_btn.click(
fn=play_sentence,
inputs=[generated_sentence_box, speed, en_voice],
outputs=None
)
generated_sentence_box.change(
fn=explain_sentence,
inputs=generated_sentence_box,
outputs=explanation_box
)
app.launch()
허깅페이스에 업로드하기
마지막으로, 허깅페이스에 만든 앱을 업로드한다.
업로드하는 법은 하단의 글을 참고하면 된다.
[Gen AI] 그라디오로 제작한 챗봇 허깅 페이스에 업로드하기
이전 내용 [Gen AI] 그라디오로 챗봇 제작하기 - 3 (소설봇)이전 내용 [Gen AI] 그라디오로 챗봇 제작하기 - 1 (상담봇)이전 내용 [Gen AI] 그라디오(Gradio)이전 내용 [Gen AI] OpenAI API 사용해보기 (로컬,
puppy-foot-it.tistory.com
이렇게 영어 학습을 도와주는 영어 문장을 생성해주는 AI앱 만들기 프로젝트는 완료!
다음 내용
[참고한 글]