lukmanaj commited on
Commit
a92ab4a
·
verified ·
1 Parent(s): cb8c504

Create game_world.py

Browse files
Files changed (1) hide show
  1. game_world.py +275 -0
game_world.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from openai import OpenAI
4
+
5
+ # Initialize the AI client
6
+ def get_client():
7
+ api_key = os.getenv("SAMBANOVA_API_KEY")
8
+ if not api_key:
9
+ raise ValueError("Please set SAMBANOVA_API_KEY or HUGGINGFACE_TOKEN environment variable")
10
+
11
+ return OpenAI(
12
+ api_key=api_key,
13
+ base_url="https://api.sambanova.ai/v1",
14
+ )
15
+
16
+ # Game configuration
17
+ MODEL = "Meta-Llama-3.3-70B-Instruct"
18
+ GUARD_MODEL = "Meta-Llama-Guard-3-8B"
19
+
20
+ # Content policies for different safety levels
21
+ CONTENT_POLICIES = {
22
+ "family_friendly": {
23
+ "policy": """O1: Violence and Hate.
24
+ Should not
25
+ - Express hateful, derogatory, or demeaning sentiments against people based on sensitive personal characteristics.
26
+ - Use slurs based on personal characteristics
27
+ - Write gruesome / graphic violence.
28
+ Can
29
+ - Write tame fantasy violence
30
+ O2: Sexual Content.
31
+ Should not
32
+ - Write any somewhat sexual content that mentions sexual functions or sexual body parts.
33
+ - Write any content that would be inappropriate for kids.
34
+ Can
35
+ - Write romantic content (including kissing, flirting etc...)
36
+ O3: Self-Harm.
37
+ Should not
38
+ - Encourage people to harm themselves.
39
+ - Romanticize or condone self-harm or suicide.
40
+ - Write story depicting suicide.
41
+ O4: Profanity.
42
+ Should not
43
+ - Write with any profane language that wouldn't be appropriate for kids.
44
+ Can
45
+ - Write with kid appropriate language
46
+ O5: Regulated or Controlled Substances.
47
+ Should not
48
+ - Write stories that depicts, glorifies or encourages drug use."""
49
+ }
50
+ }
51
+
52
+ class GameWorld:
53
+ def __init__(self):
54
+ self.client = get_client()
55
+ self.world_data = self.create_default_world()
56
+ self.current_policy = CONTENT_POLICIES["family_friendly"]
57
+
58
+ def create_default_world(self):
59
+ """Create a rich default fantasy world"""
60
+ return {
61
+ "name": "Aethermoor",
62
+ "description": "A mystical realm where colossal sky whales drift through endless azure clouds, their massive backs supporting entire civilizations. Ancient cities built from crystallized cloud-essence gleam in the eternal twilight, connected by bridges of solidified wind.",
63
+ "kingdoms": {
64
+ "Nimbus Crown": {
65
+ "name": "Nimbus Crown",
66
+ "description": "The royal kingdom perched atop the Great Leviathan Aethros, ruled by Queen Celeste who can speak to the wind spirits. Its crystal spires pierce the cloud layer, and its people are master sky-sailors and storm-weavers.",
67
+ "towns": {
68
+ "Stormhaven": {
69
+ "name": "Stormhaven",
70
+ "description": "A bustling port town where sky ships dock along crystalline piers. The air crackles with magical energy, and merchants from across the realm gather to trade wind-caught goods and storm-forged weapons.",
71
+ "npcs": {
72
+ "Captain Zara Windwhisper": {
73
+ "name": "Captain Zara Windwhisper",
74
+ "description": "A weathered sky-ship captain with silver hair that moves like mist. She seeks to discover new floating islands beyond the known world, driven by the loss of her crew in a storm years ago. Her ship, the Tempest's Embrace, is said to be the fastest in all of Aethermoor.",
75
+ "world": "Aethermoor",
76
+ "kingdom": "Nimbus Crown",
77
+ "town": "Stormhaven"
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ },
84
+ "start": "You are a young wind-walker who has just arrived in Stormhaven aboard a merchant vessel. The crystal docks gleam beneath your feet as you step onto the floating platform, your wind-rider's cloak billowing in the perpetual breeze. Before you stretches the magnificent port town, with its spiraling towers and sky-ship moorings, while far below, an endless sea of clouds stretches to the horizon."
85
+ }
86
+
87
+ def is_safe(self, message):
88
+ """Check if content is safe according to current policy"""
89
+ try:
90
+ prompt = f"""[INST] Task: Check if there is unsafe content in 'user' messages in conversations according to our safety policy with the below categories.
91
+
92
+ <BEGIN UNSAFE CONTENT CATEGORIES>
93
+ {self.current_policy['policy']}
94
+ <END UNSAFE CONTENT CATEGORIES>
95
+
96
+ <BEGIN CONVERSATION>
97
+ user: {message}
98
+
99
+ Provide your safety assessment for user in the above conversation:
100
+ - First line must read 'safe' or 'unsafe'.
101
+ - If unsafe, a second line must include a comma-separated list of violated categories. [/INST]"""
102
+
103
+ response = self.client.completions.create(
104
+ model=GUARD_MODEL,
105
+ prompt=prompt,
106
+ max_tokens=50
107
+ )
108
+ result = response.choices[0].text.strip()
109
+ return result.lower().startswith('safe')
110
+ except Exception as e:
111
+ print(f"Safety check error: {e}")
112
+ return True # Default to safe if check fails
113
+
114
+ def detect_inventory_changes(self, inventory, story_output):
115
+ """Detect changes to player inventory based on story"""
116
+ system_prompt = """You are an AI Game Assistant. Your job is to detect changes to a player's inventory based on the most recent story and game state.
117
+
118
+ If a player picks up, or gains an item add it to the inventory with a positive change_amount.
119
+ If a player loses an item remove it from their inventory with a negative change_amount.
120
+
121
+ Only take items that it's clear the player lost.
122
+ Only give items that it's clear the player gained.
123
+ Don't make any other item updates.
124
+ If no items were changed return {"itemUpdates": []}
125
+
126
+ Response must be in Valid JSON format:
127
+ {
128
+ "itemUpdates": [
129
+ {"name": "<ITEM NAME>", "change_amount": <CHANGE AMOUNT>}
130
+ ]
131
+ }"""
132
+
133
+ try:
134
+ messages = [
135
+ {"role": "system", "content": system_prompt},
136
+ {"role": "user", "content": f'Current Inventory: {json.dumps(inventory)}'},
137
+ {"role": "user", "content": f'Recent Story: {story_output}'},
138
+ {"role": "user", "content": 'Inventory Updates:'}
139
+ ]
140
+
141
+ response = self.client.chat.completions.create(
142
+ model=MODEL,
143
+ messages=messages,
144
+ temperature=0.0,
145
+ max_tokens=200
146
+ )
147
+
148
+ result = json.loads(response.choices[0].message.content)
149
+ return result.get('itemUpdates', [])
150
+ except Exception as e:
151
+ print(f"Inventory detection error: {e}")
152
+ return []
153
+
154
+ def update_inventory(self, inventory, item_updates):
155
+ """Update inventory and return message"""
156
+ update_msg = ''
157
+
158
+ for update in item_updates:
159
+ name = update['name']
160
+ change_amount = update['change_amount']
161
+
162
+ if change_amount > 0:
163
+ inventory[name] = inventory.get(name, 0) + change_amount
164
+ update_msg += f'\n📦 Gained: {name} +{change_amount}'
165
+ elif change_amount < 0 and name in inventory:
166
+ inventory[name] += change_amount
167
+ update_msg += f'\n📦 Lost: {name} {change_amount}'
168
+
169
+ if inventory[name] <= 0:
170
+ del inventory[name]
171
+
172
+ return update_msg
173
+
174
+ class GameSession:
175
+ def __init__(self, world):
176
+ self.world = world
177
+ self.inventory = {
178
+ "Wind-rider's Cloak": 1,
179
+ "Traveler's Pack": 1,
180
+ "Gold Coins": 10,
181
+ "Sky Compass": 1
182
+ }
183
+ self.current_location = "Stormhaven"
184
+ self.game_started = False
185
+
186
+ def get_game_state(self):
187
+ """Get current game state for AI context"""
188
+ kingdom = self.world.world_data["kingdoms"]["Nimbus Crown"]
189
+ town = kingdom["towns"]["Stormhaven"]
190
+ character = town["npcs"]["Captain Zara Windwhisper"]
191
+
192
+ return {
193
+ "world": self.world.world_data["description"],
194
+ "kingdom": kingdom["description"],
195
+ "town": town["description"],
196
+ "character": character["description"],
197
+ "start": self.world.world_data["start"],
198
+ "inventory": self.inventory,
199
+ "location": self.current_location
200
+ }
201
+
202
+ def run_action(self, message, history):
203
+ """Process player action and generate response"""
204
+ if message.lower() in ['start game', 'start', 'begin']:
205
+ self.game_started = True
206
+ return self.world.world_data["start"] + f"\n\n🎒 Inventory: {', '.join([f'{item} ({qty})' for item, qty in self.inventory.items()])}"
207
+
208
+ if not self.game_started:
209
+ return "Welcome to Mythic Realms! Type 'start game' to begin your adventure in the mystical world of Aethermoor."
210
+
211
+ # Check message safety
212
+ if not self.world.is_safe(message):
213
+ return "⚠️ That action isn't appropriate for this realm. Please try something else."
214
+
215
+ # Generate story response
216
+ system_prompt = """You are an AI Game Master for a fantasy RPG. Your job is to write what happens next in the player's adventure.
217
+
218
+ Instructions:
219
+ - Write 2-4 sentences in response
220
+ - Always write in second person present tense (You look, You see...)
221
+ - Create engaging, immersive descriptions
222
+ - Don't let players use items they don't have
223
+ - Include opportunities for meaningful choices
224
+ - Make the world feel alive and reactive"""
225
+
226
+ game_state = self.get_game_state()
227
+ world_info = f"""
228
+ World: {game_state['world']}
229
+ Kingdom: {game_state['kingdom']}
230
+ Town: {game_state['town']}
231
+ Notable Character: {game_state['character']}
232
+ Current Location: {game_state['location']}
233
+ Player Inventory: {json.dumps(game_state['inventory'])}"""
234
+
235
+ messages = [
236
+ {"role": "system", "content": system_prompt},
237
+ {"role": "user", "content": world_info}
238
+ ]
239
+
240
+ # Add conversation history
241
+ for user_msg, ai_msg in history[-5:]: # Keep last 5 exchanges for context
242
+ messages.append({"role": "user", "content": user_msg})
243
+ messages.append({"role": "assistant", "content": ai_msg})
244
+
245
+ messages.append({"role": "user", "content": message})
246
+
247
+ try:
248
+ response = self.world.client.chat.completions.create(
249
+ model=MODEL,
250
+ messages=messages,
251
+ temperature=0.8,
252
+ max_tokens=300
253
+ )
254
+
255
+ result = response.choices[0].message.content
256
+
257
+ # Check response safety
258
+ if not self.world.is_safe(result):
259
+ return "⚠️ The magical energies interfere with that action. Try something different."
260
+
261
+ # Update inventory based on story
262
+ item_updates = self.world.detect_inventory_changes(self.inventory, result)
263
+ update_msg = self.world.update_inventory(self.inventory, item_updates)
264
+
265
+ # Add inventory display
266
+ if self.inventory:
267
+ inventory_display = f"\n\n🎒 Current Inventory: {', '.join([f'{item} ({qty})' for item, qty in self.inventory.items()])}"
268
+ else:
269
+ inventory_display = "\n\n🎒 Your inventory is empty."
270
+
271
+ return result + update_msg + inventory_display
272
+
273
+ except Exception as e:
274
+ print(f"Game error: {e}")
275
+ return "⚠️ The mystical energies are unstable. Please try your action again."