[파이썬 Projects]/<파이썬 Gen AI, LLM>

[Gen AI] 영어 학습봇 만들기

기록자_Recordian 2025. 2. 13. 22:37
728x90
반응형
행 내용

 

그라디오를 이용하여, 영어 한 문장씩 출력해주는 영어 학습봇을 만들어본다.


레이아웃 및 기능 설명

 

대략적인 레이아웃은 아래와 같다. (이는 작업하며 변경될 수 있다.)

 

[각 레이아웃에 대한 설명은 다음과 같다.]

  • #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앱 만들기 프로젝트는 완료!


다음 내용

 

 


[참고한 글]

생성형 AI 프로그램 만들기 관련 글

728x90
반응형