humanda5 commited on
Commit
a88e1d8
·
1 Parent(s): 97627cd

Complete step 20: 모든 에러 수정 완료

Browse files
app.py CHANGED
@@ -5,6 +5,9 @@ from npc_social_network.routes.npc_route import npc_bp
5
  import os
6
  import subprocess
7
 
 
 
 
8
  def create_app():
9
  app = Flask(__name__) # static/template 경로를 기본값
10
 
@@ -18,12 +21,19 @@ def create_app():
18
 
19
  @app.route("/run_npc_simulation")
20
  def run_npc_simulation():
21
- # subprocess로 Pygame 실행
22
- python_exec = "python" # 가상환경 사용 필요시 full path로 변경 가능
 
 
 
 
 
 
 
23
  subprocess.Popen([python_exec, "-m", "npc_social_network.maps.villages.town_hall"]) # 비동기로 실행 (창 띄움)
24
 
25
  # 실행 후 사용자 안내 페이지 표시
26
- return render_template("npc_simulation_started.html")
27
 
28
  return app
29
 
 
5
  import os
6
  import subprocess
7
 
8
+ # 시뮬레이션 프로세스를 관리할 전역 변수
9
+ simulation_process = None
10
+
11
  def create_app():
12
  app = Flask(__name__) # static/template 경로를 기본값
13
 
 
21
 
22
  @app.route("/run_npc_simulation")
23
  def run_npc_simulation():
24
+ global simulation_process
25
+ # 이미 실행 중인 프로세스가 있다면 종료
26
+ if simulation_process and simulation_process.poll() is None:
27
+ simulation_process.terminate()
28
+ simulation_process.wait()
29
+
30
+ # 파이썬 가상환경의 실행 파일 경로를 명시적으로 지정할 수 있음
31
+ python_exec = "python"
32
+ # 비동기로 Pygame 시뮬레이션 실행
33
  subprocess.Popen([python_exec, "-m", "npc_social_network.maps.villages.town_hall"]) # 비동기로 실행 (창 띄움)
34
 
35
  # 실행 후 사용자 안내 페이지 표시
36
+ return redirect(url_for('npc_social.home'))
37
 
38
  return app
39
 
data/saves/simulation_state.pkl ADDED
Binary file (19.7 kB). View file
 
npc_social_network/README.txt CHANGED
@@ -170,7 +170,7 @@ GET /run_npc_simulation
170
  | 17단계 | 상징 기억 / 대표 기억 생성 | ✅ 완료 | 상징 기억 분류/요약 아직 미실행
171
  | 18단계 | 기억 체계 확장: 시간 맥락 부여 | ✅ 완료 | 기억에 시간 맥락/계절/시기 부여 미완료
172
  | 19단계 | 성격 변화 시스템 완성 | ✅ 완료 | 중요한 기억(Memory)과 강렬한 감정(Emotion)이 누적됨에 따라 NPC의 성격(sensitive, stoic 등)이 점진적으로 변화하는 로직을 구현
173
- | 20단계 | 중간 테스트 및 안정화 | 미진행 |
174
 
175
  # 사회적 상호작용 심화 (Social Interaction Deepening)
176
  | 21단계 | 소문 및 평판 시스템 도입 | ⏳ 미진행 | NPC들 사이에 '소문(Gossip)'이 퍼지는 시스템을 구현
 
170
  | 17단계 | 상징 기억 / 대표 기억 생성 | ✅ 완료 | 상징 기억 분류/요약 아직 미실행
171
  | 18단계 | 기억 체계 확장: 시간 맥락 부여 | ✅ 완료 | 기억에 시간 맥락/계절/시기 부여 미완료
172
  | 19단계 | 성격 변화 시스템 완성 | ✅ 완료 | 중요한 기억(Memory)과 강렬한 감정(Emotion)이 누적됨에 따라 NPC의 성격(sensitive, stoic 등)이 점진적으로 변화하는 로직을 구현
173
+ | 20단계 | 중간 테스트 및 안정화 | 완료 |
174
 
175
  # 사회적 상호작용 심화 (Social Interaction Deepening)
