HI,
I have a very simple streamlit chat app, and I am struggling with it.
when running it locally all works as expected
but when deploying it (on k8s) it is broken, each answer from the agent is being printed twice and the clear chat button is not working (it generate new session id but only clear the first human message)
this is my app:
import asyncio
import json
import uuid
from pathlib import Path
import streamlit as st
# Reuse your existing business logic
from escalina.server import call_llm # async function
from escalina.utilities.logging import get_logger
logger = get_logger(__name__)
# ---------- Page & Session Setup ----------
st.set_page_config(
page_title="Escalina — Streamlit",
page_icon="đź’¬",
layout="wide",
)
# Initialize session state
if "userid" not in st.session_state:
st.session_state.userid = str(uuid.uuid4())
if "history" not in st.session_state:
st.session_state.history = []
if "greeted" not in st.session_state:
st.session_state.greeted = False
if "processing" not in st.session_state:
st.session_state.processing = False
if "last_processed" not in st.session_state:
st.session_state.last_processed = None
BASE_DIR = Path(__file__).parent
IMAGE_PATH = BASE_DIR / "aa.png"
# ---------- Helpers ----------
def run_async(coro):
"""Run an async coroutine from Streamlit's sync context safely."""
try:
return asyncio.run(coro)
except RuntimeError:
loop = asyncio.new_event_loop()
try:
asyncio.set_event_loop(loop)
return loop.run_until_complete(coro)
finally:
loop.close()
asyncio.set_event_loop(None)
# ---------- Sidebar: Actions ----------
with st.sidebar:
st.subheader("Actions")
if st.button("Clear chat", use_container_width=True):
st.session_state.history = []
st.session_state.greeted = False
st.session_state.userid = str(uuid.uuid4())
st.session_state.processing = False
st.session_state.last_processed = None
st.rerun()
st.caption(f"Session ID: {st.session_state.userid}")
# ---------- Header ----------
st.title("Escalina")
if IMAGE_PATH.exists():
st.image(str(IMAGE_PATH), width=100)
else:
st.info("Place an 'aa.png' image next to this file to show a header image.")
if not st.session_state.greeted:
st.markdown("Hello there, I am Escalina!")
st.session_state.greeted = True
# ---------- Chat History ----------
for msg in st.session_state.history:
with st.chat_message(msg["role"]):
st.markdown(msg["content"])
# ---------- Chat Input ----------
if not st.session_state.processing:
prompt = st.chat_input("Ask me anything…")
if prompt and prompt != st.session_state.last_processed:
st.session_state.processing = True
st.session_state.history.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
st.session_state.last_processed = prompt
st.rerun()
else:
if st.session_state.last_processed:
with st.chat_message("assistant"):
with st.spinner("Thinking…"):
reply = run_async(
call_llm(st.session_state.last_processed, st.session_state.userid)
)
st.markdown(reply)
st.session_state.history.append({"role": "assistant", "content": reply})
st.session_state.processing = False
st.session_state.last_processed = None
st.rerun()