Hi all! As the title says, I have a st.form that includes a st.text_input and a st.form_submit_button. The form is embedded as part of the st.container, and I want to keep it at the bottom of the page as the input field for a GPT model (similar to that of ChatGPT).
Here’s a simplified example of my current code:
with st.container():
with st.form("input_form"):
col1, col2 = st.columns([9, 1])
with col1:
st.text_input("Please enter what you want to tell me here: ")
with col2:
st.form_submit_button()
I’m thinking about adding CSS styles to these elements, but don’t know exactly how. Any help would be much appreciated!
For a form. you could set the position of the div[data-testid="stForm"] absolute, however, its interaction with other elements in the page will get tricky. Here an example:
Hi, thank you very much for your reply! The reason I didn’t choose st.chat_input is that it currently doesn’t support custom starter prompt (at least based on the answers I receive on my previous post), but st.text_input does support it. I tried your code, while it did fix the input box to the bottom of the page, the chat history seemed to ignore the input box and cut through it as if it didn’t exist:
with open('style.css') as f: # This is where I put your CSS code
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
init_prompt = st.selectbox(
'You might want to try these prompts...',
['How to socialize?',
'How to focus on tasks?',
'How to find peace in daily work?']
)
chat_room = st.container()
if 'history' not in st.session_state:
st.session_state['history'] = []
for msg in st.session_state['history']:
chat_room.chat_message(msg['role']).write(msg['content'])
def add_to_history(content: str, role: str) -> None:
st.session_state['history'].append(
{'role': role, 'content': content}
)
def get_gpt_response(prompt: str) -> Iterator[dict]:
return openai.ChatCompletion.create(
model='gpt-3.5-turbo',
messages=[{'role': 'user', 'content': prompt}],
temperature=0.5,
stream=True
)
instr = 'Hi there! Enter what you want to let me know here.'
with st.form('chat_input_form'):
input_col, btn_col = st.columns([8.5, 1])
with input_col:
prompt = st.text_input(
instr,
value=init_prompt,
placeholder=instr,
label_visibility='collapsed' # Hide the label
)
with btn_col:
submitted = st.form_submit_button('Chat')
if prompt and submitted:
chat_room.chat_message('user').markdown(prompt)
add_to_history(prompt, 'user')
with chat_room.chat_message('assistant'):
msg = st.empty()
full_res = ''
gpt_res = get_gpt_response(ND_PROMPT + prompt)
next(gpt_res) # Remove the role entry
for chunk in gpt_res:
if new_text := chunk['choices'][0]['delta']:
full_res += new_text['content']
msg.markdown(full_res + ':rainbow:')
else:
# We hit the end of the GPT response
msg.markdown(full_res)
add_to_history(full_res, 'assistant')
I want the chat history to respect the input box and always stay on top of it. Alternatively, putting the custom starter prompt inside st.chat_input also works. Do you mind taking a look at this and give me some hints to achieve either one of these options?
Could split the document such that the main app occupies only the top and keep the st.form fixed to the bottom. But that is probably not the best solution, I’d expect it to break on mobile or any small window, or if a sidebar is added…
Code:
import streamlit as st
from datetime import datetime
st.markdown(
"""
<style>
div[data-testid="stAppViewContainer"]{
position:fixed;
bottom:18%;
padding: 10px;
}
div[data-testid="stForm"]{
position:fixed;
right: 10%;
left: 10%;
bottom: 2%;
border: 2px solid green;
padding: 10px;
z-index: 10;
}
</style>
""", unsafe_allow_html=True
)
if "chat_history" not in st.session_state:
st.session_state.chat_history = list()
with st.form("input_form"):
"*Enter messages here*"
col1, col2 = st.columns([6, 1])
with col1:
message = st.text_input("message", label_visibility="collapsed")
if message:
st.session_state.chat_history.append(f"{datetime.now().strftime(r'%H:%M:%S')}: {message}")
with col2:
submitted = st.form_submit_button(use_container_width=True)
if submitted:
for msg in st.session_state.chat_history:
with st.chat_message("user", avatar="🤪"):
st.write(msg)