Spaces:
Sleeping
Sleeping
File size: 8,354 Bytes
0b572d3 19c2d2e c08ff6f 19c2d2e 04f338f 0b572d3 8603187 1a6fb12 0b572d3 8603187 c08ff6f 8603187 04f338f 8603187 04f338f 19c2d2e c08ff6f 04f338f c08ff6f 04f338f c08ff6f 19c2d2e 04f338f 19c2d2e c08ff6f 19c2d2e 04f338f c08ff6f 19c2d2e c08ff6f 19c2d2e c08ff6f b03bfdc 04f338f 0b572d3 8603187 c08ff6f 0b572d3 c08ff6f 0b572d3 8603187 0b572d3 8603187 c08ff6f 04f338f 8603187 04f338f 0b572d3 04f338f c08ff6f 8603187 04f338f 0b572d3 8603187 0b572d3 04f338f 0b572d3 1a6fb12 04f338f 8603187 04f338f 8603187 0b572d3 8603187 04f338f 8603187 0b572d3 04f338f 8603187 0b572d3 |
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 |
# portfolio/npc_social_network/manager/conversation_manager.py
# ๋ํ์ ์์, ์งํ, ์ข
๋ฃ๋ฅผ ์ด๊ดํ๋ ์ญํ
from ..models.llm_helper import (summarize_text, query_llm_for_emotion
, evaluate_goal_achievement)
from ..npc.npc_manager import get_korean_postposition
from ..npc.emotion_config import EMOTION_RELATION_IMPACT, EMOTION_LIST
import threading
from typing import List, Optional, TYPE_CHECKING
if TYPE_CHECKING:
from ..npc.npc_base import NPC
class Conversation:
"""๋จ์ผ ๋ํ์ ์ํ๋ฅผ ์ ์ฅํ๋ ๋ฐ์ดํฐ ํด๋์ค"""
def __init__(self, initiator: "NPC", target: "NPC", topic: str):
self.participants: List["NPC"] = [initiator, target]
self.conversation_history: List[str] = []
self.topic: str = topic
self.turn_index: int = 0 # 0: initiator, 1: target
self.is_ending: bool = False
self.waiting_for_player: bool = False # ํ๋ ์ด์ด์ ์
๋ ฅ ๋๊ธฐ
def get_current_speaker(self) -> "NPC":
"""์ด๋ฒ์ ๋งํ ์ฐจ๋ก์ธ NPC๋ฅผ ๋ฐํ"""
return self.participants[self.turn_index]
def switch_turn(self):
"""๋ํ ํด์ ์๋๋ฐฉ์๊ฒ ๋๊น"""
self.turn_index = 1 - self.turn_index
class ConversationManager:
"""ํ์ฑํ๋ ๋ํ๋ฅผ ๊ด๋ฆฌํ๋ ์ค์ ๊ด๋ฆฌ์"""
def __init__(self):
self.active_conversation: Optional[Conversation] = None
def is_conversation_active(self) -> bool:
"""ํ์ฌ ์งํ ์ค์ธ ๋ํ๊ฐ ์๋์ง ํ์ธ"""
return self.active_conversation is not None
def _add_and_log_utterance(self,speaker: "NPC", utterance: str):
"""๋์ฌ๋ฅผ ๋ํ ๊ธฐ๋ก๊ณผ UI ๋ก๊ทธ์ ๋ชจ๋ ์ถ๊ฐ"""
from .. import simulation_core
if not self.is_conversation_active():
return
log_message = f"[{speaker.korean_name}]: {utterance}"
self.active_conversation.conversation_history.append(log_message)
simulation_core.add_log(log_message)
def _summarize_and_remember_in_background(self, conv: "Conversation"):
"""๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ํ๋ฅผ ์์ฝํ๊ณ ๊ธฐ์ตํ๋ฉฐ, ๊ด๊ณ์ ์ฑ๊ฒฉ์ ๋ฐ์, ๋ชฉํ ๋ฌ์ฑ ํ๊ฐ๋ฅผ ์ํํ๋ ํจ์"""
from .. import simulation_core
try:
if not conv.conversation_history:
print("๊ธฐ์ตํ ๋ํ ๋ด์ฉ์ด ์์ด ์ข
๋ฃ.")
return
initiator, target = conv.participants[0], conv.participants[1]
full_conversation = "\n".join(conv.conversation_history)
# 1. ๋ํ ๋ด์ฉ ์์ฝ
summary = summarize_text(full_conversation)
# 2. ๋ํ์ ์ ๋ฐ์ ์ธ ๊ฐ์ ํค ๋ถ์
overall_emotion = query_llm_for_emotion(summary)
# 3. ๋ชฉํ ๋ฌ์ฑ ์ฌ๋ถ ํ๊ฐ
initiator = conv.participants[0]
evaluation = evaluate_goal_achievement(
initiator_name=initiator.korean_name,
goal=conv.topic,
conversation_transcript=full_conversation
)
with simulation_core.simulation_lock:
# 4. ํ๊ฐ ๊ฒฐ๊ณผ ๋ก๊ทธ ์ถ๊ฐ
simulation_core.add_log(f"[{initiator.korean_name}์ ๋ชฉํ ๋ฌ์ฑ ํ๊ฐ]\n"
f"'{conv.topic}' -> ๋ฌ์ฑ: {evaluation.get('goal_achieved')}.\n"
f"์ด์ : {evaluation.get('reason')}")
target_postposition = get_korean_postposition(target.korean_name, "๊ณผ", "์")
# 5. ํ๊ฐ ๊ฒฐ๊ณผ์ ๋ฐ๋ฅธ ๊ฐ์ ์
๋ฐ์ดํธ
initiator_emotion = evaluation.get('initiator_emotion')
if initiator_emotion and initiator_emotion in EMOTION_LIST:
initiator.update_emotion(initiator_emotion, strength=5.0) # ๋ชฉํ ๋ฌ์ฑ ์ฌ๋ถ๋ ๊ฐํ ๊ฐ์ ์ ๋ฐ
# 6. ์์ฝ๋ ๋ด์ฉ์ ๋ฐํ์ผ๋ก ๊ธฐ์ต ์์ฑ
memory_content = f"'{conv.topic}'์ ๋ํด ๋ํํ๋ฉฐ '{summary}'๋ผ๋ ๊ฒฐ๋ก ์ ๋ด๋ ธ๋ค."
initiator.remember(content=f"{target.korean_name}{target_postposition} {memory_content}", importance=7, memory_type="Conversation")
target.remember(content=f"{initiator.korean_name}{target_postposition} {memory_content}", importance=7, memory_type="Conversation")
# 7. ๋ํ์ ๊ฐ์ ์ ๋ฐํ์ผ๋ก ๊ด๊ณ ์ํ ์
๋ฐ์ดํธ
if overall_emotion and overall_emotion in EMOTION_RELATION_IMPACT:
initiator.relationships.update_relationship(target.name, overall_emotion, strength=3.0)
target.relationships.update_relationship(initiator.name, overall_emotion, strength=3.0)
# 8. ๊ด๊ณ ๋ณํ๋ฅผ ๋ฐํ์ผ๋ก ์์ชฝ ๋ชจ๋์ ์ฑ๊ฒฉ ์
๋ฐ์ดํธ
initiator.update_personality()
target.update_personality()
simulation_core.add_log(f"[{initiator.korean_name}, {target.korean_name}] ๋ํ ๊ฒฝํ์ด ๊ธฐ์ต๊ณผ ๊ด๊ณ, ์ฑ๊ฒฉ์ ๋ฐ์๋์์ต๋๋ค.")
# 9. ๋ชจ๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์
์ข
๋ฃ ํ, ํ์ฌ๊น์ง์ ์๋ฎฌ๋ ์ด์
์ ์ฒด ์ํ๋ฅผ ์ฆ์ ์ ์ฅ.
simulation_core.save_simulation(simulation_core.npc_manager)
except Exception as e:
print(f"[์๋ฌ] ๋ฐฑ๊ทธ๋ผ์ด๋ ๊ธฐ์ต ์ ์ฅ ์ค ๋ฌธ์ ๋ฐ์: {e}")
import traceback
traceback.print_exc()
def start_conversation(self, initiator: "NPC", target: "NPC",
topic: Optional[str] = None):
"""์๋ก์ด ๋ํ๋ฅผ ์์, ๋ฐ๋ก ๋ค์ ํด์ ํธ์ถ"""
from .. import simulation_core
if self.is_conversation_active():
return # ์ด๋ฏธ ๋ค๋ฅธ ๋ํ๊ฐ ์งํ์ค์ด๋ฉด ์์ x
conv_topic = topic or "๊ฐ๋ฒผ์ด ์ธ์ฌ"
self.active_conversation = Conversation(initiator, target, conv_topic)
simulation_core.add_log(f"--[๋ํ ์์]--")
simulation_core.add_log(f"์ฃผ์ : {conv_topic} / ์ฐธ์ฌ์: {initiator.korean_name}, {target.korean_name}")
# 1. ์ฒซ ๋ง๋ ์์ฑ
self.next_turn()
def end_conversation(self, reason: str = "์์ฐ์ค๋ฝ๊ฒ"):
"""ํ์ฌ ๋ํ๋ฅผ ์ข
๋ฃํ๊ณ , ๋ํ ๋ด์ฉ์ ์์ฝํ์ฌ ๊ธฐ์ต์ผ๋ก ์ ์ฅ"""
from .. import simulation_core
if not self.is_conversation_active():
return
# ๋ํ๊ฐ ๋๋๋ฉด, ์ ์ฒด ๋ํ ๋ด์ฉ์ ๋ฐํ์ผ๋ก ๊ธฐ์ต์ ์์ฑํ๊ณ ๊ด๊ณ๋ฅผ ์
๋ฐ์ดํธ
conv_to_process = self.active_conversation
# 1. ๋ํ ์ํ๋ฅผ ์ฆ์ '์ข
๋ฃ'๋ก ๋ณ๊ฒฝํ์ฌ ๋ฉ์ธ ๋ฃจํ๋ฅผ ํด๋ฐฉ
self.active_conversation = None
simulation_core.add_log(f"---[๋ํ ์ข
๋ฃ: {reason}]---\n")
# 2. ์๊ฐ์ด ๊ฑธ๋ฆฌ๋ '๊ธฐ์ต ์ ์ฅ' ์์
์ ๋ณ๋์ ์ค๋ ๋๋ฅผ ์์ฑํ์ฌ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์ฒ๋ฆฌ.
background_thread = threading.Thread(
target=self._summarize_and_remember_in_background,
args=(conv_to_process,)
)
background_thread.start()
def next_turn(self):
"""๋ํ์ ๋ค์ ํด์ ์งํ, ์์ฑ๋ ๋์ฌ ์ฒ๋ฆฌ"""
if not self.is_conversation_active():
return
conv = self.active_conversation
speaker = conv.get_current_speaker()
# ํ๋ ์ด์ด ํด ์ฒ๋ฆฌ ๋ก์ง
if speaker.name == "player":
conv.waiting_for_player = True
return # ํ๋ ์ด์ด์ ์๋ต์ด ์ฌ ๋๊น์ง ๋ํ ํด ์งํ์ ๋ฉ์ถค
# ์ํ 1: ๋ง๋ฌด๋ฆฌ ๋จ๊ณ (์๋ณ ์ธ์ฌ)
if conv.is_ending:
utterance, _ = speaker.generate_dialogue_turn(conv, is_final_turn=True)
self._add_and_log_utterance(speaker, utterance)
self.end_conversation("์๋ณ ์ธ์ฌ ์๋ฃ")
return
# ์ํ 2: ์งํ ๋จ๊ณ (์ผ๋ฐ ๋ํ)
utterance, action = speaker.generate_dialogue_turn(conv)
self._add_and_log_utterance(speaker, utterance)
# ์ํ ์ ํ ๊ฒฐ์
if action != "CONTINUE" or len(conv.conversation_history) >= 10:
conv.is_ending = True
conv.switch_turn()
else:
conv.switch_turn() |