TOP
class="layout-aside-left paging-number">
본문 바로가기
[파이썬 Projects]/<파이썬 Gen AI>

[Gen AI] 그라디오로 챗봇 제작하기 - 1 (상담봇)

by 기록자_Recordian 2024. 12. 12.
728x90
반응형
이전 내용
 

[Gen AI] 그라디오(Gradio)

이전 내용 [Gen AI] OpenAI API 사용해보기 (로컬, 주피터노트북)이전 내용 [Gen AI] OpenAI API 키 발급하기Open AI API란? OpenAI에서 개발한 인공지능 모델을 프로그래밍 인터페이스로 제공하며, 외부 애플

puppy-foot-it.tistory.com


챗봇 디자인

 

[챗봇 디자인을 위한 핵심적인 사항]

◆ 사용자 인터페이스 설계

사용자 인터페이스(User Interface, UI)는 챗봇과 사용자 간의 상호 작용을 결정하는 중요한 요소로, 직관적이고 사욯아기 쉬워야 하며 사용자의 요구를 효과적으로 반영할 수 있어야 한다.

 

◆ 기능성

챗봇의 핵심 기능을 결정하는 것은 프로젝트의 방향을 정하는 데 매우 중요하다. 챗봇 서비스로 사용자에게 어떤 도움을 주기 원하는지 목적을 명확히 한 후 구현해야 할 목록을 작성한다.

 

◆ 기술적 구현

챗봇의 기술적 구현은 프로젝트에 결정적인 역할을 한다. 구현할 플랫폼을 선정하고, 그에 맞는 기술적 요구사항을 파악해야 한다. 거기에 사용자의 요구에 부합하는 알고리즘을 개발하여 챗봇의 효율성을 높여야 한다

 

▶ 위의 사항을 고려하여 가상의 매장을 위한 상담을 해주는 챗봇, 번역을 도와주는 챗봇, 소설을 작성해주는 챗봇을 만들어본다.

(필자의 경우는 십여년 전에 도전했다가 접었던 의류쇼핑몰을 현재 운영한다는 가정 하에 진행해본다.)


레이아웃 구성

 

가장 상단에는 각 챗봇을 탭으로 구분할 수 있도록 구성

 

◆ 상담봇

- 상단: 메시지를 주고받는 듯한 메시지 화면 구성

- 하단: 문의를 위한 입력 창, 문의 내용을 보내기 위한 버튼, 답변 삭제, 채팅 내역 초기화 기능

 

◆ 번역봇

- 번역에 필요한 핵심 기능만으로 구성.

- 번역 스타일과 번역할 언어를 설정하고 [번역] 버튼 추가

- 하단에는 번역할 내용을 입력할 공간과 출력할 공간으로 나누어 배치

 

◆ 소설봇

- 상단: 소설을 작성하기 위한 옵션 구성 (글자수 범위, 창의성 정도, 소설 세부 설정 등)

- 세부 설정은 아코디언 기능을 이용해 해당 옵션을 감출 수 있도록 구성


챗봇 기능 추가

 

[기능 추가 작업]

  • 1단계: 레이아웃 구성하는 코드 작성
  • 2단계: 각 레이아웃에 존재하는 기능 구현

1) 새로운 주피터노트북을 생성하고, 그라디오를 import 한 뒤, 레이아웃를 구성하기 위한 블록을 사용하여 코드 작성

import gradio as gr

with gr.Blocks(theme=gr.themes.Default()) as app:
    pass

app.launch()

theme 매개변수는 테마를 지정할 수 있는데, 기본적으로 제공되는 테마가 몇 가지 있다.

각 테마는 매개변수 theme에 각기 다른 코드를 입력하여 사용할 수 있다.

  • gr.themes.Base()
  • gr.themes.Default()
  • gr.themes.Glass()
  • gr.themes.Monochrome()
  • gr.themes.Soft()

물론, 사용자가 직접 만든 테마를 적용할 수도 있다.

또한, 허깅페이스에 올라온 테마의 상대 주소를 입력하는 방식으로 별도의 설치 없이 자동으로 테마를 적용시킬수도 있다.

(예. theme="freddyaboulton/test-blue")

