100 lines
3.7 KiB
Python
100 lines
3.7 KiB
Python
import json
|
|
import random
|
|
import requests
|
|
from .npc_data import NPC_DATABASE # <-- Add this import
|
|
|
|
def query_llm(prompt, model="neural-chat", url="http://100.103.117.14:11434/api/generate"):
|
|
# Add instruction for short answers
|
|
short_prompt = prompt + "\n\nKeep your answer short and concise (1-2 sentences)."
|
|
payload = {
|
|
"model": model,
|
|
"prompt": short_prompt,
|
|
"stream": False
|
|
}
|
|
try:
|
|
response = requests.post(url, json=payload, timeout=120)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
return data.get("response", "").strip()
|
|
except Exception as e:
|
|
print(f"LLM error: {e}")
|
|
return None
|
|
|
|
class DynamicNPC:
|
|
def __init__(self, name, data):
|
|
self.name = name
|
|
self.personality = data["personality"]
|
|
self.backstory = data["backstory"]
|
|
self.quirks = data["quirks"]
|
|
|
|
class NPCHandler:
|
|
def __init__(self, memory):
|
|
self.memory = memory
|
|
self.npcs = {name: DynamicNPC(name, data) for name, data in NPC_DATABASE.items()}
|
|
|
|
def chat_with_npc(self, npc_name, message, player_context):
|
|
npc = self.npcs.get(npc_name)
|
|
if not npc:
|
|
return "That NPC doesn't exist."
|
|
|
|
player_id = player_context['id']
|
|
|
|
# Fetch recent conversation history (last 3 exchanges)
|
|
history = self.memory.get_conversation(npc_name, player_id)
|
|
history_str = ""
|
|
if history:
|
|
history_str = "\nRecent conversation:\n"
|
|
for player_msg, npc_reply in history[-3:]:
|
|
history_str += f"Player: {player_msg}\n{npc.name}: {npc_reply}\n"
|
|
|
|
# Fetch affinity
|
|
affinity = self.memory.get_affinity(npc_name, player_id)
|
|
affinity_str = f"Affinity with player: {affinity}\n"
|
|
|
|
prompt = (
|
|
f"You are {npc.name}, an NPC in a fantasy world.\n"
|
|
f"Personality: {npc.personality}\n"
|
|
f"Backstory: {npc.backstory}\n"
|
|
f"Quirks: {', '.join(npc.quirks)}\n"
|
|
f"{history_str}"
|
|
f"{affinity_str}"
|
|
f"Player (level {player_context.get('level', 1)}): {message}\n"
|
|
f"Respond in character as {npc.name}."
|
|
)
|
|
llm_response = query_llm(prompt)
|
|
if not llm_response:
|
|
llm_response = f"{npc.name} seems lost in thought and doesn't reply."
|
|
self.memory.log_conversation(npc_name, player_id, message, llm_response)
|
|
self.memory.update_affinity(npc_name, player_id, 1)
|
|
return llm_response
|
|
|
|
def generate_quest(self, npc_name, player_level):
|
|
npc = self.npcs.get(npc_name)
|
|
if not npc:
|
|
return None
|
|
prompt = (
|
|
f"As {npc.name}, create a short quest for a level {player_level} adventurer.\n"
|
|
f"Personality: {npc.personality}\n"
|
|
f"Backstory: {npc.backstory}\n"
|
|
f"Format as JSON:\n"
|
|
"{{\n"
|
|
' "title": "Quest name",\n'
|
|
' "description": "What the player must do",\n'
|
|
' "reward": "coins/items/reputation",\n'
|
|
' "difficulty": "easy/medium/hard"\n'
|
|
"}}"
|
|
)
|
|
llm_response = query_llm(prompt)
|
|
try:
|
|
if not llm_response:
|
|
raise ValueError("No response from LLM")
|
|
quest = json.loads(llm_response)
|
|
return quest
|
|
except Exception:
|
|
quest = {
|
|
"title": f"{npc.name}'s Request",
|
|
"description": f"Help {npc.name} with a task suitable for level {player_level}.",
|
|
"reward": f"{random.randint(10, 100)} coins",
|
|
"difficulty": random.choice(["easy", "medium", "hard"])
|
|
}
|
|
return quest |