176
  | 21단계 | 소문 및 평판 시스템 도입 | ⏳ 미진행 | NPC들 사이에 '소문(Gossip)'이 퍼지는 시스템을 구현
npc_social_network/maps/engine/game_engine.py CHANGED
@@ -22,6 +22,7 @@ class GameEngine:
22
  self.village = village
23
  self.time_states = time_states
24
  self.npc_manager = npc_manager
 
25
 
26
  self.current_time_index = 0
27
  self.frame_count = 0
@@ -45,8 +46,8 @@ class GameEngine:
45
 
46
 
47
  # 실제 시간 흐름 시뮬레이션용
48
- # self.current_time = datetime.now() # 현재 시뮬레이션 시간
49
- # self.time_step = timedelta(minutes=1) # 1틱 = 1분
50
 
51
  def draw(self):
52
  self.village.draw(self.screen) # 마을 전체를 그림
@@ -88,7 +89,7 @@ class GameEngine:
88
  hud_height
89
  )
90
  # 반투명 배경
91
- s = pygame.Surface((hud_width, hud_height), pygame.SRCALRHA)
92
  s.fill((30, 30, 30, 200))
93
  self.screen.blit(s, (hud_rect.x, hud_rect.y))
94
 
@@ -155,7 +156,7 @@ class GameEngine:
155
 
156
  # NPC 기억 승격 판단
157
  if self.frame_count % 60 == 0: # 60 프레임마다 약 3초 기준
158
- for npc in self.npcs:
159
  npc.memory_store.promote_memories(time_threshold_minutes=60)
160
 
161
  # 일정 프레임마다 모든 NPC의 자율 행동 업데이트
 
22
  self.village = village
23
  self.time_states = time_states
24
  self.npc_manager = npc_manager
25
+ self.image_loader = village.image_loader
26
 
27
  self.current_time_index = 0
28
  self.frame_count = 0
 
46
 
47
 
48
  # 실제 시간 흐름 시뮬레이션용
49
+ self.current_time = datetime.now() # 현재 시뮬레이션 시간
50
+ self.time_step = timedelta(minutes=1) # 1틱 = 1분
51
 
52
  def draw(self):
53
  self.village.draw(self.screen) # 마을 전체를 그림
 
89
  hud_height
90
  )
91
  # 반투명 배경
92
+ s = pygame.Surface((hud_width, hud_height), pygame.SRCALPHA)
93
  s.fill((30, 30, 30, 200))
94
  self.screen.blit(s, (hud_rect.x, hud_rect.y))
95
 
 
156
 
157
  # NPC 기억 승격 판단
158
  if self.frame_count % 60 == 0: # 60 프레임마다 약 3초 기준
159
+ for npc in self.npc_manager.all():
160
  npc.memory_store.promote_memories(time_threshold_minutes=60)
161
 
162
  # 일정 프레임마다 모든 NPC의 자율 행동 업데이트
npc_social_network/maps/manager/village_map.py CHANGED
@@ -43,24 +43,12 @@ class VillageMap:
43
  Building(8, 8, "temple", self.image_loader.load("building", "temple", )),
44
  ]
45
 
46
- # NPC 초기 세팅값
47
- elin_path = [[2,3], [3,3], [4,3], [5,3], [5,4], [5,5], [4,5], [3, 5], [2,5], [2,4]]
48
- elin = NPC("Elin", "farmer", elin_path, self.image_loader.load("npc", "default"))
49
- self.npc_manager.add_npc(elin)
50
- # 테스트를 위해 다른 NPC들도 추가
51
- bob = NPC("Bob", "blacksmith", [[1,1], [1,2], [2,2]], self.image_loader.load("npc", "default"))
52
- self.npc_manager.add_npc(bob)
53
-
54
- alice = NPC("Alice", "merchant", [[8,8], [9,8], [9,9]], self.image_loader.load("npc", "default"))
55
- self.npc_manager.add_npc(alice)
56
-
57
-
58
  def draw(self, screen):
59
  for x, y, image in self.tiles:
60
  screen.blit(image, (x * self.tile_size, y * self.tile_size))
