|
|
import os |
|
|
import streamlit as st |
|
|
import datetime |
|
|
import google.generativeai as genai |
|
|
import time |
|
|
import google.api_core.exceptions |
|
|
|
|
|
|
|
|
st.set_page_config( |
|
|
page_title="마음 건강 다이어리 💖", |
|
|
page_icon="💖", |
|
|
layout="wide", |
|
|
) |
|
|
|
|
|
|
|
|
st.markdown( |
|
|
""" |
|
|
<style> |
|
|
/* 전체 폰트 변경 (Nanum Gothic, Google Fonts CDN 사용) */ |
|
|
@import url('https://fonts.googleapis.com/css2?family=Nanum+Gothic:wght@400;700&display=swap'); |
|
|
body { |
|
|
font-family: 'Nanum Gothic', sans-serif !important; |
|
|
} |
|
|
|
|
|
/* --- 생략된 다른 스타일들 --- */ |
|
|
/* 섹션 제목, 부제목, 버튼, Expander, Info/Success/Error/Warning Box 등 이전 스타일 유지 */ |
|
|
|
|
|
/* --- Chat UI 개선 --- */ |
|
|
/* 메시지 표시 영역 스타일 */ |
|
|
.message-container { |
|
|
max-height: 60vh; /* 화면 높이의 60%를 최대 높이로 설정 */ |
|
|
overflow-y: auto; /* 내용이 넘치면 세로 스크롤 생성 */ |
|
|
padding: 15px; /* 내부 여백 */ |
|
|
margin-bottom: 20px; /* 입력창과의 간격 */ |
|
|
display: flex; /* Flexbox 사용 */ |
|
|
flex-direction: column; /* 메시지 순서: 위에서 아래로 (기본값, 명시적 설정) */ |
|
|
border: 1px solid #e0e0e0; /* 약간 연한 테두리 */ |
|
|
border-radius: 10px; /* 둥근 모서리 */ |
|
|
background-color: #f9f9f9; /* 배경색 */ |
|
|
} |
|
|
|
|
|
/* Chat message 스타일 */ |
|
|
.stChatMessage[data-testid="stChatMessage"] { /* 정확한 셀렉터 사용 */ |
|
|
border-radius: 15px; |
|
|
padding: 12px 18px; /* 패딩 조정 */ |
|
|
margin-bottom: 10px; /* 메시지 간 간격 */ |
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.08); /* 그림자 약간 조정 */ |
|
|
width: fit-content; |
|
|
max-width: 80%; /* 메시지 최대 너비 */ |
|
|
font-size: 1rem; /* 기본 폰트 크기 */ |
|
|
word-wrap: break-word; /* 긴 단어 줄바꿈 */ |
|
|
border: none; /* 테두리 제거 */ |
|
|
} |
|
|
|
|
|
/* 사용자 메시지 정렬 및 스타일 */ |
|
|
div[data-testid="stChatMessage"]:has(div[data-testid="stChatMessageContent"][aria-label="user message"]) { |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
align-items: flex-end; /* 오른쪽 정렬 */ |
|
|
margin-left: auto; /* 컨테이너 오른쪽으로 밀기 */ |
|
|
} |
|
|
div[data-testid="stChatMessageContent"][aria-label="user message"] { |
|
|
background-color: #dcf8c6; /* 사용자 메시지 배경색 (WhatsApp 스타일) */ |
|
|
color: #303030; /* 텍스트 색상 */ |
|
|
} |
|
|
|
|
|
/* 어시스턴트 메시지 정렬 및 스타일 */ |
|
|
div[data-testid="stChatMessage"]:has(div[data-testid="stChatMessageContent"][aria-label="assistant message"]) { |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
align-items: flex-start; /* 왼쪽 정렬 */ |
|
|
margin-right: auto; /* 컨테이너 왼쪽으로 밀기 */ |
|
|
} |
|
|
div[data-testid="stChatMessageContent"][aria-label="assistant message"] { |
|
|
background-color: #ffffff; /* 챗봇 메시지 배경색 (흰색) */ |
|
|
color: #303030; /* 텍스트 색상 */ |
|
|
border: 1px solid #eee; /* 챗봇 메시지에 얇은 테두리 추가 */ |
|
|
} |
|
|
|
|
|
|
|
|
/* Toast message 스타일 */ |
|
|
div.streamlit-toast-container { |
|
|
z-index: 10000; |
|
|
} |
|
|
div[data-testid="stToast"] { |
|
|
border-radius: 15px; |
|
|
padding: 20px; |
|
|
box-shadow: 5px 5px 10px rgba(0,0,0,0.1); |
|
|
} |
|
|
|
|
|
/* 섹션 제목 스타일 */ |
|
|
.section-title { |
|
|
font-size: 28px; |
|
|
font-weight: bold; |
|
|
color: #212529; |
|
|
margin-bottom: 25px; |
|
|
padding-bottom: 15px; |
|
|
border-bottom: 3px dotted #ffb3ba; |
|
|
} |
|
|
|
|
|
/* 섹션 부제목 스타일 */ |
|
|
.section-subtitle { |
|
|
font-size: 18px; |
|
|
color: #555; |
|
|
margin-bottom: 15px; |
|
|
font-weight: 500; |
|
|
} |
|
|
|
|
|
/* 버튼 스타일 */ |
|
|
div.stButton > button { |
|
|
background-color: #ffb3ba; |
|
|
color: white; |
|
|
padding: 14px 28px; |
|
|
font-size: 18px; |
|
|
border-radius: 25px; |
|
|
border: none; |
|
|
box-shadow: 5px 5px 10px rgba(0,0,0,0.2); |
|
|
transition: background-color 0.3s ease, transform 0.3s ease; |
|
|
font-weight: bold; |
|
|
} |
|
|
div.stButton > button:hover { |
|
|
background-color: #ff808a; |
|
|
transform: scale(1.07); |
|
|
box-shadow: 5px 5px 15px rgba(0,0,0,0.3); |
|
|
} |
|
|
|
|
|
/* Expander 스타일 */ |
|
|
.streamlit-expanderHeader { |
|
|
font-weight: bold; |
|
|
color: #212529; |
|
|
border-bottom: 2px dotted #ffb3ba; |
|
|
padding-bottom: 10px; |
|
|
margin-bottom: 20px; |
|
|
font-size: 17px; |
|
|
} |
|
|
|
|
|
/* Info, Success, Error, Warning Box 스타일 */ |
|
|
div.stInfo, div.stSuccess, div.stError, div.stWarning { |
|
|
border-radius: 15px; |
|
|
padding: 20px; |
|
|
margin-bottom: 20px; |
|
|
box-shadow: 5px 5px 10px rgba(0,0,0,0.08); |
|
|
border-left: none !important; |
|
|
background-color: #ffe0e5 !important; /* 배경색 유지 */ |
|
|
border: 1px solid #ffb3ba; /* 테두리 추가 */ |
|
|
} |
|
|
</style> |
|
|
""", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
|
|
|
|
|
|
api_key = os.environ.get("GEMINI_API_KEY") or st.secrets.get("GEMINI_API_KEY") |
|
|
|
|
|
if not api_key: |
|
|
st.error("Gemini API 키가 설정되지 않았습니다. 환경 변수 또는 Streamlit Secrets에 `GEMINI_API_KEY`를 설정해주세요.") |
|
|
st.stop() |
|
|
|
|
|
try: |
|
|
genai.configure(api_key=api_key) |
|
|
except Exception as e: |
|
|
st.error(f"API 키 설정 중 오류 발생: {e}") |
|
|
st.stop() |
|
|
|
|
|
|
|
|
|
|
|
generation_config = { |
|
|
"temperature": 0.75, |
|
|
"top_p": 0.95, |
|
|
"top_k": 64, |
|
|
"max_output_tokens": 8192, |
|
|
"response_mime_type": "text/plain", |
|
|
} |
|
|
MODEL_NAME = "gemini-2.0-flash" |
|
|
|
|
|
try: |
|
|
model = genai.GenerativeModel( |
|
|
model_name=MODEL_NAME, |
|
|
generation_config=generation_config, |
|
|
|
|
|
) |
|
|
except Exception as e: |
|
|
st.error(f"Gemini 모델 로딩 중 오류 발생: {e}") |
|
|
st.stop() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if "daily_emotions" not in st.session_state: |
|
|
st.session_state["daily_emotions"] = {} |
|
|
if "chat_session" not in st.session_state: |
|
|
st.session_state["chat_session"] = None |
|
|
if "emotion_analysis_result" not in st.session_state: |
|
|
st.session_state["emotion_analysis_result"] = None |
|
|
if "counseling_messages" not in st.session_state: |
|
|
st.session_state["counseling_messages"] = [] |
|
|
if "analysis_to_chatbot" not in st.session_state: |
|
|
st.session_state["analysis_to_chatbot"] = "" |
|
|
if "counseling_history" not in st.session_state: |
|
|
st.session_state["counseling_history"] = [] |
|
|
if "section_index" not in st.session_state: |
|
|
st.session_state["section_index"] = 0 |
|
|
|
|
|
|
|
|
|
|
|
def analyze_emotion(emotion, reason): |
|
|
"""Gemini를 사용하여 감정과 이유를 분석하고 격려 메시지를 생성합니다.""" |
|
|
prompt = f""" |
|
|
**사용자 정보:** |
|
|
* 오늘의 감정: {emotion} |
|
|
* 감정 이유: {reason if reason else "특별한 이유는 없음"} |
|
|
|
|
|
**당신의 역할:** |
|
|
따뜻하고 공감 능력이 뛰어난 심리 상담가입니다. 사용자의 감정을 심리학적인 관점에서 분석하고, 긍정적인 지지와 격려를 보내주세요. |
|
|
|
|
|
**지시사항:** |
|
|
1. **감정 분석 (2-3문장):** 사용자의 감정과 그 이유(있다면)를 바탕으로 현재 심리 상태를 간결하게 분석해주세요. 전문 용어보다는 쉽고 이해하기 좋은 표현을 사용하세요. |
|
|
2. **공감 및 격려 (1-2문장):** 분석 내용을 바탕으로 사용자의 감정에 깊이 공감하고, 따뜻한 위로와 격려의 메시지를 전달해주세요. 친근하고 부드러운 말투(~해요, ~군요)를 사용해주세요. |
|
|
|
|
|
**출력 형식:** |
|
|
분석과 공감/격려 메시지를 자연스럽게 이어서 한 문단으로 작성해주세요. |
|
|
""" |
|
|
try: |
|
|
|
|
|
temp_model = genai.GenerativeModel(MODEL_NAME, generation_config=generation_config) |
|
|
response = temp_model.generate_content(prompt) |
|
|
|
|
|
analysis_text = response.text.strip().replace("**", "") |
|
|
return analysis_text |
|
|
except google.api_core.exceptions.ResourceExhausted as e: |
|
|
st.error(f"API 할당량 초과 오류가 발생했습니다. 잠시 후 다시 시도해주세요. 오류: {e}") |
|
|
return "죄송합니다. 지금은 감정 분석을 처리할 수 없습니다. 잠시 후 다시 시도해주세요." |
|
|
except Exception as e: |
|
|
st.error(f"감정 분석 중 오류가 발생했습니다: {e}") |
|
|
return "죄송합니다. 감정 분석 중 예상치 못한 오류가 발생했습니다." |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def record_emotion(emotion, reason): |
|
|
"""선택된 감정과 이유를 세션 상태에 기록합니다.""" |
|
|
now = datetime.datetime.now() |
|
|
timestamp_str = now.strftime("%Y-%m-%d %H:%M:%S") |
|
|
today = str(datetime.date.today()) |
|
|
reason_to_save = reason if reason else "" |
|
|
st.session_state["daily_emotions"][today] = { |
|
|
"emotion": emotion, |
|
|
"reason": reason_to_save, |
|
|
"timestamp": timestamp_str |
|
|
} |
|
|
st.toast(f"{timestamp_str} 감정: {emotion} 😊 기록 완료!", icon="✅") |
|
|
|
|
|
st.session_state["emotion_analysis_result"] = None |
|
|
st.session_state["analysis_to_chatbot"] = "" |
|
|
st.session_state["counseling_messages"] = [] |
|
|
st.session_state["counseling_history"] = [] |
|
|
st.session_state["chat_session"] = None |
|
|
st.session_state["section_index"] += 1 |
|
|
|
|
|
|
|
|
|
|
|
def display_emotion_history(): |
|
|
"""기록된 감정 이력을 날짜 역순으로 표시합니다.""" |
|
|
st.subheader("📊 감정 이력") |
|
|
st.markdown("지난 감정 기록을 통해 마음의 변화를 살펴보세요.") |
|
|
|
|
|
if not st.session_state["daily_emotions"]: |
|
|
st.info("아직 기록된 감정이 없어요. '💖 감정 체크인' 섹션에서 오늘 하루의 감정을 기록해보세요.") |
|
|
else: |
|
|
sorted_dates = sorted(st.session_state["daily_emotions"].keys(), reverse=True) |
|
|
for date_str in sorted_dates: |
|
|
emotion_data = st.session_state["daily_emotions"][date_str] |
|
|
display_date = datetime.datetime.strptime(date_str, "%Y-%m-%d").strftime("%Y년 %m월 %d일") |
|
|
with st.expander(f"{display_date} ({emotion_data['timestamp']}) - 감정: {emotion_data['emotion']}"): |
|
|
st.markdown(f"**감정:** {emotion_data['emotion']}") |
|
|
if emotion_data['reason']: |
|
|
st.markdown(f"**이유:**\n{emotion_data['reason']}") |
|
|
else: |
|
|
st.markdown("**이유:** (기록되지 않음)") |
|
|
st.markdown("---") |
|
|
|
|
|
|
|
|
|
|
|
def start_emotion_analysis(): |
|
|
"""오늘 기록된 감정을 분석하고 결과를 세션 상태에 저장합니다.""" |
|
|
today = str(datetime.date.today()) |
|
|
emotion_data = st.session_state["daily_emotions"].get(today) |
|
|
|
|
|
if emotion_data: |
|
|
with st.spinner("AI가 당신의 감정을 분석하고 있어요... 잠시만 기다려주세요 ✨"): |
|
|
emotion_analysis_result = analyze_emotion(emotion_data['emotion'], emotion_data['reason']) |
|
|
if emotion_analysis_result and not emotion_analysis_result.startswith("죄송합니다"): |
|
|
st.session_state["emotion_analysis_result"] = emotion_analysis_result |
|
|
st.session_state["analysis_to_chatbot"] = emotion_analysis_result |
|
|
st.success("AI 감정 분석 완료! 아래에서 결과를 확인하고 상담을 시작하세요.") |
|
|
|
|
|
else: |
|
|
|
|
|
st.warning(emotion_analysis_result or "감정 분석에 실패했습니다. 잠시 후 다시 시도해주세요.") |
|
|
else: |
|
|
st.warning("오늘의 감정이 아직 기록되지 않았어요. '감정 체크인' 섹션에서 먼저 기록해주세요.") |
|
|
|
|
|
|
|
|
|
|
|
def display_counseling_info(): |
|
|
"""학교, 학부모, 전문기관 상담 안내 정보를 표시합니다.""" |
|
|
st.subheader("📢 도움이 필요하다면 언제든 요청하세요") |
|
|
st.markdown("마음이 힘들거나 어려운 일이 있을 때, 혼자 고민하지 마세요. 기댈 수 있는 곳들이 있습니다.") |
|
|
|
|
|
with st.expander("🏫 학교 Wee클래스 / 상담 선생님"): |
|
|
st.markdown(""" |
|
|
* 학교에는 여러분의 이야기를 들어주고 도와줄 상담 선생님(Wee클래스)이 계세요. |
|
|
* 교내 상담실 위치나 상담 신청 방법을 모른다면 담임 선생님께 여쭤보세요. |
|
|
* 비밀은 보장되니 안심하고 이야기할 수 있어요. |
|
|
""") |
|
|
with st.expander("👨👩👧👦 부모님 또는 보호자"): |
|
|
st.markdown(""" |
|
|
* 가장 가까이 있는 부모님이나 보호자께 솔직하게 마음을 이야기하는 것도 좋은 방법이에요. |
|
|
* 어떻게 말을 꺼내야 할지 어렵다면, '요즘 마음이 좀 힘들어요'라고 시작해보세요. |
|
|
* 여러분의 마음을 이해하고 지지해주실 거예요. |
|
|
""") |
|
|
with st.expander("📞 청소년 상담 채널 (1388)"): |
|
|
st.markdown(""" |
|
|
* **전화:** 1388 (24시간 운영, 무료) |
|
|
* **문자:** #1388 |
|
|
* **카카오톡:** '청소년상담1388' 채널 추가 후 상담 |
|
|
* **온라인:** [청소년사이버상담센터](https://www.cyber1388.kr) |
|
|
* 혼자 해결하기 어려운 고민이 있을 때, 전문가의 도움을 받을 수 있어요. 익명으로도 상담 가능해요. |
|
|
""") |
|
|
st.markdown("---") |
|
|
st.markdown("**🌟 중요한 건 혼자 힘들어하지 않고 도움을 요청하는 용기입니다. 당신은 혼자가 아니에요!**") |
|
|
st.markdown("---") |
|
|
|
|
|
|
|
|
def main(): |
|
|
col_empty_left, col_main, col_empty_right = st.columns([0.5, 3, 0.5]) |
|
|
|
|
|
with st.sidebar: |
|
|
|
|
|
st.markdown("# 💖 마음 건강 다이어리") |
|
|
st.markdown("### 당신의 마음을 기록하고 AI와 대화해요") |
|
|
st.markdown("매일의 감정을 기록하고, AI 상담 친구와 편안하게 이야기하며 마음을 돌보세요. 🥰") |
|
|
with st.expander("🚀 앱 사용 가이드", expanded=False): |
|
|
st.markdown( |
|
|
""" |
|
|
**1단계: 감정 체크인 💖** |
|
|
- '💖 감정 체크인'에서 오늘의 감정을 선택하고, 이유를 간단히 적어주세요 (선택 사항). |
|
|
- '✅ 감정 기록 완료' 버튼을 누르면 다음 단계로 이동합니다. |
|
|
|
|
|
**2단계: AI 감정 분석 🔮** |
|
|
- '🔮 AI 감정 분석'에서 '✨ AI 감정 분석 시작하기' 버튼을 눌러주세요. |
|
|
- AI가 당신의 감정을 분석하고 따뜻한 메시지를 줄 거예요. |
|
|
- 분석 결과를 확인 후 '💬 AI 상담 챗봇 시작 👉' 버튼을 누르세요. |
|
|
|
|
|
**3단계: AI 상담 챗봇 💬** |
|
|
- '💬 AI 상담 챗봇'에서 AI와 자유롭게 대화하며 마음을 나눠보세요. |
|
|
- 대화 내용은 현재 세션 동안만 유지됩니다. (브라우저를 닫으면 사라짐) |
|
|
- 대화 후 '📊 감정 이력 확인 👉' 버튼을 눌러 다음 단계로 가세요. |
|
|
|
|
|
**4단계: 감정 이력 확인 📊** |
|
|
- '📊 감정 이력'에서 지난 감정 기록들을 날짜별로 확인할 수 있어요. |
|
|
- '📢 상담 안내 확인 👉' 버튼을 눌러 마지막 단계로 이동하세요. |
|
|
|
|
|
**5단계: 상담 안내 📢** |
|
|
- '📢 상담 안내'에서 도움이 필요할 때 연락할 수 있는 곳들의 정보를 확인하세요. |
|
|
- '💖 처음으로 돌아가기' 버튼을 누르면 다시 감정 체크인부터 시작할 수 있습니다. |
|
|
|
|
|
**💖 마음 건강 다이어리와 함께 당신의 마음을 더 깊이 이해하고 돌보는 시간을 가져보세요! 💪** |
|
|
""" |
|
|
) |
|
|
st.markdown("---") |
|
|
st.markdown("<p style='font-size: 14px; color: #777;'>Version 1.2</p>", unsafe_allow_html=True) |
|
|
|
|
|
with col_main: |
|
|
|
|
|
if st.session_state.section_index > 0: |
|
|
nav_cols = st.columns(2) |
|
|
with nav_cols[0]: |
|
|
if st.button("👈 이전 단계", key="prev_button_top", use_container_width=True): |
|
|
st.session_state.section_index -= 1 |
|
|
st.rerun() |
|
|
|
|
|
|
|
|
if st.session_state.section_index == 0: |
|
|
with st.container(border=True): |
|
|
st.markdown('<p class="section-title">💖 감정 체크인</p>', unsafe_allow_html=True) |
|
|
st.markdown('<p class="section-subtitle">오늘 하루, 당신의 마음은 어땠나요? 솔직한 감정을 기록해보세요.</p>', unsafe_allow_html=True) |
|
|
emotion_options = ["😄 행복해요", "😊 좋아요", "😶 평범해요", "🙁 슬퍼요", "😭 매우 슬퍼요", "😠 화나요", "😡 매우 화나요", "😥 불안해요", "😨 두려워요"] |
|
|
emotion = st.radio( |
|
|
"**오늘 나의 감정은?**", |
|
|
emotion_options, index=2, horizontal=True, key="emotion_radio" |
|
|
) |
|
|
reason = st.text_area( |
|
|
"**✍️ 왜 그렇게 느꼈나요? (선택 사항)**", height=100, |
|
|
placeholder="어떤 일이 있었는지, 어떤 생각이 들었는지 자유롭게 적어보세요.", key="emotion_reason_input" |
|
|
) |
|
|
if st.button("✅ 감정 기록 완료", use_container_width=True, key="record_button", type="primary"): |
|
|
record_emotion(emotion, reason) |
|
|
st.rerun() |
|
|
|
|
|
|
|
|
elif st.session_state.section_index == 1: |
|
|
with st.container(border=True): |
|
|
st.markdown('<p class="section-title">🔮 AI 감정 분석</p>', unsafe_allow_html=True) |
|
|
st.markdown('<p class="section-subtitle">AI가 당신의 감정을 이해하고 따뜻한 위로를 건네줄 거예요.</p>', unsafe_allow_html=True) |
|
|
today = str(datetime.date.today()) |
|
|
if today not in st.session_state.daily_emotions: |
|
|
st.warning("먼저 '감정 체크인' 단계에서 오늘의 감정을 기록해주세요.") |
|
|
if st.button("💖 감정 체크인으로 돌아가기", key="goto_record"): |
|
|
st.session_state.section_index = 0 |
|
|
st.rerun() |
|
|
else: |
|
|
if not st.session_state.get("emotion_analysis_result"): |
|
|
if st.button("✨ AI 감정 분석 시작하기", use_container_width=True, key="analyze_button", type="primary"): |
|
|
start_emotion_analysis() |
|
|
st.rerun() |
|
|
if st.session_state.get("emotion_analysis_result"): |
|
|
st.markdown("---") |
|
|
st.markdown("##### 📝 AI 감정 분석 결과") |
|
|
st.info(st.session_state["emotion_analysis_result"]) |
|
|
st.markdown("---") |
|
|
if st.button("💬 AI 상담 챗봇 시작 👉", use_container_width=True, key="next_chat_button"): |
|
|
st.session_state.section_index += 1 |
|
|
st.rerun() |
|
|
|
|
|
|
|
|
elif st.session_state.section_index == 2: |
|
|
with st.container(border=True): |
|
|
st.markdown('<p class="section-title">💬 AI 상담 챗봇</p>', unsafe_allow_html=True) |
|
|
st.markdown('<p class="section-subtitle">AI 상담 친구와 편안하게 대화하며 마음을 돌보세요.</p>', unsafe_allow_html=True) |
|
|
st.markdown("AI 챗봇은 당신의 이야기에 귀 기울이고 공감하며, 긍정적인 방향으로 나아갈 수 있도록 도울 거예요. 대화는 현재 세션 동안만 유지됩니다.") |
|
|
|
|
|
|
|
|
message_container = st.container() |
|
|
with message_container: |
|
|
|
|
|
st.markdown('<div class="message-container">', unsafe_allow_html=True) |
|
|
|
|
|
|
|
|
if not st.session_state["counseling_messages"] and st.session_state.get("analysis_to_chatbot"): |
|
|
today_emotion_data = st.session_state['daily_emotions'].get(str(datetime.date.today())) |
|
|
if today_emotion_data: |
|
|
today_emotion = today_emotion_data.get('emotion', '오늘') |
|
|
initial_chatbot_message = f""" |
|
|
안녕하세요! 😊 오늘 '{today_emotion}' 감정을 느끼셨군요. 제가 당신의 마음을 조금 더 이해하기 위해 분석해봤어요. |
|
|
|
|
|
"{st.session_state['analysis_to_chatbot']}" |
|
|
|
|
|
이 분석을 바탕으로, 당신에게 더 힘이 되는 대화를 나누고 싶어요. **지금 기분이 어떠신가요?** 어떤 이야기든 괜찮으니 편하게 저에게 말해주세요. 🥰 |
|
|
""" |
|
|
|
|
|
st.session_state["counseling_messages"].append({"role": "assistant", "content": initial_chatbot_message}) |
|
|
|
|
|
st.session_state["counseling_history"].append({"role": "model", "parts": [initial_chatbot_message]}) |
|
|
|
|
|
st.session_state["chat_session"] = None |
|
|
|
|
|
|
|
|
|
|
|
for msg in st.session_state["counseling_messages"]: |
|
|
|
|
|
with st.chat_message(msg["role"]): |
|
|
st.write(msg["content"]) |
|
|
|
|
|
st.markdown('</div>', unsafe_allow_html=True) |
|
|
|
|
|
|
|
|
|
|
|
if prompt := st.chat_input("AI 챗봇에게 이야기해보세요 (무엇이든 괜찮아요 😊)", key="chat_input"): |
|
|
|
|
|
st.session_state["counseling_messages"].append({"role": "user", "content": prompt}) |
|
|
st.session_state["counseling_history"].append({"role": "user", "parts": [prompt]}) |
|
|
|
|
|
|
|
|
with st.chat_message("assistant"): |
|
|
with st.spinner("AI 챗봇이 답장을 준비하고 있어요..."): |
|
|
try: |
|
|
|
|
|
if st.session_state["chat_session"] is None: |
|
|
st.session_state["chat_session"] = model.start_chat( |
|
|
|
|
|
history=st.session_state["counseling_history"][:-1] |
|
|
) |
|
|
chat_session = st.session_state["chat_session"] |
|
|
|
|
|
|
|
|
response = chat_session.send_message(prompt) |
|
|
ai_response = response.text.strip() |
|
|
|
|
|
|
|
|
st.session_state["counseling_messages"].append({"role": "assistant", "content": ai_response}) |
|
|
st.session_state["counseling_history"].append({"role": "model", "parts": [ai_response]}) |
|
|
|
|
|
|
|
|
st.write(ai_response) |
|
|
|
|
|
except google.api_core.exceptions.ResourceExhausted as e: |
|
|
st.error(f"API 할당량 초과로 응답을 받을 수 없습니다. 잠시 후 다시 시도해주세요. 오류: {e}") |
|
|
error_message = "죄송합니다. API 사용량 제한으로 지금은 답장을 드릴 수 없어요. 잠시 후 다시 시도해주세요." |
|
|
st.session_state["counseling_messages"].append({"role": "assistant", "content": error_message}) |
|
|
st.write(error_message) |
|
|
except Exception as e: |
|
|
st.error(f"챗봇 응답 생성 중 오류가 발생했습니다: {e}") |
|
|
error_message = "죄송합니다. 지금은 답장을 드릴 수 없어요. 잠시 후 다시 시도해주세요." |
|
|
st.session_state["counseling_messages"].append({"role": "assistant", "content": error_message}) |
|
|
st.write(error_message) |
|
|
|
|
|
|
|
|
st.rerun() |
|
|
|
|
|
st.markdown("---") |
|
|
|
|
|
if st.button("📊 감정 이력 확인 👉", use_container_width=True, key="history_button"): |
|
|
st.session_state.section_index += 1 |
|
|
st.rerun() |
|
|
|
|
|
|
|
|
elif st.session_state.section_index == 3: |
|
|
with st.container(border=True): |
|
|
st.markdown('<p class="section-title">📊 감정 이력</p>', unsafe_allow_html=True) |
|
|
display_emotion_history() |
|
|
if st.button("📢 상담 안내 확인 👉", use_container_width=True, key="counseling_button"): |
|
|
st.session_state.section_index += 1 |
|
|
st.rerun() |
|
|
|
|
|
|
|
|
elif st.session_state.section_index == 4: |
|
|
with st.container(border=True): |
|
|
st.markdown('<p class="section-title">📢 상담 안내</p>', unsafe_allow_html=True) |
|
|
display_counseling_info() |
|
|
if st.button("💖 처음으로 돌아가기", use_container_width=True, key="reset_button", type="primary"): |
|
|
|
|
|
st.session_state["emotion_analysis_result"] = None |
|
|
st.session_state["analysis_to_chatbot"] = "" |
|
|
st.session_state["counseling_messages"] = [] |
|
|
st.session_state["counseling_history"] = [] |
|
|
st.session_state["chat_session"] = None |
|
|
st.session_state.section_index = 0 |
|
|
st.rerun() |
|
|
|
|
|
if __name__ == "__main__": |
|
|
main() |