파이썬 Streamlit으로 WebUI, 웹 애플리케이션 쉽게 구축하는 방법 #2

지난 글에서 파이썬 Flask web framework를 다루었던 것에 이어서 오늘은 파이썬의 또 다른 web framework인 Streamlit에 대해 다뤄보겠습니다. Streamlit은 파이썬 코드를 간단히 작성하는 것 만으로도 대화형 웹 애플리케이션을 만들 수 있게 해주는 오픈소스 라이브러리입니다. 데이터 시각화나 머신러닝 모델링 같은 작업에서 짧은 시간 내에 간결하고 직관적으로 구현할 수 있다는 장점이 있습니다.

파이썬 Streamlit 웹 애플리케이션 01
파이썬 Streamlit 웹 애플리케이션 01



파이썬 Streamlit 웹 애플리케이션

설치와 기본 사용법

개발 환경 세팅

Streamlit을 시작하려면 파이썬 3.7 이상 버전이 필요합니다. 참고로, 글을 작성하는 오늘 기준 파이썬 최신 버전은 3.13입니다. 윈도우 환경에서 설치를 한다면 다음과 같이 할 수 있습니다. 물론 pip가 설치되어 있어야만 하는데, 여기에서는 pip 관련 내용은 제외합니다.

pip install streamlit

반면 할 수 있다면, 아나콘다와 같은 가상환경(venv 또는 conda)을 만들어 사용하는 편이 의존성 충돌을 방지하는 데 유리하죠. 다음과 같이 conda 환경 설정해 볼 수 있습니다.

conda create -n streamlit_env python=3.12 #streamlit_env 이란 이름의 가상환경 생성
conda activate streamlit_env
pip install streamlit

가상환경에서 Streamlit을 설치해서 사용하는 이유 중 가장 큰 장점은 다른 라이브러리와 충돌을 최소화할 수 있다는 것입니다. 하지만, 항상 정답이 있는 것은 아니므로 개인의 환경에 맞게 설정하시면 됩니다.


프로젝트 구조(예시)

Streamlit 애플리케이션은 대체로 .py 확장자를 가진 스크립트 하나만 있어도 충분합니다. 그러나 프로젝트가 커지면 여러 모듈로 분리하고, 데이터나 이미지 파일을 별도 폴더에 정리해야 유지보수하기가 쉽죠. 아래와 같은 파일 구조를 참고해 볼만 합니다.

my_streamlit_app/
 ┣ data/
 ┃  ┗ sample_data.csv
 ┣ images/
 ┃  ┗ example.webp (또는 png 등)
 ┣ app.py
 ┣ utils.py
 ┗ requirements.txt
  • data/: CSV, 엑셀 등 원본 데이터 저장
  • images/: 이미지 리소스 저장
  • app.py: Streamlit 실행 진입점
  • utils.py: 반복해서 쓰이는 함수나 클래스를 모아두는 유틸 파일
  • requirements.txt: 배포 및 협업을 위한 라이브러리 목록


간단한 예제로 기본 동작 이해하기

# app.py
import streamlit as st

def main():
    st.title("간단한 Streamlit 앱")
    name = st.text_input("이름을 입력하세요")
    if st.button("인사하기"):
        st.write(f"{name}님, 반갑습니다!")

if __name__ == "__main__":
    main()

코드를 작성한 후, 윈도우는 cmd같은 터미널에서 streamlit run app.py를 입력하면 웹 브라우저가 동작하면서 위 코드가 실행됩니다. 코드에서 알 수 있듯, st.text_input()으로 입력 필드를 만들고, st.button()으로 버튼을 만듭니다. 버튼이 클릭되면 st.write()가 실행되어 사용자의 입력값을 화면에 보여줍니다. 쉽죠? 개인적으로 Flask보다 훨씬 쉽고, GUI도 꽤 괜찮습니다.


레이아웃과 위젯 다루기

자, 이제 틀은 만들어 봤으니, 한 걸음 깊게 들어가 볼까요?

레이아웃 구성 방법

복잡한 대시보드를 만들 때는 화면을 행(row)과 열(column)로 나눠 배치하는 방식이 편합니다. st.columns() 을 이용해서, 다음과 같이 세 개의 열을 가질 수 있습니다. (열의 개수는 자유롭게 늘리거나 줄일 수 있습니다.)