61
  for b in self.buildings:
62
  b.draw(screen, self.tile_size)
63
- self.npc_manager.draw_all(screen, self.tile_size)
64
 
65
  def update_npcs(self, time_state):
66
  self.npc_manager.move_all()
 
43
  Building(8, 8, "temple", self.image_loader.load("building", "temple", )),
44
  ]
45
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  def draw(self, screen):
47
  for x, y, image in self.tiles:
48
  screen.blit(image, (x * self.tile_size, y * self.tile_size))
49
  for b in self.buildings:
50
  b.draw(screen, self.tile_size)
51
+ self.npc_manager.draw_all(screen, self.tile_size, self.image_loader)
52
 
53
  def update_npcs(self, time_state):
54
  self.npc_manager.move_all()
npc_social_network/maps/villages/town_hall.py CHANGED
@@ -27,12 +27,13 @@ def run_town_hall_simulation():
27
  # 저장/불러오기
28
  npc_manager = load_simulation() # 저장된 상태를 불러오기 시도
29
 
 
 
30
  if npc_manager is None:
31
  # 저장된 파일이 없으면 새로운 시나리오 시작
32
  npc_manager = setup_initial_scenario(image_loader)
33
 
34
  # 로딩
35
- image_loader = ImageLoader(tile_size)
36
  village = VillageMap(image_loader, tile_size, width, height, npc_manager)
37
  village.generate()
38
 
 
27
  # 저장/불러오기
28
  npc_manager = load_simulation() # 저장된 상태를 불러오기 시도
29
 
30
+ image_loader = ImageLoader(tile_size)
31
+
32
  if npc_manager is None:
33
  # 저장된 파일이 없으면 새로운 시나리오 시작
34
  npc_manager = setup_initial_scenario(image_loader)
35
 
36
  # 로딩
 
37
  village = VillageMap(image_loader, tile_size, width, height, npc_manager)
38
  village.generate()
39
 
npc_social_network/npc/npc_base.py CHANGED
@@ -73,11 +73,11 @@ class NPC:
73
  NPC 클래스
74
  NPC에 대한 기본 정보를 객체화
75
  """
76
- def __init__(self, name, job, path, image, personality=None):
77
  self.name = name
78
  self.job = job
79
  self.path = path
80
- self.image = image
81
  self.current_index = 0
82
 
83
  # npc 기억
@@ -156,12 +156,13 @@ class NPC:
156
  """
157
  return self.path[self.current_index]
158
 
159
- def draw(self, screen, tile_size):
160
  """
161
  NPC 이미지 화면에 렌더링
162
  """
 
163
  x, y = self.get_position()
164
- screen.blit(self.image, (x * tile_size, y * tile_size))
165
 
166
  def generate_dialogue(self, user_input: str, time_context: str, target_npc: Optional["NPC"]=None, use_llm: bool=True) -> str:
167
  """
@@ -257,7 +258,7 @@ class NPC:
257
 
258
  def remember(self, content: str, importance: int = 5, emotion: str = None,
259
  strength: float = 1.0, memory_type:str = "Event",
260
- context_tag: Optional[List[str]]=None) -> Memory:
261
  """
262
  NPC가 새로운 기억을 저장하고 감정 상태에 반영
263
  """
@@ -266,7 +267,7 @@ class NPC:
266
  importance = importance,
267
  emotion=emotion or "neutral",
268
  memory_type=memory_type,
269
- context_tags=context_tag
270
  )
271
  self.memory_store.add_memory(memory)
272
  if emotion and emotion in EMOTION_LIST:
@@ -538,7 +539,7 @@ class NPC:
538
  importance = 6,
539
  emotion="engagement",
540
  memory_type="Behavior",
541
- context_tag=[time_context]
542
  )
543
 
544
  # 2. 계획이 없으면 새로운 목표를 생성하도록 시도
 
73
  NPC 클래스
74
  NPC에 대한 기본 정보를 객체화
75
  """
76
+ def __init__(self, name, job, path, image_identifier, personality=None):
77
  self.name = name
78
  self.job = job
79
  self.path = path
