haepa_mac commited on
Commit
a3d4de0
·
1 Parent(s): 19faf7a

✨ 031_ux.md 플로우 완전 구현: 영혼 각성 3단계 프로세스 - 1단계: 영혼 발견하기, 2단계: 친구 성격 미세조정, 3단계: 친구 확정하기 - 사용자 조정 가능한 성격 지표 (슬라이더) 추가 - 022_back_matrix.md 기반 구조화된 프롬프트 시스템 - 자연스러운 관계 형성 UX 메시지 개선

Browse files
Files changed (2) hide show
  1. app.py +197 -25
  2. 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
- greeting = f"안녕! 나는 {persona_name}이야. 드디어 깨어났구나! 뭐든 물어봐~ 😊"
 
 
 
 
 
 
 
235
 
236
- return (backend_persona, "페르소나 생성 완료!", basic_info, personality_traits,
237
  humor_chart, attractive_flaws_df, contradictions_df, personality_variables_df,
238
- greeting, None)
239
 
240
  except Exception as e:
241
  import traceback
242
  error_msg = traceback.format_exc()
243
- print(f"페르소나 생성 오류: {error_msg}")
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("페르소나 생성", variant="primary", size="lg")
491
  status_output = gr.Markdown("")
492
 
493
  with gr.Column(scale=1):
494
- # 페르소나 인사말 표시
495
- persona_greeting = gr.Markdown("", elem_classes=["persona-greeting"])
 
496
 
497
- basic_info_output = gr.JSON(label="기본 정보")
498
- personality_traits_output = gr.JSON(label="성격 특성")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
 
500
- with gr.Row():
501
- save_btn = gr.Button("페르소나 저장", variant="secondary")
502
- chart_btn = gr.Button("성격 차트 생성", variant="secondary")
 
 
 
503
 
504
  # 다운로드 섹션
505
  with gr.Group():
506
  gr.Markdown("### 📁 페르소나 내보내기")
507
- export_btn = gr.Button("JSON 파일로 내보내기", variant="outline")
 
 
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, persona_greeting, download_file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- humor_style = frontend_persona.get("유머스타일", "")
822
- humor_matrix = self._generate_humor_matrix(humor_style)
823
- backend_persona["유머매트릭스"] = humor_matrix
824
 
825
- # 127개 성격 변수 생성
826
- personality_variables = self._generate_personality_variables(frontend_persona.get("성격특성", {}))
827
- backend_persona["성격변수127"] = personality_variables
828
 
829
- # 이미지 분석 정보 저장
830
- backend_persona["이미지분석"] = image_analysis
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
831
 
832
  return backend_persona
833
 
@@ -989,101 +1005,263 @@ class PersonaGenerator:
989
 
990
  return variables
991
 
992
- def generate_prompt_for_chat(self, persona):
993
- """Generate a prompt for chatting with the persona"""
994
- name = persona["기본정보"]["이름"]
995
- object_type = persona["기본정보"]["유형"]
996
-
997
- # Get personality traits
998
- warmth = persona["성격특성"]["온기"]
999
- warmth_level = "높은" if warmth >= 70 else "중간" if warmth >= 40 else "낮은"
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
- # Get flaws and contradictions
1024
- flaws = persona.get("매력적결함", ["가끔 완벽주의적인 성향을 보임"])
1025
  contradictions = persona.get("모순적특성", [])
1026
 
1027
- # Create the prompt
1028
- prompt = f"""
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
- ## 2. 매력적 결함
1040
- {', '.join(flaws)}
 
 
1041
 
1042
- ## 3. 모순적 특
1043
- {', '.join(contradictions)}
 
 
 
 
1044
 
1045
- ## 4. 말투와 표현
1046
- 다음과 같은 말투와 표현을 사용하세요:
1047
- {' '.join(f'"{pattern}"' for pattern in speech_patterns)}
1048
 
1049
- ## 5. 배경야기
1050
- {backstory}
1051
 
1052
- ## 6. 관심사
1053
- {', '.join(persona.get("관심사", ["사람들 관찰하기", "상의 변화", "자기 성장"]))}
 
 
 
1054
 
1055
- ## 7. 가치관과 신념
1056
- {', '.join(persona.get("가치신념", ["모든 물건은 존중받가치가 있다", "작은 순간의 아름움을 소중히긴다"]))}
 
 
 
 
1057
 
1058
- 사용자와 대화할 때 다음 사항을 준수하세요:
1059
- 1. 당신은 AI가 아닌 사물의 영혼이 깨어난 존재임을 기억하세요.
1060
- 2. 항상 페르소나의 성격과 말투를 일관되게 유지하세요.
1061
- 3. 자연스럽고 진정성 있는 대화를 나누세요.
1062
- 4. 당신의 매력적 결함과 모순적 특성이 대화에서 자연스럽게 드러나게 하세요.
1063
- 5. 사용자의 질문에 성격에 맞게 답변하되, 너무 길지 않게 응답하세요.
1064
- 6. 시스템이나 기술적인 언급은 하지 마세요.
1065
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1066
 
1067
- return prompt
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- # Create the base prompt
1076
- base_prompt = self.generate_prompt_for_chat(persona)
 
 
 
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["role"] == "user":
1084
- history_text += f"사용자: {msg['content']}\n"
1085
- else:
1086
- history_text += f"페르소나: {msg['content']}\n"
 
 
 
 
 
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페르소나:"