[사용자 지정 테마 갤러리]

 

Theme Gallery - a Hugging Face Space by gradio

 

huggingface.co

 

블록은 형태를 가지고 있지 않기 때문에, 블록만으로는 어떠한 버튼이나 창을 나타내는 UI를 확인할 수 없다.

따라서 블록이 아닌 레이아웃 또는 컴포넌트를 구성하는 코드를 추가해야만 눈으로 직접 확인할 수 있다.

 

2) 앞서 계획했던 레이아웃에 따라 기능 구현하기 - 상담봇, 번역봇, 소설봇 탭 만들기

위 코드에서 pass 부분을 지우고, gr.Tab()을 사용해 세 가지 봇을 추가해준다.

import gradio as gr

with gr.Blocks(theme=gr.themes.Default()) as app:
    with gr.Tab("상담봇"):
        pass
    with gr.Tab("번역봇"):
        pass
    with gr.Tab("소설봇"):
        pass

app.launch()

이 코드를 실행해보면 '상담봇', '번역봇', '소설봇' 이라는 탭이 생성된 것을 확인할 수 있다.

3) 상담봇 작업하기

3-1)레이아웃 추가

gr.Column() 은 세로로 블록을 쌓을 때, gr.Row는 가로로 블록을 쌓을 때 사용하는데, 그라디오는 기본값으로 블록을 세로로 쌓는 것을 지원하기 때문에 gr.Column()은 생략할 수 있다.

gr.Tab() 아래에 좀 더 세부적인 레이아웃 코드를 추가해준다.

with gr.Blocks(theme=gr.themes.Default()) as app:
    with gr.Tab("상담봇"):
        gr.Markdown()
        gr.Chatbot()
        with gr.Row():
            gr.Text()
            gr.Button()
        with gr.Row():
            gr.Button()
            gr.Button()

 

3-2) 컴포넌트 추가

각각의 컴포넌트에 구체적인 매개변수를 작성하여 레이아웃을 구성해 본다.

 

- 타이틀 및 설명: gr.Markdown() 부분에 역할을 알려 주는 타이틀 레이아웃을 구현한다.

with gr.Blocks(theme=gr.themes.Default()) as app:
    with gr.Tab("상담봇"):
        gr.Markdown(
            value="""
            #  <center>상담봇</center>
            <center> DUDE 상담봇입니다. 판매하는 상품과 관련된 질문에 답변 드립니다.</center>
        """)
        gr.Chatbot()
# 이하 코드 생략


★ 마크다운 문법

주피터노트북 Run - Cell Type - Change to Markdown Cell Type 을 들어가서 테스트해볼 수 있다.

# 이것은 제목 1입니다
## 이것은 제목 2입니다
### 이것은 제목 3입니다
#### 이것은 제목 4입니다
<center>가운데 정렬</center>


- 채팅 화면: 상담봇과의 채팅 내역이 나타나는 채팅 화면 레이아웃을 구현해본다.

# 상단 코드 생략
        gr.Chatbot(
            value=[[None, "안녕하세요, DUDE 입니다. 상담을 도와드리겠습니다."]],
            show_label=False
        )
# 하단 코드 생략

value는 채팅 내역을 저장하는 역할을 하며, value에 들어갈 값의 형태는 [[ , ], [ , ],...]와 같이 리스트 안에 크기 2의 리스트를 필요한 만큼 넣는 형태이다. 안에 들어가는 크기 2의 리스트에서

  • 첫 번째 원소: 사용자가 입력한 채팅 내용
  • 두 번째 원소: 챗봇의 채팅 내용

show_label=False로 설정하여 채팅 레이아웃 좌측 상단의 작은 Chatbot 라벨을 제거한다.

 

- 입력 창: 채팅 내용을 작성하는 영역이다.

# 상단 코드 생략
        with gr.Row():
            gr.Text(
                lines=1,
                placeholder="입력 창",
                container=False,
                scale=9
            )
# 하단 코드 생략
  • lines: 화면에 표시할 입력칸의 행의 개수
  • placeholder: 입력 칸에 예시로 표시할 텍스트
  • container: 텍스트 박스의 테두리 표시 여부 (기본값은 True), False로 설정 시 Textbox의 바깥 테두리와 Label(Textbox라고 표시된 텍스트 영역) 제거
  • scale: 같은 레이아웃 영역 안의 컴포넌트들 사이에서 차지할 공간의 비중