80
+ self.image_identifier = image_identifier
81
  self.current_index = 0
82
 
83
  # npc 기억
 
156
  """
157
  return self.path[self.current_index]
158
 
159
+ def draw(self, screen, tile_size, image_loader):
160
  """
161
  NPC 이미지 화면에 렌더링
162
  """
163
+ image = image_loader.load(*self.image_identifier)
164
  x, y = self.get_position()
165
+ screen.blit(image, (x * tile_size, y * tile_size))
166
 
167
  def generate_dialogue(self, user_input: str, time_context: str, target_npc: Optional["NPC"]=None, use_llm: bool=True) -> str:
168
  """
 
258
 
259
  def remember(self, content: str, importance: int = 5, emotion: str = None,
260
  strength: float = 1.0, memory_type:str = "Event",
261
+ context_tags: Optional[List[str]]=None) -> Memory:
262
  """
263
  NPC가 새로운 기억을 저장하고 감정 상태에 반영
264
  """
 
267
  importance = importance,
268
  emotion=emotion or "neutral",
269
  memory_type=memory_type,
270
+ context_tags=context_tags
271
  )
272
  self.memory_store.add_memory(memory)
273
  if emotion and emotion in EMOTION_LIST:
 
539
  importance = 6,
540
  emotion="engagement",
541
  memory_type="Behavior",
542
+ context_tags=[time_context]
543
  )
544
 
545
  # 2. 계획이 없으면 새로운 목표를 생성하도록 시도
npc_social_network/npc/npc_manager.py CHANGED
@@ -34,7 +34,7 @@ class NPCManager:
34
  return None
35
  return random.choice(possible_targets)
36
 
37
- def initiate_npc_to_npc_interaction(self):
38
  """
39
  NPC 간의 상호작용을 시작시키는 함수
40
  """
@@ -75,7 +75,8 @@ class NPCManager:
75
  # 2. Target이 Initiator의 말을 듣고 응답 생성
76
  # generate_dialogue 함수를 재사용하되, target_npc 인자를 전달
77
  response_utterance = target.generate_dialogue(
78
- user_input=initial_utterance,
 
79
  target_npc=initiator
80
  )
81
 
@@ -87,9 +88,9 @@ class NPCManager:
87
  for npc in self.npcs:
88
  npc.move()
89
 
90
- def draw_all(self, screen, tile_size):
91
  for npc in self.npcs:
92
- npc.draw(screen, tile_size)
93
 
94
  def get_npc_at(self, x, y):
95
  for npc in self.npcs:
 
34
  return None
35
  return random.choice(possible_targets)
36
 
37
+ def initiate_npc_to_npc_interaction(self, time_context: str):
38
  """
39
  NPC 간의 상호작용을 시작시키는 함수
40
  """
 
75
  # 2. Target이 Initiator의 말을 듣고 응답 생성
76
  # generate_dialogue 함수를 재사용하되, target_npc 인자를 전달
77
  response_utterance = target.generate_dialogue(
78
+ user_input=initial_utterance,
79
+ time_context = time_context,
80
  target_npc=initiator
81
  )
82
 
 
88
  for npc in self.npcs:
89
  npc.move()
90
 
91
+ def draw_all(self, screen, tile_size, image_loader):
92
  for npc in self.npcs:
93
+ npc.draw(screen, tile_size, image_loader)
94
 
95
  def get_npc_at(self, x, y):
96
  for npc in self.npcs:
npc_social_network/npc/npc_planner.py CHANGED
@@ -50,7 +50,7 @@ class PlannerManager:
50
  # 당신의 현재 상태 요약
51
  - 주요 감정: {self.npc.summarize_emotional_state()}
52
  - 최근 기억 3개:
53
- {chr(10).join([f' - {mem.content}' for mem in self.npc.memor.get_recent_memories(limit=3)])}
54
  - 플레이어와의 관계: {self.npc.get_relationship_description("플레이어")}
