今回は、Streamlitで簡単なChatBotの作成を行います。
2023年~2024年にかけてRAGが普及してから社内でChatBotを作成する機会が非常に増えました。
そのため、Streamlitの機能を使用して簡単に作成できるChatBotについてまとめておきます。
それでは早速見ていきましょう。
Chat elementsの解説
StreamlitのChat Elementsは、チャットアプリケーションの構築を容易にするための機能になります。
主に st.chat_message と st.chat_input の2つが提供されています。
これらの要素と、セッションステートを組み合わせることで、チャット履歴の管理や表示ができ簡単にChatBotの作成ができます。
st.chat_message()
st.chat_message()
は、チャットのメッセージを表示する関数です。
- name:メッセージの送信者を示す名前です。
“user”や”assistant”などのプリセット値を指定すると、デフォルトのアイコンが適用されます。その他の名前を指定した場合、その名前の頭文字がアイコンとして表示されます。 - avatar:メッセージの横に表示されるアバターを指定します。デフォルトでは、
name
の値に応じて自動的にアイコンが設定されます。
サンプルプログラム
import streamlit as st
# ユーザからのメッセージを表示
with st.chat_message("user"):
st.write("こんにちは!")
# アシスタントからのメッセージを表示
with st.chat_message("assistant"):
st.write("こんにちは!ユーザさん。")

st.chat_input()
st.chat_input()
は、チャットの入力欄を表示する関数です。
この関数では、ページの下部に入力欄を固定表示し、ユーザーがメッセージを入力して送信することができます。
- placeholder:入力フィールドが空のときに表示されるプレースホルダーテキストです。
- key:ウィジェットの一意な識別子として使用されるオプションのキーです。省略された場合、ウィジェットの内容に基づいてキーが自動生成されます。
- max_chars:入力可能な最大文字数を指定します。
- disabled:ウィジェットを無効化するかどうかを指定します。デフォルトはFalse。
- on_submit:メッセージが送信されたときに呼び出されるオプションのコールバック関数です。
- args:on_submit コールバックに渡されるオプションの引数のタプルです。
- kwargs:on_submit コールバックに渡されるオプションのキーワード引数の辞書です。
サンプルプログラム
import streamlit as st
# ユーザーからの入力を受け取る
user_input = st.chat_input("メッセージを入力してください")
# 入力が存在する場合、その内容を表示
if user_input:
st.write(f"あなたの入力: {user_input}")