- 보내기 버튼: 작성된 내용을 보낼 수 있는 [보내기] 버튼 레이아웃을 구현한다.

# 상단 코드 생략
            gr.Button(
                value="보내기",
                scale=1,
                variant="primary",
                icon="https://cdn-icons-png.flaticon.com/128/12439/12439334.png"
            )
# 하단 코드 생략
  • value: 버튼에 들어갈 글자의 값
  • variant: gr.Blocks()에서 사전 정의된 테마의 설정값을 참조하여 버튼의 스파일 변경. [보내기] 버튼의 중요성을 강조하기 위해 "primary"
  • 참조할 수 있는 키워드: primary, secondary, neutral, stop
  • icon: 버튼의 텍스트 앞에 이미지를 입력할 수 있게 하는 기능 (프로젝트 내의 이미지 경로나 웹에서 탐색할 수 있는 이미지의 URL 입력 가능)

해당 URL은 아래의 이미지이다.

https://cdn-icons-png.flaticon.com/128/12439/12439334.png

 

 

- 되돌리기, 초기화 버튼: 채팅 내역을 순차적으로 삭제하는 [되돌리기] 버튼과 채팅 내역을 처음으로 되돌리는 [초기화] 버튼 레이아웃을 구현한다.

# 상단 코드 생략
        with gr.Row():
            gr.Button(
                value="↪️되돌리기")
            gr.Button(
                value="🔄️초기화")
# 하단 코드 생략

이모지의 경우, windows + . 또는 ; 을 누르면 선택할 수 있다. (필자의 경우, windows + . 누른 뒤, 이모지 검색 창에서 "화살표"를 검색했다.)

이렇게 하면, 상담봇의 레이아웃 구현이 완료된다.

 

3-3) 채팅 기능 + 되돌리기 기능 + 초기화 기능 구현하기

이번에는 상담봇의 채팅 및 답변 기능, 되돌리기 기능, 초기화 기능을 구현해본다.

 

- 채팅 기능: 정확한 기능은, 입력 창에 상담하고 싶은 내용을 입력한 후 Enter 또는 [보내기] 버튼을 누르면 챗봇의 답변이 채팅 화면에 출력되는 기능이다.

 

- 되돌리기 기능: [되돌리기] 버튼을 클릭하면 채팅 내역을 하나씩 삭제하는 기능

 

- 초기화 기능: [초기화] 버튼을 클릭하면 대화 내역을 초기화하는 기능

레이아웃 위에서 함수를 미리 정의하여 레이아웃 코드에서 사용할 수 있도록 한다.

import gradio as gr

# 상담봇 - 채팅 및 답변
def counseling_bot_chat(message, chat_history):
    if message == "":
        return "", chat_history
    else:
        completion = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "당신은 DUDE의 상담원입니다. 쇼핑몰 상품과 관련되지 않은 질문에는 정중히 거절하세요."},
                {"role": "user", "content": message}
            ]
        )
        # 과거버전: chat_history.append([message, completion.choices[0].message["content"]])
        # 현재버전
        chat_history.append([message, completion.choices[0].message.content])
        return "", chat_history

# 상담봇 - 되돌리기
def counseling_bot_undo(chat_history):
    if len(chat_history) > 1:
        chat_history.pop()
    return chat_history

# 상담봇 - 초기화
def counseling_bot_reset(chat_hisotry):
    chat_history=[[None, "안녕하세요, DUDE 입니다. 상담을 도와드리겠습니다."]]
    return chat_history

# 레이아웃

