한 개만 더, 한 발만 더

어제보다 조금 더 나은 오늘을 만들기 위해 노력합니다.

파이썬/데이터 분석

Gradio와 GPT를 활용한 영어 교육 서비스 만들기

토이판다 2023. 9. 19. 22:41

Good Will Hunting, 인생 영화 중 하나

 

요즘 딥 테크 문샷이라는 프로그램을 이수하는 중이다. 프로그램에서 조별 과제를 진행하면서 Gradio라는 서비스를 알게 되어 간단하게 포스팅해보려고 한다.

 

 

Gradio

https://www.gradio.app/

 

Gradio

Build & Share Delightful Machine Learning Apps

www.gradio.app

Gradio는 누구나 어디서나 사용할 수 있도록 친숙한 웹 인터페이스로 기계 학습 모델을 시연하는 가장 빠른 방법이라고 공식 홈페이지에서 소개하고 있다. 허깅페이스나 Streamlit과는 또 다르다. 블록을 쌓아서 아주 쉽게 모델을 만들 수 있고, 특히 GPT를 활용한 생성형 서비스를 쉽게 만들 수 있다.

 

 

우리가 만든 서비스

조별 과제를 진행하면서 생성형 API를 이용해서 간단하게 영어 교육 서비스를 만들었다.

우리가 인식한 문제는 영어 교육이 개별 단어 단위로 진행되다 보니 응용이 어렵고, 새로운 문장을 접했을 때 이해가 어렵다는 것이었다.

그래서 Chunk(덩어리) 중심으로 학습해서 문장을 더 빠르게 이해할 수 있도록 돕고자 했다.

 

유료 api key 만료로 Error가 표시되고 있음

서비스 흐름은 아래와 같다.

 

1. 영어 공부를 하기 위해 유튜브에서 영어로 된 영상을 찾는다.

    예시) https://www.youtube.com/watch?v=45F2kH144zY

2. 유튜브 영상 주소를 붙여 넣고 Run을 누르면, 영상에 있는 영어 회화가 문장 단위로 추출된다.

4. 그 중 공부하고 싶은 문장을 넣고 chunk!!!를 누르면 GPT가 문장에서 chunk를 추출하고 다시 그 chunk를 활용한 예시를 3개 만들어 준다.

    예시)

🔔 chunk !!
* make sure to : 확실히 ~ 하다.

⭐ 예시로 더 잘 이해해보기 
* "Make sure to wear a helmet when riding your unicorn to work."
의미: "직장에 유니콘을 타고 갈 때 헬멧을 반드시 쓰세요."

* "Make sure to bring your pet rock to the important business meeting."
의미: "중요한 업무 회의 때 애완용 돌을 꼭 가져와 주세요."

* "Make sure to do the chicken dance at the fancy gala dinner."
의미: "화려한 갈라 디너에서 꼭 치킨 댄스를 춰 주세요."

 

 

코드

아래 코드는 openai.api_key에 유료 plan의 api key를 넣어야 제대로 동작한다. Gradio 공식 홈페이지에서 문서를 보면 유료 키 없이도 훨씬 간단하게 모델을 만들 수 있으니 한번 튜토리얼을 따라해 보면 좋을 것 같다!

import openai
import re
import gradio as gr
from youtube_transcript_api import YouTubeTranscriptApi

# API KEY
openai.api_key = 'xxxx'

prompt_template = """영어로 된 문장을 줄테니 그 안에서 chunk를 하나 추출하고 그 chunk를 바탕으로 재밌는 영문 예제를 3개 만들어 줘.
1. 문장에서 chunk를 딱 1개만 추출하고 영어와 한글 뜻을 설명해 줘.  (이 부분은 "🧚 chunk !!" 로 시작해줘!!)
2. 그리고 다음에 그 chunk를 바탕으로 재미있는 영문 예제를 3개 만들어 줘. (이 부분은 "🧞‍♂️ 예시로 더 잘 이해해보기" 로 시작해줘 ) 

이것은 예시야:
---
입력:
문장 : I always make sure to eat breakfast. 
chunk : make sure to 

출력:
🔔 chunk !!
* make sure to : 확실히 ~ 하다.

⭐ 예시로 더 잘 이해해보기 
* "Make sure to wear a helmet when riding your unicorn to work."
의미: "직장에 유니콘을 타고 갈 때 헬멧을 반드시 쓰세요."

* "Make sure to bring your pet rock to the important business meeting."
의미: "중요한 업무 회의 때 애완용 돌을 꼭 가져와 주세요."

* "Make sure to do the chicken dance at the fancy gala dinner."
의미: "화려한 갈라 디너에서 꼭 치킨 댄스를 춰 주세요."

---
문장 : {sentence}
출력:"""

def call_openai(sentence):
    # 프롬프트가 받는 유저의 인풋을 정의
    prompt = prompt_template.format(sentence=sentence)
    input_openai_format = [{"role": "user", "content": prompt }]
    response = openai.ChatCompletion.create(
        model='gpt-3.5-turbo',
        messages= input_openai_format,
        temperature=1.0,
    )
    ai_reply = response['choices'][0]['message']['content']
    # 결과 출력 파트, 나중에 이 부분을 DB 와 연결해서 데이터를 쌓을 수 있음
    # print('input: ', sentence)
    # print('result: ', ai_reply)
    return ai_reply


def get_transcripts(link):
    video_id = link.split("v=")[1]
    try:
        srt = YouTubeTranscriptApi.get_transcript(video_id, languages=['en'])
        # 시간 정보를 제거하고 텍스트만 가져오기
        full_text = " ".join([item['text'] for item in srt])
        # 문장 구분 (마침표, 물음표, 느낌표를 기준으로)
        sentences = re.split(r'(?<=[.!?])\s+', full_text)
        # 문장 앞에 번호 붙이기
        numbered_sentences = "\n".join([f"{idx+1}. {sentence}" for idx, sentence in enumerate(sentences)])
        return numbered_sentences
    except Exception as e:
        return str(e)


with gr.Blocks() as demo:
    gr.Markdown("영어 문장을 입력하시면 Chunk를 추출하고, Chunk를 활용한 재밌는 예시를 만들어 드려요 !!!")
    with gr.Row():
        with gr.Column():
            link = gr.Textbox(label="YouTube Link", placeholder="https://www.youtube.com/watch?v=...")
            link_submit = gr.Button(label='submit')
        scripts = gr.Textbox(label='script')
    with gr.Row():
        input12 = gr.Textbox(label="문장", placeholder="sentence")


    button = gr.Button("chunk !!!")
    output_field = gr.Textbox(label="result")

    link_submit.click(fn=get_transcripts, inputs=[link], outputs=scripts)
    button.click(fn=call_openai, inputs=[input12], outputs=output_field)

demo.launch(share=True)