[LangChain] MonaiGPT - Medical Imaging Chatbot을 만들어볼까? -2

반응형

코드리뷰

db_creator.py

from langchain.document_loaders import DirectoryLoader
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
import os 

from api import api_key

os.environ['OPENAI_API_KEY'] = api_key

loader = DirectoryLoader('./data')
pages = loader.load_and_split()

embeddings = OpenAIEmbeddings()
vectordb = Chroma.from_documents(pages, embedding=embeddings, persist_directory="./monai_gpt_db")
vectordb.persist()
  1. from langchain.document_loaders import DirectoryLoader:

    • langchain.document_loaders 패키지에서 DirectoryLoader 클래스를 가져옵니다. 이 클래스는 디렉터리에서 문서를 로드하는 역할을 합니다.
  2. from langchain.embeddings import OpenAIEmbeddings:

    • langchain.embeddings 패키지에서 OpenAIEmbeddings 클래스를 가져옵니다. 이 클래스는 OpenAI를 이용하여 문서나 텍스트를 임베딩(벡터화)하는 역할을 합니다.
  3. from langchain.vectorstores import Chroma:

    • langchain.vectorstores 패키지에서 Chroma 클래스를 가져옵니다. 이 클래스는 임베딩된 문서들을 저장하고 검색하는 역할을 합니다.
  4. import os:

    • os 모듈을 가져옵니다. 이 모듈은 운영 체제와 상호 작용하는 기능을 제공합니다.
  5. from api import api_key:

    • api 모듈에서 api_key를 가져옵니다. 이 키는 OpenAI 서비스에 접근하기 위한 인증 키일 것입니다.
  6. os.environ['OPENAI_API_KEY'] = api_key:

    • 환경 변수 'OPENAI_API_KEY'에 api_key 값을 설정합니다. 이는 OpenAI 서비스에 접근할 때 필요한 인증 정보를 제공하기 위함입니다.
  7. loader = DirectoryLoader('./data'):

    • 현재 디렉터리의 'data' 폴더에 있는 문서들을 로드하기 위해 DirectoryLoader 인스턴스를 생성합니다.
  8. pages = loader.load_and_split():

    • 'data' 폴더 내의 문서들을 로드하고, 필요한 경우 분할하는 작업을 수행합니다.
  9. embeddings = OpenAIEmbeddings():

    • OpenAI를 사용하여 텍스트를 임베딩하는 OpenAIEmbeddings 인스턴스를 생성합니다.
  10. vectordb = Chroma.from_documents(pages, embedding=embeddings, persist_directory="./monai_gpt_db"):

    • 로드된 pages 문서들을 임베딩하고, 이 임베딩된 벡터들을 './monai_gpt_db' 디렉터리에 저장하기 위해 Chroma 인스턴스를 생성합니다.
  11. ectordb.persist():

    • 임베딩된 벡터들을 지속적으로 저장합니다. 이를 통해 나중에 빠르게 벡터들을 불러올 수 있습니다.

ask_monaigpt_local.py

from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma 
from langchain.chains import ChatVectorDBChain
from langchain.llms import OpenAI
import os 

from api import api_key

os.environ['OPENAI_API_KEY'] = api_key

embeddings = OpenAIEmbeddings()
vectordb = Chroma(persist_directory='./monai_gpt_db', embedding_function=embeddings)

chat_qa = ChatVectorDBChain.from_llm(OpenAI(temperature=0.9, model_name='gpt-4'), vectordb, return_source_documents=True)

query = 'How does the Orientation function works in monai'
result = chat_qa({'question':query, 'chat_history':''})

print('Answer:')
print(result['answer'])
  1. from langchain.embeddings import OpenAIEmbeddings:

    • langchain.embeddings 패키지에서 OpenAIEmbeddings 클래스를 가져옵니다. 이 클래스는 OpenAI를 이용하여 문서나 텍스트를 임베딩(벡터화)하는 역할을 합니다.
  2. from langchain.vectorstores import Chroma:

    • langchain.vectorstores 패키지에서 Chroma 클래스를 가져옵니다. 이 클래스는 임베딩된 문서들을 저장하고 검색하는 역할을 합니다.
  3. from langchain.chains import ChatVectorDBChain:

    • langchain.chains 패키지에서 ChatVectorDBChain 클래스를 가져옵니다. 이 클래스는 질문과 대답의 연쇄적인 작업을 처리하는 체인입니다.
  4. from langchain.llms import OpenAI:

    • langchain.llms 패키지에서 OpenAI 클래스를 가져옵니다. 이 클래스는 OpenAI 모델을 사용하여 질문에 대한 대답을 생성하는 역할을 합니다.
  5. vectordb = Chroma(persist_directory='./monai_gpt_db', embedding_function=embeddings):

    • 임베딩된 벡터들을 './monai_gpt_db' 디렉터리에 저장하고, 이 벡터들을 생성하는 데 사용할 임베딩 함수로 embeddings를 설정하여 Chroma 인스턴스를 생성합니다.
  6. chat_qa = ChatVectorDBChain.from_llm(OpenAI(temperature=0.9, model_name='gpt-4'), vectordb, return_source_documents=True):

    • OpenAI 인스턴스와 vectordb를 사용하여 ChatVectorDBChain 인스턴스를 생성합니다. 여기서 temperature=0.9는 응답의 다양성을 조절하고, model_name='gpt-4'는 사용할 모델의 이름을 지정합니다.
  7. query = 'How does the Orientation function works in monai':

    • 사용자 질문을 설정합니다.
  8. result = chat_qa({'question':query, 'chat_history':''}):

    • chat_qa 체인을 사용하여 질문에 대한 답변을 검색합니다.
  9. print('Answer:')와 print(result['answer']):

    • 검색된 답변을 출력합니다.