col1, col2, col3 = st.columns(3)
with col1:
    st.write("첫 번째 열입니다.")
with col2:
    st.write("두 번째 열입니다.")
with col3:
    st.write("세 번째 열입니다.")

이런 식으로 열을 구분하여 그래프나 텍스트를 배치하면, 한 화면에 여러 내용을 보기 좋게 나눌 수 있다. 또는 st.sidebar를 이용해 옆에 메뉴 영역을 따로 두는 방법도 많다.

자주 사용되는 기본 위젯은 아래와 같아요.

  • 텍스트 입력(st.text_input()): 한 줄짜리 문자열 입력에 사용. 검색창이나 간단한 이름 입력에 적합하다.
  • 텍스트 영역(st.text_area()): 여러 줄의 긴 텍스트 입력에 사용. 예를 들어 사용자에게 피드백이나 코멘트를 받는 용도로 쓸 수 있다.
  • 버튼(st.button()): 특정 이벤트를 트리거할 때 사용. 한번 클릭할 때마다 함수를 호출하는 식으로 로직을 구성한다.
  • 슬라이더(st.slider()): 연속적 숫자 범위를 지정할 때 편리하다. 인덱스 선택, 확률 범위 설정 등 다양한 용도에 쓰인다.
  • 체크박스(st.checkbox()): 옵션의 온·오프 상태를 쉽게 토글할 수 있다. 선택된 경우에만 특정 그래프를 표시하도록 하는 등 유연하게 활용 가능하다.

위젯은 위 몇 가지 보다 더 많으며, 이들을 조합해서 쓰면 사용자의 인터랙션에 따라 실시간으로 화면이 갱신되는 동적인 웹 앱을 만들 수 있습니다.

데이터 시각화와 상호작용

Streamlit은 다양한 파이썬 시각화 도구와 쉽게 연동합니다. 예를 들어, matplotlib로 만든 그래프를 그릴 때는 다음과 같이 코드를 구성할 수 있습니다.

import matplotlib.pyplot as plt
import streamlit as st

def main():
    st.title("시각화 도구 matplotlib")
    fig, ax = plt.subplots()
    ax.plot([1,2,3],[10,30,20])
    st.pyplot(fig)

if __name__ == "__main__":
    main()

이렇게 matplotlib 객체 fig를 st.pyplot()에 전달하면, 즉시 다음과 같이 웹 화면에 그래프가 그려집니다.

파이썬 Streamlit 웹 애플리케이션 02
파이썬 Streamlit 웹 애플리케이션 02

Plotly, Altair 역시 비슷한 방식으로 st.plotly_chart(), st.altair_chart()를 사용하면 됩니다.


사용자 입력에 따라 변하는 그래프

사용자 상호작용이 잦아지면 렌더링이 너무 빈번히 일어날 수 있는데, 이는 불필요한 계산이 될 수 있습니다. 이 부분은 이어지는 단락을 캐싱 기능을 적절히 활용하면, 반복 계산 비용을 줄이고도 실시간 대화형을 구현할 수 있습니다. 또, UI 요소가 많아지면 코드를 구조적으로 관리해야 합니다. 함수로 나누어 “데이터 로드 → 전처리 → 필터링 → 그래프 그리기” 과정을 잘 구분해두면 체계적인 관리를 할 수 있습니다.


캐싱과 세션 상태 관리

st.cache_data(구 버전 st.cache) 기능

캐싱은, 함수 결과를 메모리에 저장해두고 동일한 입력 값으로 다시 호출할 때는 재계산을 생략하도록 도와주는 기능입니다. 예컨대, 대용량 CSV 파일을 불러오는 함수가 있다면, 한 번 계산해둔 결과를 반복적으로 재활용해 앱의 반응 속도를 높일 수 있습니다. 다음 예시를 참고하세요.

import streamlit as st
import pandas as pd

@st.cache_data
def load_data(file_path):
    df = pd.read_csv(file_path)
    # 복잡한 전처리 과정이 있다 가정
    return df

