ll7098ll commited on
Commit
5ff42d5
·
verified ·
1 Parent(s): 906c7b1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +467 -128
app.py CHANGED
@@ -1,141 +1,480 @@
1
  import os
2
- import openai
3
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- # OpenAI API 설정
6
- openai_api_key = os.getenv("OPENAI_API_KEY")
7
- openai.api_key = openai_api_key
8
 
9
- def openai_chat(text, grade_level):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  try:
11
- # 학년 수준에 따른 프롬프트 추가
12
- grade_prompt = f"이 학생은 초등학교 {grade_level}학년입니다. 질문과 설명을 이 학년 수준에 맞게 해주세요.(학생의 학년에 맞게 질문과 답하는 내용의 범위를 해당 학년의 교육과정에 맞게 범위를 조정하세요."
13
-
14
- # 시스템 메시지를 세션 시작 시 한 번만 추가
15
- if not any(message["role"] == "system" for message in st.session_state.messages):
16
- st.session_state.messages.append({"role": "system", "content": grade_prompt})
17
- else:
18
- # 기존 시스템 메시지 업데이트 (선택 사항)
19
- st.session_state.messages[0]["content"] = grade_prompt
20
-
21
- response = openai.ChatCompletion.create(
22
- model="gpt-4o",
23
- messages=st.session_state.messages, # 전체 대화 세션 전달
24
- temperature=0.7,
25
- max_tokens=1000, # max_tokens 값 조정
26
- top_p=0.9,
27
- frequency_penalty=0,
28
- presence_penalty=0
29
  )
30
- return response.choices[0].message["content"]
31
- except Exception as e:
32
- return f"에러 발생: {str(e)}"
33
 
34
- # Streamlit 앱 설정
35
- st.set_page_config(page_title="AI 튜터", page_icon="🎓", initial_sidebar_state="expanded")
36
 
37
- # 페이지 스타일 커스터마이징
38
- st.markdown(
39
- """
40
- <style>
41
- /* 전체 배경색 설정 */
42
- .stApp {
43
- background-color: #fffafa; /* 은은한 핑크색 배경 */
44
- }
45
- /* 타이틀 스타일 */
46
- .main-title {
47
- font-size: 3rem;
48
- color: #000000; /* 검은색 */
49
- font-weight: 700;
50
- text-align: center;
51
- margin-bottom: 20px;
52
- }
53
- /* 채팅 메시지 스타일 */
54
- .chat-message {
55
- border-radius: 15px;
56
- padding: 15px;
57
- margin: 10px 0;
58
- display: flex;
59
- align-items: center;
60
- flex-wrap: wrap;
61
- word-break: break-word;
62
- }
63
- .chat-message-user {
64
- background-color: #ffebef; /* 따뜻한 파스텔 핑크 */
65
- color: #8b4513;
66
- justify-content: flex-end;
67
- }
68
- .chat-message-assistant {
69
- background-color: #ffe4e6; /* 부드러운 파스텔 복숭아 핑크색 */
70
- color: #6b4226;
71
- justify-content: flex-start;
72
- }
73
- .chat-avatar {
74
- width: 40px;
75
- height: 40px;
76
- border-radius: 50%;
77
- margin-right: 10px;
78
- }
79
- .chat-avatar-user {
80
- margin-left: 10px;
81
- margin-right: 0;
82
- }
83
- /* 사용자 입력 창 스타일 */
84
- .stTextInput input {
85
- border-radius: 15px;
86
- border: 2px solid #cd857f; /* 따뜻한 핑크색 */
87
- }
88
- /* 버튼 스타일 */
89
- .stButton button {
90
- background-color: #cd857f; /* 따뜻한 핑크색 */
91
- color: #fff;
92
- border-radius: 15px;
93
- padding: 10px 20px;
94
- }
95
- </style>
96
- """,
97
- unsafe_allow_html=True
98
- )
99
 
