Attention!
Since version 1.24.0 streamlit provides official elements to build conversational apps.
The new elements are more flexible, extensible and better supported, I would suggest to use them.
However, streamlit>=1.23 requires protobuf>=4 when some package requires protobuf<=3. In this condition you can use this package(<1.0.0) with streamlit<=1.22 as alternative. They are all simple to render text messages.
This package(>=1.0.0) will focus on wrapper of official chat elements to make chat with LLMs more convenient.
Chatbox component for streamlit
A Streamlit component to show chat messages.
It's basiclly a wrapper of streamlit officeial elements including the chat elemnts.
-
demo
-
demo agent
Features
- support streaming output.
- support markdown/image/video/audio messages, and all streamlit elements could be supported by customized
OutputElement
. - output multiple messages at once, and make them collapsable.
- maintain session state context bound to chat conversation
- export & import chat histories
This make it easy to chat with langchain LLMs in streamlit.
Goto webui of langchain-chatchat to see the actual application.
Install
just pip install -U streamlit-chatbox
Usage examples
import streamlit as st
from streamlit_chatbox import *
import time
import simplejson as json
llm = FakeLLM()
chat_box = ChatBox(
use_rich_markdown=True,
user_theme="green",
assistant_theme="blue",
)
chat_box.use_chat_name("chat1")
def on_chat_change():
chat_box.use_chat_name(st.session_state["chat_name"])
chat_box.context_to_session()
with st.sidebar:
st.subheader('start to chat using streamlit')
chat_name = st.selectbox("Chat Session:", ["default", "chat1"], key="chat_name", on_change=on_chat_change)
chat_box.use_chat_name(chat_name)
streaming = st.checkbox('streaming', key="streaming")
in_expander = st.checkbox('show messages in expander', key="in_expander")
show_history = st.checkbox('show session state', key="show_history")
chat_box.context_from_session(exclude=["chat_name"])
st.divider()
btns = st.container()
file = st.file_uploader(
"chat history json",
type=["json"]
)
if st.button("Load Json") and file:
data = json.load(file)
chat_box.from_dict(data)
chat_box.init_session()
chat_box.output_messages()
def on_feedback(
feedback,
chat_history_id: str = "",
history_index: int = -1,
):
reason = feedback["text"]
score_int = chat_box.set_feedback(feedback=feedback, history_index=history_index)
st.session_state["need_rerun"] = True
feedback_kwargs = {
"feedback_type": "thumbs",
"optional_text_label": "wellcome to feedback",
}
if query := st.chat_input('input your question here'):
chat_box.user_say(query)
if streaming:
generator = llm.chat_stream(query)
elements = chat_box.ai_say(
[
Markdown("thinking", in_expander=in_expander,
expanded=True, title="answer"),
Markdown("", in_expander=in_expander, title="references"),
]
)
time.sleep(1)
text = ""
for x, docs in generator:
text += x
chat_box.update_msg(text, element_index=0, streaming=True)
chat_box.update_msg(text, element_index=0, streaming=False, state="complete")
chat_box.update_msg("\n\n".join(docs), element_index=1, streaming=False, state="complete")
chat_history_id = "some id"
chat_box.show_feedback(**feedback_kwargs,
key=chat_history_id,
on_submit=on_feedback,
kwargs={"chat_history_id": chat_history_id, "history_index": len(chat_box.history) - 1})
else:
text, docs = llm.chat(query)
chat_box.ai_say(
[
Markdown(text, in_expander=in_expander,
expanded=True, title="answer"),
Markdown("\n\n".join(docs), in_expander=in_expander,
title="references"),
]
)
cols = st.columns(2)
if cols[0].button('show me the multimedia'):
chat_box.ai_say(Image(
'https://tse4-mm.cn.bing.net/th/id/OIP-C.cy76ifbr2oQPMEs2H82D-QHaEv?w=284&h=181&c=7&r=0&o=5&dpr=1.5&pid=1.7'))
time.sleep(0.5)
chat_box.ai_say(
Video('https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'))
time.sleep(0.5)
chat_box.ai_say(
Audio('https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'))
if cols[1].button('run agent'):
chat_box.user_say('run agent')
agent = FakeAgent()
text = ""
chat_box.ai_say()
for d in agent.run_stream():
if d["type"] == "complete":
chat_box.update_msg(expanded=False, state="complete")
chat_box.insert_msg(d["llm_output"])
break
if d["status"] == 1:
chat_box.update_msg(expanded=False, state="complete")
text = ""
chat_box.insert_msg(Markdown(text, title=d["text"], in_expander=True, expanded=True))
elif d["status"] == 2:
text += d["llm_output"]
chat_box.update_msg(text, streaming=True)
else:
chat_box.update_msg(text, streaming=False)
btns.download_button(
"Export Markdown",
"".join(chat_box.export2md()),
file_name=f"chat_history.md",
mime="text/markdown",
)
btns.download_button(
"Export Json",
chat_box.to_json(),
file_name="chat_history.json",
mime="text/json",
)
if btns.button("clear history"):
chat_box.init_session(clear=True)
st.experimental_rerun()
if show_history:
st.write(st.session_state)
Todos
changelog
v1.1.13
- add Json output element
- can choose to use streamlit-markdown instead of st.markdown. currently need streamlit==1.37.1 when streaming
- user can register custom output method with
ChatBox.register_output_method
. This is useful to use thirdparty components:
from streamlit_chatbox import *
from streamlit_markdown import st_hack_markdown
ChatBox.register_output_method("st_markdown", st_hack_markdown)
cb = ChatBox()
cb.user_say(OutputElement("user defined output method", output_method="st_markdown", theme_color="blue", mermaid_theme_CSS=""))