from typing import Dict, Any
def build_main_prompt(pre: Dict[str, Any], session_id: str, npc_id: str) -> str:
tags = pre.get("tags", {})
ps = pre.get("player_state", {})
rag_docs = pre.get("rag_main_docs", [])
# RAG 문서 분리
lore_text = ""
desc_text = ""
for doc in rag_docs:
if "LORE:" in doc:
lore_text += doc + "\n"
elif "DESCRIPTION:" in doc:
desc_text += doc + "\n"
else:
# fallback: type 기반 분리 가능
if "lore" in doc.lower():
lore_text += doc + "\n"
elif "description" in doc.lower():
desc_text += doc + "\n"
prompt = [
"",
f"NPC_ID={tags.get('npc_id','')}",
f"NPC_LOCATION={tags.get('location','')}",
"TAGS:",
f" quest_stage={tags.get('quest_stage','')}",
f" relationship={tags.get('relationship','')}",
f" trust={tags.get('trust','')}",
f" npc_mood={tags.get('npc_mood','')}",
f" player_reputation={tags.get('player_reputation','')}",
f" style={tags.get('style','')}",
"",
"",
f"LORE: {lore_text.strip() or '(없음)'}",
f"DESCRIPTION: {desc_text.strip() or '(없음)'}",
"",
""
]
if ps.get("items"):
prompt.append(f"items={','.join(ps['items'])}")
if ps.get("actions"):
prompt.append(f"actions={','.join(ps['actions'])}")
if ps.get("position"):
prompt.append(f"position={ps['position']}")
prompt.append("")
prompt.append("")
for h in pre.get("context", []):
prompt.append(f"{h['role']}: {h['text']}")
prompt.append("")
prompt.append(f"{pre.get('player_utterance','').rstrip()}")
prompt.append("")
prompt.append("")
return "\n".join(prompt)
def build_fallback_prompt(pre: Dict[str, Any], session_id: str, npc_id: str) -> str:
"""
additional_trigger 값에 따라 일반 fallback / 특수 fallback 프롬프트를 한 함수에서 처리
"""
tags = pre.get("tags", {})
ps = pre.get("player_state", {})
gs = pre.get("game_state", {})
rag_text = "\n".join(f"- {doc}" for doc in pre.get("rag_fallback_docs", []))
fb_style = pre.get("fallback_style") or {}
trigger_meta = pre.get("trigger_meta", {}) or {}
items = ",".join(ps.get("items", []))
actions = ",".join(ps.get("actions", []))
location = gs.get("location") or ps.get("location", "unknown")
quest_stage = gs.get("quest_stage", "unknown")
# 기본 안내문
instr = (
"당신은 NPC persona를 가진 캐릭터입니다. "
"플레이어 발화에 자연스럽고 맥락에 맞는 대사를 생성하세요. "
"스토리 진행 조건은 충족되지 않았습니다."
)
# additional_trigger=True → 특수 fallback
if pre.get("additional_trigger"):
# trigger_meta 기반 구체화
s = fb_style.get("style") or trigger_meta.get("npc_style")
a = fb_style.get("npc_action") or trigger_meta.get("npc_action")
e = fb_style.get("npc_emotion") or trigger_meta.get("npc_emotion")
more = []
if s: more.append(f"대화 스타일={s}")
if a: more.append(f"NPC 행동={a}")
if e: more.append(f"NPC 감정={e}")
if more:
instr += " " + "; ".join(more) + "."
# 특수 fallback임을 명시
instr += " 이 반응은 플레이어의 특정 발화(금지 트리거)에 의해 유발된 것입니다."
return f"""
NPC_ID={npc_id}
SESSION_ID={session_id}
LOCATION={location}
QUEST_STAGE={quest_stage}
MOOD={tags.get("npc_mood","neutral")}
STYLE={tags.get("style","neutral")}
ITEMS={items}
ACTIONS={actions}
EMOTION_SUMMARY={', '.join([f"{k}:{round(v,2)}" for k,v in pre.get('emotion',{}).items()])}
INPUT="{pre['player_utterance']}"
RAG_CONTEXT:
{rag_text or "(none)"}
INSTRUCTION:
{instr}
""".strip()
'''
def build_fallback_prompt(pre: dict, session_id: str, npc_id: str) -> str:
tags = pre.get("tags", {})
ps = pre.get("player_state", {})
gs = pre.get("game_state", {})
rag_text = "\n".join(f"- {doc}" for doc in pre.get("rag_fallback_docs", []))
fb = pre.get("fallback_style") or {}
items = ",".join(ps.get("items", []))
actions = ",".join(ps.get("actions", []))
location = gs.get("location") or ps.get("location", "unknown")
quest_stage = gs.get("quest_stage", "unknown")
instr = "조건 불충족. 스토리 진행은 하지 않고, 캐릭터 일관성을 유지하며 자연스럽게 응답하라."
if fb:
# 선택적 구체화
s = fb.get("style"); a = fb.get("npc_action"); e = fb.get("npc_emotion")
more = []
if s: more.append(f"대화 스타일={s}")
if a: more.append(f"NPC 행동={a}")
if e: more.append(f"NPC 감정={e}")
if more:
instr += " " + "; ".join(more) + "."
return f"""
NPC_ID={npc_id}
SESSION_ID={session_id}
LOCATION={location}
QUEST_STAGE={quest_stage}
MOOD={tags.get("npc_mood","neutral")}
STYLE={tags.get("style","neutral")}
ITEMS={items}
ACTIONS={actions}
EMOTION_SUMMARY={', '.join([f"{k}:{round(v,2)}" for k,v in pre.get('emotion',{}).items()])}
INPUT="{pre['player_utterance']}"
RAG:
{rag_text or "(none)"}
INSTRUCTION:
{instr}
""".strip()
'''