icon: LiNotebook
Streamlit is a Python library that makes it a breeze for us to create and share web applications. Streamlit
is gaining traction among developers working with large language models (LLMs) for its ability to streamline web application development.
It's perfect for data scientists and developers eager to display their work, from data visualizations to interactive tools, without diving deep into the complexities of web development. The beauty of Streamlit is its simplicity in transforming data scripts into fully functional web apps with just a few lines of code, making it a go-to for quick project prototyping.
Streamlit
as their go-to platform to experiment and build generative AI apps. You can visit the gallery here to get a sensing of the application that you can build using Streamlit.
App Gallery • Streamlit
icon: LiWrench
pip
and venv
are Essential for Your Streamlit App (Python Projects)pip
and venv
are tools essential practices for setting up your Streamlit app project.
✦ They ensure that your development process is smooth, your app is portable, and your project environment is reproducible.
✦ Understand and able to apply these tools means taking a significant step towards building robust, shareable web applications.
✦ Dependency Management with pip
:
LangChain
, OpenAI
, ragas
and many otherspip
allows you to manage these dependencies efficiently.
pip
to install and manage necessary packages, you ensure that your app has all the right tools to run smoothly. pip
helps in specifying the exact versions of these packages, preventing potential conflicts that might arise from updates or incompatibilities.✦ Isolated Environments with venv
:
venv
is a best practice that offers several benefits. ✦ Reproducibility and Collaboration:
venv
and pip
together, you can create a requirements.txt
file that lists all your project's dependencies. pip
is the package installer for Python.
pip
ensures that you can easily share and manage dependencies for your projects.pip
?pip
is included by default with Python versions 3.4 and later. You can check if pip
is installed by running: pip --version
pip
Commandspip install package_name
pip uninstall package_name
pip list
pip search package_name
pip install --upgrade package_name
venv
is a module that comes pre-installed with Python 3.3 and later versions, used to create isolated Python environments. Each environment has its own installation directories and doesn’t share libraries with other environments.
venv
?To create a virtual environment, you can use the following command:
python -m venv myenv
This command creates a directory called myenv
in your current directory, containing a fresh, isolated Python environment.
myenv\Scripts\activate.bat
source myenv/bin/activate
While the virtual environment is activated, you can use pip
to install, update, or remove packages. These operations will only affect the current virtual environment.
How it works
venv
, it essentially sets up a secluded sandbox for your Python project. pip
are confined to this sandbox. pip
, these actions will only affect the virtual environment and not the global Python installation on your system. To deactivate the virtual environment and use your global Python environment again, simply run:
deactivate
Suggest to watch @ 1.25x speed and watch it directly on YouTube if you want to able to resize the video windows.
Here is some common packages that give a good starting point for the virtual environment
pip install streamlit openai tiktoken python-dotenv langchain langchain-openai langchain-experimental pandas
Alternatively, you can use this requirements.txt as the starting point.
icon: LiWrench
import streamlit as st
import pandas as pd
import numpy as np
st.title('Uber pickups in NYC')
DATE_COLUMN = 'date/time'
DATA_URL = ('https://s3-us-west-2.amazonaws.com/'
'streamlit-demo-data/uber-raw-data-sep14.csv.gz')
@st.cache_data
def load_data(nrows):
data = pd.read_csv(DATA_URL, nrows=nrows)
lowercase = lambda x: str(x).lower()
data.rename(lowercase, axis='columns', inplace=True)
data[DATE_COLUMN] = pd.to_datetime(data[DATE_COLUMN])
return data
data_load_state = st.text('Loading data...')
data = load_data(10000)
data_load_state.text("Done! (using st.cache_data)")
if st.checkbox('Show raw data'):
st.subheader('Raw data')
st.write(data)
st.subheader('Number of pickups by hour')
hist_values = np.histogram(data[DATE_COLUMN].dt.hour, bins=24, range=(0,24))[0]
st.bar_chart(hist_values)
# Some number in the range 0-23
hour_to_filter = st.slider('hour', 0, 23, 17)
filtered_data = data[data[DATE_COLUMN].dt.hour == hour_to_filter]
st.subheader('Map of all pickups at %s:00' % hour_to_filter)
st.map(filtered_data)
streamlit run hello_world.py
magic command
and how the interactions between the slider and the data filtering work.if you have been following up to this point, you would have most the required understanding to get started on building on your own Streamlit app.
Most of the time, it's about using the right widgets that allow your applications to:
widget
is an interactive element that can be added to your app, allowing users to input data or adjust parameters in real-time. Widgets can range from simple buttons and text inputs to sliders and selectors, and somethings complex like editable tables or 3D rendering.Many of these decisions are specific to your PoC project. As we will be starting to work on the PoC project very soon, it is definitely a good time to check out the different widgets available on Streamlit and scout for the widgets that are potentially useful for your project.
✦ The best way to find out how the widgets work?
Official API Reference
sectionAs your app grows large, it becomes useful to organize your script into multiple pages. This makes your app easier to manage as a developer and easier to navigate as a user. Streamlit provides a frictionless way to create multipage apps. Pages are automatically shown in a navigation widget inside your app's sidebar. If a user clicks on a page in the sidebar, Streamlit navigates to that page without reloading the frontend — making app browsing incredibly fast! In this guide, let’s learn how to create multipage apps.
Streamlit identifies pages in a multipage app by directory structure and filenames. The file you pass to streamlit run
is called your entrypoint file. This is your app's homepage. When you have a pages/
directory next to your entrypoint file, Streamlit will identify each Python file within it as a page. The following example has three pages. main.py
is the entrypoint file and homepage.
your_working_directory/
├── pages/
│ ├── a_page.py
│ └── another_page.py
└── main.py
Run your multipage app just like you would for a single-page app.
streamlit run main.py
Only .py
files in the pages/
directory will be identified as pages. Streamlit ignores all other files in the pages/
directory and its subdirectories. Streamlit also ignores Python files in subdirectories of pages/
.
The entrypoint file is your app's homepage and the first page users will see when visiting your app. Once you've added pages to your app, the entrypoint file appears as the topmost page in the sidebar. Streamlit determines the page label and ordering of each page from your filenames.
Filenames are composed of four different parts as follows:
number
. A non-negative integer.separator
. Any combination of underscore ("_"
), dash ("-"
), and space (" "
).label
. Everything up to, but not including, ".py"
.".py"
The entrypoint file
is always displayed first. The remaining pages are sorted as follows:
number
appear before files without a number
.number
(if any), followed by the label
(if any).number
as an actual number rather than a string. So 03
is the same as 3
.This table shows examples of filenames and their corresponding labels, sorted by the order in which they appear in the sidebar.
Filename | Rendered label |
---|---|
1 - first page.py |
first page |
12 monkeys.py |
monkeys |
123.py |
123 |
123_hello_dear_world.py |
hello dear world |
_12 monkeys.py |
12 monkeys |
> [!tip] We can also set labels may differ from the page title set in st.set_page_config . |
In the script for the particular page, we can place this line
st.set_page_config(page_title="Your Preferred Label for the Page")
to set the custom label.
Now that you know a little more about all the individual pieces, let's close the loop and review how it works together:
.py
files in a pages
folder.icon: LiWrench
As we build Large Language Model (LLM) applications using Streamlit, it's important to aware and have right tools and techniques to streamline our development process. One such tool is the Python Debugger in Visual Studio Code (VS Code).
In this note, we'll explore the importance of being able to debug the Streamlit code, how it enhances our development workflow, and provide a step-by-step tutorial on setting it up in VS Code.
✦ A common misunderstanding is that debugging only applicable to lousy programmer or only needed when we have bugs.
✦ Debugging is a fundamental aspect of software development. It allows us to:
Let's dive into the practical steps of setting up and using the Python Debugger in VS Code for our Streamlit app.
Here, we assume we all have installed and set up our Visual Studio code correctly for Streamlit app development. For details on setting up, see 3. Setting Up Streamlit Project with pip and venv from Topic 7.
Install the Python Debugger
extension developed by Microsoft.
To configure the debugger, we need to create a launch.json
file in our project. This file contains the configuration settings for debugging.
Ctrl+Shift+D
.launch.json
file will be created with a default configuration. Modify it to match the following configuration:{
"configurations": [
{
"name": "Streamlit Debug",
"type": "python",
"request": "launch",
"module": "streamlit",
"args": [
"run",
"${file}"
]
}
]
}
Breakpoints allow us to pause the execution of our code at specific lines, so we can inspect variables and the program state.
Now that we have configured the debugger and set breakpoints, we can start debugging.
F5
to start debugging.VS Code will launch the Streamlit app and pause execution at the breakpoints we set. We can now inspect variables, step through the code, and evaluate expressions in the Debug Console.
While debugging, we can use the following controls:
F5
): Resume execution until the next breakpoint.F10
): Execute the next line of code, but don't step into functions.F11
): Step into functions to see their execution.Shift+F11
): Step out of the current function.Ctrl+Shift+F5
): Restart the debugging session.Shift+F5
): Stop the debugging session.We can also hover over variables to see their current values or use the Variables pane to inspect them.
00:00 - Intro and Setup "Python Debugger" extension
01:45 - Configure the Debugging Session (launch.json)
03:15 - Set Breakpoints in the code
06:46 - Starting the Debugging Session
10:08 - Examine the variables and their values
14:41 - Jupyter Notebook-like Interactive Python session (Debug Console)
16:32 - Navigating the code in Debugging Session (Continue, Step Over, Step into, and etc)
icon: LiNotebook
Now that you have experience with the basics of Streamlit, we will look into some important concepts of Streamlit that have caught some developers off guard and led to unexpected behavior in their applications.
Understanding these concepts is crucial for designing and developing efficient and effective Streamlit apps. In this deep dive, we will explore session state, button behavior, and dynamic widget management, providing you with the knowledge to avoid common pitfalls and enhance your app's functionality.
By having a solid understanding of these elements, you will be better equipped to create user-friendly applications and make the most of Streamlit's features in your projects.
This note provides a concise introduction to key "advanced" concepts in Streamlit, aiming to familiarize you with the framework's mechanics and empower you to begin building apps quickly. That's the best way to understand the concepts is to open up your VS Code and try to experiment with the code.
However, it's essential to understand that this is not an exhaustive resource. The official Streamlit documentation remains the definitive guide, offering comprehensive explanations, advanced techniques, and best practices.
To ensure a thorough understanding of Streamlit, we strongly recommend reading the official documentation. We will be including the links to the corresponding section in the official documentation in the different parts of the note below.
We recommend that you first try working with the content in this note. This should be sufficient to get you started. Remember to revisit this note for the links to the official documentation after you have gained some hands-on experience or when you encounter challenges implementing certain things. This approach is more effective.
Streamlit defines access to a Streamlit app in a browser tab as a session.
A session is a single instance of viewing an app. If you view an app from two different tabs in your browser, each tab will have its own session. So each viewer of an app will have a Session State tied to their specific view. Streamlit maintains this session as the user interacts with the app. If the user refreshes their browser page or reloads the URL to the app, their Session State resets and they begin again with a new session.
Session State
is a way to share variables between reruns, for each user session. In addition to the ability to store and persist state, Streamlit also exposes the ability to manipulate state using Callbacks. Session state also persists across apps inside a multipage app.
Check out this video by Streamlit Developer Advocate Dr. Marisa Smith to on two very essential concepts for Streamlit app development:
session state
callback
Session State provides a dictionary-like interface where you can save information that is preserved between script reruns. Use st.session_state
with key or attribute notation to store and recall values. For example, st.session_state["my_key"]
or st.session_state.my_key
. Remember that widgets handle their statefulness all by themselves, so you won't always need to use Session State!
There are a few common scenarios where Session State is helpful. As demonstrated in the video above, Session State is used when you have a progressive process that you want to build upon from one rerun to the next. Session State can also be used to prevent recalculation, similar to caching. However, the differences are important:
st.button
st.button
do not retain state. They return True
on the script rerun resulting from their click and immediately return to False
on the next script rerun.
if st.button('Click me'):
False
.This note explains the use of buttons and explain common misconceptions.
if st.button()
When code is conditioned on a button's value, it will execute once in response to the button being clicked and not again (until the button is clicked again).
✅ Good to nest inside buttons:
❌ Bad to nest inside buttons:
If you want to give the user a quick button to check if an entry is valid, but not keep that check displayed as the user continues.
animal
string is in the animal_shelter
list. st.text_input
, the script reruns and the message disappears until they click "Check availability" again.import streamlit as st
animal_shelter = ['cat', 'dog', 'rabbit', 'bird']
animal = st.text_input('Type an animal')
if st.button('Check availability'):
have_it = animal.lower() in animal_shelter
'We have that animal!' if have_it else 'We don\'t have that animal.'
If you want a clicked button to continue to be True
, create a value in st.session_state
and use the button to set that value to True
in a callback.
import streamlit as st
if 'clicked' not in st.session_state:
st.session_state.clicked = False
def click_button():
st.session_state.clicked = True
st.button('Click me', on_click=click_button)
if st.session_state.clicked:
# The message and nested widget will remain on the page
st.write('Button clicked!')
st.slider('Select a value')
st.session_state
If you modify st.session_state
inside of a button, you must consider where that button is within the script.
In this example, we access st.session_state.name
both before and after the buttons which modify it. When a button ("Jane" or "John") is clicked, the script reruns. The info displayed before the buttons lags behind the info written after the button. The data in st.session_state
before the button is not updated. When the script executes the button function, that is when the conditional code to update st.session_state
creates the change. Thus, this change is reflected after the button.
import streamlit as st
import pandas as pd
if 'name' not in st.session_state:
st.session_state['name'] = 'John Doe'
st.header(st.session_state['name'])
if st.button('Jane'):
st.session_state['name'] = 'Jane Doe'
if st.button('John'):
st.session_state['name'] = 'John Doe'
st.header(st.session_state['name'])
Callbacks are a clean way to modify st.session_state
. Callbacks are executed as a prefix to the script rerunning, so the position of the button relative to accessing data is not important.
import streamlit as st
import pandas as pd
if 'name' not in st.session_state:
st.session_state['name'] = 'John Doe'
def change_name(name):
st.session_state['name'] = name
st.header(st.session_state['name'])
st.button('Jane', on_click=change_name, args=['Jane Doe'])
st.button('John', on_click=change_name, args=['John Doe'])
st.header(st.session_state['name'])
When a button is used to modify or reset another widget, it is the same as the above examples to modify st.session_state
. However, an extra consideration exists: you cannot modify a key-value pair in st.session_state
if the widget with that key has already been rendered on the page for the current script run.
import streamlit as st
st.text_input('Name', key='name')
# These buttons will error because their nested code changes
# a widget's state after that widget within the script.
if st.button('Clear name'):
st.session_state.name = ''
if st.button('Streamlit!'):
st.session_state.name = ('Streamlit')
If you assign a key to a button, you can condition code on a button's state by using its value in st.session_state
. This means that logic depending on your button can be in your script before that button.
In the following example, we use the .get()
method on st.session_state
because the keys for the buttons will not exist when the script runs for the first time. The .get()
method will return False
if it can't find the key. Otherwise, it will return the value of the key.
import streamlit as st
# Use the get method since the keys won't be in session_state
# on the first script run
if st.session_state.get('clear'):
st.session_state['name'] = ''
if st.session_state.get('streamlit'):
st.session_state['name'] = 'Streamlit'
st.text_input('Name', key='name')
st.button('Clear name', key='clear')
st.button('Streamlit!', key='streamlit')
import streamlit as st
st.text_input('Name', key='name')
def set_name(name):
st.session_state.name = name
st.button('Clear name', on_click=set_name, args=[''])
st.button('Streamlit!', on_click=set_name, args=['Streamlit'])`
By using st.container
you can have widgets appear in different orders in your script and frontend view (webpage).
import streamlit as st
begin = st.container()
if st.button('Clear name'):
st.session_state.name = ''
if st.button('Streamlit!'):
st.session_state.name = ('Streamlit')
# The widget is second in logic, but first in display
begin.text_input('Name', key='name')
Storing unencrypted secrets in a git repository is a bad practice. For applications that require access to sensitive credentials, the recommended solution is to store those credentials outside the repository - such as using a credentials file not committed to the repository or passing them as environment variables
.
Streamlit provides native file-based secrets management to easily store and securely access your secrets in your Streamlit app.
Create a file secrets.toml
in the $CWD/.streamlit
folder where $CWD
is the folder you're running Streamlit from. For example, $CWD/.streamlit/secrets.toml
.
# Everything in this section will be available as an environment variable
OPENAPI_API_KEY = "sk-1241infjsenfuhnh81n8cdn"
# You can also add other sections if you like.
# The contents of sections as shown below will not become environment variables, # but they'll be easily accessible from within Streamlit anyway as we show
# later.
[my_other_secrets]
things_i_like = ["Streamlit", "Python"]
.gitignore
so you don't upload your secrets to online repositoryAccess your secrets by querying the st.secrets
dict, or as environment variables. For example, if you enter the secrets from the section above, the code below shows you how to access them within your Streamlit app
import streamlit as st
# Everything is accessible via the st.secrets dict:
st.write("OPENAPI_API_KEY:", st.secrets["OPENAPI_API_KEY"])
# Store the value in "Environment Variable"
# This is required by some packages like LangChain
os.environ['OPENAPI_API_KEY'] = st.secrets['OPENAPI_API_KEY']
icon: LiWrench
Password protection help ensures that sensitive data and proprietary information within the app are shielded from unauthorized access, thereby preserving confidentiality and preventing data breaches.
While password protection provides a basic level of security for our Streamlit application, it is not the most secure or robust method for safeguarding sensitive data and proprietary information. This simple mechanism is suitable for prototypes and initial development stages.
However, if the developers intend to transition the prototype to more serious development or production environments, it is crucial to consider more advanced access control mechanisms. For comprehensive security guidelines and best practices, please refer to IM8 or consult the relevant teams in your agency.
Most of us will deploy the application on Streamlit Communitu Cloud, so it's obvious that we need to prevent our applications from unauthorised access.
For project teams that go for hosting services that is within Government Commercial Cloud (GCC), such as CStack Cloud and Streamlit on Snowflake, the Streamlit web application itself can still be accessed from any device that has internet access. Therefore, we want to restricted the access to our Streamlit application.
.streamlit
at the root of the project foldersecrets.toml
in the new folderpassword = "<your app password>"
# filename: utility.py
import streamlit as st
import random
import hmac
# """
# This file contains the common components used in the Streamlit App.
# This includes the sidebar, the title, the footer, and the password check.
# """
def check_password():
"""Returns `True` if the user had the correct password."""
def password_entered():
"""Checks whether a password entered by the user is correct."""
if hmac.compare_digest(st.session_state["password"], st.secrets["password"]):
st.session_state["password_correct"] = True
del st.session_state["password"] # Don't store the password.
else:
st.session_state["password_correct"] = False
# Return True if the passward is validated.
if st.session_state.get("password_correct", False):
return True
# Show input for password.
st.text_input(
"Password", type="password", on_change=password_entered, key="password"
)
if "password_correct" in st.session_state:
st.error("😕 Password incorrect")
return False
We may need to install
hmac
into thevenv
(virtual environment)
from utility import check_password()
# Do not continue if check_password is not True.
if not check_password():
st.stop()
Here is an example, based on a main.py
file
import streamlit as st
from utility import check_password
# region <--------- Streamlit Page Configuration --------->
st.set_page_config(
layout="centered",
page_title="My Streamlit App"
)
# Do not continue if check_password is not True.
if not check_password():
st.stop()
# endregion <--------- Streamlit Page Configuration --------->
st.title("Streamlit App")
form = st.form(key="form")
form.subheader("Prompt")
user_prompt = form.text_area("Enter your prompt here", height=200)
if form.form_submit_button("Submit"):
print(f"User has submitted {user_prompt}")
icon: RiMeteorLine
This guide will walk you through the essential GitHub basics required to upload your Streamlit project to a GitHub
repository, enabling you to deploy your application on the Streamlit Community Cloud.
GitHub is a web-based platform that uses Git, a version control system, to help developers collaborate on projects. It allows you to store your code in repositories, track changes, manage project versions, and collaborate with others seamlessly.
GitHub is a web-based platform that hosts Git repositories. It provides additional features for collaboration and project management, such as:
For deploying Streamlit applications, GitHub serves as the central repository where your project files reside, which Streamlit Community Cloud can access to run your app.
Git is a distributed version control system that allows us to track changes in our codebase over time. It enables us to:
Before you can use GitHub, you need to create an account.
✦ Steps to Create an Account:
Download GitHub Desktop
from here and install the software on your laptop that you are using for this Bootcamp.
git
separately since GitHub comes with its own bundled version of git
.💪🏼 This is a great tutorial from Official YouTube channel of Visual Studio Code. This 7-min video covers all the key steps to use Git within VC Code
, allows you to efficiently manage your code repositories, push your code to the remote repository, and track changes, directly from the code editor.
GitHub Desktop
, we can skip the step for installing git
. The rest of the video is still applicable..gitignore
?The .gitignore
file is a special file used by Git to determine which files and directories to ignore in a project. When you add files to your repository, Git tracks changes to those files. However, some files should not be tracked—for example, temporary files, sensitive information, or dependencies that can be recreated. The .gitignore
file tells Git to exclude these files from version control.
Key Points:
.gitignore
placed in the root directory of your project..gitignore
?Using a .gitignore
file offers several benefits:
.env
or secrets.toml
files)venv
folder).gitignore
?within VS Code
, create a plain text file named .gitignore
placed in the root directory of your project. Add the filenames or directories for the file or folders that you want to exclude from being tracked by git or GitHub into the .gitignore
file.
Below are some common entries in the .gitingore
for a Python project.
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# Virtual environments
venv/
env/
ENV/
.venv/
.env/
# Distribution / packaging
build/
dist/
*.egg-info/
# VS Code
.vscode/
# PyCharm
.idea/
# Streamlit
.streamlit/secrets.toml
💡👨🏻💻👩🏻💻 If you want to collaborate in real-time with your team members in VS Code
, this is a great video to get started:
🍽️ Wanting more? Here is a series from GitHub's official YouTube channel designed to help you master the basics of GitHub, whether you're new to coding or looking to enhance your version control skills.
icon: LiWrench
Streamlit has great documentation on how to deploy on Streamlit Community Cloud. Instead of replicating the content, we direct you to the official resources so you can always refer to the most up-to-date information.
💻 Minimally, complete the following subsections in the "Streamlit Community Cloud" section: