File size: 21,712 Bytes
f5b0d3e
1d5b6a4
 
 
86cdc58
fabb74d
0b70568
 
 
f4ce89b
 
a4863ca
f4ce89b
86cdc58
 
 
 
 
 
 
f4ce89b
86cdc58
f4ce89b
22032f3
86cdc58
fabb74d
 
4cac0d6
 
 
86cdc58
fabb74d
 
f4ce89b
86cdc58
 
 
f4ce89b
 
 
 
 
86cdc58
 
 
 
 
 
 
f4ce89b
86cdc58
 
f4ce89b
 
86cdc58
 
 
f4ce89b
 
fabb74d
5e6a8f1
0a67eb6
b428688
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0a67eb6
 
b428688
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e6a8f1
 
0a67eb6
 
 
b428688
0a67eb6
f4ce89b
0a67eb6
 
 
5e6a8f1
f4ce89b
5e6a8f1
f4ce89b
5e6a8f1
 
f4ce89b
5e6a8f1
 
0a67eb6
f4ce89b
 
5e6a8f1
f4ce89b
5e6a8f1
f4ce89b
5e6a8f1
86cdc58
 
 
 
 
 
 
 
 
 
 
 
 
 
0a67eb6
86cdc58
 
5e6a8f1
b428688
5e6a8f1
f4ce89b
 
 
 
 
5e6a8f1
86cdc58
f4ce89b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86cdc58
f4ce89b
 
 
 
 
 
 
b428688
fabb74d
feb03cf
1d5b6a4
 
f4ce89b
1d5b6a4
f4ce89b
1d5b6a4
86cdc58
f4ce89b
86cdc58
 
 
 
f4ce89b
 
1d5b6a4
f4ce89b
86cdc58
f4ce89b
86cdc58
 
 
 
 
 
 
1d5b6a4
 
 
f4ce89b
 
 
 
86cdc58
f4ce89b
 
 
 
b428688
 
 
 
 
 
 
f4ce89b
 
 
b428688
f4ce89b
86cdc58
f4ce89b
 
86cdc58
 
b428688
86cdc58
 
 
b428688
86cdc58
 
 
 
 
 
 
b428688
 
 
 
 
 
f4ce89b
 
 
 
 
 
b428688
f4ce89b
86cdc58
b428688
5e6a8f1
f4ce89b
7a425d6
b428688
 
f4ce89b
 
 
b428688
f4ce89b
86cdc58
b428688
86cdc58
f4ce89b
b428688
0a67eb6
86cdc58
f4ce89b
86cdc58
 
f4ce89b
 
86cdc58
 
f4ce89b
 
86cdc58
f4ce89b
 
 
86cdc58
 
 
 
 
f4ce89b
 
86cdc58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f4ce89b
b428688
f4ce89b
86cdc58
 
 
f4ce89b
b428688
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
import time
import streamlit as st
import google.generativeai as genai
from streamlit_extras.colored_header import colored_header
import markdown # markdown 라이브러리 임포트 확인

# --- Must be the first Streamlit command ---
st.set_page_config(page_title="MBTI 관계 시뮬레이터", page_icon="🤝", layout="wide")

# --- Configuration ---

# Google Gemini API Key 설정 (Streamlit secrets 사용)
try:
    # secrets에서 키 로드 시도
    api_key = st.secrets.get("GEMINI_API_KEY")
    if not api_key:
        st.error("Streamlit secrets에 'GEMINI_API_KEY'를 설정해주세요.")
        st.info("Secrets 설정 방법: [Streamlit Docs](https://docs.streamlit.io/library/advanced-features/secrets-management)")
        st.stop()
    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.8,
    "top_k": 40,
    "max_output_tokens": 15000,
}

# 특정 모델 이름으로 설정 (사용자 요청 반영)
# 참고: 'gemini-2.0-flash-thinking-exp-01-21'는 실험적 모델일 수 있습니다.
# 안정적인 최신 모델을 원하시면 'gemini-1.5-flash-latest' 또는 'gemini-1.5-pro-latest' 사용을 고려하세요.
target_model_name = "gemini-2.0-flash-thinking-exp-01-21" # 안정적인 모델로 변경 권장 (필요시 원래 모델명 사용)

