Showcase: How I used st.session_state, Groq, and Pydantic to scale an AI app during a viral 450+ user surge

Hey Streamlit Community! :waving_hand:

I wanted to share a project I built called DM Co-Pilot, an open-source AI assistant for Dungeons & Dragons. It generates VTT-ready JSON data (monsters, items, etc.) for Game Masters.

This weekend, the app unexpectedly went viral in a few TTRPG forums, hitting 450+ concurrent users. My streamlit-analytics2 dashboard just clocked 711 pageviews, 1,200+ widget interactions, and over 27 hours of active session time. Going from a quiet local build to a live stress test immediately broke my generation pipeline, so I had to re-architect it on the fly.

Here is how I kept it alive using Streamlit:

  • Global Session Memory: With 22 different generation modules, users were losing their generated JSON when switching tabs. I built a custom caching system using st.session_state to hold the JSON payloads globally, allowing them to switch between the Bestiary and the Loot Artificer without wiping their data.

  • The Engine & Safeguards: I swapped to the Groq LPU API to bring inference latency down to sub-2-seconds. To prevent the massive traffic from generating bad JSON formats for VTT exports, I wrapped all outputs in strict Pydantic validators and used Tenacity for auto-retries.

  • Audio Scribe (New!): I just integrated the new st.audio_input widget paired with Groq’s whisper-large-v3. Users can now literally speak their chaotic campaign ideas out loud, and the AI organizes them into structured text notes!

  • Database: I hooked it up to Google Cloud Firestore (NoSQL) so users can publish their generated items to a live “Community Vault.”

The App: https://dm-copilot-app.streamlit.app/ The Repo: https://github.com/Cmccombs01/DM-Copilot-App

I would love any feedback from the veterans here on how you handle complex st.session_state management when dealing with large nested JSON dictionaries!