ChatBotの作成
では、StreamlitのChat elementsを用いて、ChatBotの作成を行います。
まず、全体のコードは以下の通りとなります。
import streamlit as st
import openai
import os
from dotenv import load_dotenv
# 環境変数を読み込む
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
# Streamlit アプリのタイトル
st.title("ChatGPT Chatbot")
# セッション状態を初期化
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
# チャット履歴を表示
for message in st.session_state.chat_history:
with st.chat_message(message["role"]):
st.write(message["content"])
# チャット入力
user_input = st.chat_input("質問を入力してください:")
if user_input:
# セッション状態を更新
st.session_state.chat_history.append({"role": "user", "content": user_input})
# チャットメッセージとして表示
with st.chat_message("user"):
st.markdown(user_input)
# ストリーミングモードでAPIを呼び出し
response = openai.chat.completions.create(
model="gpt-4o-mini", # 必要に応じてモデルを変更
messages=st.session_state.chat_history,
stream=True # ストリーミングを有効にする
)
# チャンクごとに応答を処理
with st.chat_message("assistant"):
# プレースホルダーを用意
full_response = ""
placeholder = st.empty()
for chunk in response:
content = chunk.choices[0].delta.content
if content is not None:
full_response += content
placeholder.markdown(full_response) # 途中経過を表示
placeholder.markdown(full_response) # 最終的な応答を表示
# 応答をチャット履歴に保存
st.session_state.chat_history.append({"role": "assistant", "content": full_response })
以下順にコードの解説を行います。
環境変数の読み込み
以下でまず、環境変数の読み込みを行います。
環境変数は.envファイルに保存されているOPENAI_API_KEY
を読み込むようにしています。
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
セッション状態の初期化
st.session_stateを使い、ユーザーのチャット履歴をアプリの状態として保持するようにしています。
初めてアプリが起動したときに、chat_historyキーが存在しない場合、空のリストで初期化を実施しています。
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
チャット履歴の表示
過去ユーザが入力した内容と、chatGPTの回答を表示するようにしています。
for message in st.session_state.chat_history:
with st.chat_message(message["role"]):
st.write(message["content"])
ユーザー入力の処理
st.chat_inputで、ユーザーが入力できるテキストボックスを表示しています。
ユーザー入力がされるとchat_historyにユーザー入力内容を追加しています。
そして、入力内容を即座にチャットメッセージとして画面に表示しています。
user_input = st.chat_input("質問を入力してください:")
if user_input:
st.session_state.chat_history.append({"role": "user", "content": user_input})
with st.chat_message("user"):
st.markdown(user_input)
OpenAI APIの呼び出し
OpenAI APIの呼び出しを実施します。
今回モデルは、「gpt-4o-mini」を使用しており、ストリーミングを有効にしています。
response = openai.chat.completions.create(
model="gpt-4o-mini", # 必要に応じてモデルを変更
messages=st.session_state.chat_history,
stream=True # ストリーミングを有効にする
)
ストリーミング応答の処理
ストリーミング機能をsteamlit上で実現させるためのコードになります。
st.empty()をプレースホルダーとして使用し、応答が完全に送信される前でも、途中経過をリアルタイムで表示するようにしています。
with st.chat_message("assistant"):
full_response = ""
placeholder = st.empty()
for chunk in response:
content = chunk.choices[0].delta.content
if content is not None:
full_response += content
placeholder.markdown(full_response) # 途中経過を表示
placeholder.markdown(full_response) # 最終的な応答を表示
コードを実行した結果がこちらになります。
問題なく回答を生成してくれました。

Perplexityを使用したChatBotの作成
最後に、PerplexityのAPIを用いてWeb検索を行う生成AIを作成しました。
内容としては、OpenAIのAPIではなく、PerplexityのAPIを使うだけでそのほかの部分は変わりありませんので、コードをそのまま載せておきます。
import streamlit as st
from openai import OpenAI
import os
from dotenv import load_dotenv
# 環境変数を読み込む
load_dotenv()
api_key = os.getenv("Perplexity_API_KEY")
# Streamlit アプリのタイトル
st.title("ChatGPT Chatbot with Streaming")
# セッション状態を初期化
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
# チャット履歴を表示
for message in st.session_state.chat_history:
with st.chat_message(message["role"]):
st.write(message["content"])
# チャット入力
user_input = st.chat_input("質問を入力してください:")
if user_input:
# セッション状態を更新
st.session_state.chat_history.append({"role": "user", "content": user_input})
# チャットメッセージとして表示
with st.chat_message("user"):
st.markdown(user_input)
messages = [
{
"role": "system",
"content": (
"You are an artificial intelligence assistant and you need to "
"engage in a helpful, detailed, polite conversation with a user."
),
},
{
"role": "user",
"content": (
user_input
),
},
]
client = OpenAI(api_key=api_key, base_url="https://api.perplexity.ai")
response = client.chat.completions.create(
model="llama-3.1-sonar-large-128k-online",
messages=messages,
stream=True
)
# チャンクごとに応答を処理
with st.chat_message("assistant"):
# プレースホルダーを用意
full_response = ""
placeholder = st.empty()
for chunk in response:
content = chunk.choices[0].delta.content
if content is not None:
full_response += content
placeholder.markdown(full_response) # 途中経過を表示
placeholder.markdown(full_response) # 最終的な応答を表示
# 応答をチャット履歴に保存
st.session_state.chat_history.append({"role": "assistant", "content": full_response })

まとめ
Streamlitで作成するChatBotの簡単なコードを確認しました。
今回作成したコードのうち、ChatBotのロジック部分はChatGPTやPerplexityにそのまま回答させている形のため、非常に簡易的なものになっています。
ChatBotのロジック部分にRAGを適用したりすることで、応用的なChatBotを作成していくことができますので試してみてください。
今後もしばらくは、ChatBot需要はありそうですので、様々なChatBotアプリを作成していこうと思います。