Streamlit
데이터를 시각화하고 웹 애플리케이션을 구축하기 위한 Python 라이브러리
📚 강의 https://youtu.be/ZVmLe3odQvc?feature=shared
📌 메시지 입력
1. 페이지 설정
- set_page_config
st.set_page_config(page_title=None, page_icon=None, layout="centered", initial_sidebar_state="auto", menu_items=None)
2. 채팅 기능
📑 공식 문서 Chat elements https://docs.streamlit.io/develop/api-reference/chat
- chat_input : 사용자로부터 메시지를 입력받는다.
st.chat_input(placeholder="Your message", *, key=None, max_chars=None, disabled=False, on_submit=None, args=None, kwargs=None)
- chat_message : 사용자에게 메시지 표시한다.
st.chat_message(name, *, avatar=None)
-
- name "user" → user 아이콘으로 메시지 출력
코드
import streamlit as st
st.set_page_config(page_title="테스트 봇", page_icon="👨💻")
st.title("👨💻 테스트")
if user_input := st.chat_input("메시지를 입력해주세요."):
st.chat_message("user").write(f"{user_input}")
실행
streamlit run app.py
화면



사용자가 메시지를 입력하면 user_input으로 들어오게 되고, if 조건문을 타서 user 아이콘으로 그 메시지를 뿌려준다.
기본적으로 streamlit은 메시지를 입력할 때마다 전체 새로고침(재실행) 되기 때문에 메시지 내용이 교체된다.
데이터 보관이 되지 않기 때문에 메시지가 누적될 수 있도록 수동으로 구현해야 한다.
📌 답변 구현
3. 답변 메시지 추가
사용자가 메시지를 입력할 때, user 아이콘으로 사용자 메시지를 출력하고,
그 다음 이어서 설정한 메시지 내용을 assistant 아이콘으로 출력해서 답변 메시지처럼 만들었다.
코드
import streamlit as st
st.set_page_config(page_title="테스트 봇", page_icon="👨💻")
st.title("👨💻 테스트")
if user_input := st.chat_input("메시지를 입력해주세요."):
st.chat_message("user").write(f"{user_input}")
with st.chat_message("assistant"):
st.write(f"당신이 입력한 내용: {user_input}")
화면

📌 데이터 보관 (메시지 누적)
메시지를 입력할 때마다 특정 변수에 저장하고, 새로운 메시지가 입력될 때마다 변수에 저장한 메시지를 먼저 출력하고 그 다음 새 메시지를 출력하게 한다.
4. 캐싱
- session_state
messages라는 키 값이 session_state에 없으면 새로운 키로 리스트 형식으로 만들어주고,
이 messages에는 사용자가 입력한 메시지를 계속해서 추가해준다.
그냥 append 하지 않고 ("user", user_input) 튜플 형식으로 넣어준다.
코드
import streamlit as st
st.set_page_config(page_title="테스트 봇", page_icon="👨💻")
st.title("👨💻 테스트")
if "messages" not in st.session_state:
st.session_state["messages"] = []
if user_input := st.chat_input("메시지를 입력해주세요."):
st.chat_message("user").write(f"{user_input}")
# 사용자 메시지 저장
st.session_state["messages"].append(("user", user_input))
with st.chat_message("assistant"):
msg = f"당신이 입력한 내용: {user_input}"
st.write(msg)
# 답변 메시지 저장
st.session_state["messages"].append(("assistant", msg))
5. 저장된 메시지 먼저 출력
session_state에 "messages" 키 값이 저장되어 있고 메시지가 들어 있다면, 새 메시지를 저장하기 전에 저장된 메시지 먼저 출력한다.
각 role에 맞춰서 user 메시지는 user가, assistant 메시지는 assistant가 출력하도록 반복 돌려준다.
코드
import streamlit as st
st.set_page_config(page_title="테스트 봇", page_icon="👨💻")
st.title("👨💻 테스트")
if "messages" not in st.session_state:
st.session_state["messages"] = []
# 이전 대화 기록 출력
# messages 키 값이 저장되어 있고, 메시지가 들어 있다면 먼저 출력
if "messages" in st.session_state and len(st.session_state["messages"]) > 0:
# user, assistant 각 role에 맞게 출력
for role, message in st.session_state["messages"]:
st.chat_message(role).write(message)
if user_input := st.chat_input("메시지를 입력해주세요."):
st.chat_message("user").write(f"{user_input}")
st.session_state["messages"].append(("user", user_input))
with st.chat_message("assistant"):
msg = f"당신이 입력한 내용: {user_input}"
st.write(msg)
st.session_state["messages"].append(("assistant", msg))
화면

