간단하면서 확인이 가능한 주제를 선택했어요. 처음엔 창대한 아이디어가 있었으나 … 지금은 결과가 나온 것만으로도 좋습니다.🤗
목차
Langchain으로 영화 찾아보기
데이터 준비
프로그램 흐름
프로그램 코딩
실행 결과
정리
1. Langchain으로 영화 찾아보기
영화 데이터베이스를 대상으로 자연어로 질문하고, 원하는 정보를 얻는 심플한 내용입니다. 유사한 주제를 찾아보니 웹 크롤링을 하여 데이터를 만드는 사례가 있었는데, 초보답게 데이터베이스를 이용했습니다.😁 웹 UI에서 질문하고, 응답을 얻을 수 있도록 Gradio를 추가했습니다.
다음을 참고했습니다.
2. 데이터 준비
Kaggle에서 최신의 영화 정보를 포함한 Full TMDB Movies Dataset 2024 (1M Movies)를 다운로드합니다. 파일명은 ‘TMDB_movie_dataset_v11.csv’로 csv 포맷이고, 총 레코드는 1,048,575 개이고 column 구성은 다음과 같습니다.
id: Unique identifier for each movie. (type: int)
title: Title of the movie. (type: str)
vote_average: Average vote or rating given by viewers. (type: float)
vote_count: Total count of votes received for the movie. (type: int)
status: The status of the movie (e.g., Released, Rumored, Post Production, etc.). (type: str)
release_date: Date when the movie was released. (type: str)
revenue: Total revenue generated by the movie. (type: int)
runtime: Duration of the movie in minutes. (type: int)
adult: Indicates if the movie is suitable only for adult audiences. (type: bool)
backdrop_path: URL of the backdrop image for the movie. (type: str)
budget: Budget allocated for the movie. (type: int)
homepage: Official homepage URL of the movie. (type: str)
imdb_id: IMDb ID of the movie. (type: str)
original_language: Original language in which the movie was produced. (type: str)
original_title: Original title of the movie. (type: str)
overview: Brief description or summary of the movie. (type: str)
popularity: Popularity score of the movie. (type: float)
poster_path: URL of the movie poster image. (type: str)
tagline: Catchphrase or memorable line associated with the movie. (type: str)
genres; List of genres the movie belongs to. (type: str)
production_companies: List of production companies involved in the movie. (type: str)
production_countries: List of countries involved in the movie production. (type: str)
spoken_languages: List of languages spoken in the movie. (type: str)
keywords: Keywords associated with the movie. Do `.split(", ")` to convert to a list. (type: str)
3. 프로그램 흐름
(Excalidraw를 처음 써보았는데 재미있습니다 😍)
중요 기능
csv 파일로 SQLite 데이터베이스를 구성합니다.
입력 처리: 사용자 입력을 SQL 쿼리로 변환하고 실행하여 결과 반환하는 에이전트인 agent_executor를 생성합니다.
출력 처리: SQL 결과를 자연어 응답으로 변환하는 체인 answer_chain을 구성합니다.
Gradio UI 스타일을 위한 CSS 정의합니다.
웹에서 실행: 사용자 입력을 처리하고 영화 정보를 검색하여 응답을 생성하는 함수인 movie_assistant를 작성합니다.
웹 UI의 입력창에 질문이 입력되면 movie_assistant가 동작하여 먼저 SQL 쿼리를 데이터베이스에 실행하고 결과를 반환(agent_executor)합니다. 이 결과는 자연어 응답으로 변환되어(answer_chain) 출력창에 표시됩니다.
4. 프로그램 코딩
# 환경변수 등록
import pandas as pd
from sqlalchemy import create_engine
from langchain_community.utilities import SQLDatabase
from langchain_community.agent_toolkits import create_sql_agent
from langchain_openai import ChatOpenAI
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# CSV 파일에서 영화 데이터를 읽어 pandas 데이터프레임으로 변환
df = pd.read_csv('./db/TMDB_movie_dataset_v11.csv')
# SQLite 데이터베이스 연결을 위한 엔진 생성
engine = create_engine("sqlite:///movies.db")
# 생성된 데이터프레임을 SQLite 데이터베이스의 movies 테이블로 저장(기존 테이블이 있으면 덮어쓰기)
df.to_sql('movies', engine, if_exists='replace', index=False)
# SQLAlchemy를 사용하여 SQLite 데이터베이스 객체 생성
movies_db = SQLDatabase.from_uri("sqlite:///movies.db")
# OpenAI의 GPT-4o 모델을 사용하여 LLM 인스턴스 생성
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# SQL 데이터베이스와 상호작용하는 에이전트 생성
# 에이전트는 사용자 입력을 SQL 쿼리로 변환하고 실행하여 결과 반환
agent_executor = create_sql_agent(llm, db=movies_db, agent_type="openai-tools", verbose=True)
# 사용자 질문에 대한 응답을 생성하기 위한 프롬프트 템플릿 정의
answer_prompt = """
You're a friendly AI assistant. See the results of running a given SQL query and generate natural responses to questions.
SQL query execution result:
{sql_result}
Natural language response:
"""
# 프롬프트 템플릿 객체 생성
answer_prompt_template = ChatPromptTemplate.from_template(answer_prompt)
# SQL 결과를 자연어 응답으로 변환하는 체인 구성
answer_chain = answer_prompt_template | llm | StrOutputParser()
import gradio as gr # Gradio UI 구성용
import base64 # 이미지 인코딩용
# 로고 이미지를 Base64 형식으로 인코딩하여 HTML에 직접 삽입 가능하도록 변환
with open("assets/movie1.gif", "rb") as image_file:
encoded_string = base64.b64encode(image_file.read()).decode()
# Gradio UI 스타일을 위한 CSS 정의
css = """
#custom-title {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
}
#custom-title img {
width: 50px;
height: 50px;
margin-right: 10px;
}
#custom-title h1 {
font-size: 24px;
}
"""
# 인코딩된 이미지와 제목을 포함한 HTML 구조 정의
title_html = f"""
<div id="custom-title">
<img src="data:image/png;base64,{encoded_string}" alt="AI CineSearch Icon">
<h1>AI CineSearch</h1>
</div>
"""
# 사용자 입력을 처리하고 영화 정보를 검색하여 응답을 생성하는 함수
def movie_assistant(user_input):
query = agent_executor.invoke({"input": user_input}) # 사용자 입력을 SQL 쿼리로 변환 및 실행
result = answer_chain.invoke({"sql_result": query}) # SQL 결과를 자연어 응답으로 변환
return result # 생성된 응답 반환
# Gradio UI 구성 및 설정
iface = gr.Interface(
fn=movie_assistant, # 인터페이스에서 호출할 함수 지정
inputs=[gr.Textbox(label="어떤 영화를 찾으시나요?", lines=10)], # 사용자 입력 텍스트박스
outputs=[gr.Textbox(label="AI가 찾은 영화입니다.", lines=10)], # 결과 출력 텍스트박스
description=title_html, # 상단에 표시될 제목 및 로고
examples=[["픽사 영화를 추천해줘"], ["로맨틱 코미디 top 5"], ["해리 포터 시리즈를 인기도 순으로 알려줘"]], # 예시 질문 설정
article="by Aeon Kim",
css=css # CSS 스타일 적용
)
# 디버그 모드로 Gradio 인터페이스 실행
iface.launch(debug = True)5. 실행 결과
Vscode에서 프로그램을 실행하고, 콘솔에 나온 다음 로컬 주소를 웹 브라우저에 입력합니다.
첫 화면은 타이틀, 입력창, 출력창, 그리고 예시질문으로 구성되어 있습니다.
예시 질문을 수행한 화면입니다.
6. 정리
체인이 무엇인지, LLM과 결합한다는 것이 어떤 의미인지 조금은 알 것 같습니다. 이런 효과 때문에 지피터스의 사례 작성이 정말 좋은 학습법이라고 생각합니다. 다음엔 보다 발전된 예시를 만들어보 …ㄹ 수 있을까요?! 🥲
#11기랭체인