[toyp] CDocs - 4. 화면 구성

이우철·2026년 3월 27일

cdocs

목록 보기
3/4

[UI] 사용자와 소통하는 챗봇 화면 구성하기

이번 토이프로젝트에선 화면 구성에 신경을 안써서...

핵심 코드: src/main.py (사고 과정 시각화)
Streamlit의 expander를 활용해 AI의 속마음을 보여줍니다.

import os
import sys
import streamlit as st

# [설정 가이드]
# 프로젝트 루트 경로를 sys.path에 추가하여 src 패키지를 인식하게 합니다.
# 이 코드가 없으면 'from src.chain...' 호출 시 모듈을 찾을 수 없는 에러가 발생할 수 있습니다.
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from src.chain import ask_question
from src.utils.logger import get_logger

# 웹 페이지의 기본 정보를 설정합니다 (탭 제목, 아이콘 등).
st.set_page_config(
  page_title="CDocs Agent - 지능형 사내 문서 비서",
  page_icon="🤖",
  layout="wide"
)

logger = get_logger("StreamlitApp")

# [상태 관리: session_state]
# Streamlit은 사용자가 상호작용할 때마다 스크립트가 처음부터 다시 실행됩니다.
# 따라서 대화 내역(messages)을 유지하려면 st.session_state라는 특수 저장소를 써야 합니다.
if "messages" not in st.session_state:
  st.session_state.messages = []

# 사이드바 구성: 앱의 설명이나 초기화 버튼을 둡니다.
with st.sidebar:
  st.title("🤖 CDocs Agent")
  st.info("노션, 웹, 로컬 파일을 통합 검색하여 답변합니다.")
  if st.button("대화 내용 초기화"):
      st.session_state.messages = []
      st.rerun()

st.title("지능형 에이전트 Q&A")

# 1. 기존 대화 내역 출력
# 사용자(user)와 비서(assistant)의 메시지를 구분하여 화면에 그립니다.
for message in st.session_state.messages:
  with st.chat_message(message["role"]):
      st.markdown(message["content"])
      # 답변 시 저장해둔 '사고 과정'이 있다면 다시 보여줍니다.
      if "thoughts" in message and message["thoughts"]:
          with st.expander("지난 사고 과정 (Thought Process)"):
              for idx, step in enumerate(message["thoughts"]):
                  st.write(f"**Step {idx+1}: {step['tool']} 호출**")
                  st.caption(f"결과 요약: {step['observation']}")

# 2. 새로운 질문 입력 처리
if prompt := st.chat_input("궁금한 사내 규정이나 업무 내용을 물어보세요"):
  # 사용자의 질문을 화면에 표시하고 이력에 저장
  st.session_state.messages.append({"role": "user", "content": prompt})
  with st.chat_message("user"):
      st.markdown(prompt)

  # 3. AI의 답변 생성 및 시각화
  with st.chat_message("assistant"):
      # st.status: AI가 생각하는 동안 '진행 중'임을 알려주는 멋진 UI 요소입니다.
      with st.status("에이전트가 최적의 답변을 위해 고민 중입니다...", expanded=True) as status:
          # chain.py에 정의된 에이전트 호출 (질문과 이전 대화 이력 전달)
          result = ask_question(prompt, chat_history=[])
          status.update(label="분석 완료!", state="complete", expanded=False)
      
      full_response = result["answer"]
      thoughts = result["thoughts"]
      
      # AI의 최종 답변 출력
      st.markdown(full_response)
      
      # [사고 과정 시각화]
      # 에이전트가 어떤 도구(노션 검색, 웹 검색 등)를 썼는지 투명하게 보여줍니다.
      # 신뢰도를 높이는 가장 좋은 방법입니다.
      if thoughts:
          with st.expander("에이전트 사고 과정 (Thought Process)", expanded=False):
              for idx, step in enumerate(thoughts):
                  st.write(f"**Step {idx+1}: {step['tool']} 도구 활용**")
                  if step['thought']:
                      st.text(step['thought']) # AI의 내부 판단 근거
                  st.caption(f"도구 실행 결과: {step['observation']}")

  # 답변 내용과 사고 과정을 세션에 저장하여 페이지가 새로고침되어도 유지되게 합니다.
  st.session_state.messages.append({
      "role": "assistant", 
      "content": full_response,
      "thoughts": thoughts
  })
profile
개발 정리 공간 - 업무일때도 있고, 공부일때도 있고...

0개의 댓글