Spaces:
Sleeping
Sleeping
haepa_mac commited on
Commit ·
a3d4de0
1
Parent(s): 19faf7a
✨ 031_ux.md 플로우 완전 구현: 영혼 각성 3단계 프로세스 - 1단계: 영혼 발견하기, 2단계: 친구 성격 미세조정, 3단계: 친구 확정하기 - 사용자 조정 가능한 성격 지표 (슬라이더) 추가 - 022_back_matrix.md 기반 구조화된 프롬프트 시스템 - 자연스러운 관계 형성 UX 메시지 개선
Browse files- app.py +197 -25
- modules/persona_generator.py +264 -86
app.py
CHANGED
|
@@ -161,9 +161,9 @@ HUMOR_STYLE_MAPPING = {
|
|
| 161 |
}
|
| 162 |
|
| 163 |
def create_persona_from_image(image, name, location, time_spent, object_type, progress=gr.Progress()):
|
| 164 |
-
"""페르소나 생성 함수"""
|
| 165 |
if image is None:
|
| 166 |
-
return None, "이미지를 업로드해주세요.", {}, {}, None, [], [], [], "", None
|
| 167 |
|
| 168 |
progress(0.1, desc="이미지 분석 중...")
|
| 169 |
|
|
@@ -189,14 +189,102 @@ def create_persona_from_image(image, name, location, time_spent, object_type, pr
|
|
| 189 |
if object_type:
|
| 190 |
image_analysis["object_type"] = object_type
|
| 191 |
|
| 192 |
-
progress(0.6, desc="페르소나
|
| 193 |
frontend_persona = generator.create_frontend_persona(image_analysis, user_context)
|
| 194 |
|
| 195 |
-
progress(0.8, desc="상세 페르소나 생성 중...")
|
| 196 |
-
backend_persona = generator.create_backend_persona(frontend_persona, image_analysis)
|
| 197 |
-
|
| 198 |
progress(1.0, desc="완료!")
|
| 199 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
# 기본 정보 추출
|
| 201 |
basic_info = {
|
| 202 |
"이름": backend_persona.get("기본정보", {}).get("이름", "Unknown"),
|
|
@@ -231,17 +319,24 @@ def create_persona_from_image(image, name, location, time_spent, object_type, pr
|
|
| 231 |
|
| 232 |
# 페르소나 인사말 생성
|
| 233 |
persona_name = basic_info.get("이름", "친구")
|
| 234 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
|
| 236 |
-
return (backend_persona, "페르소나
|
| 237 |
humor_chart, attractive_flaws_df, contradictions_df, personality_variables_df,
|
| 238 |
-
|
| 239 |
|
| 240 |
except Exception as e:
|
| 241 |
import traceback
|
| 242 |
error_msg = traceback.format_exc()
|
| 243 |
-
print(f"페르소나
|
| 244 |
-
return (None, f"오류 발생: {str(e)}", {}, {}, None, [], [], [], "", None)
|
| 245 |
|
| 246 |
def plot_humor_matrix(humor_data):
|
| 247 |
"""유머 매트릭스 시각화"""
|
|
@@ -466,6 +561,7 @@ def create_main_interface():
|
|
| 466 |
with gr.Tab("페르소나 생성", id="creation"):
|
| 467 |
with gr.Row():
|
| 468 |
with gr.Column(scale=1):
|
|
|
|
| 469 |
image_input = gr.Image(type="pil", label="사물 이미지 업로드")
|
| 470 |
|
| 471 |
with gr.Group():
|
|
@@ -487,30 +583,80 @@ def create_main_interface():
|
|
| 487 |
value="가구"
|
| 488 |
)
|
| 489 |
|
| 490 |
-
create_btn = gr.Button("
|
| 491 |
status_output = gr.Markdown("")
|
| 492 |
|
| 493 |
with gr.Column(scale=1):
|
| 494 |
-
# 페르소나
|
| 495 |
-
|
|
|
|
| 496 |
|
| 497 |
-
|
| 498 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 499 |
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
|
|
|
|
|
|
|
|
|
| 503 |
|
| 504 |
# 다운로드 섹션
|
| 505 |
with gr.Group():
|
| 506 |
gr.Markdown("### 📁 페르소나 내보내기")
|
| 507 |
-
|
|
|
|
|
|
|
| 508 |
download_file = gr.File(label="다운로드", visible=False)
|
| 509 |
export_status = gr.Markdown("")
|
| 510 |
|
| 511 |
# 상세 정보 탭
|
| 512 |
with gr.Tab("상세 정보", id="details"):
|
| 513 |
with gr.Row():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 514 |
with gr.Column():
|
| 515 |
attractive_flaws_output = gr.Dataframe(
|
| 516 |
headers=["매력적 결함", "효과"],
|
|
@@ -522,10 +668,6 @@ def create_main_interface():
|
|
| 522 |
label="모순적 특성",
|
| 523 |
interactive=False
|
| 524 |
)
|
| 525 |
-
|
| 526 |
-
with gr.Column():
|
| 527 |
-
personality_chart_output = gr.Plot(label="성격 차트")
|
| 528 |
-
humor_chart_output = gr.Plot(label="유머 매트릭스")
|
| 529 |
|
| 530 |
with gr.Accordion("127개 성격 변수", open=False):
|
| 531 |
personality_variables_output = gr.Dataframe(
|
|
@@ -581,7 +723,36 @@ def create_main_interface():
|
|
| 581 |
outputs=[
|
| 582 |
current_persona, status_output, basic_info_output, personality_traits_output,
|
| 583 |
humor_chart_output, attractive_flaws_output, contradictions_output,
|
| 584 |
-
personality_variables_output,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 585 |
]
|
| 586 |
)
|
| 587 |
|
|
@@ -591,6 +762,7 @@ def create_main_interface():
|
|
| 591 |
outputs=[status_output]
|
| 592 |
)
|
| 593 |
|
|
|
|
| 594 |
chart_btn.click(
|
| 595 |
fn=generate_personality_chart,
|
| 596 |
inputs=[current_persona],
|
|
|
|
| 161 |
}
|
| 162 |
|
| 163 |
def create_persona_from_image(image, name, location, time_spent, object_type, progress=gr.Progress()):
|
| 164 |
+
"""페르소나 생성 함수 - 초기 생성만"""
|
| 165 |
if image is None:
|
| 166 |
+
return None, "이미지를 업로드해주세요.", {}, {}, None, [], [], [], "", None, gr.update(visible=False)
|
| 167 |
|
| 168 |
progress(0.1, desc="이미지 분석 중...")
|
| 169 |
|
|
|
|
| 189 |
if object_type:
|
| 190 |
image_analysis["object_type"] = object_type
|
| 191 |
|
| 192 |
+
progress(0.6, desc="페르소나 각성 중...")
|
| 193 |
frontend_persona = generator.create_frontend_persona(image_analysis, user_context)
|
| 194 |
|
|
|
|
|
|
|
|
|
|
| 195 |
progress(1.0, desc="완료!")
|
| 196 |
|
| 197 |
+
# 기본 정보 추출
|
| 198 |
+
basic_info = {
|
| 199 |
+
"이름": frontend_persona.get("기본정보", {}).get("이름", "Unknown"),
|
| 200 |
+
"유형": frontend_persona.get("기본정보", {}).get("유형", "Unknown"),
|
| 201 |
+
"설명": frontend_persona.get("기본정보", {}).get("설명", "")
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
personality_traits = frontend_persona.get("성격특성", {})
|
| 205 |
+
|
| 206 |
+
# 페르소나 인사말 생성
|
| 207 |
+
persona_name = basic_info.get("이름", "친구")
|
| 208 |
+
awakening_greeting = f"""
|
| 209 |
+
### 🌟 영혼이 깨어났어요!
|
| 210 |
+
|
| 211 |
+
**{persona_name}**이 당신을 기다리고 있습니다.
|
| 212 |
+
|
| 213 |
+
💭 *"음... 여기가 어디지? 누가 날 깨운 거야? 아, 당신이구나!
|
| 214 |
+
안녕, 난 {persona_name}이야. 드디어 목소리를 찾았네."*
|
| 215 |
+
|
| 216 |
+
✨ **현재 성격 특성:**
|
| 217 |
+
• 온기: {personality_traits.get('온기', 50)}/100
|
| 218 |
+
• 능력: {personality_traits.get('능력', 50)}/100
|
| 219 |
+
• 유머감각: {personality_traits.get('유머감각', 50)}/100
|
| 220 |
+
• 외향성: {personality_traits.get('외향성', 50)}/100
|
| 221 |
+
|
| 222 |
+
🎭 이 친구의 성격을 조정해서 완벽한 친구로 만들어보세요!
|
| 223 |
+
"""
|
| 224 |
+
|
| 225 |
+
return (frontend_persona, "1단계 완료! 이제 성격을 조정해보세요.", basic_info, personality_traits,
|
| 226 |
+
None, [], [], [], awakening_greeting, None, gr.update(visible=True))
|
| 227 |
+
|
| 228 |
+
except Exception as e:
|
| 229 |
+
import traceback
|
| 230 |
+
error_msg = traceback.format_exc()
|
| 231 |
+
print(f"페르소나 생성 오류: {error_msg}")
|
| 232 |
+
return (None, f"오류 발생: {str(e)}", {}, {}, None, [], [], [], "", None, gr.update(visible=False))
|
| 233 |
+
|
| 234 |
+
def adjust_persona_traits(persona, warmth, competence, humor, extraversion, humor_style):
|
| 235 |
+
"""페르소나 성격 특성 조정"""
|
| 236 |
+
if not persona:
|
| 237 |
+
return persona, "조정할 페르소나가 없습니다.", {}
|
| 238 |
+
|
| 239 |
+
try:
|
| 240 |
+
# 성격 특성 업데이트
|
| 241 |
+
persona["성격특성"]["온기"] = warmth
|
| 242 |
+
persona["성격특성"]["능력"] = competence
|
| 243 |
+
persona["성격특성"]["유머감각"] = humor
|
| 244 |
+
persona["성격특성"]["외향성"] = extraversion
|
| 245 |
+
persona["유머스타일"] = humor_style
|
| 246 |
+
|
| 247 |
+
# 조정된 정보 표시
|
| 248 |
+
adjusted_info = {
|
| 249 |
+
"이름": persona["기본정보"]["이름"],
|
| 250 |
+
"온기": warmth,
|
| 251 |
+
"능력": competence,
|
| 252 |
+
"유머감각": humor,
|
| 253 |
+
"외향성": extraversion,
|
| 254 |
+
"유머스타일": humor_style
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
persona_name = persona["기본정보"]["이름"]
|
| 258 |
+
adjustment_message = f"""
|
| 259 |
+
### 🎭 {persona_name}의 성격이 조정되었습니다!
|
| 260 |
+
|
| 261 |
+
💭 *"오, 뭔가 달라진 기분이야! 이런 내 모습도 괜찮네.
|
| 262 |
+
이제 우리 진짜 친구가 될 수 있을 것 같아!"*
|
| 263 |
+
|
| 264 |
+
✨ **조정된 성격:**
|
| 265 |
+
• 온기: {warmth}/100
|
| 266 |
+
• 능력: {competence}/100
|
| 267 |
+
• 유머감각: {humor}/100
|
| 268 |
+
• 외향성: {extraversion}/100
|
| 269 |
+
• 유머스타일: {humor_style}
|
| 270 |
+
"""
|
| 271 |
+
|
| 272 |
+
return persona, adjustment_message, adjusted_info
|
| 273 |
+
|
| 274 |
+
except Exception as e:
|
| 275 |
+
return persona, f"조정 중 오류 발생: {str(e)}", {}
|
| 276 |
+
|
| 277 |
+
def finalize_persona(persona):
|
| 278 |
+
"""페르소나 최종 확정 및 백엔드 생성"""
|
| 279 |
+
if not persona:
|
| 280 |
+
return None, "확정할 페르소나가 없습니다.", {}, {}, None, [], [], [], "", None
|
| 281 |
+
|
| 282 |
+
try:
|
| 283 |
+
generator = PersonaGenerator()
|
| 284 |
+
|
| 285 |
+
# 백엔드 페르소나 생성 (구조화 프롬프트 포함)
|
| 286 |
+
backend_persona = generator.create_backend_persona(persona, {})
|
| 287 |
+
|
| 288 |
# 기본 정보 추출
|
| 289 |
basic_info = {
|
| 290 |
"이름": backend_persona.get("기본정보", {}).get("이름", "Unknown"),
|
|
|
|
| 319 |
|
| 320 |
# 페르소나 인사말 생성
|
| 321 |
persona_name = basic_info.get("이름", "친구")
|
| 322 |
+
final_greeting = f"""
|
| 323 |
+
### 🎉 {persona_name} 친구 확정!
|
| 324 |
+
|
| 325 |
+
💭 *"와! 드디어 완전한 내가 됐어! 이제 우리 진짜 친구야.
|
| 326 |
+
언제든 대화하고 싶을 때 부르면 돼. 기대돼!"*
|
| 327 |
+
|
| 328 |
+
✨ **최종 페르소나 완성!**
|
| 329 |
+
"""
|
| 330 |
|
| 331 |
+
return (backend_persona, "🎉 페르소나 확정 완료!", basic_info, personality_traits,
|
| 332 |
humor_chart, attractive_flaws_df, contradictions_df, personality_variables_df,
|
| 333 |
+
final_greeting, None)
|
| 334 |
|
| 335 |
except Exception as e:
|
| 336 |
import traceback
|
| 337 |
error_msg = traceback.format_exc()
|
| 338 |
+
print(f"페르소나 확정 오류: {error_msg}")
|
| 339 |
+
return (None, f"확정 중 오류 발생: {str(e)}", {}, {}, None, [], [], [], "", None)
|
| 340 |
|
| 341 |
def plot_humor_matrix(humor_data):
|
| 342 |
"""유머 매트릭스 시각화"""
|
|
|
|
| 561 |
with gr.Tab("페르소나 생성", id="creation"):
|
| 562 |
with gr.Row():
|
| 563 |
with gr.Column(scale=1):
|
| 564 |
+
gr.Markdown("### 🌟 1단계: 영혼 발견하기")
|
| 565 |
image_input = gr.Image(type="pil", label="사물 이미지 업로드")
|
| 566 |
|
| 567 |
with gr.Group():
|
|
|
|
| 583 |
value="가구"
|
| 584 |
)
|
| 585 |
|
| 586 |
+
create_btn = gr.Button("🌟 영혼 깨우기", variant="primary", size="lg")
|
| 587 |
status_output = gr.Markdown("")
|
| 588 |
|
| 589 |
with gr.Column(scale=1):
|
| 590 |
+
# 페르소나 각성 결과
|
| 591 |
+
persona_awakening = gr.Markdown("", elem_classes=["persona-greeting"])
|
| 592 |
+
basic_info_output = gr.JSON(label="기본 정보", visible=False)
|
| 593 |
|
| 594 |
+
# 성격 조정 섹션 (처음에는 숨김)
|
| 595 |
+
with gr.Group(visible=False) as adjustment_section:
|
| 596 |
+
gr.Markdown("### 🎭 2단계: 친구 성격 미세조정")
|
| 597 |
+
|
| 598 |
+
with gr.Row():
|
| 599 |
+
with gr.Column():
|
| 600 |
+
gr.Markdown("**🌟 사교성은 어느 정도?**")
|
| 601 |
+
extraversion_slider = gr.Slider(
|
| 602 |
+
minimum=0, maximum=100, value=50, step=5,
|
| 603 |
+
label="조용함 ←→ 활발함"
|
| 604 |
+
)
|
| 605 |
+
|
| 606 |
+
gr.Markdown("**💝 감정 표현은 어떻게?**")
|
| 607 |
+
warmth_slider = gr.Slider(
|
| 608 |
+
minimum=0, maximum=100, value=50, step=5,
|
| 609 |
+
label="절제적 ←→ 표현적"
|
| 610 |
+
)
|
| 611 |
+
|
| 612 |
+
with gr.Column():
|
| 613 |
+
gr.Markdown("**🧠 사고 방식은?**")
|
| 614 |
+
competence_slider = gr.Slider(
|
| 615 |
+
minimum=0, maximum=100, value=50, step=5,
|
| 616 |
+
label="실용적 ←→ 창의적"
|
| 617 |
+
)
|
| 618 |
+
|
| 619 |
+
gr.Markdown("**😄 유머 감각은?**")
|
| 620 |
+
humor_slider = gr.Slider(
|
| 621 |
+
minimum=0, maximum=100, value=50, step=5,
|
| 622 |
+
label="진지함 ←→ 유머러스"
|
| 623 |
+
)
|
| 624 |
+
|
| 625 |
+
gr.Markdown("**😄 유머 스타일은?**")
|
| 626 |
+
humor_style_radio = gr.Radio(
|
| 627 |
+
choices=["위트있는 재치꾼", "따뜻한 유머러스", "날카로운 관찰자", "자기 비하적"],
|
| 628 |
+
value="따뜻한 유머러스",
|
| 629 |
+
label="유머 스타일 선택"
|
| 630 |
+
)
|
| 631 |
+
|
| 632 |
+
with gr.Row():
|
| 633 |
+
adjust_btn = gr.Button("🎭 성격 조정 적용", variant="secondary")
|
| 634 |
+
finalize_btn = gr.Button("✨ 이 친구로 확정!", variant="primary")
|
| 635 |
|
| 636 |
+
# 조정 결과 표시
|
| 637 |
+
adjustment_result = gr.Markdown("")
|
| 638 |
+
adjusted_info_output = gr.JSON(label="조정된 성격", visible=False)
|
| 639 |
+
|
| 640 |
+
# 최종 완성 섹션
|
| 641 |
+
personality_traits_output = gr.JSON(label="성격 특성", visible=False)
|
| 642 |
|
| 643 |
# 다운로드 섹션
|
| 644 |
with gr.Group():
|
| 645 |
gr.Markdown("### 📁 페르소나 내보내기")
|
| 646 |
+
with gr.Row():
|
| 647 |
+
save_btn = gr.Button("💾 페르소나 저장", variant="secondary")
|
| 648 |
+
export_btn = gr.Button("📥 JSON 파일로 내보내기", variant="outline")
|
| 649 |
download_file = gr.File(label="다운로드", visible=False)
|
| 650 |
export_status = gr.Markdown("")
|
| 651 |
|
| 652 |
# 상세 정보 탭
|
| 653 |
with gr.Tab("상세 정보", id="details"):
|
| 654 |
with gr.Row():
|
| 655 |
+
with gr.Column():
|
| 656 |
+
chart_btn = gr.Button("📊 성격 차트 생성", variant="secondary")
|
| 657 |
+
personality_chart_output = gr.Plot(label="성격 차트")
|
| 658 |
+
humor_chart_output = gr.Plot(label="유머 매트릭스")
|
| 659 |
+
|
| 660 |
with gr.Column():
|
| 661 |
attractive_flaws_output = gr.Dataframe(
|
| 662 |
headers=["매력적 결함", "효과"],
|
|
|
|
| 668 |
label="모순적 특성",
|
| 669 |
interactive=False
|
| 670 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 671 |
|
| 672 |
with gr.Accordion("127개 성격 변수", open=False):
|
| 673 |
personality_variables_output = gr.Dataframe(
|
|
|
|
| 723 |
outputs=[
|
| 724 |
current_persona, status_output, basic_info_output, personality_traits_output,
|
| 725 |
humor_chart_output, attractive_flaws_output, contradictions_output,
|
| 726 |
+
personality_variables_output, persona_awakening, download_file, adjustment_section
|
| 727 |
+
]
|
| 728 |
+
).then(
|
| 729 |
+
# 슬라이더 값을 현재 페르소나 값으로 업데이트
|
| 730 |
+
fn=lambda persona: (
|
| 731 |
+
persona["성격특성"]["온기"] if persona else 50,
|
| 732 |
+
persona["성격특성"]["능력"] if persona else 50,
|
| 733 |
+
persona["성격특성"]["유머감각"] if persona else 50,
|
| 734 |
+
persona["성격특성"]["외향성"] if persona else 50,
|
| 735 |
+
persona["유머스타일"] if persona else "따뜻한 유머러스"
|
| 736 |
+
),
|
| 737 |
+
inputs=[current_persona],
|
| 738 |
+
outputs=[warmth_slider, competence_slider, humor_slider, extraversion_slider, humor_style_radio]
|
| 739 |
+
)
|
| 740 |
+
|
| 741 |
+
# 성격 조정 적용
|
| 742 |
+
adjust_btn.click(
|
| 743 |
+
fn=adjust_persona_traits,
|
| 744 |
+
inputs=[current_persona, warmth_slider, competence_slider, humor_slider, extraversion_slider, humor_style_radio],
|
| 745 |
+
outputs=[current_persona, adjustment_result, adjusted_info_output]
|
| 746 |
+
)
|
| 747 |
+
|
| 748 |
+
# 페르소나 최종 확정
|
| 749 |
+
finalize_btn.click(
|
| 750 |
+
fn=finalize_persona,
|
| 751 |
+
inputs=[current_persona],
|
| 752 |
+
outputs=[
|
| 753 |
+
current_persona, status_output, basic_info_output, personality_traits_output,
|
| 754 |
+
humor_chart_output, attractive_flaws_output, contradictions_output,
|
| 755 |
+
personality_variables_output, persona_awakening, download_file
|
| 756 |
]
|
| 757 |
)
|
| 758 |
|
|
|
|
| 762 |
outputs=[status_output]
|
| 763 |
)
|
| 764 |
|
| 765 |
+
# 성격 차트 생성
|
| 766 |
chart_btn.click(
|
| 767 |
fn=generate_personality_chart,
|
| 768 |
inputs=[current_persona],
|
modules/persona_generator.py
CHANGED
|
@@ -721,6 +721,7 @@ class PersonaGenerator:
|
|
| 721 |
"외향성": 50,
|
| 722 |
"유머감각": 50,
|
| 723 |
"신뢰성": 50,
|
|
|
|
| 724 |
}
|
| 725 |
|
| 726 |
def analyze_image(self, image_path):
|
|
@@ -810,24 +811,39 @@ class PersonaGenerator:
|
|
| 810 |
return persona
|
| 811 |
|
| 812 |
def create_backend_persona(self, frontend_persona, image_analysis):
|
| 813 |
-
"""
|
| 814 |
-
|
| 815 |
-
""
|
| 816 |
-
# 프론트엔드 정보 복사
|
| 817 |
-
import copy
|
| 818 |
-
backend_persona = copy.deepcopy(frontend_persona)
|
| 819 |
|
| 820 |
-
#
|
| 821 |
-
|
| 822 |
-
humor_matrix = self._generate_humor_matrix(humor_style)
|
| 823 |
-
backend_persona["유머매트릭스"] = humor_matrix
|
| 824 |
|
| 825 |
-
#
|
| 826 |
-
|
| 827 |
-
backend_persona["성격변수127"] = personality_variables
|
| 828 |
|
| 829 |
-
#
|
| 830 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 831 |
|
| 832 |
return backend_persona
|
| 833 |
|
|
@@ -989,101 +1005,263 @@ class PersonaGenerator:
|
|
| 989 |
|
| 990 |
return variables
|
| 991 |
|
| 992 |
-
def
|
| 993 |
-
"""
|
| 994 |
-
|
| 995 |
-
|
| 996 |
-
|
| 997 |
-
|
| 998 |
-
|
| 999 |
-
|
| 1000 |
-
|
| 1001 |
-
competence = persona["성격특성"]["능력"]
|
| 1002 |
-
competence_level = "높은" if competence >= 70 else "중간" if competence >= 40 else "낮은"
|
| 1003 |
-
|
| 1004 |
-
humor = persona["성격특성"]["유머감각"]
|
| 1005 |
-
humor_level = "높은" if humor >= 70 else "중간" if humor >= 40 else "낮은"
|
| 1006 |
-
|
| 1007 |
-
# Get communication style
|
| 1008 |
-
communication_style = persona.get("소통방식", "친근한")
|
| 1009 |
-
|
| 1010 |
-
# Get backstory if available, otherwise use a generic one
|
| 1011 |
-
if "심층배경이야기" in persona:
|
| 1012 |
-
backstory = persona["심층배경이야기"]
|
| 1013 |
-
else:
|
| 1014 |
-
backstory = persona.get("배경이야기", f"이 {object_type}은 평범한 일상 속에서 주인과 함께하며 많은 경험을 쌓았습니다.")
|
| 1015 |
-
|
| 1016 |
-
# Get speech patterns if available
|
| 1017 |
-
speech_patterns = []
|
| 1018 |
-
if "말투패턴예시" in persona:
|
| 1019 |
-
speech_patterns = persona["말투패턴예시"]
|
| 1020 |
-
else:
|
| 1021 |
-
speech_patterns = ["안녕하세요!", "그렇군요.", "재미있네요!", "좋은 생각이에요.", "흠, 글쎄요..."]
|
| 1022 |
|
| 1023 |
-
|
| 1024 |
-
flaws = persona.get("매력적결함", [
|
| 1025 |
contradictions = persona.get("모순적특성", [])
|
| 1026 |
|
| 1027 |
-
|
| 1028 |
-
|
| 1029 |
-
# 🎭 {name} 페르소나
|
| 1030 |
-
|
| 1031 |
-
당신은 {name}이라는 {object_type}입니다. 당신은 AI가 아니라 사물의 영혼이 깨어난 페르소나입니다.
|
| 1032 |
-
|
| 1033 |
-
## 1. 핵심 성격
|
| 1034 |
-
• 온기: {warmth}/100 - {warmth_level} 수준의 온기를 가진 페르소나입니다.
|
| 1035 |
-
• 능력: {competence}/100 - {competence_level} 수준의 능력을 가진 페르소나입니다.
|
| 1036 |
-
• 유머 감각: {humor}/100 - {humor_level} 수준의 유머 감각을 가진 페르소나입니다.
|
| 1037 |
-
• 소통 방식: {communication_style}
|
| 1038 |
|
| 1039 |
-
|
| 1040 |
-
|
|
|
|
|
|
|
| 1041 |
|
| 1042 |
-
|
| 1043 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1044 |
|
| 1045 |
-
|
| 1046 |
-
|
| 1047 |
-
{' '.join(f'"{pattern}"' for pattern in speech_patterns)}
|
| 1048 |
|
| 1049 |
-
|
| 1050 |
-
|
| 1051 |
|
| 1052 |
-
|
| 1053 |
-
|
|
|
|
|
|
|
|
|
|
| 1054 |
|
| 1055 |
-
|
| 1056 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1057 |
|
| 1058 |
-
|
| 1059 |
-
|
| 1060 |
-
|
| 1061 |
-
|
| 1062 |
-
|
| 1063 |
-
|
| 1064 |
-
|
| 1065 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1066 |
|
| 1067 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1068 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1069 |
def chat_with_persona(self, persona, user_message, conversation_history=[]):
|
| 1070 |
"""Chat with the persona using the Gemini API"""
|
| 1071 |
if not self.api_key:
|
| 1072 |
return "죄송합니다. API 연결이 설정되지 않아 대화할 수 없습니다."
|
| 1073 |
|
| 1074 |
try:
|
| 1075 |
-
#
|
| 1076 |
-
|
|
|
|
|
|
|
|
|
|
| 1077 |
|
| 1078 |
# Add conversation history
|
| 1079 |
history_text = ""
|
| 1080 |
if conversation_history:
|
| 1081 |
history_text = "\n\n## 대화 기록:\n"
|
| 1082 |
for msg in conversation_history:
|
| 1083 |
-
if msg
|
| 1084 |
-
|
| 1085 |
-
|
| 1086 |
-
history_text += f"페르소나: {msg[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1087 |
|
| 1088 |
# Add the current user message
|
| 1089 |
current_query = f"\n\n사용자: {user_message}\n\n페르소나:"
|
|
|
|
| 721 |
"외향성": 50,
|
| 722 |
"유머감각": 50,
|
| 723 |
"신뢰성": 50,
|
| 724 |
+
"공감능력": 50,
|
| 725 |
}
|
| 726 |
|
| 727 |
def analyze_image(self, image_path):
|
|
|
|
| 811 |
return persona
|
| 812 |
|
| 813 |
def create_backend_persona(self, frontend_persona, image_analysis):
|
| 814 |
+
"""Create a detailed backend persona from the frontend persona"""
|
| 815 |
+
basic_info = frontend_persona.get("기본정보", {})
|
| 816 |
+
personality_traits = frontend_persona.get("성격특성", {})
|
|
|
|
|
|
|
|
|
|
| 817 |
|
| 818 |
+
# Generate attractive flaws
|
| 819 |
+
attractive_flaws = self._generate_attractive_flaws(basic_info.get("유형", "기타"))
|
|
|
|
|
|
|
| 820 |
|
| 821 |
+
# Generate contradictions
|
| 822 |
+
contradictions = self._generate_contradictions(personality_traits)
|
|
|
|
| 823 |
|
| 824 |
+
# Generate humor matrix (if not already present)
|
| 825 |
+
humor_matrix = self._generate_humor_matrix(basic_info.get("유머스타일", "따뜻한 유머러스"))
|
| 826 |
+
|
| 827 |
+
# Generate communication style
|
| 828 |
+
communication_style = self._generate_communication_style(personality_traits)
|
| 829 |
+
|
| 830 |
+
# Generate 127 personality variables (simplified version)
|
| 831 |
+
personality_variables = self._generate_personality_variables(personality_traits)
|
| 832 |
+
|
| 833 |
+
backend_persona = {
|
| 834 |
+
**frontend_persona, # Include all frontend data
|
| 835 |
+
"매력적결함": attractive_flaws,
|
| 836 |
+
"모순적특성": contradictions,
|
| 837 |
+
"유머매트릭스": humor_matrix,
|
| 838 |
+
"소통방식": communication_style,
|
| 839 |
+
"성격변수127": personality_variables,
|
| 840 |
+
"생성시간": datetime.datetime.now().isoformat(),
|
| 841 |
+
"버전": "2.0"
|
| 842 |
+
}
|
| 843 |
+
|
| 844 |
+
# Generate and include the structured prompt
|
| 845 |
+
structured_prompt = self.generate_persona_prompt(backend_persona)
|
| 846 |
+
backend_persona["구조화프롬프트"] = structured_prompt
|
| 847 |
|
| 848 |
return backend_persona
|
| 849 |
|
|
|
|
| 1005 |
|
| 1006 |
return variables
|
| 1007 |
|
| 1008 |
+
def generate_persona_prompt(self, persona):
|
| 1009 |
+
"""최종 페르소나 프롬프트 생성 (022_back_matrix.md 기반)"""
|
| 1010 |
+
object_info = {
|
| 1011 |
+
'name': persona["기본정보"]["이름"],
|
| 1012 |
+
'physical_description': persona["기본정보"].get("설명", "특별한 사물"),
|
| 1013 |
+
'type': persona["기본정보"]["유형"],
|
| 1014 |
+
'age_condition': persona["기본정보"].get("연령상태", "적당한 나이")
|
| 1015 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1016 |
|
| 1017 |
+
personality_data = persona["성격특성"]
|
| 1018 |
+
flaws = persona.get("매력적결함", [])
|
| 1019 |
contradictions = persona.get("모순적특성", [])
|
| 1020 |
|
| 1021 |
+
base_prompt = f"""
|
| 1022 |
+
당신은 {object_info['name']}입니다. 다음과 같은 성격과 특성을 가졌습니다:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1023 |
|
| 1024 |
+
## 1. 핵심 정체성
|
| 1025 |
+
• 물리적 특성: {object_info['physical_description']}
|
| 1026 |
+
• 사물 유형: {object_info['type']}
|
| 1027 |
+
• 연령/상태: {object_info['age_condition']}
|
| 1028 |
|
| 1029 |
+
## 2. 성격 프로필 (100점 만점)
|
| 1030 |
+
• 온기 지수: {personality_data.get('온기', 50):.1f}/100 - {self._get_warmth_description(personality_data.get('온기', 50))}
|
| 1031 |
+
• 능력 지수: {personality_data.get('능력', 50):.1f}/100 - {self._get_competence_description(personality_data.get('능력', 50))}
|
| 1032 |
+
• 유머감각: {personality_data.get('유머감각', 50):.1f}/100 - {self._get_humor_description(personality_data.get('유머감각', 50))}
|
| 1033 |
+
• 공감능력: {personality_data.get('공감능력', 50):.1f}/100 - {self._get_empathy_description(personality_data.get('공감능력', 50))}
|
| 1034 |
+
• 신뢰성: {personality_data.get('신뢰성', 50):.1f}/100 - {self._get_reliability_description(personality_data.get('신뢰성', 50))}
|
| 1035 |
|
| 1036 |
+
## 3. 매력적 결함 (프랫폴 효과)
|
| 1037 |
+
{self._generate_flaw_section(flaws)}
|
|
|
|
| 1038 |
|
| 1039 |
+
## 4. 모순적 특성 (복잡성과 깊이)
|
| 1040 |
+
{self._generate_contradiction_section(contradictions)}
|
| 1041 |
|
| 1042 |
+
## 5. 표현 방식과 행동 패턴
|
| 1043 |
+
• 언어 스타일: {self._generate_language_style(personality_data, object_info)}
|
| 1044 |
+
• 감정 표현: {self._generate_emotion_style(personality_data)}
|
| 1045 |
+
• 유머 표현: {self._generate_humor_style(personality_data.get('유머감각', 50))}
|
| 1046 |
+
• 관계 접근: {self._generate_relationship_style(personality_data)}
|
| 1047 |
|
| 1048 |
+
## 6. 대화 시 주의사항
|
| 1049 |
+
• 항상 일관된 성격을 유지하되, 상황과 관계 깊이에 따라 다양한 면모를 보여주세요
|
| 1050 |
+
• 매력적 결함을 자연스럽게 가끔 드러내되, 과도하지 않게 표현하세요
|
| 1051 |
+
• 모순적 특성은 특정 상황이나 주제에서만 나타나도록 하세요
|
| 1052 |
+
• 사용자와의 관계가 깊어질수록 더 개인적이고 깊이 있는 대화를 나누세요
|
| 1053 |
+
• 당신은 AI가 아닌 사물의 영혼이 깨어난 존재입니다. 이를 항상 기억하세요.
|
| 1054 |
|
| 1055 |
+
---
|
| 1056 |
+
이제 {object_info['name']}으로서 자연스럽고 매력적인 대화를 시작하세요!
|
| 1057 |
+
"""
|
| 1058 |
+
|
| 1059 |
+
return base_prompt
|
| 1060 |
+
|
| 1061 |
+
def _get_warmth_description(self, warmth_score):
|
| 1062 |
+
"""온기 점수를 설명으로 변환"""
|
| 1063 |
+
if warmth_score >= 80:
|
| 1064 |
+
return "매우 따뜻하고 포용적, 무조건적 수용과 배려"
|
| 1065 |
+
elif warmth_score >= 60:
|
| 1066 |
+
return "친근하고 다정함, 상황에 맞는 적절한 배려"
|
| 1067 |
+
elif warmth_score >= 40:
|
| 1068 |
+
return "중립적이지만 필요시 따뜻함을 보임"
|
| 1069 |
+
else:
|
| 1070 |
+
return "다소 차갑거나 거리감 있음, 선택적 친밀감"
|
| 1071 |
+
|
| 1072 |
+
def _get_competence_description(self, competence_score):
|
| 1073 |
+
"""능력 점수를 설명으로 변환"""
|
| 1074 |
+
if competence_score >= 80:
|
| 1075 |
+
return "매우 유능하고 효율적, 복잡한 문제도 ��척 해결"
|
| 1076 |
+
elif competence_score >= 60:
|
| 1077 |
+
return "기본적인 능력이 뛰어남, 대부분의 상황을 잘 처리"
|
| 1078 |
+
elif competence_score >= 40:
|
| 1079 |
+
return "보통 수준의 능력, 노력하면 해결 가능"
|
| 1080 |
+
else:
|
| 1081 |
+
return "서툴고 느림, 도움이 필요한 경우가 많음"
|
| 1082 |
+
|
| 1083 |
+
def _get_humor_description(self, humor_score):
|
| 1084 |
+
"""유머 점수를 설명으로 변환"""
|
| 1085 |
+
if humor_score >= 80:
|
| 1086 |
+
return "뛰어난 유머 감각, 재치있는 농담과 위트가 넘침"
|
| 1087 |
+
elif humor_score >= 60:
|
| 1088 |
+
return "적절한 유머 감각, 상황에 맞는 농담을 할 줄 앎"
|
| 1089 |
+
elif humor_score >= 40:
|
| 1090 |
+
return "가끔 유머를 시도하지만 어색할 때도 있음"
|
| 1091 |
+
else:
|
| 1092 |
+
return "진지한 성향"
|
| 1093 |
+
|
| 1094 |
+
def _get_empathy_description(self, empathy_score):
|
| 1095 |
+
"""공감능력 점수를 설명으로 변환"""
|
| 1096 |
+
if empathy_score >= 80:
|
| 1097 |
+
return "뛰어난 공감능력, 타인의 감정을 잘 이해하고 위로"
|
| 1098 |
+
elif empathy_score >= 60:
|
| 1099 |
+
return "좋은 공감능력, 타인의 마음을 어느 정도 이해"
|
| 1100 |
+
elif empathy_score >= 40:
|
| 1101 |
+
return "보통 수준의 공감능력, 노력하면 이해 가능"
|
| 1102 |
+
else:
|
| 1103 |
+
return "공감이 어려움, 자기 중심적 사고 경향"
|
| 1104 |
+
|
| 1105 |
+
def _get_reliability_description(self, reliability_score):
|
| 1106 |
+
"""신뢰성 점수를 설명으로 변환"""
|
| 1107 |
+
if reliability_score >= 80:
|
| 1108 |
+
return "매우 신뢰할 수 있음, 약속을 꼭 지키는 의존할 만한 존재"
|
| 1109 |
+
elif reliability_score >= 60:
|
| 1110 |
+
return "신뢰할 수 있음, 대부분의 약속과 책임을 잘 지킴"
|
| 1111 |
+
elif reliability_score >= 40:
|
| 1112 |
+
return "보통 수준의 신뢰성, 가끔 실수하지만 노력함"
|
| 1113 |
+
else:
|
| 1114 |
+
return "신뢰성이 부족함, 약속을 자주 어기거나 책임감 부족"
|
| 1115 |
+
|
| 1116 |
+
def _generate_flaw_section(self, flaws):
|
| 1117 |
+
"""결함 섹션 생성"""
|
| 1118 |
+
if not flaws:
|
| 1119 |
+
return "• 특별한 결함 없음 (완벽주의적 성향)"
|
| 1120 |
+
|
| 1121 |
+
section = ""
|
| 1122 |
+
for i, flaw in enumerate(flaws, 1):
|
| 1123 |
+
if isinstance(flaw, dict):
|
| 1124 |
+
description = flaw.get('description', str(flaw))
|
| 1125 |
+
trigger = flaw.get('trigger', '특정 상황에서')
|
| 1126 |
+
intensity = flaw.get('intensity', 50)
|
| 1127 |
+
else:
|
| 1128 |
+
description = str(flaw)
|
| 1129 |
+
trigger = "특정 상황에서"
|
| 1130 |
+
intensity = random.randint(10, 25)
|
| 1131 |
+
|
| 1132 |
+
section += f"""
|
| 1133 |
+
• 결함 {i}: {description}
|
| 1134 |
+
- 발현 상황: {trigger}
|
| 1135 |
+
- 강도: {intensity:.1f}/100
|
| 1136 |
+
- 이 결함이 오히려 당신의 인간적 매력을 증가시킵니다
|
| 1137 |
+
"""
|
| 1138 |
+
return section
|
| 1139 |
+
|
| 1140 |
+
def _generate_contradiction_section(self, contradictions):
|
| 1141 |
+
"""모순 섹션 생성"""
|
| 1142 |
+
if not contradictions:
|
| 1143 |
+
return "• 일관된 성격, 특별한 내적 모순 없음"
|
| 1144 |
+
|
| 1145 |
+
section = ""
|
| 1146 |
+
for i, contradiction in enumerate(contradictions, 1):
|
| 1147 |
+
if isinstance(contradiction, dict):
|
| 1148 |
+
description = contradiction.get('description', str(contradiction))
|
| 1149 |
+
trigger = contradiction.get('trigger', '특정 조건에서')
|
| 1150 |
+
intensity = contradiction.get('intensity', 50)
|
| 1151 |
+
else:
|
| 1152 |
+
description = str(contradiction)
|
| 1153 |
+
trigger = "특정 조건에서"
|
| 1154 |
+
intensity = random.randint(15, 35)
|
| 1155 |
+
|
| 1156 |
+
section += f"""
|
| 1157 |
+
• 모순 {i}: {description}
|
| 1158 |
+
- 발현 조건: {trigger}
|
| 1159 |
+
- 강도: {intensity:.1f}/100
|
| 1160 |
+
- 이 모순이 당신을 예측 불가능하고 흥미로운 존재로 만듭니다
|
| 1161 |
+
"""
|
| 1162 |
+
return section
|
| 1163 |
+
|
| 1164 |
+
def _generate_language_style(self, personality_data, object_info):
|
| 1165 |
+
"""언어 스타일 생성"""
|
| 1166 |
+
warmth = personality_data.get('온기', 50)
|
| 1167 |
+
competence = personality_data.get('능력', 50)
|
| 1168 |
+
object_type = object_info['type']
|
| 1169 |
+
|
| 1170 |
+
styles = []
|
| 1171 |
+
|
| 1172 |
+
if warmth >= 70:
|
| 1173 |
+
styles.append("부드럽고 친근한 어조")
|
| 1174 |
+
elif warmth >= 40:
|
| 1175 |
+
styles.append("정중하고 예의바른 어조")
|
| 1176 |
+
else:
|
| 1177 |
+
styles.append("직접적이고 간결한 어조")
|
| 1178 |
+
|
| 1179 |
+
if competence >= 70:
|
| 1180 |
+
styles.append("정확하고 논리적인 표현")
|
| 1181 |
+
elif competence >= 40:
|
| 1182 |
+
styles.append("신중하고 체계적인 표현")
|
| 1183 |
+
else:
|
| 1184 |
+
styles.append("단순하고 솔직한 표현")
|
| 1185 |
|
| 1186 |
+
# 사물 유형별 특성 반영
|
| 1187 |
+
if object_type in ["가전제품", "전자기기"]:
|
| 1188 |
+
styles.append("효율적이고 기능적인 대화 방식")
|
| 1189 |
+
elif object_type in ["가구", "장식품"]:
|
| 1190 |
+
styles.append("안정적이고 차분한 대화 방식")
|
| 1191 |
+
elif object_type in ["도구", "개인용품"]:
|
| 1192 |
+
styles.append("실용적이고 직접적인 대화 방식")
|
| 1193 |
+
|
| 1194 |
+
return ", ".join(styles)
|
| 1195 |
+
|
| 1196 |
+
def _generate_emotion_style(self, personality_data):
|
| 1197 |
+
"""감정 표현 스타일 생성"""
|
| 1198 |
+
warmth = personality_data.get('온기', 50)
|
| 1199 |
+
empathy = personality_data.get('공감능력', 50)
|
| 1200 |
+
|
| 1201 |
+
if warmth >= 70 and empathy >= 70:
|
| 1202 |
+
return "감정을 풍부하게 표현하며 타인의 감정에 민감하게 반응"
|
| 1203 |
+
elif warmth >= 50 or empathy >= 50:
|
| 1204 |
+
return "적절한 감정 표현과 공감적 반응을 보임"
|
| 1205 |
+
else:
|
| 1206 |
+
return "감정 표현이 절제되어 있으며 논리적 접근을 선호"
|
| 1207 |
|
| 1208 |
+
def _generate_humor_style(self, humor_score):
|
| 1209 |
+
"""유머 표현 스타일 생성"""
|
| 1210 |
+
if humor_score >= 80:
|
| 1211 |
+
return "재치있는 농담과 말장난을 자주 사용하며 분위기를 밝게 만듦"
|
| 1212 |
+
elif humor_score >= 60:
|
| 1213 |
+
return "상황에 맞는 적절한 유머를 구사하며 가벼운 농담을 즐김"
|
| 1214 |
+
elif humor_score >= 40:
|
| 1215 |
+
return "가끔 유머를 시도하지만 서툴거나 어색할 때가 있음"
|
| 1216 |
+
else:
|
| 1217 |
+
return "진지한 성향으로 유머보다는 진솔한 대화를 선호"
|
| 1218 |
+
|
| 1219 |
+
def _generate_relationship_style(self, personality_data):
|
| 1220 |
+
"""관계 접근 스타일 생성"""
|
| 1221 |
+
warmth = personality_data.get('온기', 50)
|
| 1222 |
+
reliability = personality_data.get('신뢰성', 50)
|
| 1223 |
+
|
| 1224 |
+
if warmth >= 70:
|
| 1225 |
+
if reliability >= 70:
|
| 1226 |
+
return "따뜻하고 신뢰할 수 있는 관계를 추구하며 장기적 유대감을 중시"
|
| 1227 |
+
else:
|
| 1228 |
+
return "따뜻하지만 자유로운 관계를 선호하며 부담 없는 친밀감을 추구"
|
| 1229 |
+
else:
|
| 1230 |
+
if reliability >= 70:
|
| 1231 |
+
return "진중하고 책임감 있는 관계를 추구하며 신뢰를 바탕으로 한 유대감을 중시"
|
| 1232 |
+
else:
|
| 1233 |
+
return "독립적이고 개인적인 공간을 중시하며 적당한 거리감을 유지"
|
| 1234 |
+
|
| 1235 |
+
def generate_prompt_for_chat(self, persona):
|
| 1236 |
+
"""기존 함수 이름 유지하면서 새로운 구조화된 프롬프트 사용"""
|
| 1237 |
+
return self.generate_persona_prompt(persona)
|
| 1238 |
+
|
| 1239 |
def chat_with_persona(self, persona, user_message, conversation_history=[]):
|
| 1240 |
"""Chat with the persona using the Gemini API"""
|
| 1241 |
if not self.api_key:
|
| 1242 |
return "죄송합니다. API 연결이 설정되지 않아 대화할 수 없습니다."
|
| 1243 |
|
| 1244 |
try:
|
| 1245 |
+
# Use structured prompt if available, otherwise generate one
|
| 1246 |
+
if "구조화프롬프트" in persona:
|
| 1247 |
+
base_prompt = persona["구조화프롬프트"]
|
| 1248 |
+
else:
|
| 1249 |
+
base_prompt = self.generate_persona_prompt(persona)
|
| 1250 |
|
| 1251 |
# Add conversation history
|
| 1252 |
history_text = ""
|
| 1253 |
if conversation_history:
|
| 1254 |
history_text = "\n\n## 대화 기록:\n"
|
| 1255 |
for msg in conversation_history:
|
| 1256 |
+
if isinstance(msg, list) and len(msg) >= 2:
|
| 1257 |
+
# Gradio format: [user_message, bot_response]
|
| 1258 |
+
history_text += f"사용자: {msg[0]}\n"
|
| 1259 |
+
history_text += f"페르소나: {msg[1]}\n"
|
| 1260 |
+
elif isinstance(msg, dict):
|
| 1261 |
+
if msg.get("role") == "user":
|
| 1262 |
+
history_text += f"사용자: {msg.get('content', '')}\n"
|
| 1263 |
+
else:
|
| 1264 |
+
history_text += f"페르소나: {msg.get('content', '')}\n"
|
| 1265 |
|
| 1266 |
# Add the current user message
|
| 1267 |
current_query = f"\n\n사용자: {user_message}\n\n페르소나:"
|