Spaces:
Sleeping
Sleeping
File size: 6,451 Bytes
7d6d833 |
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 178 179 180 181 182 |
import json
import re
import time
from typing import List
from mistralai import Mistral
import hackathon.agent.character as ch
import hackathon.game_mechanics.entities as entities
class Agent:
def __init__(self, client: Mistral, model: str):
self.client = client
self.model = model
class CardAgent(Agent):
def add_cards_to_personal_context(
self, character: ch.AIAgent, cards: List[entities.Card]
):
system_prompt = (
"You are a conversationnal game update engine "
"Given the two AI characters traits, and his current personnal context, "
"you will propose a new personnal personal context"
)
user_prompt = ""
for card in cards:
if card.change_personal_context:
user_prompt += f"""
Character: {character}
Current personal context: {character.personal_context}
The context to be added to the personnal context :
Fact description : {card.description}
Description of the effect on the player : {card.game_context}
"""
user_prompt += """
Instructions:
Gives a new synthetic personal context to take into account this new description in less then 150 words, should return only the text format as string variable.
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
]
# print(f"{messages=}")
response = self.client.chat.complete(model=self.model, messages=messages)
time.sleep(1)
raw_text = response.choices[0].message.content.strip()
character.personal_context = raw_text
def add_card_to_personal_context(self, character: ch.AIAgent, card: entities.Card):
if card.change_personal_context:
system_prompt = (
"You are a conversationnal game update engine "
"Given the two AI characters traits, and his current personnal context, "
"you will propose a new personnal personal context"
)
user_prompt = f"""
Character: {character}
Current personal context: {character.personal_context}
The context to be added to the personnal context :
Fact description : {card.description}
Description of the effect on the player : {card.game_context}
"""
user_prompt += """
Instructions:
Gives a new synthetic personal context to take into account this new description in less then 150 words, should return only the text format as string variable.
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
]
# print(f"{messages=}")
response = self.client.chat.complete(model=self.model, messages=messages)
time.sleep(1)
raw_text = response.choices[0].message.content.strip()
character.personal_context = raw_text
class EmotionAgent:
"""
Uses a LLM (Mistral) to handle:
- update_emotions
- update_attitude
- create_memory_context
Each method returns strictly valid JSON, parsed into Python dicts.
"""
def __init__(self, client: Mistral, model: str):
self.client = client
self.model = model
def update_emotions(self, character):
"""
Calls the LLM to produce new emotion values in valid JSON.
Each emotion in [0.0, 1.0].
"""
system_prompt = (
"You are an emotion update engine. "
"Given the AI's character traits, current emotions, general context, and context memory, "
"you will propose updated emotion and attitudes values. The output must be strictly valid JSON, "
"Give a particular attention to anger value."
)
user_prompt = f"""
Character: {character}
Personal context: {character.personal_context}
Current Emotions: {character.emotions}
Current Attitudes: {character.attitudes}
Conversation History: {character.context_memory}
Instructions:
1. Analyze the information provided above.
2. Propose new values for emotions and attitudes in valid JSON format.
JSON structure attributes must be respected:
{{
"emotions": {character.emotions},
"attitudes": {character.attitudes}
}}
Requirements:
- All numeric values must be floats in the range [0.0, 1.0].
- Text values should be descriptive and context-appropriate.
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
]
# print(f"{messages=}")
time.sleep(1)
response = self.client.chat.complete(
model=self.model,
messages=messages,
response_format={"type": "json_object"},
max_tokens=200,
)
raw_text = response.choices[0].message.content.strip()
# print(f'{raw_text=}')
cleaned_response = re.sub(r"```(json)?", "", raw_text).strip()
try:
updated_emotions = json.loads(cleaned_response)
except json.JSONDecodeError:
print(
f"Error: Could not parse JSON for emotions. Using old emotions.\nResponse: {cleaned_response}"
)
return character.emotions, character.attitudes
# Clamp to [0.0, 1.0]
final_emotions = {}
final_attitudes = {}
for emotion, val in updated_emotions["emotions"].items():
if isinstance(val, (int, float)):
final_emotions[emotion] = max(0.0, min(1.0, float(val)))
else:
# Fallback if invalid
final_attitudes[emotion] = updated_emotions.get(emotion, 0.5)
for attitude, val in updated_emotions["attitudes"].items():
if attitude == "patience":
final_attitudes["patience"] = 0
else:
final_attitudes[attitude] = val
return final_emotions, final_attitudes
return final_emotions, final_attitudes
|