Spaces:
Sleeping
Sleeping
# κ°μ -νλ μ°λ λ§€ν λ° νλ μμ± | |
# 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 |