6. 메시지 출력 함수 분리
메시지 출력하는 코드를 함수로 분리하고 utils.py 파일로 옮겨서 import 하면 코드가 깔끔!
코드
import streamlit as st
from utils import print_messages
st.set_page_config(page_title="테스트 봇", page_icon="👨💻")
st.title("👨💻 테스트")
if "messages" not in st.session_state:
st.session_state["messages"] = []
# 이전 대화 기록 출력
print_messages()
if user_input := st.chat_input("메시지를 입력해주세요."):
st.chat_message("user").write(f"{user_input}")
st.session_state["messages"].append(("user", user_input))
with st.chat_message("assistant"):
msg = f"당신이 입력한 내용: {user_input}"
st.write(msg)
st.session_state["messages"].append(("assistant", msg))
import streamlit as st
# 이전 대화 기록 출력
def print_messages():
if "messages" in st.session_state and len(st.session_state["messages"]) > 0:
for role, message in st.session_state["messages"]:
st.chat_message(role).write(message)
7. ChatMessage로 메시지 객체화
메시지를 튜플로 넣지 않고, ChatMessage를 이용해서 role과 content로 메시지를 넣을 수 있다.
채팅 메시지임을 알려주므로 가독성이 좋다.
(아래부터는 import, 나머지 코드 생략)
if user_input := st.chat_input("메시지를 입력해주세요."):
st.chat_message("user").write(f"{user_input}")
st.session_state["messages"].append(ChatMessage(role="user", content=user_input))
with st.chat_message("assistant"):
msg = f"당신이 입력한 내용: {user_input}"
st.write(msg)
st.session_state["messages"].append(ChatMessage(role="assistant", content=msg))
객체화 시켰으니 마찬가지로 utils.py에서도 수정해줘야 한다.
def print_messages():
if "messages" in st.session_state and len(st.session_state["messages"]) > 0:
for chat_message in st.session_state["messages"]:
st.chat_message(chat_message.role).write(chat_message.content)
📌 LLM 적용
8. secrets.toml 파일 생성
Streamlit 앱에서 비밀 정보를 안전하게 관리하기 위한 파일이다.
- .gitignore에 추가
- API 키 정의
OPENAI_API_KEY="{API키}"
9. API 키 적용
import os
os.environ["OPENAI_API_KEY"] = st.secrets["OPENAI_API_KEY"]
10. 프롬프트 만들기
# LLM을 사용하여 AI의 답변을 생성
prompt = ChatPromptTemplate.from_template(
"""질문에 간결하게 답변해주세요.
{question}
"""
)
11. 체인 만들기
chain = prompt | ChatOpenAI()
12. 결과 만들기
response = chain.invoke({"question": user_input})
msg = response.content
# AI의 답변
with st.chat_message("assistant"):
#msg = f"당신이 입력한 내용: {user_input}"
st.write(msg)
st.session_state["messages"].append(ChatMessage(role="assistant", content=msg))
화면

13. StrOutputParser 사용
StrOutputParser를 사용하면 content를 꺼낼 필요가 없다.
chain = prompt | ChatOpenAI() | StrOutputParser()
msg = chain.invoke({"question": user_input})
📌 메모리 기능 구현
눈으로는 누적된 메시지가 확인이 되지만 시스템적으로는 대화 기록을 보관하고 있지 않아서 AI가 이전의 답변을 조회하지 못한다.
RunnableWithMessageHistory
작성중
'자율 학습 > 스터디' 카테고리의 다른 글
| [Docker, Redis] 애플리케이션 도커 이미지 만들기 (host.docker.internal) (0) | 2024.06.23 |
|---|---|
| [Docker] dockerfile 작성해서 도커 image 만들기 (커스텀 이미지) (0) | 2024.06.20 |
| [Docker, Redis] Port mapping 방법 (0) | 2024.06.20 |
| 윈도우에서 Docker 사용하기 (redis) (0) | 2024.06.04 |
| [정보처리기사 실기] 스터디 - 문제 내기 (0) | 2022.09.13 |