55
  """
56
 
@@ -119,7 +119,7 @@ class PlannerManager:
119
  return f"({plan.goal.description} 목표를 달성하여 만족스럽습니다.)"
120
 
121
  current_step = plan.steps[step_index]
122
- print(f"[{self.npc.name}의 행동 계획 실헹] {step_index + 1}/{len(plan.steps)}: {current_step}")
123
 
124
  # 다음 단계로
125
  plan.current_step_index += 1
 
50
  # 당신의 현재 상태 요약
51
  - 주요 감정: {self.npc.summarize_emotional_state()}
52
  - 최근 기억 3개:
53
+ {chr(10).join([f' - {mem.content}' for mem in self.npc.memory_store.get_recent_memories(limit=3)])}
54
  - 플레이어와의 관계: {self.npc.get_relationship_description("플레이어")}
55
  """
56
 
 
119
  return f"({plan.goal.description} 목표를 달성하여 만족스럽습니다.)"
120
 
121
  current_step = plan.steps[step_index]
122
+ print(f"[{self.npc.name}의 행동 계획 실행] {step_index + 1}/{len(plan.steps)}: {current_step}")
123
 
124
  # 다음 단계로
125
  plan.current_step_index += 1
npc_social_network/routes/npc_route.py CHANGED
@@ -37,20 +37,23 @@ def home():
37
  # 웹 페이지가 처음 로드될 때, 저장된 NPC 목록을 전달
38
  npc_manager = get_npc_manager()
39
  npc_names = list(npc_manager.npc_dict.keys())
40
- return render_template("chat.html", npc_names=npc_names)
 
41
 
42
  # 채팅 처리 API
43
  @npc_bp.route("/chat", methods=['POST'])
44
  def chat():
45
  """웹 채팅 상호작용 후, 변경된 상태 파일에 저장"""
46
  npc_manager = get_npc_manager()
 
 
 
47
  user_input = request.json.get("message")
48
  npc_name = request.json.get("npc")
49
-
50
  npc = npc_manager.get_npc_by_name(npc_name)
51
 
52
  if npc is None:
53
- return jsonify({"error": "NPC not found. Pygame 시뮬레이션을 먼저 실행하여 NPC를 생성해주세요."}), 404
54
 
55
  # generate_dialogue가 time_context를 요구하므로 임시 값을 전달
56
  # generate_dialogue를 통해 응답 생성 및 내부 상태 업데이트
 
37
  # 웹 페이지가 처음 로드될 때, 저장된 NPC 목록을 전달
38
  npc_manager = get_npc_manager()
39
  npc_names = list(npc_manager.npc_dict.keys())
40
+ # chat.html 시뮬레이션 실행 상태와 NPC 목록을 전달
41
+ return render_template("chat.html", npc_names=npc_names or ["(시뮬레이션 미실행)"])
42
 
43
  # 채팅 처리 API
44
  @npc_bp.route("/chat", methods=['POST'])
45
  def chat():
46
  """웹 채팅 상호작용 후, 변경된 상태 파일에 저장"""
47
  npc_manager = get_npc_manager()
48
+ if not npc_manager.all():
49
+ return jsonify({"error": "시뮬레이션이 실행되지 않았습니다. 먼저 시뮬레이션을 시작해주세요."}), 400
50
+
51
  user_input = request.json.get("message")
52
  npc_name = request.json.get("npc")
 
53
  npc = npc_manager.get_npc_by_name(npc_name)
54
 
55
  if npc is None:
56
+ return jsonify({"error": "NPC 찾을 없습니다."}), 404
57
 
58
  # generate_dialogue가 time_context를 요구하므로 임시 값을 전달
59
  # generate_dialogue를 통해 응답 생성 및 내부 상태 업데이트
npc_social_network/scenarios/scenario_setup.py CHANGED
@@ -15,23 +15,23 @@ def setup_initial_scenario(image_loader) -> NPCManager:
15
  # --- 1. NPC 객체 생성 ---
16
  # 엘린: 호기심 많고 감정적인 마법사
17
  personality_elin = {"sensitive": 0.8, "stoic": 0.3, "cognitive_bias": 0.7}
18
- elin = NPC("엘린", "마법사", [[2,3], [3,3], [4,3], [5,3], [5,4], [5,5]], image_loader.load("npc", "default"), personality=personality_elin)
19
 
