7장. 웹 UI 연동과 배포
Streamlit 기초와 화면 부품
식당의 주문 키오스크를 떠올려 보세요. 화면에 가게 이름이 크게 뜨고, 메뉴를 고르는 단추와 수량을 정하는 칸이 있고, 옆에는 "매장 / 포장"을 고르는 작은 막대가 붙어 있습니다. 키오스크를 만드는 사람이 그림을 그리듯 화면을 짜는 대신 "여기에 제목, 여기에 고르기 상자"라고 차례로 적어 주기만 하면 화면이 생긴다면 편할 것입니다. Streamlit 이 이렇게 일합니다. 파이썬 파일에 st.title(...), st.selectbox(...) 를 위에서부터 적으면 그 차례대로 웹 화면에 부품이 놓입니다.
왼쪽 파랑 상자는 보통의 웹 화면입니다. 화면의 뼈대(HTML), 꾸밈(CSS), 움직임(자바스크립트)을 따로 쓰고, 그와 별도로 파이썬 서버를 둡니다. 오른쪽 보라 상자는 Streamlit 입니다. 파이썬 파일 하나에 화면과 로직을 함께 적고, Streamlit 이 그것을 웹 화면으로 바꿔 줍니다. 여기서 키오스크 화면이 웹 UI, 키오스크의 단추와 칸이 위젯, 옆의 작은 막대가 사이드바입니다. 비유와 다른 점은, 키오스크는 화면 배치를 마음대로 바꿀 수 있지만 Streamlit 은 부품을 위에서 아래로 쌓는 꼴이 정해져 있어서 화려한 배치에는 맞지 않는다는 것입니다.
자주 쓰는 화면 부품
| 함수 | 원래 말 | 하는 일 | 돌려주는 값 |
|---|---|---|---|
st.set_page_config(page_title=…) | 쪽 설정 | 브라우저 탭의 제목을 정한다. 화면 코드 가운데 맨 먼저 부른다 | 없음 |
st.title("…") | 제목 | 가장 큰 제목 | 없음 |
st.write(…), st.markdown("…") | 쓰다, 마크다운 | 글을 쓴다. write 는 표나 사전도 알아서 그린다 | 없음 |
st.caption("…") | 설명 글 | 작고 흐린 설명 글 | 없음 |
st.text_input("이름") | 글 입력 | 한 줄 입력칸 | 적은 글(str) |
st.selectbox("여행지", [...]) | 고르기 상자 | 목록에서 하나 고르기 | 고른 값 |
st.slider("박수", 1, 5, 2) | 밀대 | 최솟값, 최댓값, 처음 값 사이에서 고르기 | 고른 수 |
st.button("인사하기") | 단추 | 누른 실행에서만 True | True / False |
with st.sidebar: | 옆 막대 | 이 안의 부품을 왼쪽 사이드바에 놓는다 | 없음 |
짧은 예시
앱을 브라우저로 띄우지 않고 AppTest 로 한 번 실행해, 화면에 무엇이 놓였는지 꺼내 봅니다. 앱 코드는 글자열로 적었습니다. 실제로는 이 글이 .py 파일 하나가 됩니다.
from streamlit.testing.v1 import AppTest
# 앱 코드를 글자열로 적어 둔다. 실제로는 이 글이 .py 파일 하나가 된다
APP = """
import streamlit as st
st.title("구름다리여행 여행 비서")
st.write("가고 싶은 곳을 골라 보세요.")
city = st.selectbox("여행지", ["제주도", "부산", "강릉"])
nights = st.slider("박수", 1, 5, 2)
st.write(f"{city} {nights}박 {nights + 1}일을 골랐습니다.")
"""
# from_string: 글자열의 앱을 브라우저 없이 한 번 실행한다
at = AppTest.from_string(APP).run()
print("제목:", at.title[0].value)
print("고르기 상자:", at.selectbox[0].label, "→", at.selectbox[0].value)
print("밀대:", at.slider[0].label, "→", at.slider[0].value)
print("마지막 글:", at.markdown[-1].value)제목: 구름다리여행 여행 비서
고르기 상자: 여행지 → 제주도
밀대: 박수 → 2
마지막 글: 제주도 2박 3일을 골랐습니다.고르기 상자는 손님이 아직 아무것도 고르지 않았으므로 목록의 첫 값 "제주도"를, 밀대는 처음 값 2 를 돌려주었습니다. 위젯 함수가 돌려준 값(city, nights)을 보통 변수처럼 다음 줄에서 바로 썼습니다. st.write 로 쓴 글은 화면에서 마크다운 글이 되므로 at.markdown 에서 꺼냅니다.
코드가 의미하는 것
이 코드는 키오스크 화면을 "여기에 제목, 여기에 고르기 상자"라고 차례로 적어 만든 뒤, 직원이 화면을 한 번 켜서 무엇이 놓였는지 훑어보는 일을 흉내 낸 것입니다. 화면 적기, 브라우저 없이 켜기, 부품 꺼내 보기의 세 동작입니다.
| 코드 | 하는 일 | 챗봇에서 뜻하는 것 |
|---|---|---|
APP = """ … """ | 앱 코드를 글자열로 담는다 | 실제로는 이 글이 .py 파일 한 장입니다. 챗봇의 웹 화면도 이렇게 파이썬 줄 몇 개로 적습니다 |
st.title(…), st.write(…)(앱 안) | 제목과 글을 위에서부터 놓는다 | 적은 차례가 곧 화면의 차례입니다. 챗봇 화면의 제목과 안내 글이 이 자리에 옵니다 |
city = st.selectbox(…), nights = st.slider(…)(앱 안) | 위젯을 놓고 손님이 고른 값을 받는다 | 위젯 함수는 부품을 그리면서 값도 돌려줍니다. 챗봇에서는 설정 칸이 이런 위젯입니다 |
AppTest.from_string(APP).run() | 앱을 브라우저 없이 한 번 실행한다 | 손님 없이 직원이 화면을 켜 보는 시험입니다. 이 장의 실습은 모두 이 방법으로 화면을 확인합니다 |
at.title[0].value, at.selectbox[0].value | 화면에 놓인 부품과 값을 꺼낸다 | 눈으로 보는 대신 코드로 화면을 읽습니다. 그래서 브라우저 없이 같은 결과를 되풀이해 얻습니다 |
결과에서 읽을 것은 두 가지입니다.
- 아무것도 고르지 않으면 위젯은 처음 값을 돌려줍니다. 고르기 상자는 목록의 첫 값 "제주도", 밀대는 처음 값 2 를 돌려주었습니다.
- 돌려받은 값은 다음 줄에서 바로 화면 글이 됩니다. 마지막 글 "제주도 2박 3일을 골랐습니다." 는
city와nights로 만든 글입니다.
주의할 점
- Streamlit 앱은
python 파일.py가 아니라streamlit run 파일.py로 실행합니다. 그냥python으로 돌리면 화면이 뜨지 않고 "missing ScriptRunContext" 같은 경고만 나옵니다. - 위젯의 이름표(
"여행지")가 같은 위젯을 두 번 만들면 "같은 위젯이 둘"이라는 오류가 납니다. 이름표가 같아야 하면key="city2"처럼 서로 다른 key 를 줍니다. - 이 장의 실습은 앱을
out_ch07_….py파일로 저장한 뒤AppTest.from_file(...)로 시험합니다. 실습이 끝나면 같은 파일을streamlit run으로 열어 브라우저에서도 확인해 보세요.