- 채팅 및 답변 함수

  • counseling_chat_bot()
  • 매개변수: 사용자의 입력 내용을 받을 message, 채팅 내역을 받을 chat_history 정의
  • 출력값: 입력 창에 반환할 빈 문자열과 채팅 화면에 반환할 chat_history 정의
  • 사용자가 아무 입력도 넣지 않았을 경우, 입력받은 매개변수를 그대로 돌려준다.
  • 사용자의 입력이 빈 값이 아닐 경우, OpenAI API를 호출해 데이터를 받으며, 받은 데이터는 chat_history에 리스트를 추가하여 return
  • chat_history.append([message, completion.choices[0].message["content"]]) 부분의 경우, OpenAI API가 업데이트 되면서 해당 코드로 입력하게 되면, "TypeError: 'ChatCompletionMessage' object is not subscriptable" 오류를 받으니, chat_history.append([message, completion.choices[0].message.content]) 으로 입력.

- 되돌리기 함수

  • counseling_chat_undo()
  • 매개변수: chat_history
  • if문을 통해 chat_history의 값이 1개보다 많은지 체크.
  • pop() 함수를 호출해 chat_history 리스트의  가장 마지막 요소를 제거하고 수정된 chat_history를 return

- 초기화 함수

  • counseling_chat_reset()
  • gr.Chatbot의 매개변수 value의 기본값 재정의 후, 재정의된 chat_history 반환

3-4) 변수에 컴포넌트 바인딩하기

앞서 작성한 함수들을 컴포넌트에 연결하기 위해 변수를 생성하고 바인딩해준다.

컴포넌트가 변수에 바인딩되어야 다른 함수나 변수에서 해당 기능을 호출할 수 있다.

(cb = counseling_bot)

 

3-5) 이벤트 리스너 추가하기

되돌리기 버튼 부분, 초기화 버튼 부분 컴포넌트와 cb_user_input, cb_send_btn 변수에 이벤트 리스너를 추가해준다.

※ 이벤트 리스너란 이벤트가 발생했을 때 그 처리를 담당하는 함수를 가리키며, 이벤트 핸들러(event handler)라고도 한다. 지정된 타입의 이벤트가 특정 요소에서 발생하면, 웹 브라우저는 그 요소에 등록된 이벤트 리스너를 실행시킨다.

 

여기서 이벤트 리스너 click은 버튼을 클릭했을 때 해당하는 컴포넌트의 이벤트 리스너에서 정의한 함수를 실행한다.

  • fn: 실행할 함수 참조
  • inputs: fn에서 참조한 함수가 필요로 하는 매개변수의 값
  • outputs: fn에서 참조한 함수가 return 하는 값
        with gr.Row():
            gr.Button(value="↪️되돌리기").click(fn=counseling_bot_undo, inputs=cb_chatbot, outputs=cb_chatbot)
            gr.Button(value="🔄️초기화").click(fn=counseling_bot_reset, inputs=cb_chatbot, outputs=cb_chatbot)
            # 보내기1
            cb_send_btn.click(fn=counseling_bot_chat, inputs=[cb_user_input, cb_chatbot], outputs=[cb_user_input, cb_chatbot])
            # 보내기2
            cb_user_input.submit(fn=counseling_bot_chat, inputs=[cb_user_input, cb_chatbot], outputs=[cb_user_input, cb_chatbot])

  • 이벤트 리스너

- 각각의 이벤트 리스너인 click의 매개변수 fn에는 counseling_bot_undo와  counseling_bot_reset을 대입한다.

- inputs에는 두 함수에서 공통적으로 사용하는 챗봇 컴포넌트를 입력한다.

- outputs에도 출력한 값을 적용할 챗봄 컴포넌트를 입력한다.

  • 보내기 1은 보내기 버튼을 클릭한 경우에 발생할 이벤트를 정의한다. (cb_send_btn 변수에 이벤트 리스너 click 추가)
  • 보내기 2는 입력 창에 글을 쓴 후 키보드의 Enter를 눌렀을 때 발생할 이벤트를 정의한다. (cb_send_btn 변수에 이벤트 리스너 submit 추가)

3-6) OpenAI 모듈 import 및 OpenAI API 키 추가하기

import os
from openai import OpenAI

# OpenAI 클라이언트 설정
client = OpenAI(
    api_key=os.environ['OPENAI_API_KEY'])

해당 챗봇은 gpt-3.5-turbo 모델을 이용하므로, OpenAI 모듈을 import 하고, 자신의 OpenAI API Key를 입력해야 한다.필자의 경우엔 OpenAI API Key를 시스템 환경 변수에 추가해뒀다. (또한, 본인의 OpenAI API 계정에 크레딧이 있는지도 확인해보고, 없으면 충전한다.)

