How to display user and assistant chat on opposite sides when streaming like a conversation

Iโ€™m trying to display user and assistant chat on opposite sides when streaming like a conversation. Normally this is enabled by setting is_user=True in the message component. is_user=True displays the message from user on left and assistant on right
but while streaming is enabled we display content (user or assistant) message using st.markdown. In this case what is the workaround to setup something similar to the capability mentioned

message_placeholder = st.empty()
.
.
message_placeholder.markdown(full_response)

iโ€™m trying to achieve something like this image

This method still works as of streamlit 1.30

@blackary
What is the streamlit-chat you are working with? I tried executing this code block but mine were all aligned on the same side


This works for me on 1.31.0, with a slightly different class name

import streamlit as st

st.write("Streamlit version", st.__version__)

st.markdown(
    """
<style>
    .st-emotion-cache-4oy321 {
        flex-direction: row-reverse;
        text-align: right;
    }
</style>
""",
    unsafe_allow_html=True,
)

messages = [
    {
        "author": "user",
        "message": "hi",
    },
    {"author": "assistant", "message": "I'm a bot"},
] * 3

for message in messages:
    with st.chat_message(message["author"]):
        st.write(message["message"])

I updated it from the 1.30 version by inspecting the bot chats, and figuring out what the class name on them was.

1 Like

For 1.32.0, with a different class name

st.markdown(
            """
        <style>
            .st-emotion-cache-1c7y2kd {
                flex-direction: row-reverse;
                text-align: right;
            }
        </style>
        """,
            unsafe_allow_html=True,
        )

The above works for me in 1.32.0

Thank you @blackary

2 Likes

Is there a way to make it version independent?

This should be fairly independent of versions, and works by inserting an empty span with a specific class into each chat message, and then styling based on that class (in this case, it looks for a message that contains something the class chat-assistant)

import streamlit as st

st.write("Streamlit version", st.__version__)

messages = [
    {
        "author": "user",
        "message": "hi",
    },
    {"author": "assistant", "message": "I'm a bot"},
] * 3

for message in messages:
    with st.chat_message(message["author"]):
        st.html(f"<span class='chat-{message['author']}'></span>")
        st.write(message["message"])


st.html(
    """
<style>
    .stChatMessage:has(.chat-assistant) {
        flex-direction: row-reverse;
        text-align: right;
    }
</style>
"""
)