2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

StreamlitとLangchainで作る会話型PDFアシスタント

Last updated at Posted at 2023-12-19

初めに

この記事では、StreamlitLangchainを使用して開発した会話型PDFアシスタントについて紹介します。StreamlitとLangchainを学ぶために簡易的に作成したものです。これから、Streamlit、Langchainを使って簡単にチャットボットを作成してみたい!という方におすすめです。

概要

PDFデータを読み込んで、PDFの内容を回答してくれるチャットボット。

Streamlitとは

Streamlitは、PythonでWebアプリケーションを作成するためのフレームワークで、特にデータの可視化や分析を行うアプリケーションに適しています。Streamlitを用いることで、フロントエンドの技術がなくてもWebアプリケーションを作成することができます。

Langchainとは

Langchainは、GPTなどの大規模言語モデル(Large Language Model:LLM)を活用してサービスを開発する際に役立つライブラリです。このライブラリは、LLMと外部リソース(データソース、言語処理系)を組み合わせて、より高度なアプリケーションやサービスの開発をサポートすることができます。

開発環境の詳細とバージョン情報

ツール / ライブラリ バージョン
Python 3.11.3
Streamlit 1.29.0
Langchain 0.0.350

ライブラリ

pip install streamlit streamlit_chat langchain openai faiss-cpu tiktoken pypdf

ディレクトリ構成

├── ChatBot-env/       # 仮想環境フォルダ
│   ├── bin/
│   ├── include/
│   ├── lib/
│   └── ...
│
├── app.py             # Streamlitアプリケーション
├── chatbot.py         # チャットボットのロジック
├── pdf_loader.py      # PDF読み込み用のスクリプト

app.py

import os
import streamlit as st
from streamlit_chat import message
from chatbot import conversational_chat, setup_chain
from pdf_loader import load_pdf_data

# UI設定
st.set_page_config(page_title="DocTalk", page_icon=":speech_balloon:")

# タイトルと説明文を追加
st.title("DocTalk: PDF会話型アシスタント")
st.markdown("""
    PDFドキュメントから情報を引き出すためのチャットボットです。
    OpenAI APIキーを入力し、PDFファイルをアップロードしてください。
""")

# セッション状態の初期化
def initialize_state():
    if 'history' not in st.session_state:
        st.session_state['history'] = []
    if 'generated' not in st.session_state:
        st.session_state['generated'] = ["会話を始めるには、PDFファイルをアップロードしてください。"]
    if 'past' not in st.session_state:
        st.session_state['past'] = ["やあ!"]
initialize_state()

# サイドバー設定
st.sidebar.title("設定")
user_api_key = st.sidebar.text_input("OpenAI APIキー", type="password")
uploaded_file = st.sidebar.file_uploader("PDFファイルをアップロード", type="pdf")

# APIキーとファイルの確認
if user_api_key:
    os.environ['OPENAI_API_KEY'] = user_api_key
    if uploaded_file:
        data = load_pdf_data(uploaded_file)
        setup_chain(data)

# チャット履歴の表示
if st.session_state['generated']:
    for i in range(len(st.session_state['generated'])):
        message(st.session_state["past"][i], is_user=True, key=str(i) + '_user')
        message(st.session_state["generated"][i], key=str(i))

# チャット入力と送信ボタンの設定
user_input = st.text_input("質問:", placeholder="PDFデータについてここで話しましょう :)", key='input')
submit_button = st.button('送信')

# ユーザー入力の処理
if submit_button and user_input:
    if user_api_key and uploaded_file is not None:
        output = conversational_chat(user_input)
        st.session_state['past'].append(user_input)
        st.session_state['generated'].append(output)
    else:
        st.warning("APIキーとPDFファイルの両方が必要です。")

chatbot.py

import streamlit as st
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationalRetrievalChain
from langchain.vectorstores import FAISS

chain = None

def setup_chain(data):
    global chain
    embeddings = OpenAIEmbeddings()
    vectors = FAISS.from_documents(data, embeddings)
    chain = ConversationalRetrievalChain.from_llm(
        llm=ChatOpenAI(temperature=0.0, model_name='gpt-3.5-turbo-16k'),
        retriever=vectors.as_retriever())

def conversational_chat(query):
    if chain is None:
        return "Chain is not initialized."

    result = chain({"question": query, "chat_history": st.session_state['history']})
    st.session_state['history'].append((query, result["answer"]))
    return result["answer"]

pdf_loader.py

import tempfile
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

def load_pdf_data(uploaded_file):
    with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
        tmp_file.write(uploaded_file.getvalue())
        tmp_file_path = tmp_file.name

    loader = PyPDFLoader(file_path=tmp_file_path)
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=2000,
        chunk_overlap=100,
        length_function=len)
    
    return loader.load_and_split(text_splitter)

今回使ったPDF資料

Gammaを使って、架空の会社のメンバー自己紹介スライドを作成しました。
Gammaは、ビジュアルよく簡単にスライドが作成できるのでおすすめです!

スクリーンショット 2023-12-19 23.56.16.png
スクリーンショット 2023-12-19 23.56.45.png
スクリーンショット 2023-12-20 0.03.12.png

完成した会話型PDFアシスタント

Chatbot.gif

まとめ

Langchain、Streamlitを使って、自分自身で手軽にアプリケーションを作成してみたいと思い、今回作成してみました。今回、作成してみて、Streamlitの簡単な操作性に驚きました。直感的で使いやすいUI構築機能になっていて、まだ試していないUIの機能もあるので、これから試していきたいです。

参考資料

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?