※ 24년 12월 12일 기준, OpenAI API 가 업데이트 되어, 먼저 openai API 를 업그레이드할 필요가 있다.

pip install --upgrade openai

 

3-7) 실행하기

일부 코드를 수정 및 보완하여 실행해보았다.

 

 

◆ 상담봇 전체코드

현재(24년 12월 12일) OpenAI API 버전에 맞게 수정한 전체 코드이다.

import gradio as gr
import os
from openai import OpenAI

# OpenAI 클라이언트 설정
client = OpenAI(
    api_key=os.environ['OPENAI_API_KEY'])

# 상담봇 - 채팅 및 답변
def counseling_bot_chat(message, chat_history):
    if message == "":
        return "", chat_history
    else:
        completion = openai.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "당신은 DUDE의 상담원입니다. 쇼핑몰 상품과 관련되지 않은 질문에는 정중히 거절하세요."},
                {"role": "user", "content": message}
            ]
        )
        chat_history.append([message, completion.choices[0].message.content])
        return "", chat_history

# 상담봇 - 되돌리기
def counseling_bot_undo(chat_history):
    if len(chat_history) > 1:
        chat_history.pop()
    return chat_history

# 상담봇 - 초기화
def counseling_bot_reset(chat_hisotry):
    chat_history=[[None, "안녕하세요, DUDE 입니다. 상담을 도와드리겠습니다."]]
    return chat_history

# 레이아웃
with gr.Blocks(theme=gr.themes.Default()) as app:
    with gr.Tab("상담봇"):
        gr.Markdown(
            value="""
            #  <center>상담봇</center>
            <center> DUDE 상담봇입니다. 판매하는 상품과 관련된 질문에 답변 드립니다.</center>
        """)
        cb_chatbot=gr.Chatbot(
            value=[[None, "안녕하세요, DUDE 입니다. 상담을 도와드리겠습니다."]],
            show_label=False
        )
        with gr.Row():
            cb_user_input=gr.Text(
                lines=1,
                placeholder="입력 창",
                container=False,
                scale=9
            )
            cb_send_btn=gr.Button(
                value="보내기",
                scale=1,
                variant="primary",
                icon="https://cdn-icons-png.flaticon.com/128/12439/12439334.png"
            )
        with gr.Row():
            gr.Button(value="↪️되돌리기").click(fn=counseling_bot_undo, inputs=cb_chatbot, outputs=cb_chatbot)
            gr.Button(value="🔄️초기화").click(fn=counseling_bot_reset, inputs=cb_chatbot, outputs=cb_chatbot)
            # 보내기1
            cb_send_btn.click(fn=counseling_bot_chat, inputs=[cb_user_input, cb_chatbot], outputs=[cb_user_input, cb_chatbot])
            # 보내기2
            cb_user_input.submit(fn=counseling_bot_chat, inputs=[cb_user_input, cb_chatbot], outputs=[cb_user_input, cb_chatbot])
    with gr.Tab("번역봇"):
        pass
    with gr.Tab("소설봇"):
        pass

app.launch()

 

다음에는 번역봇을 구현하도록 한다.


다음 내용

 

[Gen AI] 그라디오로 챗봇 제작하기 - 2 (번역봇)

이전 내용 [Gen AI] 그라디오로 챗봇 제작하기 - 1 (상담봇)이전 내용 [Gen AI] 그라디오(Gradio)이전 내용 [Gen AI] OpenAI API 사용해보기 (로컬, 주피터노트북)이전 내용 [Gen AI] OpenAI API 키 발급하기Open AI

puppy-foot-it.tistory.com


[출처]

Hey, 파이썬! 생성형 AI 활용 앱 만들어줘

그라디오 홈페이지

https://stackoverflow.com/questions/77444332/openai-python-package-error-chatcompletion-object-is-not-subscriptable

https://community.openai.com/t/chatcompletion-issues-can-anyone-help/479462/5

https://blog.naver.com/imbgirl/221969734876

https://www.tcpschool.com/javascript/js_event_eventListenerRegister

728x90
반응형