100
- # 메인 타이틀
101
- st.markdown("<div class='main-title'>AI 튜터 🎓</div>", unsafe_allow_html=True)
102
-
103
- # 채팅 세션 초기화
104
- if "messages" not in st.session_state:
105
- st.session_state.messages = [
106
- {"role": "system", "content": "친절하고 든든한 튜터가 되어 학생이 목표를 달성하도록 안내하고, 학생이 주제에서 벗어나면 부드럽게 다시 집중하도록 도와주세요. 학생이 질문에 대해 틀린 대답을 하는 경우, 정답을 알려주거나 왜 틀렸는지 설명해주고, 추가 질문을 통해 학생 스스로 오류를 발견하고 정답을 찾도록 유도해주세요. 학생이 큰 개념을 단계적으로 이해하도록 돕는 질문을 하고, 그 개념을 깊이 파고들 수 있도록 탐구 질문을 던지세요. 학생이 부담을 느끼지 않도록 한 번에 한 질문만 하세요. 학생이 이해한 것을 보여주면 대화를 마무리하세요."}
107
- ]
108
-
109
- # 사용자와 AI 아이콘 URL 설정
110
- user_icon_url = "https://cdn-icons-png.flaticon.com/512/1995/1995531.png" # 학생 아이콘 (책을 학생)
111
- assistant_icon_url = "https://cdn-icons-png.flaticon.com/512/4323/4323008.png" # 튜터 아이콘 (안경 쓴 선생님)
112
-
113
- # 학년 수준 선택
114
- with st.sidebar:
115
- grade_level = st.selectbox("📚 학년준을 선택하세요:", ["1", "2", "3", "4", "5", "6"], index=0, format_func=lambda x: f"초등학교 {x}학년")
116
- # 초기화 버튼
117
- if st.button("💡 초기화"):
118
- del st.session_state.messages # 메시지 세 상태 삭제
119
- st.rerun()
120
-
121
- # 채팅 메시지 표시
122
- for message in st.session_state.messages:
123
- if message["role"] != "system":
124
- role_class = "chat-message-user" if message["role"] == "user" else "chat-message-assistant"
125
- avatar_url = user_icon_url if message["role"] == "user" else assistant_icon_url
126
- avatar_class = "chat-avatar-user" if message["role"] == "user" else "chat-avatar"
 
 
 
 
 
127
  st.markdown(
128
- f"<div class='chat-message {role_class}'><img src='{avatar_url}' class='chat-avatar {avatar_class}'>{message['content']}</div>",
129
- unsafe_allow_html=True
 
 
 
 
130
  )
131
 
