Streamlitによるチャット機能の実装はst.chat_input、st.chat_messageが中心になるといえるでしょう。
st.chat_input()
チャット入力を受け付けるためのウィジェットを表示。このウィジェットならではのパラメータは以下のようなものがあります。
| パラメータ | 値 |
|---|---|
| accept_file | ファイルの投稿を付けつけるかどうか。 False: 受け付けない。(デフォルト) True:単一ファイルを受け付ける。 "multiple":複数ファイルを受け付ける。 "directory":指定したディレクトリ内のファイルを全て送信対象とする。 |
| file_type | 送信を許可するファイルの拡張子。リスト指定可能。許可されていない拡張子のファイルは、ウィジェットでの入力はできるもののサーバへは送信されない。 |
ファイルの投稿が可能かどうかは、ウィジェットの見た目で判別可能です。
返り値は以下の通り。
| 値 | 説明 |
|---|---|
| None | 何も送信していない場合。 |
| 文字列 | accept_file=Falseで、メッセージを送信した場合。 |
| dict-like object | accept_file=False以外で、少なくともメッセージかファイルのいずれか一方を送信した場合。 メッセージは"text"属性(文字列)に、ファイルは"files"属性(UploadedFileのリスト)に保持される。 |
st.chat_message()
戻り値はチャット風のメッセージ表示をするためのコンテナ。
誤解を恐れずいうと「アバターと表示枠を提供してくれる機能」
表示する内容や見せ方については相応の実装が必要です。シンプルなものだと、以下のような感じになります。
st.chat_message( name='発信者名' ).write( 'メッセージ' )
| パラメータ | 値 |
|---|---|
| name | メッセージ発信者の名前。 |
| avatar | メッセージの左側に表示するアバター。指定なしの場合はnameで指定した値の頭文字。 絵文字やGoogle Icon (:material/icon_name: で指定)も可。 |
気を付けるべき点
st.chat_input()やst.chat_message()は履歴管理の仕組みを持っているわけではありません。従って、次のようなコードではHumanとAIのやり取りは直近1往復分しか表示されません。
import streamlit as st
from datetime import datetime
text = st.chat_input( "入力してください" )
if text :
st.chat_message( "Human" ).write( text )
with st.chat_message( "AI" ) :
st.info( str( datetime.now() ) )
st.write( f"Your input is '{text}'." )
過去のやり取りを記憶し一連のやり取りを表示するには、そのための実装が別途必要です。
例えばcache_resourceを活用して過去のやり取りを全て保持する方法が考えられます。
以下は、"AI"(という名前の何か)とやり取りしている風のチャット機能の実装例。
まあ、これだと、ユーザーがどんなメッセージを送っても"AI"はほぼ固定の回答しか返してこないわけですが。
import streamlit as st
import time
from datetime import datetime
class ChatMessage :
def __init__( self, name:str, text:str, avatar=None ) :
self.name = name
self.text = text
self.avatar = avatar
def toStreamText( text:str ) :
for c in text :
yield c
time.sleep( 0.02 )
def display( cm:ChatMessage, is_stream=False ) :
with st.chat_message( cm.name, avatar=cm.avatar ) :
if is_stream :
st.write_stream( toStreamText( cm.text ) )
else :
st.write( cm.text )
@st.cache_resource
def getChatHistory( name:str ) :
return []
name = st.text_input( "Please input your name.", max_chars=10, width=150 )
history = None
if name :
history = getChatHistory( name )
for cm in history :
display( cm )
text = st.chat_input( "Please ask me anything." )
if text :
if history is None :
history = getChatHistory( name )
cm = ChatMessage( name, text, avatar='😀' )
display( cm )
history.append( cm )
with st.spinner( "Please wait to answer from AI..." ) :
time.sleep( 3 )
cm = ChatMessage( 'AI', f'This message is generated by AI. {str(datetime.now())}' )
display( cm, is_stream=True )
history.append( cm )