김이언
김이언
🏅 AI 마스터
🌿 뉴비 파트너
🌈 지피터스금손

Langchain으로 영화 찾아보기(+Gradio)

간단하면서 확인이 가능한 주제를 선택했어요. 처음엔 창대한 아이디어가 있었으나 … 지금은 결과가 나온 것만으로도 좋습니다.🤗

목차

  1. Langchain으로 영화 찾아보기

  2. 데이터 준비

  3. 프로그램 흐름

  4. 프로그램 코딩

  5. 실행 결과

  6. 정리



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기랭체인

11
10개의 답글

👉 이 게시글도 읽어보세요