Langchain [5]

yuyeong·2024년 7월 27일
0

LangChain

목록 보기
4/4
post-thumbnail

문장 나누기

rag 기법으로 처리하기에는 너무 길어질 수 있기 때문에 text splitters모듈로 문맥을 유지하면서 문장을 적절히 분할해야한다.

spaCy

spaCy는 파이썬으로 개발된 자연어 처리 라이브러리이다.
자연어 처리는 인간이 일상에서 사용하는 언어를 컴퓨터가 이해하고 분석할 수 있는 일련의 기술이다.

1. spaCy 설치

python3 -m pip install spacy

한국어에 대응하는 다운로드 실행

python3 -m spacy download ko_core_news_sm
from langchain.document_loaders import PyMuPDFLoader
from langchain.text_splitter import SpacyTextSplitter  #← SpacyTextSplitter를 가져옴

file_path = "/Users/jeong-yuyeong/Documents/GitHub/LangChain/03_retrieval/sample.pdf"
loader = PyMuPDFLoader(file_path) # sample.pdf 로드
documents = loader.load()

text_splitter = SpacyTextSplitter(  #← SpacyTextSplitter를 초기화
    chunk_size=300,  #← 분할할 크기를 설정
    pipeline="ko_core_news_sm"  #← 분할에 사용할 언어 모델을 설정
)
splitted_documents = text_splitter.split_documents(documents) #← 문서를 분할

print(f"분할 전 문서 개수: {len(documents)}")
print(f"분할 후 문서 개수: {len(splitted_documents)}")

의 결과는 다음과 같다.

분할 전 문서 개수: 12
분할 후 문서 개수: 70

위 코드에서는 SpacyTextSplitter를 가져오고 chunk_size 매개변수를 통해 문장을 분할할 크기를 설정한다.

분할된 문장을 벡터화해 데이터베이스에 저장한다.

open ai 임베딩을 이용하려면 파이썬 패키지인 tiktoken이 필요하다.

python3 -m pip install tiktoken

벡터 데이터 베이스로 크로마를 사용한다. 크로마는 오픈 소프 벡터 데이터베이스로 설치로 쉽게 작동 가능하다.

python3 -m pip install chromadb
from langchain.document_loaders import PyMuPDFLoader
from langchain.embeddings import OpenAIEmbeddings  #← OpenAIEmbeddings 가져오기
from langchain.text_splitter import SpacyTextSplitter
from langchain.vectorstores import Chroma  #← Chroma 가져오기

loader = PyMuPDFLoader("./sample.pdf")
documents = loader.load()

text_splitter = SpacyTextSplitter(
    chunk_size=300, 
    pipeline="ko_core_news_sm"
)
splitted_documents = text_splitter.split_documents(documents)

embeddings = OpenAIEmbeddings( #← OpenAIEmbeddings를 초기화
    model="text-embedding-ada-002" #← 모델명을 지정
)

database = Chroma(  #← Chroma를 초기화
    persist_directory="./.data",  #← 영속화 데이터 저장 위치 지정
    embedding_function=embeddings  #← 벡터화할 모델을 지정
)

database.add_documents(  #← 문서를 데이터베이스에 추가
    splitted_documents,  #← 추가할 문서 지정
)

print("데이터베이스 생성이 완료되었습니다.") #← 완료 알림

이를 통해 랭체인을 사용하여 pdf 문장을 읽고 문장을 적절한 크기로 분할하고, 그 문장을 벡터화해 데이터베이스에 저장하기까지의 작동을 확인하고 작업을 완료했다.

채팅 화면 만들기

파이썬으로 채팅화면을 만들 수 있는 chainlit 이란 라이브러리를 사용해 브라우저에서 실제 사용할 수 있는 애플리케이션을 만들어보자.

python -m pip install chainit==0.5.1
import chainlit as cl


@cl.on_chat_start #← 채팅이 시작될 때 실행할 함수를 정의
async def on_chat_start():
    await cl.Message(content="준비되었습니다! 메시지를 입력하세요!").send() #← 초기에 표시할 메시지를 보냄

@cl.on_message #← 메시지를 보낼 때 실행할 함수를 정의
async def on_message(input_message):
    print("입력된 메시지: " + input_message)
    await cl.Message(content="안녕하세요!").send() #← 챗봇의 답변을 보냄