20
  # 밥: 무뚝뚝하지만 정직한 대장장이
21
  personality_bob = {"sensitive": 0.2, "stoic": 0.8, "cognitive_bias": 0.4}
22
- bob = NPC("밥", "대장장이", [[1,1], [1,2], [2,2], [3,2], [3,1]], image_loader.load("npc", "default"), personality=personality_bob)
23
 
24
  # 앨리스: 사교적이고 계산적인 상인
25
  personality_alice = {"sensitive": 0.5, "stoic": 0.5, "cognitive_bias": 0.8}
26
- alice = NPC("앨리스", "대장장이", [[8,8], [9,8], [9,9], [8,9]], image_loader.load("npc", "default"), personality=personality_alice)
27
 
28
  # 찰리: 성실하고 평화로운 농부
29
  personality_charlie = {"sensitive": 0.6, "stoic": 0.6, "cognitive_bias": 0.3}
30
- charlie = NPC("찰리", "농부", [[10,3], [11,3], [12,3], [12,4]], image_loader.load("npc", "default"), personality=personality_charlie)
31
 
32
  # 다이애나: 조용하고 관찰력 있는 사서
33
  personality_diana = {"sensitive": 0.7, "stoic": 0.7, "cognitive_bias": 0.9}
34
- diana = NPC("다이애나", "사서", [[7,7], [7,8], [8,8]], image_loader.load("npc", "default"), personality=personality_diana)
35
 
36
  # --- 2. 초기 기억 주입 ---
37
  elin.remember(content="어젯밤 앨리스와 시장 가격 때문에 크게 다퉜다.", importance=8, emotion="anger")
 
15
  # --- 1. NPC 객체 생성 ---
16
  # 엘린: 호기심 많고 감정적인 마법사
17
  personality_elin = {"sensitive": 0.8, "stoic": 0.3, "cognitive_bias": 0.7}
18
+ elin = NPC("엘린", "마법사", [[2,3], [3,3], [4,3], [5,3], [5,4], [5,5]], ("npc", "default"), personality=personality_elin)
19
 
20
  # 밥: 무뚝뚝하지만 정직한 대장장이
21
  personality_bob = {"sensitive": 0.2, "stoic": 0.8, "cognitive_bias": 0.4}
22
+ bob = NPC("밥", "대장장이", [[1,1], [1,2], [2,2], [3,2], [3,1]], ("npc", "default"), personality=personality_bob)
23
 
24
  # 앨리스: 사교적이고 계산적인 상인
25
  personality_alice = {"sensitive": 0.5, "stoic": 0.5, "cognitive_bias": 0.8}
26
+ alice = NPC("앨리스", "대장장이", [[8,8], [9,8], [9,9], [8,9]], ("npc", "default"), personality=personality_alice)
27
 
28
  # 찰리: 성실하고 평화로운 농부
29
  personality_charlie = {"sensitive": 0.6, "stoic": 0.6, "cognitive_bias": 0.3}
30
+ charlie = NPC("찰리", "농부", [[10,3], [11,3], [12,3], [12,4]], ("npc", "default"), personality=personality_charlie)
31
 
32
  # 다이애나: 조용하고 관찰력 있는 사서
33
  personality_diana = {"sensitive": 0.7, "stoic": 0.7, "cognitive_bias": 0.9}
34
+ diana = NPC("다이애나", "사서", [[7,7], [7,8], [8,8]], ("npc", "default"), personality=personality_diana)
35
 
36
  # --- 2. 초기 기억 주입 ---
37
  elin.remember(content="어젯밤 앨리스와 시장 가격 때문에 크게 다퉜다.", importance=8, emotion="anger")
npc_social_network/templates/chat.html CHANGED
@@ -9,15 +9,22 @@
9
  <link rel="stylesheet" herf="{{ url_for('npc_social.static', filename='css/style.css') }}">
10
  </head>
11
  <body>
12
- <h2>NPC 소셜 네트워크</h2>
13
 
 
 
 
 
 
 
 
14
  <div class="meta-info">
15
  <select id="npc" onchange="loadNPCInfo()">
