agentsclimarketplace

Building streamlit chat ui

Skill mouadja02/skills/skills/streamlit/developing-with-streamlit/skills/building-streamlit-chat-ui

Building chat interfaces in StreamlitFrom its SKILL.md

Install
npx -y skills add mouadja02/skills --skill building-streamlit-chat-ui

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

5.6 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it

Attribution: Sourced from streamlit/agent-skills by Streamlit.

Streamlit chat interfaces

Build conversational UIs with Streamlit's chat elements.

Basic chat structure

import streamlit as st

if "messages" not in st.session_state:
    st.session_state.messages = []

# Display chat history
for msg in st.session_state.messages:
    with st.chat_message(msg["role"]):
        st.write(msg["content"])

# Handle new input
if prompt := st.chat_input("Ask a question"):
    st.session_state.messages.append({"role": "user", "content": prompt})

    with st.chat_message("user"):
        st.write(prompt)

    with st.chat_message("assistant"):
        response = get_response(prompt)  # Your LLM call
        st.write(response)

    st.session_state.messages.append({"role": "assistant", "content": response})

Streaming responses

Use st.write_stream for token-by-token display. Pass any generator that yields strings, including the OpenAI generator directly:

def get_streaming_response(prompt):
    # Replace with your LLM client (OpenAI, Anthropic, Cortex, etc.)
    for chunk in your_llm_client.stream(prompt):
        yield chunk

with st.chat_message("assistant"):
    response = st.write_stream(get_streaming_response(prompt))

st.session_state.messages.append({"role": "assistant", "content": response})

With OpenAI, you can pass the stream directly:

from openai import OpenAI

client = OpenAI()
with st.chat_message("assistant"):
    stream = client.chat.completions.create(
        model="gpt-4o",
        messages=st.session_state.messages,
        stream=True,
    )
    response = st.write_stream(stream)

Chat message avatars

Streamlit provides default avatars for "user" and "assistant" roles—only customize if you have a specific need. You can use icons or images:

# With icons
with st.chat_message("assistant", avatar=":material/robot:"):
    st.write(assistant_message)

# With images
with st.chat_message("user", avatar="https://example.com/avatar.png"):
    st.write(user_message)

Suggestion chips

Offer clickable suggestions before the first message. The pills disappear once the user sends a message, creating a clean onboarding experience:

SUGGESTIONS = {
    ":blue[:material/help:] What is Streamlit?": "Explain what Streamlit is",
    ":green[:material/code:] Show me an example": "Show a simple Streamlit example",
}

# Only show before first message - they disappear after
if not st.session_state.messages:
    selected = st.pills("Try asking:", list(SUGGESTIONS.keys()), label_visibility="collapsed")
    if selected:
        # Use the selection as the first prompt
        prompt = SUGGESTIONS[selected]
        st.session_state.messages.append({"role": "user", "content": prompt})
        st.rerun()

The if not st.session_state.messages check ensures the suggestions only appear on an empty chat. Once a message is added, the pills vanish and the conversation takes over.

File uploads

Enable file attachments with accept_file. When enabled, st.chat_input returns a dict-like object with text and files attributes:

prompt = st.chat_input(
    "Ask about an image",
    accept_file=True,
    file_type=["jpg", "jpeg", "png"],
)

if prompt:
    with st.chat_message("user"):
        if prompt.text:
            st.write(prompt.text)
        if prompt.files:
            st.image(prompt.files[0])

    # Send to vision model
    with st.chat_message("assistant"):
        response = analyze_image(prompt.files[0], prompt.text)
        st.write(response)

Use accept_file="multiple" to allow multiple files.

Audio input

Enable voice recording with accept_audio. The recorded audio is available as a WAV file:

prompt = st.chat_input("Say something", accept_audio=True)

if prompt:
    if prompt.audio:
        st.audio(prompt.audio)
    if prompt.text:
        st.write(prompt.text)

Dictation with speech-to-text

Convert audio to text and inject it back into the chat input:

prompt = st.chat_input("Say something", accept_audio=True, key="chat")

if prompt and prompt.audio:
    # Transcribe with Whisper or another STT model
    transcript = openai.audio.transcriptions.create(
        model="whisper-1",
        file=prompt.audio,
    )
    # Set the transcribed text as the next input
    st.session_state.chat = transcript.text
    st.rerun()

User feedback

Add thumbs up/down feedback to assistant messages. Also supports "stars" and "faces" ratings:

with st.chat_message("assistant"):
    st.markdown(response)
    feedback = st.feedback("thumbs")
    if feedback is not None:
        st.toast(f"Feedback received: {'👍' if feedback == 1 else '👎'}")

Clear chat

Add a button to reset the conversation:

def clear_chat():
    st.session_state.messages = []

st.button("Clear chat", on_click=clear_chat)

Related skills

  • connecting-streamlit-to-snowflake: Database queries and Cortex chat example
  • optimizing-streamlit-performance: Caching strategies for LLM calls

References

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,790. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.