[Gradio] 챗봇 어플리케이션

Hunie_07·2025년 3월 26일
0

Langchain

목록 보기
3/35

📌 Gradio

1️⃣ 라이브러리 설치

  • conda 환경 : pip install gradio
  • poetry 환경 : poetry add gradio

2️⃣ 기본 구조

import gradio as gr

# 챗봇 함수 정의
def chat_function(message, history):
    return "응답 메시지"

# 챗봇 인터페이스 생성
demo = gr.ChatInterface(
    fn=chat_function,  # 실행할 함수
    analytics_enabled=False,  # 사용 정보 제공 여부
)

# 챗봇 인터페이스 실행
demo.launch()

- 출력 1

* Running on local URL:  http://127.0.0.1:7860

To create a public link, set `share=True` in `launch()`.

Notebook 파일 (.ipynb) 에서 실행할 경우 셀에 바로 출력된다.

local URL 을 실행하면 웹에 Gradio 인터페이스가 실행된다.


- 출력 2

* Running on local URL:  http://127.0.0.1:7863
* Running on public URL: https://8d7a7ed2653b830de4.gradio.live

This share link expires in 72 hours. For free permanent hosting and GPU upgrades, run `gradio deploy` from the terminal in the working directory to deploy to Hugging Face Spaces (https://huggingface.co/spaces)

실행 시 demo.launch(share=True) 옵션을 부여하면 72시간동안 공유 가능한 링크가 추가 생성된다.

HuggingFace 의 개인 Spaces 에 배포도 가능하다. (추후 업로드 예정)



# 인터페이스 종료
demo.close()

- 출력

Closing server running on port: 7860

인터페이스 및 서버 종료 하는 것을 잊지 말자.


3️⃣ 간단한 예제: Echo 챗봇

def echo_bot(message, history):
    return f"당신이 입력한 메시지: {message}"

demo = gr.ChatInterface(
    fn=echo_bot,
    title="Echo 챗봇",
    description="입력한 메시지를 그대로 되돌려주는 챗봇입니다.",
    analytics_enabled=False,  
)

demo.launch()

demo.close()

4️⃣ 스트리밍 응답

# 스트리밍 챗봇 함수 정의
import time

def streaming_bot(message, history):
    response = f"처리 중인 메시지: {message}"
    for i in range(len(response)):
        time.sleep(0.1)          # 0.1초 대기
        yield response[:i+1]
# 스트리밍 챗봇 인터페이스 생성
demo = gr.ChatInterface(
    fn=streaming_bot,
    title="스트리밍 챗봇",
    description="입력한 메시지를 한 글자씩 처리하는 챗봇입니다.",
    analytics_enabled=False,  
)

# 스트리밍 챗봇 인터페이스 실행
demo.launch()


5️⃣ 추가 입력 컴포넌트

  • Temperature, max_tokens 등과 같은 설정을 위한 추가 입력
from langchain_openai import ChatOpenAI
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# 프롬프트 템플릿 정의
prompt = ChatPromptTemplate.from_messages([
    ("system", "당신은 파이썬(Python) 코드 작성을 도와주는 AI 어시스턴트입니다."),
    ("human", "{user_input}")
])

# 챗봇 함수 정의
def chat_function(message, history, model, temperature):
    if model == "gpt-4o-mini":
        model = ChatOpenAI(model=model, temperature=temperature)
    elif model == "gemini-1.5-flash":
        model = ChatGoogleGenerativeAI(model=model, temperature=temperature)

    chain = prompt | model | StrOutputParser()

    response = chain.invoke({
        "user_input": message
    })
    return response

# 챗봇 인터페이스 생성
with gr.Blocks() as demo:
    model_selector = gr.Dropdown(["gpt-4o-mini", "gemini-1.5-flash"], label="모델 선택")
    slider = gr.Slider(0.0, 1.0, label="Temperature", value=0.3, step=0.1, render=False)   

    gr.ChatInterface(
        fn=chat_function, 
        additional_inputs=[model_selector, slider],
        analytics_enabled=False,  
    )
    
# 챗봇 인터페이스 실행
demo.launch()

demo.close()

6️⃣ 예시 질문 설정

# 스트리밍 챗봇 함수 정의
import time

def streaming_bot(message, history):
    response = f"처리 중인 메시지: {message}"
    for i in range(len(response)):
        time.sleep(0.1)          # 0.1초 대기
        yield response[:i+1]
# 스트리밍 챗봇 인터페이스 생성
demo = gr.ChatInterface(
    fn=streaming_bot,
    title="스트리밍 챗봇",
    description="입력한 메시지를 한 글자씩 처리하는 챗봇입니다.",
    analytics_enabled=False,  
    examples=[
        "파이썬 코드를 작성하는 방법을 알려주세요",
        "파이썬에서 리스트를 정렬하는 방법은 무엇인가요?",
    ]    
)

# 스트리밍 챗봇 인터페이스 실행
demo.launch()

demo.close()    

7️⃣ 멀티모달 기능

  • multimodal=True 옵션

  • 이미지나 파일을 처리할 수 있는 멀티모달 챗봇 구현

  • message 파라미터:

    {
        "text": "user input", 
        "files": [
            "updated_file_1_path.ext",
            "updated_file_2_path.ext", 
            ...
        ]
    }
  • history 파라미터:

    [
        {"role": "user", "content": ("cat1.png")},
        {"role": "user", "content": ("cat2.png")},
        {"role": "user", "content": "What's the difference between these two images?"},
    ]
import gradio as gr
import base64
from langchain_core.messages import HumanMessage
from langchain_google_genai import ChatGoogleGenerativeAI

def convert_to_url(image_path):
    """이미지를 URL 형식으로 변환"""
    with open(image_path, "rb") as image_file:
        # 이미지를 base64로 인코딩
        encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
        return f"data:image/jpeg;base64,{encoded_string}"

def multimodal_bot(message, history):

    model = ChatGoogleGenerativeAI(model="gemini-1.5-pro")
    
    if isinstance(message, dict):
        # 텍스트와 파일 추출
        text = message.get("text", "")
        
        # 히스토리와 현재 메시지에서 모든 파일 경로 추출
        filepath_list = []
        
        # 히스토리에서 이미지 파일 추출
        print("History:", history)  # 디버깅용
        for exchange in history:
            user_message = exchange[0]
            if isinstance(user_message, tuple):  # 이미지 메시지 확인
                filepath_list.append(user_message[0])
        
        # 현재 메시지의 파일들도 추가
        files = message.get("files", [])
        filepath_list.extend(files)
        
        print("Filepath list:", filepath_list)  # 디버깅용
        
        if filepath_list:
            # 모든 이미지 처리
            image_urls = []
            for file_path in filepath_list:
                try:
                    image_url = convert_to_url(file_path)
                    image_urls.append({"type": "image_url", "image_url": image_url})
                except Exception as e:
                    print(f"이미지 처리 중 오류 발생: {e}")
                    continue
            
            if not image_urls:
                return "이미지 처리 중 오류가 발생했습니다."
            
            # 메시지 구성
            content = [
                {"type": "text", "text": text if text else "이 이미지들에 대해 설명해주세요."},
                *image_urls
            ]
            
            try:
                # API 호출
                response = model.invoke([
                    HumanMessage(content=content)
                ])
                return response.content
            except Exception as e:
                return f"모델 응답 생성 중 오류가 발생했습니다: {str(e)}"
        
        return text if text else "이미지를 업로드해주세요."
    
    return "텍스트나 이미지를 입력해주세요."

# Gradio 인터페이스 설정
demo = gr.ChatInterface(
    fn=multimodal_bot,
    multimodal=True,
    title="멀티모달 챗봇",
    description="텍스트와 이미지를 함께 처리할 수 있는 챗봇입니다. 이전 대화의 이미지들도 함께 고려합니다.",
    analytics_enabled=False,  
    textbox=gr.MultimodalTextbox(placeholder="텍스트를 입력하거나 이미지를 업로드해주세요.", file_count="multiple", file_types=["image"]),
)

# 인터페이스 실행
demo.launch()

demo.close()

8️⃣ PDF 뷰어

  • conda 환경 : pip install gradio_pdf
  • poetry 환경 : poetry add gradio_pdf
from gradio_pdf import PDF

def answer_invoke(message, history):   
    return message

with gr.Blocks(
    analytics_enabled=False,  
) as demo:
    with gr.Row():
        # API Key Section
        api_key_input = gr.Textbox(
            label="Enter OpenAI API Key",
            type="password",
            placeholder="sk-..."
        )
        
    with gr.Row():
        # PDF Upload and Chat Interface
        with gr.Column(scale=2):
            pdf_file = PDF(
                label="Upload PDF File",
                height=600,  # PDF 뷰어 높이 설정
            )
        with gr.Column(scale=1):
            chatbot = gr.ChatInterface(
                fn=answer_invoke,
                title="PDF-based Chatbot",
                description="Upload a PDF file and ask questions about its contents.",
            )

demo.launch()

demo.close()

9️⃣ Memory 추가

# chat_history 플레이스홀더를 사용
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage

# 메시지 플레이스홀더가 있는 프롬프트 템플릿 정의
prompt = ChatPromptTemplate.from_messages([
    ("system", "당신은 파이썬(Python) 코드 작성을 도와주는 AI 어시스턴트입니다."),
    MessagesPlaceholder("chat_history"),
    ("system", "이전 대화 내용을 참고하여 질문에 대해서 친절하게 답변합니다."),
    ("human", "{user_input}")
])

# 프롬프트 템플릿 + LLM 모델 + 출력파서를 연결하여 체인 생성
chain = prompt | model | StrOutputParser()

# 사용자 메시지를 처리하고 AI 응답을 생성하는 함수 (chat_history 사용)
def answer_invoke(message, history):

    history_messages = []
    for msg in history:
        if msg['role'] == "user":
            history_messages.append(HumanMessage(content=msg['content']))
        elif msg['role'] == "assistant":
            history_messages.append(AIMessage(content=msg['content']))

    history_messages.append(HumanMessage(content=message))
    response = chain.invoke({
        "chat_history": history_messages,
        "user_input": message
    })
    return response

# Gradio ChatInterface 객체 생성
demo = gr.ChatInterface(
    fn=answer_invoke,         # 메시지 처리 함수
    title="파이썬 코드 어시스턴트", # 채팅 인터페이스의 제목
    )

# Gradio 인터페이스 실행
demo.launch()
# Gradio 인터페이스 종료
demo.close()

0개의 댓글