16
  <!-- [MOD] 서버에서 전달받은 NPC 이름으로 동적 생성 -->
17
  {% for name in npc_names %}
18
  <option value="{{ name }}">{{ name }}</option>
19
  {% else %}
20
- <option>NPC 없음</option>
21
  {% endfor %}
22
  </select>
23
  <span id="relationStatus" style="margin-left:20px";>관계 점수: 로딩 중...</span>
@@ -26,7 +33,6 @@
26
  <div id="chatBox"></div>
27
  <input type="text" id="message" placeholder="메세지를 입력하세요" style="width:80%">
28
  <button onclick="sendMessage()">보내기</button>
29
- <button onclick="triggerNPCInteractions()">NPC 상호작용 실행</button>
30
 
31
  <!-- Memory 영역 추가 -->
32
  <div class="meta-info">
@@ -44,6 +50,8 @@
44
  </ul>
45
  </div>
46
 
 
 
47
  <script src="{{ url_for('npc_social.static', filename='js/npc_chat.js') }}"></script>
48
  </body>
49
  </html>
 
9
  <link rel="stylesheet" herf="{{ url_for('npc_social.static', filename='css/style.css') }}">
10
  </head>
11
  <body>
12
+ <h1>NPC 소셜 네트워크 - 통합 대시보드</h1>
13
 
14
+ <!-- 시뮬레이션 제어 버튼 -->
15
+ <div class="controls">
16
+ <a href="{{ url_for('run_npc_simulation') }}"><button>시뮬레이션 시작 / 재시작</button></a>
17
+ <p>시뮬레이션을 시작하면 별도의 Pygame 창이 열립니다.</p>
18
+ </div>
19
+
20
+ <h2>NPC와 대화하기</h2>
21
  <div class="meta-info">
22
  <select id="npc" onchange="loadNPCInfo()">
23
  <!-- [MOD] 서버에서 전달받은 NPC 이름으로 동적 생성 -->
24
  {% for name in npc_names %}
25
  <option value="{{ name }}">{{ name }}</option>
26
  {% else %}
27
+ <option disabled>NPC 없음</option>
28
  {% endfor %}
29
  </select>
30
  <span id="relationStatus" style="margin-left:20px";>관계 점수: 로딩 중...</span>
 
33
  <div id="chatBox"></div>
34
  <input type="text" id="message" placeholder="메세지를 입력하세요" style="width:80%">
35
  <button onclick="sendMessage()">보내기</button>
 
36
 
37
  <!-- Memory 영역 추가 -->
38
  <div class="meta-info">
 
50
  </ul>
51
  </div>
52
 
53
+ <a href="{{ url_for('index') }}">Back to Main Page</a>
54
+
55
  <script src="{{ url_for('npc_social.static', filename='js/npc_chat.js') }}"></script>
56
  </body>
57
  </html>
