💬

Streamlit で ChatGPT みたいに, テキストを word ごとにインタラクティブ(streaming)表示したいメモ

2023/04/21に公開

ChatGPT っぽいの Streamlit でほしいネ...

Streamlitで自分用ChatGPTを作る
https://zenn.dev/kentarok/articles/5e326b627c1b2c

streamlit-chat で Chat UI あるけど, インタラクティブ(streamling)表示できん...

Streamlit UI で無理やり頑張ってみた!

背景

Streamlit の UI widgets は基本インタラクティブアップデートみたいなのは考えられていません. たとえばテキスト領域でテキストの内容変わった場合, UI 全部再描画で対応となります.

st.experimental_rerun() で, 描画のリフレッシュをスクリプト側からリクエストすることができます.

ただ, UI widgets の数に変更なければチラツキとかレイアウト崩れはないですが, UI 数が多いと描画が遅くなりますので注意です.

方法

スクリプトのグローバルでカウンタを持ち, 文字(word)を一つづつメッセージを追加していき, ページのリドローでむりくり頑張ります.
(80 年代の UI みたいな感じ)

streamlit 自体にはグローバルなタイマー(animation update trigger)は無いようです.

今回はボタン押したら 0.2 秒ごとに word を append してリドローする, で ChatGPT っぽさを出してみました.

widget は st.text_area を使います.

import streamlit as st
import time

msg = "Originally a fishing village named Edo, the city became politically prominent in 1603, when it became the seat of the Tokugawa shogunate".split()

if "idx" not in st.session_state:
    st.session_state["idx"] = 0

if "msglen" not in st.session_state:
    st.session_state["msglen"] = len(msg)

def get_word():

    idx = st.session_state["idx"]
    #st.write(idx)

    st.session_state["idx"] += 1

    if idx < st.session_state["msglen"]:
        return msg[idx]
    else:
        return ""

 
if "msg" not in st.session_state:
    st.session_state["msg"] = "Tokyo: "


if "streaming" in st.session_state:
    st.session_state["msg"] += get_word() + " "

text = st.text_area("Awesome Chat AI", value=st.session_state["msg"], disabled=False, key="bora")

if st.button("stream"):
    st.session_state["idx"] = 0
    st.session_state["streaming"] = True


if "streaming" in st.session_state:
    if st.session_state["idx"] < st.session_state["msglen"]:
        time.sleep(0.2)
        st.experimental_rerun()
    else:
        del st.session_state["streaming"]

さらなる高みを目指して

chat メッセージ数増えると描画が遅くなるのが想定されるので, streamlit-chat のように React component で, ReactJS(JavaScript)側で streaming 表示頑張るのがよいでしょう.

st.text_area だとフォント変えたりとかレイアウト変えたりとかできないですし.

https://docs.streamlit.io/library/components

TODO

  • streamlit-chat のように React component で, ReactJS(JavaScript)側で streaming 表示頑張る

Discussion