채팅 화면에서 질문을 입력할 수 있게 하기

import chainlit as cl
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import PromptTemplate
from langchain.schema import HumanMessage
from langchain.vectorstores import Chroma

embeddings = OpenAIEmbeddings(
    model="text-embedding-ada-002"
)

chat = ChatOpenAI(model="gpt-3.5-turbo")

prompt = PromptTemplate(template="""문장을 바탕으로 질문에 답하세요.

문장: 
{document}

질문: {query}
""", input_variables=["document", "query"])

database = Chroma(
    persist_directory="./.data", 
    embedding_function=embeddings
)

@cl.on_chat_start
async def on_chat_start():
    await cl.Message(content="준비되었습니다! 메시지를 입력하세요!").send()

@cl.on_message
async def on_message(input_message):
    print("입력된 메시지: " + input_message)
    documents = database.similarity_search(input_message) #← input_message로 변경

    documents_string = ""

    for document in documents:
        documents_string += f"""
    ---------------------------
    {document.page_content}
    """

    result = chat([
        HumanMessage(content=prompt.format(document=documents_string,
                                           query=input_message)) #← input_message로 변경
    ])
    await cl.Message(content=result.content).send() #← 챗봇의 답변을 보냄

채팅 시작시 파일 업로드 기능

import os
import chainlit as cl
from langchain.chat_models import ChatOpenAI
from langchain.document_loaders import PyMuPDFLoader
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import PromptTemplate
from langchain.schema import HumanMessage
from langchain.text_splitter import SpacyTextSplitter
from langchain.vectorstores import Chroma


embeddings = OpenAIEmbeddings(
    model="text-embedding-ada-002"
)

chat = ChatOpenAI(model="gpt-3.5-turbo")

prompt = PromptTemplate(template="""문장을 기반으로 질문에 답하세요. 

문장: 
{document}

질문: {query}
""", input_variables=["document", "query"])

text_splitter = SpacyTextSplitter(chunk_size=300, pipeline="ko_core_news_sm")

@cl.on_chat_start
async def on_chat_start():
    files = None #← 파일이 선택되어 있는지 확인하는 변수

    while files is None: #← 파일이 선택될 때까지 반복
        files = await cl.AskFileMessage(
            max_size_mb=20,
            content="PDF를 선택해 주세요",
            accept=["application/pdf"],
            raise_on_timeout=False,
        ).send()
    file = files[0]

    if not os.path.exists("tmp"): #← tmp 디렉터리가 존재하는지 확인
        os.mkdir("tmp") #← 존재하지 않으면 생성
    with open(f"tmp/{file.name}", "wb") as f: #← PDF 파일을 저장
        f.write(file.content) #← 파일 내용을 작성

    documents = PyMuPDFLoader(f"tmp/{file.name}").load() #← 저장한 PDF 파일을 로드
    splitted_documents = text_splitter.split_documents(documents) #← 문서를 분할

    database = Chroma( #← 데이터베이스 초기화
        embedding_function=embeddings,
        # 이번에는 persist_directory를 지정하지 않음으로써 데이터베이스 영속화를 하지 않음
    )

    database.add_documents(splitted_documents) #← 문서를 데이터베이스에 추가

    cl.user_session.set(  #← 데이터베이스를 세션에 저장
        "database",  #← 세션에 저장할 이름
        database  #← 세션에 저장할 값
    )

    await cl.Message(content=f"`{file.name}` 로딩이 완료되었습니다. 질문을 입력하세요.").send() #← 불러오기 완료를 알림

@cl.on_message
async def on_message(input_message):
    print("입력된 메시지: " + input_message)

    database = cl.user_session.get("database") #← 세션에서 데이터베이스를 가져옴

    documents = database.similarity_search(input_message)

    documents_string = ""

    for document in documents:
        documents_string += f"""
    ---------------------------
    {document.page_content}
    """
    
    result = chat([
        HumanMessage(content=prompt.format(document=documents_string,
                                           query=input_message)) #← input_message로 변경
    ])
    await cl.Message(content=result.content).send()

p138

profile
이겨내

0개의 댓글

관련 채용 정보