df = load_data("data/huge_file.csv")
st.write(df)
  • 모델 로딩: @st.cache_resource를 붙인 함수 load_model()에서 모델을 불러오고, 이후 예측 단계에서는 필요한 입력값을 넣어 결과만 얻습니다.
  • 데이터 전처리: 매일 일정 시간에 갱신되는 CSV 파일을 @st.cache_data로 읽어오면, 파일 내용이 동일한 한도 내에서 한 번만 로딩하도록 하여 앱 반응 속도를 높일 수 있습니다.


세션 상태(st.session_state)를 통한 사용자별 상태 유지 방법

웹 애플리케이션을 사용하다 보면, 페이지 새로 고침 시 이전에 입력했던 정보가 유지되길 원할 때가 있어요. 이때 세션 상태를 활용해야만 하는 것이죠.

st.session_state는 파이썬의 딕셔너리 형태로, 사용자별로 유지되는 상태값을 저장합니다.

if 'count' not in st.session_state:
    st.session_state.count = 0

if st.button("카운트 올리기"):
    st.session_state.count += 1

st.write(f"현재 카운트: {st.session_state.count}")

위 예시코드를 보면, 버튼을 누를 때마다 count 값이 증가하고, 페이지를 새로 고쳐도 사용자가 같은 세션 안에 있다면 해당 값이 유지됩니다. 이런 방식으로 사용자별 데이터를 관리하면, 간단한 로그인 세션이나 사용자 맞춤형 추천 시스템도 Streamlit 안에서 구현 가능합니다.


캐싱 전략 수립 및 성능 최적화

  • 데이터 전처리와 같은 CPU 집약적 작업은 @st.cache_data로 감싸 재활용
  • 그래프 렌더링은 상태에 따라 빈번히 바뀔 수 있으므로, 필요하다면 부분 캐싱 고려
  • 라이브러리 버전에 따라 캐싱 동작이 달라질 수 있으므로, Streamlit 버전을 고정하고 의존 라이브러리도 적절히 관리

이처럼 효율적인 캐싱과 상태 관리로 대용량 데이터나 복잡한 계산을 다루는 애플리케이션에서 성능을 개선해줄 수 있습니다.


파일 업로드, 다운로드 및 멀티미디어 처리

파일 처리

파일 업·다운로드 기능은 분석 업무나 사용자 피드백을 받을 때 필요하기도 합니다.

  • 업로드: st.file_uploader() 함수를 사용해 CSV, 이미지, 텍스트 등 다양한 파일을 받을 수 있다. 파일 객체는 BytesIO 형태로 제공되므로, pandas의 read_csv()나 PIL의 Image.open() 등을 통해 변환합니다.
  • 다운로드: st.download_button()을 통해 사용자가 데이터나 결과 파일을 내려받을 수 있도록 해줍니다.
uploaded_file = st.file_uploader("CSV 파일 업로드", type=["csv"])
if uploaded_file is not None:
    df = pd.read_csv(uploaded_file)
    st.write(df)


이미지, 동영상 등 미디어 파일 표시

  • 이미지 표시: st.image()를 사용하면 된다. 크기 조정, 캡션 표시가 가능하므로 빠르게 대시보드에 시각 자료를 추가할 수 있다.
  • 동영상 재생: st.video() 함수에 동영상 URL 또는 파일 객체를 넘기면, 웹 상에서 동영상 플레이어를 표시해준다.

이제 위 기능에 대한 예시 코드를 구현해 보겠습니다. 머신러닝 모델에서 사용자에게 이미지를 업로드받아 즉석에서 분류 결과를 보여주는 식의 데모가 Streamlit에서 자주 볼 수 있는 케이스입니다.

from PIL import Image
import streamlit as st

uploaded_image = st.file_uploader("이미지를 업로드하세요", type=["jpg", "png"])
if uploaded_image:
    img = Image.open(uploaded_image)
    st.image(img, caption="업로드한 이미지")

    # 예: 간단한 분류 모델 결과 시뮬레이션
    # model = load_model(...) # 실제 모델 로딩
    # result = model.predict(img) # 예측
    # st.write("분류 결과:", result)


이 외에도 텍스트 음성 변환(TTS) 결과를 오디오 파일로 재생하거나, 특정 웹캠 영상을 스트리밍하는 기능도 구현 가능하다. 다양한 미디어를 다룸으로써 사용자에게 풍부한 경험을 제공할 수 있다.




답글 남기기