요약하면, 이 코드는 OpenAI의 'gpt-4' 모델과 임베딩된 벡터 데이터베이스를 사용하여 사용자의 질문에 대한 답변을 검색하고 출력하는 작업을 수행합니다.

ask_monai_gpt_online.py

import streamlit as st
from streamlit_chat import message
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chains import ChatVectorDBChain
import os
import re
from langchain.llms import OpenAI

from api import api_key

os.environ['OPENAI_API_KEY'] = api_key

def get_bot():
    # Create the embeddings
    embeddings = OpenAIEmbeddings()
    vectordb = Chroma(persist_directory='./monai_gpt_db', embedding_function=embeddings)

    #Prediction part
    bot_qa = ChatVectorDBChain.from_llm(OpenAI(temperature=0.9, model_name="gpt-3.5-turbo"),
                                        vectordb, return_source_documents=True)

    return bot_qa

def extract_code_text(answer):
    # Extract code block from message
    code_block_pattern = re.compile(r'```(.*?)```', re.DOTALL)
    code_blocks = code_block_pattern.findall(answer)

    # Remove code blocks from the message
    message_clean = code_block_pattern.sub('', answer)

    return message_clean, code_blocks

def get_text():
    st.header("How can I assist you")
    input_text = st.text_input("", "Give me a definition of MONAI?", key="input")
    return input_text



# From here down is all the StreamLit UI.
st.set_page_config(page_title="MONAI GPT", page_icon=":robot:")
st.header("MONAI :robot_face: GPT - Demo")
st.image('utils/banner.jpg')
st.markdown('For specific information about the MONAI documentation, you can visite the website [here](https://docs.monai.io/en/stable/api.html).')

if "generated" not in st.session_state:
    st.session_state["generated"] = []

if "generated_code" not in st.session_state:
    st.session_state["generated_code"] = []

if "past" not in st.session_state:
    st.session_state["past"] = []

user_input = get_text()

if user_input:
    bot_qa = get_bot()
    result = bot_qa({"question": user_input, "chat_history": ""})

    message_clean, code_blocks = extract_code_text(result['answer'])

    st.session_state.past.append(user_input)
    st.session_state.generated.append(message_clean)
    st.session_state.generated_code.append(code_blocks)

if st.session_state["generated"]:

    for i in range(len(st.session_state["generated"]) - 1, -1, -1):
        message(st.session_state["past"][i], is_user=True, key=str(i) + "_user")
        # Display the extracted code block(s) with formatting
        message(st.session_state["generated"][i], key=str(i))
        for code_block in st.session_state["generated_code"][i]:
            st.code(code_block.strip())

함수 정의

  1. get_bot():

    • OpenAI 임베딩과 Chroma 벡터 데이터베이스를 설정하여 채팅 봇을 반환합니다.
  2. extract_code_text(answer):

    • 주어진 답변에서 코드 블록을 추출하고, 코드 블록을 제외한 나머지 메시지도 반환합니다.
  3. get_text():

    • Streamlit UI를 사용하여 사용자에게 질문을 입력받습니다.

Streamlit UI 설정

  1. 페이지 설정 및 제목, 이미지, 마크다운 텍스트를 표시합니다.

  2. 세션 상태를 관리하기 위해 st.session_state를 사용합니다. 이를 통해 이전의 대화 내역이나 생성된 코드 블록 등을 저장합니다.

  3. get_text() 함수를 사용하여 사용자의 입력을 받습니다.

  4. 사용자의 입력이 있을 경우, get_bot() 함수를 통해 봇을 설정하고, 사용자의 질문에 대한 답변을 얻습니다.

  5. 답변에서 코드 블록을 추출하고, 세션 상태에 저장합니다.

  6. 저장된 대화 내역을 반복하여 Streamlit UI에 표시합니다.

요약하면, 이 코드는 Streamlit을 사용하여 웹 기반의 채팅 인터페이스를 생성하고, 사용자의 질문에 OpenAI를 활용하여 답변을 제공합니다. 답변 내에 코드 블록이 포함되어 있을 경우, 이를 따로 추출하여 깔끔하게 표시합니다.


터미널에서 streamlit run ask_monai_gpt_online.py 를 입력하면 아래와 같이 웹에서 Monai gpt를 구동할 수 있습니다.

Screenshot from 2023-09-11 17-22-06

Streamlit 배포

[share.streamlit.io] 에 접속하여 깃허브와 연결합니다.

위의 코드들이 담긴 레포지토리를 선택하고, main path에 ask_monai_gpt_online.py 파일을 입력해주면 애플리케이션이 성공적으로 실행됩니다. :)

streamlit에서 배포하는건 매우 쉽습니다..ㅎ

Screenshot from 2023-09-11 17-32-39

추가 아이디어

현재 만든 MonaiGPT는 Monai 공식 문서로부터 만들어졌기 때문에 텍스트가 모두 영어로 되어있습니다.
Monai는 따로 한국어 레퍼런스가 없기 때문에 html만 추출하여 한국어로 번역 후 한국어로 된 챗봇을 다시 만들어볼 수 있을 것 같습니다.

또한 Monai 뿐만 아니라 많은 문서들이 있는 사이트나 파일들이 있다면 ( 텍스트 내용이 비슷하다면 ) 특정 도메인에 특화된 Custom한 gpt도 만들어볼 수 있을거 같네요 !

반응형