こんにちは、JS2IIUです。
StreamlitとOpenAIのAPIを組み合わせることで、GPT-4oを使ったチャットボットを簡単に作成できます。今回は、ストリーミングという技術を使って、まるで人間がタイピングしているかのような、より自然なチャット体験を実現する方法を解説します。今回もよろしくお願いします。
はじめに
今回のサンプルコードに使うテクニックはこちらの記事で詳しく説明しているので、事前に確認しておくとスムーズに進めることができます。st.chat_message()、st.chat_input()、そしてst.session_state()の使い方について解説しています。
サンプルコード
まずは、今回解説するサンプルコード全体をご紹介します。API KEYのところだけご自身のものを入力してから実行して下さい。
import streamlit as st
from openai import OpenAI
# OpenAIクライアントを生成
client = OpenAI(api_key="YOUR API KEY HERE") # ここにあなたのAPIキーを入力してください
# セッションステートを初期化
if "messages" not in st.session_state:
st.session_state.messages = []
# メッセージ履歴を表示
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# ユーザーからの入力を受け取る
if prompt := st.chat_input("What is up?"):
# ユーザーのメッセージを履歴に追加
st.session_state.messages.append({"role": "user", "content": prompt})
# チャットメッセージとして表示
with st.chat_message("user"):
st.markdown(prompt)
# OpenAI APIを使ってAIからの応答をストリーミングで生成
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
*st.session_state.messages,
],
stream=True # ストリーミングを有効にする
)
# AIのメッセージをチャンクごとに表示
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) # 最終的な応答を表示
# AIのメッセージを履歴に追加
st.session_state.messages.append({"role": "assistant", "content": full_response})解説
それでは、上記のコードをステップバイステップで詳しく解説していきます。
1. 必要なライブラリをインポート
import streamlit as st
from openai import OpenAIstreamlit: ユーザーインターフェースを構築するためのライブラリです。openai: OpenAIのAPIにアクセスするためのライブラリです。
2. OpenAIクライアントを生成
client = OpenAI(api_key="YOUR API KEY HERE") # ここにあなたのAPIキーを入力してくださいOpenAI(api_key="YOUR API KEY HERE")でOpenAIのAPIにアクセスするためのクライアントオブジェクトを生成します。YOUR API KEY HEREの部分を、ご自身のOpenAI APIキーに置き換えてください。
3. セッションステートを初期化
if "messages" not in st.session_state:
st.session_state.messages = []st.session_stateは、Streamlitが提供するセッション状態管理機能です。- このコードでは、
messagesというキーでチャットのメッセージ履歴をリストとして保存します。 if "messages" not in st.session_state:で、セッション状態にmessagesが存在しない場合(つまり、アプリが初めて起動された場合)に、空のリスト[]をst.session_state.messagesに代入して初期化しています。
4. メッセージ履歴を表示
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])st.session_state.messagesに保存されているメッセージ履歴をforループで一つずつ取り出します。- 各メッセージについて、
st.chat_message(message["role"])を使ってチャットメッセージを表示します。message["role"]は、メッセージの送信者が “user” か “assistant” かを示します。
st.markdown(message["content"])で、メッセージの内容をMarkdown形式で表示します。
5. ユーザーからの入力を受け取る
if prompt := st.chat_input("What is up?"):
# ユーザーのメッセージを履歴に追加
# ...st.chat_input("What is up?")で、”What is up?” というプレースホルダーテキストを持つチャット入力欄を表示します。- ユーザーが入力して送信ボタンを押すと、入力されたテキストが
promptに代入されます。 if prompt := ...は、promptに値が入力された場合にのみ、以降の処理を実行することを意味します。この「:=」セイウチ演算子については、以下のリンク先に詳しいので参照してみて下さい。
6. ユーザーのメッセージを履歴に追加 & 表示
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)- ユーザーが入力した
promptを、{"role": "user", "content": prompt}という辞書形式でst.session_state.messagesに追加します。 - これにより、メッセージ履歴にユーザーの入力が保存されます。
st.chat_message("user")を使って、ユーザーのメッセージをチャット画面に表示します。
7. OpenAI APIを使ってAIからの応答をストリーミングで生成
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
*st.session_state.messages,
],
stream=True # ストリーミングを有効にする
)client.chat.completions.create(...)で、OpenAIのAPIを呼び出してAIからの応答を生成します。model="gpt-4o-mini": 使用する言語モデルをGPT-4o-miniに指定します。messages=[...]: AIに渡すメッセージのリストを指定します。{"role": "system", "content": "You are a helpful assistant."}は、AIの役割を「役に立つアシスタント」として設定します。*st.session_state.messagesで、これまでのメッセージ履歴をすべてAIに渡します。これにより、AIは過去の会話の流れを踏まえて応答を生成できます。
stream=True: ストリーミング応答を有効にします。これにより、AIの応答をチャンクごとに受け取ることができます。
8. AIのメッセージをチャンクごとに表示
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.chat_message("assistant")を使って、AIからのメッセージを表示する領域を作成します。full_response = "": AIからの応答全体を格納する変数を初期化します。placeholder = st.empty(): 応答を表示するためのプレースホルダーを作成します。for chunk in response:: ストリーミングで受け取った応答をチャンクごとに処理します。content = chunk.choices[0].delta.content: チャンクから応答テキストを取り出します。if content is not None: 応答テキストが存在する場合にのみ、以下の処理を実行します。full_response += content: 応答テキストをfull_responseに追加します。placeholder.markdown(full_response + "▌"): プレースホルダーに現在の応答内容と「▌」を表示することで、タイピング中の様子を表現します。
placeholder.markdown(full_response): すべてのチャンクを受信後、最終的な応答をプレースホルダーに表示します。
9. AIのメッセージを履歴に追加
st.session_state.messages.append({"role": "assistant", "content": full_response})- AIが生成した
full_responseを、{"role": "assistant", "content": full_response}という辞書形式でst.session_state.messagesに追加します。
まとめ
StreamlitとOpenAIのAPI、そしてストリーミングを組み合わせることで、まるで人間と会話しているかのような自然なチャットボットを構築できます。ぜひ、ご自身のアプリケーションにこの技術を組み込んで、ユーザーに新しい体験を提供してみてください。
さらに発展として、LangChainを使ったアプリ構築について、こちらの記事で確認してみて下さい。
参考リンク
最後に、書籍のPRです。
最新のOpenAIのチャットAPIの使い方もしっかりと解説されている良書です。2024年11月初版発行、「LangChainとLangGraphによるRAG・AIエージェント[実践]入門」西見、吉田、大嶋著。
最後まで読んでいただきありがとうございました。73




コメント