Spaces:
Sleeping
Sleeping
File size: 7,865 Bytes
0a47069 3eb99bc 97627cd b5ff045 9009e60 93a860a d57920f 93a860a eb96cb9 93a860a eb96cb9 d57920f 1a6fb12 93a860a 97627cd eb96cb9 d57920f 146c098 3eb99bc 1a6fb12 97627cd 3eb99bc d57920f 3eb99bc 93a860a d57920f cf1ebab 9009e60 8411a77 9009e60 cf1ebab 9f97a01 9009e60 8411a77 9f97a01 9009e60 8411a77 9009e60 d57920f b5ff045 9f97a01 2fe1b55 6b7a4d5 2fe1b55 6b7a4d5 9009e60 6b7a4d5 2fe1b55 9009e60 2fe1b55 9f97a01 2fe1b55 6b7a4d5 9f97a01 6b7a4d5 2fe1b55 9f97a01 2fe1b55 9f97a01 2fe1b55 b5ff045 2fe1b55 b5ff045 2fe1b55 b5ff045 9009e60 b5ff045 d57920f 9f97a01 9009e60 b5ff045 9009e60 b5ff045 a88e1d8 9009e60 b5ff045 798df17 8750468 798df17 2fe1b55 c08ff6f 2fe1b55 798df17 b5ff045 798df17 b5ff045 9009e60 |
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 |
# portfolio/npc_social_network/npc/npc_manager.py
import random
from typing import TYPE_CHECKING, List, Optional
from .. import simulation_core
if TYPE_CHECKING:
from .npc_base import NPC
def get_korean_postposition(name, first_char, second_char):
"""์ด๋ฆ์ ๋ง์ง๋ง ๊ธ์ ๋ฐ์นจ ์ ๋ฌด์ ๋ฐ๋ผ ์ฌ๋ฐ๋ฅธ ์กฐ์ฌ๋ฅผ ๋ฐํ"""
if (ord(name[-1]) - 0xAC00) % 28 > 0:
return first_char
else:
return second_char
class NPCManager:
"""๋ชจ๋ NPC๋ฅผ ๊ด๋ฆฌํ๋ ์ค์ ๊ด๋ฆฌ์"""
def __init__(self):
self.npcs: list['NPC'] = []
self.npc_dict: dict[str, 'NPC'] = {}
self.korean_name_to_npc: dict[str, 'NPC'] = {} # ํ๊ธ ์ด๋ฆ ๊ฒ์์ฉ ๋์
๋๋ฆฌ
self.player_is_active = True # ํ๋ ์ด์ด ํ์ฑํ ์ํ ํ๋๊ทธ
def add_npc(self, npc: 'NPC'):
"""NPC๋ฅผ ๋งค๋์ ์ ์ถ๊ฐํฉ๋๋ค."""
if npc.name not in self.npc_dict:
self.npcs.append(npc)
self.npc_dict[npc.name] = npc
self.korean_name_to_npc[npc.korean_name] = npc
npc.manager = self
def set_player_active(self, is_active: bool):
"""ํ๋ ์ด์ด์ ํ์ฑํ ์ํ๋ฅผ ์ค์ """
self.player_is_active = is_active
def get_all_npcs_except_player(self) -> List['NPC']:
"""ํ๋ ์ด์ด๋ฅผ ์ ์ธํ ์์ NPC ๋ชฉ๋ก์ ๋ฐํ"""
return [npc for npc in self.npcs if npc.name != "player"]
def get_interactive_npcs(self) -> List['NPC']:
"""ํ์ฌ ์ํ์์ฉ์ด ๊ฐ๋ฅํ NPC ๋ชฉ๋ก์ ๋ฐํ"""
if self.player_is_active:
return self.npcs # ํ๋ ์ด์ด๊ฐ ํ์ฑํ ์ํ์ด๋ฉด ๋ชจ๋ ๋ฐํ
else:
return self.get_all_npcs_except_player() # ๋นํ์ฑํ ์ํ์ด๋ฉด ํ๋ ์ด์ด ์ ์ธ
def get_npc_by_name(self, name: str) -> Optional['NPC']:
"""
NPC ์์ด ID๋ฅผ ํตํด์ NPC์ ์ ๋ณด๋ฅผ ๋ฐํ
"""
return self.npc_dict.get(name)
def get_npc_by_korean_name(self, korean_name: str) -> Optional['NPC']:
"""NPC ํ๊ธ ์ด๋ฆ์ ํตํด์ NPC์ ์ ๋ณด๋ฅผ ๋ฐํ"""
return self.korean_name_to_npc.get(korean_name)
def get_random_npc(self, exclude: Optional['NPC']=None) -> Optional['NPC']:
"""
ํน์ NPC๋ฅผ ์ ์ธํ๊ณ ๋๋คํ NPC๋ฅผ ์ ํ
์์ ํ์: ์๋ NPC๊ฐ ๋๋ค์ด ์๋๋ผ, ์ํธ์์ฉํ ๋งํ ๊ทผ๊ฑฐ๊ฐ ์์ด์ผํ๋ค.
์) ๊ทผ์ฒ์ ์ฐ๋ค, ํน๋ณํ ์ด๋ฒคํธ๊ฐ ์์๋ค ๋ฑ ๊ณผ ๊ฐ์ ์ด์
"""
possible_targets = [n for n in self.npcs if n != exclude]
if not possible_targets:
return None
return random.choice(possible_targets)
def all(self) -> List['NPC']:
"""๊ด๋ฆฌ ์ค์ธ ๋ชจ๋ NPC์ ๋ฆฌ์คํธ๋ฅผ ๋ฐํํฉ๋๋ค."""
return self.npcs
def initiate_npc_to_npc_interaction(self, initiator: 'NPC', target: 'NPC',
time_context: str, topic: Optional[str] = None):
"""
NPC ๊ฐ์ ์ํธ์์ฉ์ ์์์ํค๋ ํจ์
- ์ฐธ์ฌํ NPC๋ฅผ ๋ฐํํด์ ์๋ฌธ์ ํผํธ๋ฆด '๋ชฉ๊ฒฉ์' ์์ฑ
- ์ฃผ์ ๊ฐ ์์ ๊ฒฝ์ฐ, ๋ชฉํ ์งํฅ์ ๋ํ๋ฅผ ์์ฑ
"""
from ..models.llm_helper import query_llm_with_prompt
if len(self.npcs) < 2:
return None, None # ์ํธ์์ฉํ NPC๊ฐ ์ต์ 2๋ช
ํ์
initiator_postposition = get_korean_postposition(initiator.korean_name, "์ด", "๊ฐ")
target_postposition = get_korean_postposition(target.korean_name, "์๊ฒ", "์๊ฒ")
simulation_core.add_log(f"\n---[NPC ์ํธ์์ฉ ์ด๋ฒคํธ]---\n{initiator.korean_name}{initiator_postposition} {target.korean_name}{target_postposition} ์ํธ์์ฉ์ ์๋ํฉ๋๋ค.")
if topic:
# ์ฃผ์ ๊ฐ ์๋ ๊ฒฝ์ฐ
prompt = f"""
# Persona
๋น์ ์ '{initiator.korean_name}'์
๋๋ค.
# Context
- ๋น์ ์ ์ง๊ธ '{target.korean_name}'์ ๋ง์ฃผ์ณค์ต๋๋ค.
- ๋น์ ๊ณผ ์๋์ ๊ด๊ณ: {initiator.relationships.get_relationship_summary(target.name)}
- ๋ํ ์ฃผ์ : "{topic}"
# Instruction
- ์ฃผ์ด์ง ์ํฉ๊ณผ ๋ํ ์ฃผ์ ์ ๋ง์ถฐ, ์๋๋ฐฉ์๊ฒ ๊ฑด๋ฌ ์์ฐ์ค๋ฌ์ด ์ฒซ ๋์ฌ **ํ ๋ฌธ์ฅ๋ง** ์์ฑํ์ธ์.
- **์ ๋๋ก** ๋ค๋ฅธ ๋ถ๊ฐ ์ค๋ช
, ์ด์ , ์ฃผ์ ๋ฑ์ ํฌํจํ์ง ๋ง์ธ์.
- ๋น์ ์ ์๋ต์ ์ค์ง ์๋๋ฐฉ์๊ฒ ๋งํ ๋์ฌ ๋ด์ฉ ๊ทธ ์์ฒด์ฌ์ผ ํฉ๋๋ค.
{initiator.korean_name}:
"""
else:
# ์ฃผ์ ๊ฐ ์๋ ๊ฒฝ์ฐ (๊ธฐ์กด์ ๊ฐ๋ฒผ์ด ์ธ์ฌ)
prompt = f"""
# Persona
๋น์ ์ "{initiator.korean_name}"์
๋๋ค.
# Context
- ๋น์ ์ ์ง๊ธ "{target.korean_name}"์ ๋ง์ฃผ์ณค์ต๋๋ค.
- ๋น์ ๊ณผ ์๋์ ๊ด๊ณ: {initiator.relationships.get_relationship_summary(target.name)}
# Instruction
- ์ฃผ์ด์ง ์ํฉ์ ๋ง์ถฐ, ์๋๋ฐฉ์๊ฒ ๊ฑด๋ฌ ์์ฐ์ค๋ฝ๊ณ ๊ฐ๋ฒผ์ด ์ฒซ ์ธ์ฌ ๋์ฌ **ํ ๋ฌธ์ฅ๋ง** ์์ฑํ์ธ์.
- **์ ๋๋ก** ๋ค๋ฅธ ๋ถ๊ฐ ์ค๋ช
, ์ด์ , ์ฃผ์ ๋ฑ์ ํฌํจํ์ง ๋ง์ธ์.
- ๋น์ ์ ์๋ต์ ์ค์ง ์๋๋ฐฉ์๊ฒ ๋งํ ๋์ฌ ๋ด์ฉ ๊ทธ ์์ฒด์ฌ์ผ ํฉ๋๋ค.
{initiator.korean_name}:
"""
initial_utterance = query_llm_with_prompt(prompt).strip()
# ๋ฐ์ดํ๋ ์ ๊ฑฐ
clean_utterance = initial_utterance.strip('"')
# ์ด๋ฆ ์ ๋์ฌ๊ฐ ์๋์ง ํ์ธํ๊ณ ์ ๊ฑฐ
name_prefix = f"{initiator.korean_name}:"
if clean_utterance.startswith(name_prefix):
clean_utterance = clean_utterance[len(name_prefix):].strip()
# ๋ฐ์ดํ๋ ์ ๊ฑฐ
final_utterance = clean_utterance.strip().strip('"')
if "[LLM Error]" in final_utterance or not final_utterance:
simulation_core.add_log("[Error: {initiator.korean_name} ๋ํ ์์ ์คํจ]")
print(f"[{initiator.korean_name}] ๋ํ ์์์ ์คํจํ์ต๋๋ค.")
return None, None, None
simulation_core.add_log(f"[{initiator.korean_name}]: {final_utterance}")
# 2. Target์ด Initiator์ ๋ง์ ๋ฃ๊ณ ์๋ต ์์ฑ
# generate_dialogue ํจ์๋ฅผ ์ฌ์ฌ์ฉํ๋, target_npc ์ธ์๋ฅผ ์ ๋ฌ
response_utterance = target.generate_dialogue(
user_input=final_utterance,
time_context = time_context,
target_npc=initiator
)
simulation_core.add_log(f"[{target.korean_name}]: {response_utterance}")
# 3. ๋ํ๊ฐ ๋๋ ํ, ๋ชฉ๊ฒฉ์๋ฅผ ์ ์ ํ์ฌ ์๋ฌธ์ ์์ฑํฉ๋๋ค.
potential_witnesses = [npc for npc in self.npcs if npc not in [initiator, target]]
if potential_witnesses and random.random() < 0.25: # 25% ํ๋ฅ ๋ก ๋ชฉ๊ฒฉ์ ๋ฐ์
witness = random.choice(potential_witnesses)
initiator_postposition = get_korean_postposition(initiator.korean_name, "์ด", "๊ฐ")
target_postposition = get_korean_postposition(target.korean_name, "์๊ฒ", "์๊ฒ")
witness_postposition = get_korean_postposition(witness.korean_name, "์ด", "๊ฐ")
gossip_content = f"'{initiator.korean_name}'{initiator_postposition} '{target.korean_name}'{target_postposition} '{initial_utterance[:100]}...'๋ผ๊ณ ๋งํ๋ ๊ฒ์ ๋ดค๋ค."
# ๋ชฉ๊ฒฉ์๊ฐ '์๋ฌธ'์ ๊ธฐ์ตํ๋๋ก ํจ
witness.remember(
content=gossip_content,
importance=4,
emotion="curiosity",
memory_type="Gossip",
)
# ๋ก๊ทธ๋ simulation_core์ add_log๋ฅผ ์ง์ ํธ์ถํ ์ ์์ผ๋ฏ๋ก print๋ก ๋์ฒด
simulation_core.add_log(f"[๋ชฉ๊ฒฉ] {witness.korean_name}{witness_postposition} {initiator.korean_name}์ {target.korean_name}์ ๋ํ๋ฅผ ๋ชฉ๊ฒฉํจ.")
return initiator, target, final_utterance
|