try:
    model = genai.GenerativeModel(
        model_name=target_model_name,
        generation_config=generation_config,
        # safety_settings 설정 추가 (콘텐츠 필터링 관련)
        safety_settings=[
            {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
            {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
            {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
            {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
        ]
    )
    # 모델 로딩 성공 시 간단한 정보 표시 (선택 사항)
    # st.sidebar.caption(f"Using model: {target_model_name}")
except Exception as e:
    st.error(f"Gemini 모델 '{target_model_name}' 로딩 중 오류 발생: {e}")
    st.error("모델 이름을 다시 확인하거나, 사용 가능한 다른 모델(예: 'gemini-1.5-flash-latest')을 시도해보세요.")
    # 사용 가능한 모델 목록 확인 링크 (선택 사항)
    st.info("사용 가능한 모델 목록은 Google AI Studio 또는 Gemini API 문서를 참조하세요.")
    st.stop()


# MBTI 유형 정보 (상세 설명 고도화)
mbti_types = {
    "INTJ": "전략가 (Architect)",
    "INTP": "논리술사 (Logician)",
    "ENTJ": "통솔자 (Commander)",
    "ENTP": "변론가 (Debater)",
    "INFJ": "옹호자 (Advocate)",
    "INFP": "중재자 (Mediator)",
    "ENFJ": "선도자 (Protagonist)",
    "ENFP": "활동가 (Campaigner)",
    "ISTJ": "현실주의자 (Logistician)",
    "ISFJ": "수호자 (Defender)",
    "ESTJ": "경영자 (Executive)",
    "ESFJ": "관리자 (Consul)",
    "ISTP": "장인 (Virtuoso)",
    "ISFP": "모험가 (Adventurer)",
    "ESTP": "사업가 (Entrepreneur)",
    "ESFP": "연예인 (Entertainer)"
}

mbti_descriptions = { # 상세 설명 추가 (프롬프트에 활용)
    "INTJ": "상상력이 풍부하며 결단력이 있는 전략가입니다. 모든 일에 계획을 세우며, 지식을 갈망하고 논리적 사고를 중시합니다. 독립적이며 때로는 비판적으로 보일 수 있습니다.",
    "INTP": "끊임없이 새로운 지식에 목말라 하는 혁신가입니다. 분석적이고 객관적이며, 복잡한 문제를 해결하는 데 뛰어난 능력을 보입니다. 때로는 추상적인 개념에 몰두하는 경향이 있습니다.",
    "ENTJ": "대담하며 상상력이 풍부한 강력한 의지의 소유자로, 항상 길을 찾거나 만들어냅니다. 타고난 리더이며, 목표 지향적이고 효율성을 추구합니다. 때로는 다른 사람의 감정을 간과할 수 있습니다.",
    "ENTP": "지적 도전을 즐기는 똑똑하고 호기심 많은 사색가입니다. 새로운 아이디어를 탐구하고 논쟁하는 것을 좋아하며, 틀에 박힌 것을 싫어합니다. 때로는 일관성이 부족할 수 있습니다.",
    "INFJ": "조용하고 신비로우면서도 샘솟는 영감으로 지칠 줄 모르는 이상주의자입니다. 깊은 통찰력과 강한 직관력으로 사람들을 돕고자 하며, 의미 있는 관계를 추구합니다. 때로는 지나치게 완벽주의적일 수 있습니다.",
    "INFP": "상냥한 성격의 이타주의자로, 건강하고 밝은 사회 건설에 앞장서는 낭만형입니다. 깊은 감수성과 공감 능력을 지녔으며, 자신의 가치관에 따라 행동합니다. 때로는 현실 감각이 부족할 수 있습니다.",
    "ENFJ": "넘치는 카리스마와 영향력으로 청중을 압도하는 리더형입니다. 사람들에게 영감을 주고 긍정적인 변화를 이끌어내는 것을 목표로 하며, 타인의 성장을 돕는 데 열정적입니다. 때로는 타인의 인정을 지나치게 갈망할 수 있습니다.",
    "ENFP": "창의적이며 항상 웃을 거리를 찾아다니는 활발한 성격으로, 사람들과 자유롭게 어울리기를 좋아합니다. 열정적이고 사교적이며, 새로운 가능성을 탐색하는 것을 즐깁니다. 때로는 쉽게 싫증을 느낄 수 있습니다.",
    "ISTJ": "사실에 근거하여 사고하며 이성적이고 믿을 수 있는 현실주의자입니다. 책임감이 강하고 철저하며, 전통과 질서를 중시합니다. 때로는 변화에 저항적일 수 있습니다.",
    "ISFJ": "소중한 이들을 보호하는 데 심혈을 기울이는 헌신적이고 따뜻한 수호자입니다. 세심하고 충실하며, 타인의 감정에 민감하고 실질적인 도움을 주고자 합니다. 때로는 자신의 필요를 간과할 수 있습니다.",
    "ESTJ": "사물이나 사람을 관리하는 데 타의 추종을 불허하는 뛰어난 실력의 소유자입니다. 조직적이고 단호하며, 규칙과 절차를 중요하게 생각합니다. 때로는 지나치게 통제하려 할 수 있습니다.",
    "ESFJ": "타인을 향한 세심한 관심과 사교적인 성향으로 사람들 내에서 인기가 많으며, 타인을 돕는 데 열성적입니다. 협조적이고 동정심이 많으며, 조화로운 관계를 중요시합니다. 때로는 비판에 민감할 수 있습니다.",
    "ISTP": "대담하고 현실적인 성향으로 다양한 도구를 능숙하게 다루는 탐험형입니다. 논리적이고 실용적이며, 문제 해결 능력이 뛰어납니다. 위기 상황에서 침착함을 유지합니다. 때로는 감정 표현에 서툴 수 있습니다.",
    "ISFP": "항상 새로운 것을 찾아 시도하거나 도전할 준비가 되어 있는 융통성 있는 성격의 매력 넘치는 예술가입니다. 온화하고 겸손하며, 현재의 순간을 즐기고 미적 감각이 뛰어납니다. 때로는 장기적인 계획 수립에 어려움을 겪을 수 있습니다.",
    "ESTP": "명석한 두뇌와 에너지, 그리고 뛰어난 직관력으로 위험을 기회로 만드는 재치 있는 사업가입니다. 행동 지향적이고 사교적이며, 현실적인 문제 해결에 능숙합니다. 때로는 충동적일 수 있습니다.",
    "ESFP": "주위에 있으면 인생이 지루할 새가 없을 정도로 즉흥적이며 열정과 에너지가 넘치는 연예인형입니다. 사교적이고 낙천적이며, 사람들과 어울리는 것을 즐깁니다. 때로는 깊이 있는 관계 형성에 어려움을 느낄 수 있습니다."
}


# 관계 유형 (2인 관계와 다인 관계 분리)
relationship_types_two = {
    "연인": "Romantic Couple",
    "부부": "Married Couple",
    "친구": "Friends",
    "가족 (형제자매, 부모자식 등)": "Family",
    "직장 동료": "Coworkers",
    "상사-부하": "Supervisor-Subordinate",
    "기타": "Others"
}

relationship_types_multiple = {
    "친구들": "Friends Group",
    "가족": "Family",
    "직장 팀": "Work Team",
    "프로젝트 팀": "Project Team",
    "스터디 그룹": "Study Group",
    "동호회/모임": "Club/Social Group",
    "기타": "Others"
}

# --- Functions ---

def generate_relationship_scenario(people, relationship, situation):
    """Generates the relationship scenario using the Gemini API."""

    # 참여자 정보 문자열 생성 함수
    def create_type_info(person):
        # 입력값이 없을 경우 기본값 처리
        name = person.get('name', '이름없음')
        gender = person.get('gender', '미지정')
        mbti_type = person.get('type', '미지정')
        type_description = mbti_descriptions.get(mbti_type, '알 수 없는 유형') # 상세 설명 사용
        return f"{name} ({gender}, {mbti_type}): {type_description}"

    # 참여자 정보 목록 생성 (people 리스트가 비어있지 않을 때만 생성)
    if people:
        people_info = "\n".join([f"- {create_type_info(person)}" for person in people])
    else:
        # people 리스트가 비어있는 예외적인 경우 처리
        st.error("참여자 정보가 올바르게 전달되지 않았습니다. 사이드바 입력을 확인해주세요.")
        return "" # 오류 발생 시 빈 문자열 반환

    # 관계 유형 영문명 가져오기
    relationship_en = relationship_types_two.get(relationship, relationship_types_multiple.get(relationship, ''))

    # 시스템 프롬프트 (개선됨: 속마음/의도, 상호작용 역학, 오해 지점, 명확한 구조 강조, 테이블 형식 지양)
    system_prompt = f"""
    당신은 MBTI 심층 분석가이자 관계 코칭 전문가입니다. 제공된 정보를 바탕으로 매우 상세하고 통찰력 있는 관계 시나리오를 생성해주세요. 각 MBTI 유형의 대표적인 특징뿐만 아니라, 개인 간의 미묘한 상호작용과 심리적 역학에 초점을 맞춰 분석해야 합니다.

    **[기본 정보]**

    *   **참여자:**
    {people_info}
    *   **관계 유형:** {relationship} ({relationship_en})
    *   **주어진 상황:** {situation}

    **[요청 사항]**

    **1. 참여자 MBTI 심층 분석:**
        *   각 참여자의 MBTI 유형에 대해 핵심 가치, 주요 동기, 의사소통 스타일, 스트레스 반응, 잠재적 강점 및 약점을 깊이 있게 설명해주세요.
        *   단순한 유형 설명을 넘어, 해당 유형이 주어진 **상황**과 **관계** 속에서 어떻게 발현될 가능성이 높은지 예측해주세요.

    **2. 관계 시나리오 상세 묘사:**
        *   주어진 상황을 바탕으로, 참여자들 간의 상호작용을 단계별 시나리오로 구체화해주세요.
        *   **각 단계별로 다음 요소를 반드시 포함하여 상세하게 묘사해주세요:**
            *   **구체적인 대화:** 실제 대화처럼 자연스럽게 작성해주세요.
            *   **관찰 가능한 행동:** 표정, 몸짓, 말투 등 비언어적 표현을 포함해주세요.
            *   **⭐ 중요: 각 인물의 '속마음' 또는 '숨겨진 의도':** 대화나 행동 이면에 있는 각 인물의 생각, 감정, 진짜 원하는 것, 혹은 우려하는 바를 괄호 안에 명확하게 서술해주세요. (예: OO (속마음: 사실은 불안하지만, 약하게 보이고 싶지 않아.))
            *   **MBTI 기반 해석:** 각 인물의 대화, 행동, 속마음이 그들의 MBTI 유형적 특성(예: 외향/내향, 감각/직관, 사고/감정, 판단/인식)과 어떻게 연결되는지 구체적으로 설명해주세요. 특히, **유형 간의 차이**가 상호작용에 어떤 영향을 미치는지 분석해주세요.

    **3. 상호작용 분석 및 잠재적 오해 지점:**
        *   시나리오 전반에 걸쳐 나타나는 참여자들 간의 **긍정적 상호작용(시너지)**과 **부정적 상호작용(갈등/오해 유발 지점)**을 명확히 식별하고 분석해주세요.
        *   MBTI 유형 차이(예: T/F의 의사결정 방식 차이, J/P의 계획성 차이 등)로 인해 발생할 수 있는 **구체적인 오해의 순간들**을 지적하고, 왜 그런 오해가 발생하는지 설명해주세요.

    **4. 관계 개선을 위한 실질적 조언:**
        *   **각 참여자에게 맞춤화된 조언**을 제공해주세요. 이 조언은 시나리오에서 드러난 **구체적인 상호작용, 속마음, 오해 지점**을 직접적으로 다루어야 합니다.
        *   서로를 더 잘 이해하고 **건강한 관계**를 구축하기 위해 각자가 **시도해볼 수 있는 구체적인 말과 행동**을 제안해주세요. (예: "{people[0]['name']}({people[0]['type']})님, {people[1]['name']}({people[1]['type']})님이 아이디어를 낼 때 즉시 분석하기보다, 먼저 '흥미로운 생각인데!'라고 반응하며 {people[1]['name']}님의 열정을 인정해주세요. 그 후에 함께 현실적인 부분을 논의하는 것이 좋습니다.")
        *   조언에는 반드시 **모든 참여자의 이름, 성별, MBTI 유형**이 명시되어야 합니다.

    **[출력 형식]**

    *   결과는 Markdown 형식을 사용하여 가독성을 높여주세요.
    *   위 요청사항의 번호(1, 2, 3, 4)에 맞춰 명확한 제목 (예: `## 1. 참여자 MBTI 심층 분석`)을 사용하여 내용을 구분해주세요.
    *   특히 시나리오(2번 항목)에서는 대화, 행동, 속마음, MBTI 해석을 명확히 구분하여 작성해주세요.
    *   **표 형식의 출력은 지양하고, headings, lists, paragraphs 위주로 마크다운을 사용해주세요.**
    """

    full_text = ""
    try:
        # 스트리밍 방식으로 응답 생성 및 표시
        response = model.generate_content([system_prompt], stream=True)
        response_container = st.empty() # 응답 표시 영역 미리 확보
        for chunk in response:
            # chunk.text가 None이 아닌지 확인
            if chunk.text:
                full_text += chunk.text # Append chunk text to full_text
                # Markdown으로 실시간 업데이트 (unsafe_allow_html=False가 더 안전)
                response_container.markdown(full_text, unsafe_allow_html=False) # HTML 대신 마크다운 직접 렌더링
            time.sleep(0.01) # 딜레이 약간 줄임
        return full_text # 최종 전체 텍스트 반환

    except Exception as e:
        st.error(f"시나리오 생성 중 오류 발생: {e}")
        # 오류 유형과 메시지를 함께 출력하여 디버깅에 도움
        st.error(f"오류 상세 정보: {type(e).__name__} - {e}")
        # API 호출 관련 오류일 수 있으므로 추가 정보 제공
        if "API key" in str(e):
            st.error("API 키가 유효하지 않거나 할당량이 초과되었을 수 있습니다. Streamlit secrets 설정을 확인하세요.")
        elif "model" in str(e).lower():
             st.error(f"모델 '{target_model_name}'을 찾을 수 없거나 접근 권한이 없을 수 있습니다. 모델 이름을 확인하거나 다른 모델을 시도해보세요.")
        elif "safety" in str(e).lower() or "filtered" in str(e).lower():
             st.error("콘텐츠 안전 설정에 의해 응답이 필터링되었습니다. 입력 내용을 수정하거나 안전 설정을 조정해보세요.")
        return ""


# --- Streamlit UI ---

# 헤더 색상 적용
colored_header(
    label="🤝 MBTI 관계 시뮬레이터 v2.1", # 버전 업데이트
    description="참여자들의 MBTI, 관계, 상황을 입력하여 심층적인 관계 시나리오와 조언을 받아보세요.",
    color_name="blue-70"
)

# UI/UX 개선
with st.sidebar:
    st.header("⚙️ 설정")

    # Instructions at the top of sidebar
    st.markdown("##### 1. 참여자 정보 입력")
    st.markdown("참여자의 이름, 성별, MBTI 유형을 선택하세요.")

    # 참여자 정보 입력 섹션
    num_people = st.number_input("참여자 수", min_value=2, max_value=5, value=2, key="num_people",
                                 help="최소 2명, 최대 5명까지 설정할 수 있습니다.")

    people = [] # 리스트 초기화를 루프 바깥에서 수행
    # 참여자 수에 맞춰 동적으로 입력 필드 생성
    for i in range(num_people):
        # 첫 번째 참여자만 기본으로 확장되도록 수정
        with st.expander(f"👤 참여자 {i+1}", expanded=(i == 0)):
            person = {}
            # 이름 예시 플레이스홀더 추가
            default_names = ['철수', '영희', '민준', '서연', '지우']
            person['name'] = st.text_input(f"이름/닉네임", key=f"name_{i}", placeholder=f"예: {default_names[i % len(default_names)]}")
            person['gender'] = st.radio("성별", ["남성", "여성", "기타"], key=f"gender_{i}", horizontal=True)
            # 기본 MBTI 선택 인덱스 계산 (오류 방지)
            default_mbti_index = i % len(mbti_types)
            person['type'] = st.selectbox(f"MBTI 유형", list(mbti_types.keys()), format_func=lambda x: f"{x} ({mbti_types[x]})", key=f"type_{i}", index=default_mbti_index)

            # --- ★★★ 수정된 부분 ★★★ ---
            people.append(person) # 입력받은 참여자 정보를 리스트에 추가
            # ---------------------------

    st.divider()

    # Instructions for relationship and situation
    st.markdown("##### 2. 관계 및 상황 설정")
    st.markdown("관계 유형과 구체적인 상황을 설정하세요.")

    # 관계 및 상황 설정 섹션
    if num_people == 2:
        relationship_options = relationship_types_two
    else:
        relationship_options = relationship_types_multiple
    relationship = st.selectbox("관계 유형", list(relationship_options.keys()), key="relationship")

    situation = st.text_area("구체적인 상황", key="situation", height=100, # 높이 유지
                             placeholder="예: 중요한 프로젝트 마감일을 앞두고 의견 충돌 발생")

    st.divider()

    # Generate button at the bottom, with clear instruction
    st.markdown("##### 3. 시나리오 생성")
    generate_button = st.button("🚀 시나리오 생성하기", use_container_width=True, type="primary")


# Main area - Scenario output
st.header("💡 생성된 시나리오")
# Use st.container() for better layout control if needed, otherwise direct markdown is fine
scenario_output_area = st.container()
# scenario_output_area = st.empty() # Use empty() if you want to replace content completely on each run

# Button click logic
if generate_button:
    # Input validation 강화
    valid_input = True
    # 이름 입력 확인 (공백만 입력된 경우도 방지)
    if not all(p.get('name', '').strip() for p in people):
        st.error("모든 참여자의 이름을 입력해주세요.")
        valid_input = False
    # 상황 입력 확인 (공백만 입력된 경우도 방지)
    if not situation.strip():
        st.error("구체적인 상황을 입력해주세요.")
        valid_input = False
    # 관계 유형 선택 확인 (selectbox는 기본값이 있으므로 일반적으로 문제는 없으나 명시적으로 확인)
    if not relationship:
        st.error("관계 유형을 선택해주세요.")
        valid_input = False
    # people 리스트 자체 확인 (만약을 대비)
    if not people:
        st.error("참여자 정보가 없습니다. 페이지를 새로고침하거나 참여자 수를 다시 설정해보세요.")
        valid_input = False


    if valid_input:
        # 시나리오 생성 영역 초기화 (이전 결과 제거)
        scenario_output_area.empty()
        with scenario_output_area: # 컨테이너 내에서 스피너와 결과 표시
            with st.spinner("🧠 MBTI 전문가가 시나리오 분석 및 생성 중... 잠시만 기다려주세요."):
                # people 리스트가 제대로 채워졌는지 확인 (디버깅용)
                # st.write("전달되는 참여자 정보:", people)
                full_text_result = generate_relationship_scenario(people, relationship, situation)

            if full_text_result:
                # 최종 결과를 Markdown으로 렌더링 (unsafe_allow_html=True 사용 시 주의)
                # html_output = markdown.markdown(full_text_result)
                # scenario_output_area.markdown(html_output, unsafe_allow_html=True)
                scenario_output_area.markdown(full_text_result, unsafe_allow_html=False) # 마크다운 직접 렌더링 권장
                st.success("🎉 시나리오 생성 완료!")
            else:
                # generate_relationship_scenario 함수 내에서 이미 오류 메시지가 표시됨
                st.warning("시나리오 생성에 실패했습니다. 오류 메시지를 확인해주세요.")
    else:
        st.warning("입력값을 다시 확인해주세요.")

# Initial message when the app loads or before generation
# Check if the button has been clicked at least once using session state if needed
# For simplicity, just show if the button wasn't clicked in this run
if not generate_button:
     scenario_output_area.info("왼쪽 사이드바에서 참여자 정보, 관계, 상황을 설정 후 '시나리오 생성하기' 버튼을 클릭하세요.")