132
- # 사용입력
133
- if prompt := st.chat_input("📝학습 내용을 입력하면 AI 튜터가 질문을 통해서 개념을 이해하도록 도와줍니다."):
134
- # 사용자의 메시지를 세션에 추가
135
- st.session_state.messages.append({"role": "user", "content": prompt})
136
- st.markdown(f"<div class='chat-message chat-message-user'>{prompt}<img src='{user_icon_url}' class='chat-avatar chat-avatar-user'></div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
- # OpenAI API 호출
139
- response = openai_chat(prompt, grade_level)
140
- st.session_state.messages.append({"role": "assistant", "content": response})
141
- st.markdown(f"<div class='chat-message chat-message-assistant'><img src='{assistant_icon_url}' class='chat-avatar'>{response}</div>", unsafe_allow_html=True)
 
1
  import os
 
2
  import streamlit as st
3
+ import datetime
4
+ import google.generativeai as genai
5
+ import time
6
+
7
+ # --- Streamlit 설정 ---
8
+ st.set_page_config(
9
+ page_title="마음 건강 다이어리 💖",
10
+ page_icon="💖",
11
+ layout="wide",
12
+ )
13
+
14
+ # --- Custom CSS (스타일링) ---
15
+ st.markdown(
16
+ """
17
+ <style>
18
+ /* 전체 폰트 변경 (Nanum Gothic, Google Fonts CDN 사용) */
19
+ @import url('https://fonts.googleapis.com/css2?family=Nanum+Gothic:wght@400;700&display=swap');
20
+ body {
21
+ font-family: 'Nanum Gothic', sans-serif !important;
22
+ }
23
+
24
+ /* 섹션 제목 스타일 */
25
+ .section-title {
26
+ font-size: 28px; /* 더 크게 */
27
+ font-weight: bold;
28
+ color: #212529;
29
+ margin-bottom: 25px; /* 간격 증가 */
30
+ padding-bottom: 15px; /* 패딩 증가 */
31
+ border-bottom: 3px dotted #ffb3ba; /* 더 굵게 */
32
+ }
33
+
34
+ /* 섹션 부제목 스타일 */
35
+ .section-subtitle {
36
+ font-size: 18px; /* 약간 더 크게 */
37
+ color: #555;
38
+ margin-bottom: 15px; /* 간격 증가 */
39
+ font-weight: 500; /* 살짝 굵게 */
40
+ }
41
+
42
+ /* 버튼 스타일 (둥근 모양, 파스텔톤, 그림자 효과, 강조) */
43
+ div.stButton > button {
44
+ background-color: #ffb3ba; /* 메인 버튼 색상 (분홍) */
45
+ color: white;
46
+ padding: 14px 28px; /* 패딩 증가 */
47
+ font-size: 18px; /* 폰트 크기 증가 */
48
+ border-radius: 25px; /* 더 둥근 모양 */
49
+ border: none;
50
+ box-shadow: 5px 5px 10px rgba(0,0,0,0.2); /* 그림자 효과 더 강하게 */
51
+ transition: background-color 0.3s ease, transform 0.3s ease; /* 변환 효과 추가 */
52
+ font-weight: bold; /* 텍스트 굵게 */
53
+ }
54
+ div.stButton > button:hover {
55
+ background-color: #ff808a; /* 호버 시 버튼 색상 (더 진한 분홍) */
56
+ transform: scale(1.07); /* 살짝 더 커지는 효과 */
57
+ box-shadow: 5px 5px 15px rgba(0,0,0,0.3); /* 호버 시 그림자 효과 증가 */
58
+ }
59
+
60
+ /* 보조 버튼 스타일 (회색, 둥근 모양) */
61
+ div.stButton > button.secondary-button {
62
+ background-color: #ced4da; /* 보조 버튼 색상 */
63
+ color: #495057;
64
+ padding: 12px 24px; /* 패딩 약간 증가 */
65
+ font-size: 16px; /* 폰트 크기 유지 */
66
+ border-radius: 25px; /* 더 둥근 모양 */
67
+ border: none;
68
+ transition: background-color 0.3s ease;
69
+ }
70
+ div.stButton > button.secondary-button:hover {
71
+ background-color: #bac0c5; /* 호버 시 보조 버튼 색상 */
72
+ }
73
+
74
+ /* Expander 스타일 (제목 굵게, 밑줄) */
75
+ .streamlit-expanderHeader {
76
+ font-weight: bold;
77
+ color: #212529;
78
+ border-bottom: 2px dotted #ffb3ba; /* 점선 밑줄 (분홍) */
79
+ padding-bottom: 10px; /* 패딩 증가 */
80
+ margin-bottom: 20px; /* 간격 증가 */
81
+ font-size: 17px; /* 폰트 약간 키움 */
82
+ }
83
+
84
+ /* Info, Success, Error, Warning Box 스타일 (파스텔톤, 아이콘 추가) */
85
+ div.stInfo, div.stSuccess, div.stError, div.stWarning {
86
+ border-radius: 15px; /* 더 둥글게 */
87
+ padding: 20px; /* 패딩 증가 */
88
+ margin-bottom: 20px; /* 간격 증가 */
89
+ box-shadow: 5px 5px 10px rgba(0,0,0,0.08); /* 그림자 효과 약간 증가 */
90
+ border-left: none !important; /* 기존 왼쪽 테두리 제거 */
91
+ background-color: #ffe0e5 !important; /* 기본 배경색 (연한 분홍) */
92
+ }
93
+ div.stInfo {
94
+ background-color: #e0f7fa !important; /* Info 배경색 */
95
+ }
96
+ div.stSuccess {
97
+ background-color: #e8f5e9 !important; /* Success 배경색 */
98
+ }
99
+ div.stError {
100
+ background-color: #ffebee !important; /* Error 배경색 */
101
+ }
102
+ div.stWarning {
103
+ background-color: #fffde7 !important; /* Warning 배경색 */
104
+ }
105
+
106
+ /* Info, Success, Error, Warning Box 아이콘 스타일 */
107
+ div.stInfo::before, div.stSuccess::before, div.stError::before, div.stWarning::before {
108
+ content: "";
109
+ display: inline-block;
110
+ width: 30px; /* 아이콘 크기 증가 */
111
+ height: 30px; /* 아이콘 크기 증가 */
112
+ margin-right: 15px; /* 간격 증가 */
113
+ vertical-align: middle;
114
+ background-size: contain;
115
+ background-repeat: no-repeat;
116
+ }
117
+ div.stInfo::before {
118
+ background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%2303a9f4"%3E%3Cpath d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V5h2v4z"/%3E%3C/svg%3E'); /* Info 아이콘 (물음표) */
119
+ }
120
+ div.stSuccess::before {
121
+ background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%234caf50"%3E%3Cpath d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/%3E%3C/svg%3E'); /* Success 아이콘 (체크) */
122
+ }
123
+ div.stError::before {
124
+ background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23f44336"%3E%3Cpath d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/%3E%3C/svg%3E'); /* Error 아이콘 (느낌표) */
125
+ }
126
+ div.stWarning::before {
127
+ background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23ff9800"%3E%3Cpath d="M10.29 3.86L1.83 18a2 2 0 0 0 1.73 3h16.94a2 2 0 0 0 1.73-3L13.71 3.86a2 2 0 0 0-3.42 0zM12 15c-.55 0-1-.45-1-1v-2c0-.55.45-1 1-1s1 .45 1 1v2c0 .55-.45 1-1 1zm0-5c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1 .45 1 1 1z"/%3E%3C/svg%3E'); /* Warning 아이콘 (경고) */
128
+ }
129
+
130
+ /* Chat message 스타일 */
131
+ .stChatMessage[data-streamlit="true"] {
132
+ border-radius: 15px; /* 더 둥글게 */
133
+ padding: 15px 20px; /* 패딩 증가 */
134
+ margin-bottom: 15px; /* 간격 증가 */
135
+ box-shadow: 3px 3px 7px rgba(0,0,0,0.08); /* 그림자 효과 약간 증가 */
136
+ width: fit-content;
137
+ max-width: 80%;
138
+ font-size: 16px; /* 폰트 크기 약간 증가 */
139
+ }
140
+
141
+ .stChatMessage[data-streamlit="true"].user {
142
+ background-color: #e0f7fa; /* User message background: light blue-green, slightly lighter */
143
+ align-self: flex-end; /* User messages to the right */
144
+ }
145
+
146
+ .stChatMessage[data-streamlit="true"].assistant {
147
+ background-color: #f0f8ff; /* Assistant message background: very light gray, slightly lighter */
148
+ align-self: flex-start; /* Assistant messages to the left */
149
+ }
150
+
151
+
152
+ /* Toast message 스타일 */
153
+ div.streamlit-toast-container {
154
+ z-index: 10000; /* Toast를 항상 맨 위에 표시 */
155
+ }
156
+ div[data-testid="stToast"] {
157
+ border-radius: 15px; /* 더 둥글게 */
158
+ padding: 20px; /* 패딩 증가 */
159
+ box-shadow: 5px 5px 10px rgba(0,0,0,0.1); /* 그림자 효과 약간 증가 */
160
+ }
161
+
162
+ /*챗 컨테이너 스타일 삭제 (더이상 필요 없음)*/
163
+
164
+ </style>
165
+ """,
166
+ unsafe_allow_html=True,
167
+ )
168
 
 
 
 
169
 
170
+ # --- API 키 설정 (Hugging Face Secrets에서 관리 권장) ---
171
+ if "GEMINI_API_KEY" not in os.environ:
172
+ st.error("GEMINI_API_KEY 환경 변수가 설정되지 않았습니다. API 키를 설정해주세요.")
173
+ st.stop()
174
+ genai.configure(api_key=os.environ["GEMINI_API_KEY"])
175
+
176
+ # --- Gemini 모델 설정 ---
177
+ generation_config = {
178
+ "temperature": 0.7,
179
+ "top_p": 0.95,
180
+ "top_k": 64,
181
+ "max_output_tokens": 25000,
182
+ "response_mime_type": "text/plain",
183
+ }
184
+ model = genai.GenerativeModel(
185
+ model_name="gemini-2.0-flash-exp", # 또는 "gemini-pro"
186
+ generation_config=generation_config,
187
+ )
188
+
189
+
190
+ # --- 세션 상태 초기화 ---
191
+ if "daily_emotions" not in st.session_state:
192
+ st.session_state["daily_emotions"] = {}
193
+ if "current_tab" not in st.session_state:
194
+ st.session_state["current_tab"] = "❤️ 감정 체크인" # 더 이상 탭이 없으므로 무의미하지만 유지
195
+ if "chat_session" not in st.session_state:
196
+ st.session_state["chat_session"] = model.start_chat(history=[])
197
+ if "emotion_analysis_result" not in st.session_state:
198
+ st.session_state["emotion_analysis_result"] = None
199
+ if "counseling_messages" not in st.session_state:
200
+ st.session_state["counseling_messages"] = []
201
+ if "analysis_to_chatbot" not in st.session_state:
202
+ st.session_state["analysis_to_chatbot"] = ""
203
+ if "counseling_history" not in st.session_state: # 상담 로그 기록을 위한 세션 상태 추가
204
+ st.session_state["counseling_history"] = []
205
+ if "section_index" not in st.session_state: # 현재 섹션 index 저장
206
+ st.session_state["section_index"] = 0
207
+
208
+
209
+ # --- 감정 분석 함수 ---
210
+ def analyze_emotion(emotion, reason):
211
+ prompt = f"""
212
+ **오늘의 감정:** {emotion}
213
+ **감정 이유:** {reason}
214
+
215
+ **지시:**
216
+ 1. **감정 분석:** 제시된 감정과 이유를 바탕으로 **심리적인 관점**에서 감정을 분석하고, 2~3 문장으로 요약해주세요.
217
+ 2. **격려 및 공감:** 분석 내용을 바탕으로 **따뜻하고 친절하게** 격려와 공감 메시지를 1~2 문장으로 덧붙여주세요.
218
+
219
+ **출력 형식:**
220
+ **[감정 분석]**
221
+ - [감정 분석 내용]
222
+
223
+ **[격려 및 공감]**
224
+ - [격려 및 공감 메시지]
225
+
226
+ **주의:**
227
+ - 초등학생 3학년이 이해하기 쉬운 단어로, 친절하고 객관적인 어조로, **존댓말**을 사용해주세요.
228
+ - 부정적인 감정에 대한 분석일 경우, 긍정적인 방향으로 전환될 수 있도록 격려하는 내용을 포함해주세요.
229
+ """
230
+ chat_session = st.session_state["chat_session"]
231
  try:
232
+ response = chat_session.send_message(prompt)
233
+ analysis_text = response.text.strip()
234
+ return analysis_text
235
+ except google.api_core.exceptions.ResourceExhausted as e:
236
+ st.error(
237
+ f"API 할당량 초과 오류가 발생했습니다. 잠시 후 다시 시도해주세요. 오류 메시지: {e}"
 
 
 
 
 
 
 
 
 
 
 
 
238
  )
239
+ return None
 
 
240
 
 
 
241
 
242
+ # --- 감정 기록 함수 ---
243
+ def record_emotion(emotion, reason):
244
+ today = datetime.date.today()
245
+ st.session_state["daily_emotions"][str(today)] = {"emotion": emotion, "reason": reason}
246
+ st.toast(f"{today} 감정: {emotion} 😊 기록 완료!", icon="✅")
247
+ st.session_state["emotion_analysis_result"] = None
248
+ st.session_state["analysis_to_chatbot"] = None
249
+ st.session_state["counseling_messages"] = []
250
+ st.session_state["counseling_history"] = [] # 감정 기록 시 상담 기록 초기화
251
+ st.session_state["section_index"] += 1 # 다음 섹션으로 이동
252
+
253
+
254
+ # --- 감정 이력 표시 함수 ---
255
+ def display_emotion_history():
256
+ st.subheader("📊 감정 이력")
257
+ st.markdown("날짜별 감정 변화와 그때의 이유를 확인해보세요.")
258
+
259
+ if not st.session_state["daily_emotions"]:
260
+ st.info("아직 기록된 감정이 없어요. '💖 감정 체크인' 섹션에서 오늘 하루의 감정을 기록해보세요.") # 탭 -> 섹션으로 변경, 아이콘 변경
261
+ else:
262
+ sorted_dates = sorted(st.session_state["daily_emotions"].keys(), reverse=True)
263
+ for date_str in sorted_dates:
264
+ emotion_data = st.session_state["daily_emotions"][date_str]
265
+ st.write(f"- {date_str}: **{emotion_data['emotion']}**")
266
+ if emotion_data['reason']:
267
+ st.write(f" > {emotion_data['reason']}")
268
+ st.markdown("---")
269
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
 
271
+ # --- AI 감정 분석 및 상담 시작 함수 ---
272
+ def start_emotion_analysis_and_counseling():
273
+ today = str(datetime.date.today())
274
+ emotion_data = st.session_state["daily_emotions"].get(today)
275
+ if emotion_data and emotion_data['reason']:
276
+ with st.spinner("AI가 감정을 분석하고 있어요..."):
277
+ emotion_analysis_result = analyze_emotion(emotion_data['emotion'], emotion_data['reason'])
278
+ st.session_state["emotion_analysis_result"] = emotion_analysis_result
279
+ st.session_state["analysis_to_chatbot"] = emotion_analysis_result
280
+ st.success("AI 감정 분석 완료! '🔮 AI 감정 분석' 섹션에서 결과를 확인하고, '💬 AI 상담 챗봇' 섹션에서 상담을 시작해보세요.") # 탭 -> 섹션으로 변경, 아이콘 변경
281
+ st.session_state["section_index"] += 1 # 다음 섹션으로 이동
282
+ else:
283
+ st.warning("오늘의 감정과 감정 이유를 먼저 기록해주세요.")
284
+
285
+
286
+ # --- 상담 안내 ---
287
+ def display_counseling_info():
288
+ st.subheader("📢 상담 안내")
289
+ st.markdown("마음이 힘들거나 어려운 일이 있을 때, 혼자 고민하요. ")
290
+ st.markdown("학교 선생님이나 부모님께 이야기하거나, 전문 상담 선생님의 도움을 받는 것도 좋은 방법입니다.")
291
+
292
+ with st.expander("🏫 학교 상담"):
293
+ st.markdown(
294
+ """
295
+ **학교 상담 선생님**께서는 여러분의 마음 건강을 위해 항상 도움을 주실 준비가 되어 있습니다.
296
+ - **상담 가능 내용:** 학교생활의 어려움, 친구 관계, 가족 문제, 진로 고민 등
297
+ - **상담 신청 방법:** 담임 선생님께 말씀드리거나, 상담실에 직접 방문하여 신청할 수 있습니다.
298
+ - **상담 시간:** (예시) 점심시간, 방과 후 시간 등 (학교 상담실 운영 시간에 따라 다름)
299
+ """
300
+ )
301
+
302
+ with st.expander("👨‍👩‍👧‍👦 학부모 상담"):
303
  st.markdown(
304
+ """
305
+ 부모님께 솔직하게 이야기하고 도움을 요청하는 것도 좋은 방법입니다.
306
+ - **상담 가능 내용:** 가정 문제, 학교 문제, 개인적인 고민 등 모든 내용
307
+ - **상담 방법:** 편안한 시간과 장소에서 부모님과 대화해보세요.
308
+ - **팁:** 부모님께 먼저 '이야기하고 싶은 것이 있다'고 말씀드리면, 부모님께서 더 잘 들어주실 거예요.
309
+ """
310
  )
311
 
312
+ st.markdown("**🌟 중요한 건 혼힘들어하지 않고, 주변에 도움을 요청하는 용입니다. 여러분은 혼자가 아니에요!**")
313
+ st.markdown("---")
314
+
315
+
316
+
317
+ # --- 메인 화면 ---
318
+ def main():
319
+ # 메인 컬럼 설정
320
+ col_empty_left, col_main, col_empty_right = st.columns([1, 3, 1])
321
+
322
+ with st.sidebar: # 사이드바 내용
323
+ st.markdown("# 💖 마음 건강 다이어리") # 앱 이름 변경, 아이콘 변경
324
+ st.markdown("### 당신의 마음을 기록하고, AI와 상담하세요") # 부제목 변경
325
+ st.markdown("매일 감정을 기록하고, AI와 마음 건강 상담을 시작해보세요! 🥰")
326
+ with st.expander("🚀 앱 사용 가이드", expanded=False):
327
+ st.markdown(
328
+ """
329
+ **1단계: 감정 체크인 💖**
330
+ - '💖 감정 체크인' 섹션에서 오늘 하루의 감정을 선택하고, 왜 그런 감정을 느꼈는지 이유를 적어주세요.
331
+ - '✅ 감정 기록 완료' 버튼을 눌러 감정을 기록하면 다음 섹션으로 이동합니다.
332
+
333
+ **2단계: AI 감정 분석 🔮**
334
+ - '🔮 AI 감정 분석' 섹션에서 '✨ AI 감정 분석 시작' 버튼을 눌러 AI 감정 분석을 시작합니다.
335
+ - AI 분석 결과를 확인하고, '다음 단계' 버튼을 눌러 다음 섹션으로 이동하세요.
336
+
337
+ **3단계: AI 상담 챗봇 💬**
338
+ - '💬 AI 상담 챗봇' 섹션에서 AI 챗봇과 자유롭게 대화하며 마음을 정리해보세요.
339
+ - '📊 감정 이력' 버튼을 눌러 다음 섹션으로 이동하세요.
340
+
341
+ **4단계: 감정 이력 확인 📊**
342
+ - '📊 감정 이력' 섹션에서 날짜별 감정 변화와 감정 이유를 확인할 수 있습니다.
343
+ - '📢 상담 안내' 버튼을 눌러 다음 섹션으로 이동하세요.
344
+
345
+ **5단계: 상담 안내 📢**
346
+ - '📢 상담 안내' 섹션에서 학교 상담, 학부모 상담 정보를 확인하고 필요시 도움을 요청하세요.
347
+ - 모든 단계를 완료했습니다! '💖 감정 체크인' 섹션으로 돌아가 다시 시작해보세요.
348
+
349
+ **💖 마음 건강 다이어리와 함께 행복한 하루를 만들어가세요! 💪** # 마무리 문구 변경
350
+ - 이 앱을 통해 자신의 감정을 이해하고, AI 상담을 통해 마음을 건강하게 관리해보세요! 😊
351
+ """
352
+ )
353
+ st.markdown("---")
354
+ st.markdown("<p style='font-size: 14px; color: #777;'>Version 1.0</p>", unsafe_allow_html=True) # 버전 정보 추가
355
+
356
+
357
+ with col_main: # 메인 컬럼 내용
358
+
359
+ sections = [
360
+ "❤️ 감정 체크인",
361
+ "🔮 AI 감정 분석",
362
+ "💬 AI 상담 챗봇",
363
+ "📊 감정 이력",
364
+ "📢 상담 안내",
365
+ ]
366
+
367
+ current_section_index = st.session_state.get("section_index", 0)
368
+
369
+ # --- ❤️ 감정 체크인 섹션 ---
370
+ if st.session_state.section_index == 0:
371
+ with st.container():
372
+ st.markdown('<p class="section-title">💖 감정 체크인</p>', unsafe_allow_html=True) # 섹션 제목, 아이콘 변경
373
+ st.markdown('<p class="section-subtitle">오늘 하루를 되돌아보고, 당신의 감정을 기록해보세요.</p>', unsafe_allow_html=True) # 섹션 부제목
374
+
375
+ emotion_options = ["😄 행복해요", "😊 좋아요", "😶 평범해요", "🙁 슬퍼요", "😭 매우 슬퍼요", "😠 화나요", "😡 매우 화나요", "😥 불안해요", "😨 무서워요"]
376
+ emotion = st.radio("오늘 나의 감정", emotion_options, index=2) # 라디오 버튼 제목 변경
377
+ reason = st.text_area("✍️ 감정 이유 (선택 사항, 간단하게 적어보세요)", height=100) # 텍스트 area 제목 변경, 선택 사항 안내
378
+
379
+ if st.button("✅ 감정 기록 완료", use_container_width=True): # 버튼 텍스트 변경
380
+ if reason:
381
+ record_emotion(emotion, reason)
382
+ else:
383
+ record_emotion(emotion, reason)
384
+
385
+ # --- 🔮 AI 감정 분석 섹션 ---
386
+ if st.session_state.section_index == 1:
387
+ with st.container():
388
+ st.markdown('<p class="section-title">🔮 AI 감정 분석</p>', unsafe_allow_html=True) # 섹션 제목, 아이콘 변경
389
+ st.markdown('<p class="section-subtitle">AI가 당신의 감정을 분석하고, 따뜻한 위로와 공감 메시지를 전달합니다.</p>', unsafe_allow_html=True) # 섹션 부제목
390
+
391
+ if st.button("✨ AI 감정 분석 시작", use_container_width=True): # 버튼 텍스트 유지
392
+ start_emotion_analysis_and_counseling()
393
+
394
+ if st.session_state["emotion_analysis_result"]:
395
+ analysis_result_text = st.session_state["emotion_analysis_result"]
396
+ st.info(analysis_result_text) # 분석 결과 표시
397
+ if st.button("💬 AI 상담 챗봇 시작", use_container_width=True): # 다음 섹션 이동 버튼
398
+ st.session_state.section_index += 1
399
+ st.rerun()
400
+ elif st.session_state["daily_emotions"].get(str(datetime.date.today())) and st.session_state["daily_emotions"].get(str(datetime.date.today())).get('reason'):
401
+ st.info("👆 **'✨ AI 감정 분석 시작'** 버튼을 클릭하여 감정 분석을 시작해보세요.") # 안내 문구 유지
402
+ else:
403
+ st.info("🤔 먼저 '💖 감정 체크인' 섹션에서 감정을 기록해야 AI 감정 분석을 시작할 수 있습니다.") # 안내 문구 개선, 아이콘 변경
404
+
405
+ # --- 💬 AI 상담 챗봇 섹션 ---
406
+ if st.session_state.section_index == 2:
407
+ with st.container():
408
+ st.markdown('<p class="section-title">💬 AI 상담 챗봇</p>', unsafe_allow_html=True) # 섹션 제목
409
+ st.markdown('<p class="section-subtitle">AI 챗봇과 편안하게 대화하며 당신의 마음을 돌보세요.</p>', unsafe_allow_html=True) # 섹션 부제목
410
+ st.markdown("AI 챗봇은 익명의 상담 친구처럼 당신의 이야기에 귀 기울이고 공감하며, 긍정적인 방향으로 나아갈 수 있도록 부드럽게 대화를 이끌어 줄 것입니다.") # 챗봇 설명 추가
411
+
412
+ if prompt := st.chat_input("AI 챗봇에게 이야기해보세요 (무엇이든 괜찮아요 😊)", key="chat_input"): # 입력창 placeholder 변경, 이모티콘 추가
413
+ st.session_state["counseling_messages"].append({"role": "user", "content": prompt})
414
+ st.session_state["counseling_history"].append({"role": "user", "content": prompt}) # 상담 history에 사용자 메시지 추가
415
+ with st.chat_message("user"):
416
+ st.write(prompt)
417
+
418
+ with st.chat_message("assistant"):
419
+ with st.spinner("AI 챗봇이 생각 중..."):
420
+ chat_session = st.session_state["chat_session"]
421
+ # 이전 상담 로그를 프롬프트에 포함하여 전달
422
+ history_text = "\n".join([f"{msg['role']}: {msg['content']}" for msg in st.session_state["counseling_history"]]) # 상담 history를 텍스트로 변환
423
+ enhanced_prompt = f"""**이전 상담 기록:**\n{history_text}\n\n**사용자 입력:** {prompt}\n\n**AI 상담사 역할:**
424
+ - 30대 여성 심리 상담 전문가
425
+ - 내담자의 감정에 깊이 공감하고, 따뜻하게 위로와 격려를 건네는 역할
426
+ - 친절하고 부드러운 말투 사용 (예: ~군요, ~요, ~게요)
427
+ - 단답형, 명령형, 비판적인 말투는 지양
428
+ - 질문을 통해 내담자의 감정을 더 깊이 이해하려고 노력
429
+ - 해결책 제시보다는 공감과 경청, 지지를 통해 내담자 스스로 답을 찾도록 돕는 역할
430
+
431
+ **응답:**""" # AI 상담사 역할 및 지시사항 추가
432
+ response = chat_session.send_message(enhanced_prompt) # 향상된 프롬프트 사용
433
+ ai_response = response.text.strip()
434
+ st.session_state["counseling_messages"].append(
435
+ {"role": "assistant", "content": ai_response}
436
+ )
437
+ st.session_state["counseling_history"].append({"role": "assistant", "content": ai_response}) # 상담 history에 챗봇 응답 추가
438
+ st.write(ai_response)
439
+
440
+
441
+ if "counseling_messages" not in st.session_state:
442
+ st.session_state["counseling_messages"] = []
443
+
444
+ # 챗봇 시작 메시지 (분석 결과가 있을 때, 최초 1회만)
445
+ if not st.session_state["counseling_messages"] and st.session_state["analysis_to_chatbot"]:
446
+ initial_chatbot_message = f"안녕하세요! 😊 오늘 {st.session_state['daily_emotions'][str(datetime.date.today())]['emotion']} 감정을 느끼셨군요. AI 감정 분석 결과는 이렇습니다.\n\n{st.session_state['analysis_to_chatbot']}\n\n 이전 상담 기록을 바탕으로, {st.session_state['daily_emotions'][str(datetime.date.today())]['emotion']}님에게 더 **따뜻하고 편안한** 상담을 제공해드릴 수 있을 것 같아요. **지금 기분이 어떠신가요?** 저에게 **편하게** 이야기해주세요. 🥰"
447
+ st.session_state["counseling_messages"].append({"role": "assistant", "content": initial_chatbot_message})
448
+ st.session_state["counseling_history"].append({"role": "assistant", "content": initial_chatbot_message}) # 상담 history에도 시작 메시지 추가
449
+
450
+ for msg in st.session_state["counseling_messages"]: # 메시지 순서대로 표시 (reversed 삭제)
451
+ with st.chat_message(msg["role"]):
452
+ st.write(msg["content"])
453
+ if st.button("📊 감정 이력 확인", use_container_width=True): # 다음 섹션 이동 버튼
454
+ st.session_state.section_index += 1
455
+ st.rerun()
456
+
457
+
458
+ # --- 📊 감정 이력 섹션 ---
459
+ if st.session_state.section_index == 3:
460
+ with st.container():
461
+ st.markdown('<p class="section-title">📊 감정 이력</p>', unsafe_allow_html=True) # 섹션 제목
462
+ st.markdown('<p class="section-subtitle">지난 감정 기록을 통해 마음��� 변화를 살펴보세요.</p>', unsafe_allow_html=True) # 섹션 부제목
463
+ display_emotion_history()
464
+ if st.button("📢 상담 안내 확인", use_container_width=True): # 다음 섹션 이동 버튼
465
+ st.session_state.section_index += 1
466
+ st.rerun()
467
+
468
+
469
+ # --- 📢 상담 안내 섹션 ---
470
+ if st.session_state.section_index == 4:
471
+ with st.container():
472
+ st.markdown('<p class="section-title">📢 상담 안내</p>', unsafe_allow_html=True) # 섹션 제목
473
+ st.markdown('<p class="section-subtitle">혼자 힘든가요? 언제든 전문가의 도움을 요청하세요.</p>', unsafe_allow_html=True) # 섹션 부제목
474
+ display_counseling_info()
475
+ if st.button("💖 처음으로 돌아가기", use_container_width=True): # 처음 섹션 이동 버튼
476
+ st.session_state.section_index = 0
477
+ st.rerun()
478
 
479
+ if __name__ == "__main__":
480
+ main()