File size: 8,537 Bytes
ef82d45
 
 
0482473
 
ef82d45
 
 
0482473
 
 
 
 
 
 
 
ef82d45
0482473
 
 
 
 
 
 
 
 
 
 
 
 
ef82d45
0482473
 
 
 
 
 
 
 
 
 
 
ef82d45
0482473
 
 
 
 
 
 
 
 
 
ef82d45
 
96692cf
 
 
0482473
 
 
 
 
 
 
 
 
 
785b76a
0482473
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
785b76a
 
0482473
 
 
 
 
 
 
785b76a
ef82d45
0482473
785b76a
0482473
785b76a
0482473
 
785b76a
0482473
 
96692cf
0482473
 
785b76a
 
ef82d45
0482473
 
 
 
 
 
 
 
 
 
 
 
 
785b76a
0482473
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef82d45
785b76a
 
 
96692cf
785b76a
 
 
96692cf
785b76a
 
 
 
 
 
 
0482473
 
785b76a
0482473
96692cf
0482473
 
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
# 감정-행동 연동 λ§€ν•‘ 및 행동 생성
# portfolio/npc_social_network/npc/npc_behavior.py

from .emotion_config import EMOTION_CATEGORY_MAP

class BehaviorManager:
    def __init__(self):
        self.mapping = {
            # Core (κΈ°λ³Έ 감정)
            "joy": "jump",                  # 기쁨 : 점프 λ›°λ‹€
            "sadness": "sit_down",          # μŠ¬ν”” : μ£Όμ € 앉닀
            "anger": "shout",               # λΆ„λ…Έ : μ†Œλ¦¬μΉ˜λ‹€
            "fear": "run_away",             # 곡포 : λ„λ§μΉ˜λ‹€
            "disgust": "avoid",             # 혐였 : ν”Όν•˜λ‹€
            "surprise": "gasp",             # λ†€λžŒ : κ°νƒ„ν•˜λ©° μˆ¨μ„ 듀이쉼
            "neutral": "idle",              # 쀑립 : 아무것도 ν•˜μ§€ μ•ŠμŒ

            # Social (μ‚¬νšŒμ  감정)
            "gratitude": "thank",           # 감사 : κ°μ‚¬ν•˜λ‹€
            "shame": "hide_face",           # μˆ˜μΉ˜μ‹¬ : 얼꡴을 감좔닀
            "guilt": "apologize",           # 죄책감 : λ―Έμ•ˆν•˜λ‹€κ³  말함
            "pride": "show_off",            # μžλΆ€μ‹¬ : μžλž‘ν•˜λ‹€
            "jealousy": "glare",            # 질투 : 노렀보닀
            "compassion": "console",        # μ—°λ―Ό/동정 : μœ„λ‘œν•˜λ‹€
            "love": "embrace",              # μ‚¬λž‘/μ• μ • : ν¬μ˜Ήν•˜λ‹€
            "admiration": "cheer",          # μ‘΄κ²½/감탄 : ν™˜ν˜Έν•˜λ‹€
            "empathy": "listen_carefully",  # 곡감 : μ§‘μ€‘ν•˜λ‹€
            "awe": "gasp",                  # 경외심 : κ°νƒ„ν•˜λ©° μˆ¨μ„ 듀이쉼
            "attachment": "hold_hands",     # μ• μ°© : μ†Œμœ ν•˜λ‹€
            "comfort": "pat",               # μœ„λ‘œ 좔ꡬ : ν† λ‹₯거리닀

            # Cognitive (인지적 μƒνƒœ)
            "anticipation": "prepare",      # κΈ°λŒ€ : μ€€λΉ„ν•˜λ‹€
            "curiosity": "inspect",         # ν˜ΈκΈ°μ‹¬ : μ‚΄νŽ΄λ³΄λ‹€
            "confusion": "scratch_head",    # ν˜Όλž€ : 머리λ₯Ό 긁닀
            "interest": "lean_forward",     # ν₯λ―Έ : μ§‘μ€‘ν•˜λ‹€
            "engagement": "focus",          # λͺ°μž… : μ§‘μ€‘ν•˜λ‹€
            "boredom": "idle",              # 지루함 : 아무것도 ν•˜μ§€ μ•ŠμŒ
            "relief": "exhale",             # μ•ˆλ„ : μˆ¨μ„ 내쉬닀
            "anxiety": "fidget",            # λΆˆμ•ˆ/κΈ΄μž₯ : μ•ˆμ ˆλΆ€μ ˆ λͺ»ν•˜λ‹€
            "calm": "relax",                # ν‰μ˜¨ : μ§„μ •ν•˜λ‹€
            "skepticism": "raise_eyebrow",  # 회의 : λˆˆμΉμ„ μ˜¬λ¦¬λ‹€

            # Complex (볡합 감정)
            "nostalgia": "stare_into_distance",     # ν–₯수
            "bittersweet": "smile_then_look_down",  # λ‹¬μ½€μŒ‰μ‹Έλ¦„ν•¨
            "schadenfreude": "smirk",               # λ‚¨μ˜ λΆˆν–‰μ—μ„œ λŠλΌλŠ” 기쁨
            "hope": "brighten_up",                  # 희망
            "resentment": "scowl",                  # λΆ„κ°œ
            "anticipatory_joy": "rub_hands",        # κΈ°λŒ€ μ†μ˜ 기쁨
            "regret": "look_down",                  # ν›„νšŒ
            "rumination": "mutter_to_self",         # λ°˜μΆ”
            "groundedness": "steady_posture",       # μ•ˆμ •κ°
        }

        # 행동에 λ”°λ₯Έ 감정 (μ—­λ§€ν•‘)
        self.action_to_emotion = {v: k for k, v in self.mapping.items()}

        # Layer μš°μ„  μˆœμœ„ / weight μ„€μ • (νŠœλ‹ κ°€λŠ₯)
        self.layer_priority = ["core", "social", "cognitive", "complex"]
        self.layer_weights = {
            "core" : 1.0,
            "social" : 0.8,
            "cognitive" : 0.6,
            "complex" : 0.4,
        }
    
    def get_layer_dominant_emotions(self, buffer):
        """
        layer별 dominant emotion 계산
        """
        layer_emotions = {layer: [] for layer in self.layer_priority}
        for emo, val in buffer.items():
            if val > 0:
                layer = EMOTION_CATEGORY_MAP.get(emo)
                if layer:
                    layer_emotions[layer].append((emo, val))

        # 각 layerμ—μ„œ κ°€μž₯ κ°•ν•œ 감정 μΆ”μΆœ
        layer_dominant = {}
        for layer, emos in layer_emotions.items():
            if emos:
                dominant_emo = max(emos, key=lambda x: x[1])
                layer_dominant[layer] = dominant_emo
            
        return layer_dominant
    
    def decide_layered_sequence(self, layer_dominant_emotions):
        """
        layer priority + weight 기반 μ‹œν€€μŠ€ 생성
        """
        sequence = []
        for layer in self.layer_priority:
            if layer in layer_dominant_emotions:
                emo, score = layer_dominant_emotions[layer]
                weighted_score = round(score * self.layer_weights[layer], 2)
                action = self.mapping.get(emo)
                if action:
                    sequence.append((action, weighted_score))
        return sequence
    
    def perform_sequence(self, name, job, emotion_buffer, return_trace=False):
        """
        Layer-aware Behavior μ‹œν€€μŠ€ ꡬ성 + Behavior Trace λ°˜ν™˜
        """
        layer_dominant_emotions = self.get_layer_dominant_emotions(emotion_buffer)
        sequence = self.decide_layered_sequence(layer_dominant_emotions)
        if not sequence:
            behavior_output = f"{name}은(λŠ”) νŠΉλ³„ν•œ 행동을 ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."
            if return_trace:
                return behavior_output, []
            else:
                return behavior_output
        
        # 행동 ν…μŠ€νŠΈ ν…œν”Œλ¦Ώ
        behavior_lines = {
            # Core
            "jump": "κΈ°λ»μ„œ κΉ‘μΆ© λœλ‹ˆλ‹€.",
            "sit_down": "μŠ¬νΌμ„œ μ£Όμ €μ•‰μŠ΅λ‹ˆλ‹€....",
            "shout": "ν™”κ°€ λ‚˜μ„œ μ†Œλ¦¬λ₯Ό μ§€λ¦…λ‹ˆλ‹€!",
            "run_away": "λ¬΄μ„œμ›Œ λ„λ§κ°‘λ‹ˆλ‹€!",
            "avoid": "λ’€λ‘œ λ¬ΌλŸ¬μ„œ ν”Όν•˜λ € ν•©λ‹ˆλ‹€.",
            "gasp": "깜짝 λ†€λžλ‹ˆλ‹€.",
            "idle": "κ°€λ§Œνžˆ μžˆμŠ΅λ‹ˆλ‹€.",

            # Social
            "thank": "κ°μ‚¬ν•œ λ§ˆμŒμ„ ν‘œν˜„ν•©λ‹ˆλ‹€.",
            "hide_face": "μˆ˜μΉ˜μ‹¬μ— 얼꡴을 κ°€λ¦½λ‹ˆλ‹€.",
            "apologize": "λ―Έμ•ˆν•˜λ‹€κ³  λ§ν•©λ‹ˆλ‹€.",
            "show_off": "μžλž‘μŠ€λŸ¬μš΄ λͺ¨μŠ΅μ„ λ³΄μ—¬μ€λ‹ˆλ‹€.",
            "glare": "μƒλŒ€λ₯Ό λ…Έλ €λ΄…λ‹ˆλ‹€.",
            "console": "μƒλŒ€λ°©μ„ λ”°λœ»ν•˜κ²Œ μœ„λ‘œν•©λ‹ˆλ‹€.",
            "embrace": "μƒλŒ€λ₯Ό ν¬μ˜Ήν•©λ‹ˆλ‹€.",
            "cheer": "κ°νƒ„ν•˜λ©° μ‘μ›ν•©λ‹ˆλ‹€.",
            "listen_carefully": "μƒλŒ€μ˜ 말을 μ§‘μ€‘ν•΄μ„œ λ“£μŠ΅λ‹ˆλ‹€.",
            "hold_hands": "손을 μž‘μŠ΅λ‹ˆλ‹€.",
            "pat": "κ°€λ³κ²Œ 등을 λ‘λ“œλ € μœ„λ‘œν•©λ‹ˆλ‹€.",

            # Cognitive
            "prepare": "무언가λ₯Ό μ€€λΉ„ν•©λ‹ˆλ‹€.",
            "inspect": "μœ μ‹¬νžˆ κ΄€μ°°ν•©λ‹ˆλ‹€.",
            "scratch_head": "머리λ₯Ό κΈμ μž…λ‹ˆλ‹€.",
            "lean_forward": "μ•žμœΌλ‘œ μˆ™μ΄λ©° μ§‘μ€‘ν•©λ‹ˆλ‹€.",
            "focus": "λͺ°μž…ν•˜μ—¬ μ§‘μ€‘ν•©λ‹ˆλ‹€.",
            "exhale": "μ•ˆλ„ν•˜λ©° μˆ¨μ„ μ‰½λ‹ˆλ‹€.",
            "fidget": "λΆˆμ•ˆν•˜κ²Œ λͺΈμ„ μ›€μ§μž…λ‹ˆλ‹€.",
            "relax": "ν‰μ˜¨ν•˜κ²Œ νœ΄μ‹ν•©λ‹ˆλ‹€.",
            "raise_eyebrow": "μ˜μ‹¬μŠ€λŸ½κ²Œ λˆˆμΉμ„ μΉ˜μΌœλœΉλ‹ˆλ‹€.",

            # Complex
            "stare_into_distance": "λ¨Ό 곳을 바라보며 νšŒμƒμ— μž κΉλ‹ˆλ‹€.",
            "smile_then_look_down": "λ―Έμ†Œλ₯Ό μ§“λ‹€κ°€ 고개λ₯Ό μˆ™μž…λ‹ˆλ‹€.",
            "smirk": "λΉ„μ›ƒλŠ” ν‘œμ •μ„ μ§“μŠ΅λ‹ˆλ‹€.",
            "brighten_up": "κΈ°λŒ€κ°μ— λˆˆλΉ›μ΄ λΉ›λ‚©λ‹ˆλ‹€.",
            "scowl": "인상을 μ°Œν‘Έλ¦½λ‹ˆλ‹€.",
            "rub_hands": "λ“€λœ¬ λ§ˆμŒμ— 손을 λΉ„λΉ•λ‹ˆλ‹€.",
            "look_down": "고개λ₯Ό μˆ™μ΄λ©° ν›„νšŒν•©λ‹ˆλ‹€.",
            "mutter_to_self": "ν˜Όμž£λ§μ„ μ€‘μ–Όκ±°λ¦½λ‹ˆλ‹€.",
            "steady_posture": "μ•ˆμ •λœ μžμ„Έλ₯Ό μœ μ§€ν•©λ‹ˆλ‹€.",
        }

        # 행동 λ¬Έμž₯ 생성
        lines = []
        trace_pairs = []
        for action, score in sequence:
            msg = behavior_lines.get(action, f"{action} 행동을 ν•©λ‹ˆλ‹€.")
            lines.append(f"({round(score,1)}) {msg}")
            trace_pairs.append((action, round(score, 1)))

        # 직업 라인 μΆ”κ°€
        job_line = {
            "farmer": "밭일도 ν•΄μ•Ό ν•˜κ² κ΅°μš”.",
            "blacksmith": "λŒ€μž₯κ°„ λΆˆλ„ μ§€νŽ΄μ•Όμ£ .",
        }.get(job, "μ˜€λŠ˜λ„ λ°”μœ ν•˜λ£¨λ„€μš”.")

        behavior_output = f"{name} 행동 μ‹œν€€μŠ€: \n" + "\n".join(lines) + f"\n{job_line}"

        # μ΅œμ’… 좜λ ₯ λ¬Έμž₯
        if return_trace:
            return behavior_output, trace_pairs
        else:
            return behavior_output