Spaces:
Sleeping
Sleeping
| 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 | |