Code Monkey home page Code Monkey logo

streamlit-chatbox's Introduction

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()
chat_box.use_chat_name("chat1") # add a chat conversatoin

def on_chat_change():
    chat_box.use_chat_name(st.session_state["chat_name"])
    chat_box.context_to_session() # restore widget values to st.session_state when chat name changed


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"]) # save widget values to chat context

    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) # convert emoji to integer
    # do something
    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(
            [
                # you can use string for Markdown output if no other parameters provided
                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)
        # update the element without focus
        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 = ""

    # streaming:
    chat_box.ai_say() # generate a blank placeholder to render messages
    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

  • wrapper of official chat elements

  • input messages: (this depends on the official st.chat_input improvement by #7069)

    • TEXT
    • IMAGE
      • file upload
      • paste from clipboard(streamlit_bokeh_events)
    • VIDEO
      • file upload
    • AUDIO
      • file upload
      • audio-recorder-streamlit
  • output message types:

    • Text/Markdown/Image/Audio/Video
    • any other output types supported by streamlit
  • improve output performance

    • streaming output message
    • show message in expander
    • style the output message
    • feedback by user
  • export & import chat history

    • export to markdown
    • export to json
    • import json
  • support output of langchain' Agent.

  • conext bound to chat

changelog

v1.1.12

  • fix type hint error with streamlit >= 1.33.0 (#8)
  • add ChatBox.change_chat_name to rename a chat conversation
  • maintain a context bound to chat conversation, it is like to be a sub session_state for every chat, context will get changed when you switch chat names.
    • user can save chat bound values by ChatBox.context['x'] = 1
    • values of widgets specified with a key can be saved to chat context with ChatBox.context_from_session and restored to st.session_state by ChatBox.context_to_session

streamlit-chatbox's People

Contributors

liunux4odoo avatar proseguys avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

streamlit-chatbox's Issues

反馈按钮报错

多用户同时问答时,报错
Bad message format
Bad 'setIn' index 3 (should be between [0, 2])

导入历史出现异常

将通过to_dict导出的数据通过from_dict进行导入之后,调用output_messages方法会提示:
File "D:\PythonProject\di-kb\venv\Lib\site-packages\streamlit_chatbox\messages.py", line 335, in output_messages
feedback_kwargs = msg["metadata"].get("feedback_kwargs", {})
~~~^^^^^^^^^^^^
KeyError: 'metadata'

st.session_state keyerror chat_history

运行中随机出现报错。不明白为什么明明在chat_box.init_session()里已经重新设置了session_state,但是却还是空字典{}。而且网络越差,出现的概率越高,当然localhost也会出现。有没有什么好的解决办法。

咨询chatchat项目

你好,大佬,我看chatchat项目下的agent功能是您开发的,我想咨询一些问题,您看可以吗,有偿

导入历史会话

chatbox.history导出的内容可以直接导入到下一次会话吗?

AttributeError: module 'streamlit' has no attribute '_DeltaGenerator'

2024-04-15 19:09:16.492 Uncaught app exception
Traceback (most recent call last):
  File "D:\Anaconda3\envs\streamlit-learn\Lib\site-packages\streamlit\runtime\scriptrunner\script_runner.py", line 584, in _run_script
    exec(code, module.__dict__)
  File "D:\code\streamlit-learn\main.py", line 2, in <module>
    from streamlit_chatbox import *
  File "D:\Anaconda3\envs\streamlit-learn\Lib\site-packages\streamlit_chatbox\__init__.py", line 4, in <module>
    from .messages import *
  File "D:\Anaconda3\envs\streamlit-learn\Lib\site-packages\streamlit_chatbox\messages.py", line 1, in <module>
    from streamlit_chatbox.elements import *
  File "D:\Anaconda3\envs\streamlit-learn\Lib\site-packages\streamlit_chatbox\elements.py", line 6, in <module>
    class Element:
  File "D:\Anaconda3\envs\streamlit-learn\Lib\site-packages\streamlit_chatbox\elements.py", line 43, in Element
    def __call__(self, render_to: st._DeltaGenerator=None) -> st._DeltaGenerator:
                                  ^^^^^^^^^^^^^^^^^^
AttributeError: module 'streamlit' has no attribute '_DeltaGenerator'

when i run example.py, I met this error

支持动态变更头像吗

比如,登录用户是多个,每个人都有自己的头像,所以在对应聊天问答过程中用户头像能使用用户设置的头像吗,现在好像就是默认的初始化头像,后期不能针对每个人用户自适应的变更,请问这个可以做吗?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.