# Concept
- `Streamlit`은 `AI/ML engineer`들이 데화형 데이터 앱을 만들 수 있도록 돕는 `open-source Python framework`이다.
- 다양한 Widgit이 구현되어 있으며 이를 불러와 **나만의 UI을 쉽게 제작할 수 있다.**
- `import streamlit`을 통해 불러올 수 있다.
- Steamlit이 설치되어있는 가상환경에서 cmd에서 `streamlit run {file}.py`를 하면 streamlit server(offline)을 작동시킬 수 있다.
- cmd에서 `Ctrl+c`를 하게 될 시 Server가 종료된다.
# Reference
#### with
- 특정 `Resource`를 사용할 때 `with` 구문을 사용해서 간편화 할 수 있다.
```python
st.sidebar.title("sidebar titile")
st.sidebar.text_input("XXX")
```
->
```python
with st.sidebar:
st.title("sidebar title")
st.subheader("sidebar Subheader")
```
#### session_state
- `.session_state`을 사용하면 페이지가 초기화(사용자 상호 작용이나 코드 변경마다) 돼도 특정 값을 유지 할 수 있다.
- `session_state["{variable name}"] = {type}`을 하게 되면 streamlit에서 `session_state["{variable name}"]`의 값은 초기화 하지 않는다.
- 단 `session_state["{variable name}"] = {type}`만 단독으로 쓰게 될 시, 전체 코드가 다시 실행되면서 값이 초기화 되기 때문에 `if "messages" not in st.session_state` 같은 조건을 추가해 해당 변수에 값이 없을 때만 초기화 할 수 있도록 조정해주어야 한다.
- 변수를 사용할 때도 `st.session_state["variable"]`로 불러오면 된다.
```python
if "messages" not in st.session_state:
st.session_state["messages"] = []
st.session_state["messages"].append({"message" : message, "role" : role})
```
#### @st.cache
##### st.cache_resource
- `@st.cache_data` or `@st.cache_resource`을 사용하면 streamlit에서 해당 함수의 데이터가 변하기 전까지 함수를 다시 실행하지 않고 전의 있던 결과를 return 시킨다.
- `st.cache_data`는 함수의 return 값이 **`pickle`로 직렬화 될 수 있는 type인 경우** 사용할 수 있고 `st.cache_resource`는 데이터베이스 연결이나 `Tensorflow` 세션 같이 **`pickle`가 직렬화 할 수 없는 type**를 cache 하려고 할 때 사용한다.
```python
@st.cache_resource(show_spinner="Embedding file...")
def embed_file(file):
```
- `st.cache`안에 함수의 Parameter가 **hash** 할 수 없는 경우에 `UnhashableParamError`가 발생한다.
- `hash`의 뜻은 들어오는 데이터의 **서명**을 생성한다는 것을 의미한다. `st.cache`는 해당 데이터의 서명을 근거로 데이터가 바뀌였는지, 아닌지를 판단하고 이를 기준으로 **함수의 실행 여부**를 결정한다.
- 따라서 hash 할 수 없는 데이터가 들어왔을 경우 `st.cache`는 오류를 발생시킨다.
- 이를 해결하기 위해 hash 할 수 없는 데이터의 변수명 앞에 `_` 을 포함 시키면 `streamlit`에서 해당 문서를 hash 하려 하지 않는다. 그리고 **다른 hash 할 수 있는 변수를 추가로 포함**한다면 `UnhashableParamError`를 해결할 수 있다.
##### st.cache_data
```python
@st.cache_data(show_spinner="Making quiz...")
def run_quiz_chain(_docs, topic):
chain = {"context": questions_chain} | formatting_chain | output_parser
return chain.invoke(_docs)
```
- * hash를 할 수 없다는 뜻은 해당 데이터가 **변경 가능(Mutable)한 인자**를 가지고 있다는 뜻이다. ex) list, dic, etc..
##### st.cache_clear
- `cache`된 데이터들을 초기화 할 수 있다.
```python
st.cache_clear()
```
#### pages
- streamlit `{main}.py`에 `pages` 폴더를 만들고 거기에 하위 python file를 넣는다면 streamlit에서 자동으로`sidebar`에 해당 files을 연결시켜준다.
![[Streamlit Page Detail.png]]
# Widget
- `Streamlit`에는 수 많은 `Widget`이 있다. 여기 문서에는 [[LangChain Introduction]]에서 사용한 `Widgit`만 정리 하였다.
- [Steamlit widget 문서](https://docs.streamlit.io/develop/api-reference)을 통해 더 자세한 정보를 알 수 있다.
## Display Widget
#### write and magic
- `.write({any types})` : write 함수는 어떤 타입의 값이 나와도 화면에 출력해준다. LangChain의 module을 그대로 출력하면 module의 사용방법, funtion 등도 함께 포함되어 나온다.(LangChain에서 module의 적어놓은 정보들)
- `write` 함수를 쓰지 않아도 그냥 변수만 적으면 write와 동일하게 화면에 출력 시켜주는데 이를 streamlit에서는 `magic`이라고 표현한다.
```python
st.write("hello")
st.write([1, 2, 3])
st.write({"x": 1})
ChatPromptTemplate # 이렇게 적어도 화면에 표시된다. -> it's magic
```
#### write_stream
- [[Streamlit#write and magic|write]] 형식으로 문자를 `Streaming`으로 보여준다.
```python
def stream_data(content):
for word in content.split(" "):
yield word + " "
time.sleep(0.01)
st.write_stream(stream_data(message))
```
#### set_page_config
- `page_title` : web 상단 이름을 지정한다.
- `page_title` : web 상단 아이콘을 지정한다.
```python
st.set_page_config(
page_title="FullstackGPT",
page_icon="🤣",
)
```
#### title
- 화면에 title 양식으로 값을 출력한다.
```python
st.title("Hello world!")
```
#### subheader
- 화면에 subheader 양식으로 값을 출력한다.
```python
st.subheader("Welcome to Streamlit!")
```
#### markdown
- 화면에 markdown 형식으로 값을 출력한다.
```python
st.markdown(
"""
#### I love it!
"""
)
```
#### sidebar
- `.sidebar` 형식으로 사이트 옆에 값들을 출력한다.
```python
with st.sidebar:
st.title("sidebar titile")
st.text_input("XXX")
```
#### tabs
- `.tabs(["tab1", "tab2", ...])` : 여러 tab 항목을 List 형식을 지정한다.
- `.tab_name` 형식으로 각 tab 안의 내용들을 구성할 수 있다.
```python
transcript_tabs, summary_tabs, qa_tab = st.tabs(
[
"A_tabs",
"B_tabs",
"C_tabs",
]
)
with A_tabs:
st.write("A_tabs")
with B_tabs:
st.write("B_tabs")
with C_tabs:
st.write("C_tabs")
```
#### chat_message
- `role`은 "ai", "human" 등이 있으며 해당 역할로 값들을 출력한다.
```python
with st.chat_message(role):
st.markdown(message)
```
#### success
- 해당 `String`을 success format으로 출력한다.
```python
st.success("Correct!")
```
#### error
해당 `String`을 error format으로 출력한다.
```python
st.error("Wrong!")
```
#### dialog
- 데코레이션을 통해 해당 함수를 `dialog` 형태로 출력한다.
```python
@st.dialog("파일 목록", width="large")
def view_all_file_path():
st.markdown("### 불러온 문서 목록")
st.markdown("### 불러온 이미지 목록")
```
#### columns
- 해당 페이지를 나누어 표현할 수 있다.
- `number` : 몇 개로 나눌 지를 결정할 수 있다.
- `vertical_alignment` : 정렬 방식을 선택할 수 있다.
```python
left, right = st.columns(2, vertical_alignment="top")
with left:
st.markdown("### 불러온 문서 목록")
with right:
st.markdown("### 불러온 이미지 목록")
```
#### container
- 출력 값들을 하나의 Box로 출력할 수 있다.
- `height` : Box의 크기를 정할 수 있다.
- `border=True` : Box의 테두리 여부를 정할 수 있다.
```python
with st.container(height=800, border=True):
question = st.chat_input("여기에 물어보고 싶은 내용을 입력해주세요!")
```
## Input Widget
- `Stremlit`에서 input widget을 사용하여 data가 변경될 때 마다, **python 파일 전체가 다시 실행**된다.
- `session_state`을 통해 특정 데이터를 **Caching**할 수 있다.
#### selectbox
- `{String}, {tuple}`로 `String`은 selectbox widgit의 내용을 표현하고 `tuple`은 selectbox의 options을 설정한다.
```python
model = st.selectbox(
"Choose your model",
("GPT-3", "GPT-4"),
)
if model == "GPT-3":
st.write("cheep")
else:
st.write("not cheep")
```
#### slider
- `{String}, min_value={float}, max_value={float}`로 `String`은 slider widgit의 내용을 표현하고 `min_value`는 slider의 최소값을 `max_value`는 최대값을 설정한다.
```python
value = st.slider(
"htemperature",
min_value=0.1,
max_value=1.0,
)
```
#### text_input
- `text` 형태의 `input bar`가 생기며 `String` 값을 전달 받는다.
```python
name = st.text_input("What is your name?")
```
#### chat_input
- 사이트 하단에 `chatting bar`이 생기며 `String` 값을 전달 받는다.
```python
message = st.chat_input("Send a message to the ai")
```
#### radio
- 여러 `options`들 중 하나를 선택할 수 있는 `select bar`을 만들어 준다.
- `String`으로 해당radio를 설명할 수 있으며, `list`로 options을 표현한다. `index`는 처음 상태에서 어떤 값이 선택되어있는지를 설정할 수 있는 Parameter이다.
```python
value = st.radio(
"Select an options",
[answer["answer"] for answer in question["answers"]],
index=None,
)
```
#### uploading file
- `{String}, type = {list}`로 `String`은 upload widgit의 내용을 표현하고 `type`은 `list`에 포함된 확장자만 input 받을 수 있도록 설정한다.
```python
file = st.file_uploader(
"Upload a .txt .pdf or .docx file",
type=["pdf", "txt", "docx"],
)
```
#### form
- 값들을 `form` 형식으로 출력해준다.
- `form` 내부에는 form을 이루는 값들과 `form_submit_button()`이 있어야 한다.
- `form` 내부에서 작동하는 일들은 `streamlit`에서 `form_submit_button()`을 누르기 전까지 데이터를 업데이트 시키지 않는다.
```python
with st.form("questions_form"):
for question in response["questions"]:
st.write(question["question"])
value = st.radio(
"Select an options",
[answer["answer"] for answer in question["answers"]],
index=None,
)
button = st.form_submit_button()
```