npc_social_network/templates/test_memory_tools.html DELETED
@@ -1,55 +0,0 @@
1
- <!-- portfolio/npc_social_network/templates/test_memory_tools.html -->
2
- <!DOCTYPE html>
3
- <html lang="ko">
4
- <head>
5
- <meta charset="UTF-8">
6
- <title>NPC Memory Test Tools</title>
7
- </head>
8
- <body>
9
- <h2>🧠 NPC 기억 임베딩 요청</h2>
10
- <form id="embedForm">
11
- NPC 이름: <input type="text" id="embedNpcName" value="엘라">
12
- <button type="submit">임베딩 요청</button>
13
- </form>
14
- <pre id="embedResult"></pre>
15
-
16
- <hr>
17
-
18
- <h2>🔍 NPC 기억 검색 요청</h2>
19
- <form id="searchForm">
20
- NPC 이름: <input type="text" id="searchNpcName" value="엘라"><br>
21
- 질의 내용: <input type="text" id="searchQuery" value="누군가와 다퉜던 기억이 있어?">
22
- <button type="submit">검색 요청</button>
23
- </form>
24
- <pre id="searchResult"></pre>
25
-
26
- <script>
27
- // 임베딩 요청
28
- document.getElementById('embedForm').addEventListener('submit', async (e) => {
29
- e.preventDefault();
30
- const npc = document.getElementById('embedNpcName').value;
31
- const res = await fetch("/npc_social_network/test_embed_memory", {
32
- method: "POST",
33
- headers: { "Content-Type": "application/json" },
34
- body: JSON.stringify({ npc })
35
- });
36
- const json = await res.json();
37
- document.getElementById('embedResult').innerText = JSON.stringify(json, null, 2);
38
- });
39
-
40
- // 검색 요청
41
- document.getElementById('searchForm').addEventListener('submit', async (e) => {
42
- e.preventDefault();
43
- const npc = document.getElementById('searchNpcName').value;
44
- const query = document.getElementById('searchQuery').value;
45
- const res = await fetch("/npc_social_network/test_search_memory", {
46
- method: "POST",
47
- headers: { "Content-Type": "application/json" },
48
- body: JSON.stringify({ npc, query })
49
- });
50
- const json = await res.json();
51
- document.getElementById('searchResult').innerText = JSON.stringify(json, null, 2);
52
- });
53
- </script>
54
- </body>
55
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
run_npc_interactions.py DELETED
@@ -1,39 +0,0 @@
1
- # portfolio/run_npc_interactions.py
2
-
3
- import time
4
- from npc_social_network.npc.npc_manager import npc_manager
5
- from npc_social_network.npc.npc_base import NPC
6
-
7
- def run_npc_test_scenario(npc_name="엘라"):
8
- npc = npc_manager.get_npc_by_name[npc_name]
9
-
10
- test_inputs = [
11
- "오늘 하루는 최악이었어. 왜 다들 날 무시하는 거지?",
12
- "고마워. 나 도와줘서 정말 감사했어.",
13
- "그때 화낸 건 미안해. 내 잘못이었어.",
14
- "내가 선물한 책 어땠어?",
15
- "우리 예전에 함께 일했던 거 기억나?",
16
- ]
17
-
18
- for input_text in test_inputs:
19
- print(f"\n[플레이어 입력] {input_text}")
20
- response = npc.interact_with_player(input_text)
21
- print(f"[NPC 응답] {response}")
22
-
23
- # 기억 기반 관계 반영까지 테스트
24
- npc.reflect_memory_emotions_on_relationship("플레이어")
25
-
26
- # 상태 요약 출력
27
- print("\n🧠 현재 감정 상태 요약:")
28
- print(npc.summarize_emotional_state())
29
-
30
- print("\n📚 최근 기억:")
31
- for m in npc.memory_store.get_recent_memories(limit=5):
32
- print(f"- {m.content} ({m.emotion})")
33
-
34
- print("\n🔗 플레이어와의 관계:")
35
- print(npc.get_relationship_description("플레이어"))
36
-
37
-
38
- if __name__ == "__main__":
39
- run_npc_test_scenario()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/main.html CHANGED
@@ -8,8 +8,6 @@
8
  </head>
9
  <body>
10
  <h1>Welcome to the Portfolio</h1>
11
- <a href="{{ url_for('npc_social.home') }}">Go to Project 1</a>
12
- <br><br>
13
  <form action="{{ url_for('run_npc_simulation') }}" method="get">
14
  <button type = "submit"> Run NPC Simulation (pygame) </button>
15
  </form>
 
8
  </head>
9
  <body>
10
  <h1>Welcome to the Portfolio</h1>
 
 
11
  <form action="{{ url_for('run_npc_simulation') }}" method="get">
12
  <button type = "submit"> Run NPC Simulation (pygame) </button>
13
  </form>
templates/npc_simulation_started.html DELETED
@@ -1,14 +0,0 @@
1
- <!--portfolio/templates/npc_simulation_started.html-->
2
- <!DOCTYPE html>
3
- <html lang="en">
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>NPC Simulation Running</title>
8
- </head>
9
- <body>
10
- <h1>NPC Simulation is now running!</h1>
11
- <p>You can interact with the Pygame window that has opened.</p>
12
- <a href="{{ url_for('index') }}">Back to Main Page</a>
13
- </body>
14
- </html>