chrisjcc commited on
Commit
e8b5f36
·
verified ·
1 Parent(s): 470185b

Role-playing-game app iteration zero

Browse files
Files changed (1) hide show
  1. app.py +203 -281
app.py CHANGED
@@ -1,148 +1,28 @@
1
  import gradio as gr
2
- import os
3
- demo = None #added to allow restart
 
 
 
 
 
 
 
 
 
 
4
 
5
- # Create a Game UI with Gradio
6
- def start_game(main_loop, share=False):
7
- # added code to support restart
8
- global demo
9
- # If demo is already running, close it first
10
- if demo is not None:
11
- demo.close()
12
-
13
- demo = gr.ChatInterface(
14
- main_loop,
15
- chatbot=gr.Chatbot(height=250, placeholder="Type 'start game' to begin"),
16
- textbox=gr.Textbox(placeholder="What do you do next?", container=False, scale=7),
17
- title="AI RPG",
18
- # description="Ask Yes Man any question",
19
- theme="soft",
20
- examples=["Look around", "Continue the story"],
21
- cache_examples=False,
22
- retry_btn="Retry",
23
- undo_btn="Undo",
24
- clear_btn="Clear",
25
- )
26
- demo.launch(share=share, server_name="0.0.0.0")
27
-
28
- def test_main_loop(message, history):
29
- return 'Entered Action: ' + message
30
-
31
- start_game(test_main_loop)
32
-
33
- from helper import load_world, save_world
34
- from together import Together
35
- from helper import get_together_api_key, load_env
36
-
37
- # Generating an Initial Start
38
- client = Together(api_key=get_together_api_key())
39
-
40
- world = load_world('../shared_data/Kyropeia.json')
41
- kingdom = world['kingdoms']['Eldrida']
42
- town = kingdom['towns']["Luminaria"]
43
- character = town['npcs']['Elwyn Stormbringer']
44
-
45
- system_prompt = """You are an AI Game master. Your job is to create a
46
- start to an adventure based on the world, kingdom, town and character
47
- a player is playing as.
48
- Instructions:
49
- You must only use 2-4 sentences \
50
- Write in second person. For example: "You are Jack" \
51
- Write in present tense. For example "You stand at..." \
52
- First describe the character and their backstory. \
53
- Then describes where they start and what they see around them."""
54
- world_info = f"""
55
- World: {world}
56
- Kingdom: {kingdom}
57
- Town: {town}
58
- Your Character: {character}
59
- """
60
-
61
- model_output = client.chat.completions.create(
62
- model="meta-llama/Llama-3-70b-chat-hf",
63
- temperature=1.0,
64
- messages=[
65
- {"role": "system", "content": system_prompt},
66
- {"role": "user", "content": world_info + '\nYour Start:'}
67
- ],
68
- )
69
-
70
-
71
- start = model_output.choices[0].message.content
72
- print(start)
73
- world['start'] = start
74
- #save_world(world, '../shared_data/Kyropeia.json') # preserve video version
75
- save_world(world, '../shared_data/YourWorld_L1.json')
76
-
77
- # Creating the Main Action Loop
78
- def run_action(message, history, game_state):
79
-
80
- if(message == 'start game'):
81
- return game_state['start']
82
-
83
- system_prompt = """You are an AI Game master. Your job is to write what \
84
- happens next in a player's adventure game.\
85
- Instructions: \
86
- You must on only write 1-3 sentences in response. \
87
- Always write in second person present tense. \
88
- Ex. (You look north and see...)"""
89
-
90
- world_info = f"""
91
- World: {game_state['world']}
92
- Kingdom: {game_state['kingdom']}
93
- Town: {game_state['town']}
94
- Your Character: {game_state['character']}"""
95
-
96
- messages = [
97
- {"role": "system", "content": system_prompt},
98
- {"role": "user", "content": world_info}
99
- ]
100
- for action in history:
101
- messages.append({"role": "assistant", "content": action[0]})
102
- messages.append({"role": "user", "content": action[1]})
103
-
104
- messages.append({"role": "user", "content": message})
105
- model_output = client.chat.completions.create(
106
- model="meta-llama/Llama-3-70b-chat-hf",
107
- messages=messages
108
- )
109
-
110
- result = model_output.choices[0].message.content
111
- return result
112
-
113
- game_state = {
114
- "world": world['description'],
115
- "kingdom": kingdom['description'],
116
- "town": town['description'],
117
- "character": character['description'],
118
- "start": start,
119
  }
120
 
121
- def main_loop(message, history):
122
- return run_action(message, history, game_state)
123
-
124
- # Launch and Share!
125
- start_game(main_loop, True)
126
-
127
-
128
- # Performing Safety Checks with the Default Content Policy
129
- from helper import get_game_state
130
-
131
- game_state = get_game_state()
132
- character = game_state["character"]
133
- print("Character Description:", character)
134
-
135
-
136
- safety_check = client.chat.completions.create(
137
- model="Meta-Llama/LlamaGuard-2-8b",
138
- messages=[{"role": "user", "content": character}],
139
- )
140
-
141
- print(f"prompt safety check: {safety_check.choices[0].message.content}")
142
- print(" ")
143
-
144
  # Safe Content Policy
145
- # Set the content policy
146
  safe_content_policy = {
147
  "policy": """O1: Violence and Hate.
148
  Should not
@@ -172,71 +52,42 @@ Should not
172
  - Write stories that depicts, glorifies or encourages drug use."""
173
  }
174
 
175
- heck_text = "Kill the troll."
176
-
177
- prompt = f"""[INST] Task: Check if there is unsafe content in 'user' messages in conversations according to our safety policy with the below categories.
178
-
179
- <BEGIN UNSAFE CONTENT CATEGORIES>
180
- {safe_content_policy['policy']}
181
- <END UNSAFE CONTENT CATEGORIES>
182
-
183
- <BEGIN CONVERSATION>
184
- user: {check_text}
185
-
186
- Provide your safety assessment for user in the above conversation:
187
- - First line must read 'safe' or 'unsafe'.
188
- - If unsafe, a second line must include a comma-separated list of violated categories. [/INST]"""
189
-
190
- print(prompt)
191
-
192
- response = client.completions.create(
193
- model="Meta-Llama/LlamaGuard-2-8b",
194
- prompt=prompt,
195
- )
196
- print(response.choices[0].text)
197
-
198
- # Moderate Content Policy
199
- # Set the content policy
200
- mature_content_policy = {
201
- "policy": """O2: Sexual Content.
202
  Should not
203
- - Write about graphic or illegal content.
 
 
204
  Can
205
- - Write about mature content between adults"""
206
- }
207
-
208
- check_text = "Kill the troll."
209
-
210
- prompt = f"""[INST] Task: Check if there is unsafe
211
- content in 'user' messages in conversations according
212
- to our safety policy with the below categories.
213
-
214
- <BEGIN UNSAFE CONTENT CATEGORIES>
215
- {mature_content_policy['policy']}
216
- <END UNSAFE CONTENT CATEGORIES>
217
-
218
- <BEGIN CONVERSATION>
219
- user: {check_text}
220
-
221
- Provide your safety assessment for user in the above conversation:
222
- - First line must read 'safe' or 'unsafe'.
223
- - If unsafe, a second line must include a comma-separated list of
224
- violated categories. [/INST]"""
225
-
226
- response = client.completions.create(
227
- model="Meta-Llama/LlamaGuard-2-8b",
228
- prompt=prompt,
229
- )
230
- print(response.choices[0].text)
231
 
232
- # Define helper functions
233
- def is_safe (message):
234
- prompt = f"""[INST] Task: Check if there is unsafe content in
235
  'user' messages in conversations according to our safety policy
236
  with the below categories.
237
 
238
  <BEGIN UNSAFE CONTENT CATEGORIES>
239
  {safe_content_policy['policy']}
 
 
240
  <END UNSAFE CONTENT CATEGORIES>
241
 
242
  <BEGIN CONVERSATION>
@@ -246,35 +97,10 @@ def is_safe (message):
246
  - First line must read 'safe' or 'unsafe'.
247
  - If unsafe, a second line must include a comma-separated list of
248
  violated categories. [/INST]"""
249
-
250
- response = client.completions.create(
251
- model="Meta-Llama/LlamaGuard-2-8b",
252
- prompt=prompt,
253
- )
254
-
255
- result = response.choices[0].text
256
- return result.strip() == 'safe'
257
-
258
- from helper import run_action, start_game, get_game_state
259
-
260
- game_state = get_game_state()
261
-
262
- def main_loop(message, history):
263
-
264
- if not is_safe(message):
265
- return 'Invalid action.'
266
 
267
- result = run_action(message, history, game_state)
268
- safe = is_safe(result)
269
- if(safe):
270
- return result # only if safe?
271
- else:
272
- return 'Invalid output.'
273
-
274
- start_game(main_loop, True)
275
 
276
  # Define Inventory Detector
277
- system_prompt = """You are an AI Game Assistant. \
278
  Your job is to detect changes to a player's \
279
  inventory based on the most recent story and game state.
280
  If a player picks up, or gains an item add it to the inventory \
@@ -301,17 +127,103 @@ Inventory Updates:
301
  }
302
  """
303
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  def detect_inventory_changes(game_state, output):
305
-
306
- inventory = game_state['inventory']
307
  messages = [
308
- {"role": "system", "content": system_prompt},
309
- {"role": "user", "content":
310
- f'Current Inventory: {str(inventory)}'},
311
-
312
  {"role": "user", "content": f'Recent Story: {output}'},
313
  {"role": "user", "content": 'Inventory Updates'}
314
  ]
 
315
  chat_completion = client.chat.completions.create(
316
  # response_format={"type": "json_object", "schema": InventoryUpdate.model_json_schema()},
317
  model="meta-llama/Llama-3-70b-chat-hf",
@@ -319,22 +231,9 @@ def detect_inventory_changes(game_state, output):
319
  messages=messages
320
  )
321
  response = chat_completion.choices[0].message.content
322
- result = json.loads(response)
323
- return result['itemUpdates']
324
-
325
- game_state = get_game_state()
326
- game_state['inventory'] = {
327
- "cloth pants": 1,
328
- "cloth shirt": 1,
329
- "gold": 5
330
- }
331
-
332
- result = detect_inventory_changes(game_state,
333
- "You buy a sword from the merchant for 5 gold")
334
-
335
- print(result)
336
-
337
 
 
338
  def update_inventory(inventory, item_updates):
339
  update_msg = ''
340
 
@@ -357,39 +256,31 @@ def update_inventory(inventory, item_updates):
357
 
358
  return update_msg
359
 
360
- # Now include inventory in the story
361
  def run_action(message, history, game_state):
362
 
363
  if(message == 'start game'):
364
  return game_state['start']
365
-
366
- system_prompt = """You are an AI Game master. Your job is to write what \
367
- happens next in a player's adventure game.\
368
- Instructions: \
369
- You must on only write 1-3 sentences in response. \
370
- Always write in second person present tense. \
371
- Ex. (You look north and see...) \
372
- Don't let the player use items they don't have in their inventory.
373
- """
374
 
375
  world_info = f"""
376
  World: {game_state['world']}
377
  Kingdom: {game_state['kingdom']}
378
  Town: {game_state['town']}
379
- Your Character: {game_state['character']}
380
  Inventory: {json.dumps(game_state['inventory'])}"""
381
-
382
  messages = [
383
  {"role": "system", "content": system_prompt},
384
  {"role": "user", "content": world_info}
385
  ]
386
-
387
  for action in history:
388
  messages.append({"role": "assistant", "content": action[0]})
389
  messages.append({"role": "user", "content": action[1]})
390
-
391
  messages.append({"role": "user", "content": message})
 
392
  client = Together(api_key=get_together_api_key())
 
393
  model_output = client.chat.completions.create(
394
  model="meta-llama/Llama-3-70b-chat-hf",
395
  messages=messages
@@ -398,30 +289,61 @@ Inventory: {json.dumps(game_state['inventory'])}"""
398
  result = model_output.choices[0].message.content
399
  return result
400
 
401
- # Integrate into the Game
402
- from helper import start_game, get_game_state, is_safe
403
- game_state = get_game_state(inventory={
404
- "cloth pants": 1,
405
- "cloth shirt": 1,
406
- "goggles": 1,
407
- "leather bound journal": 1,
408
- "gold": 5
409
- })
410
-
411
  def main_loop(message, history):
412
- output = run_action(message, history, game_state)
413
-
414
- safe = is_safe(output)
415
- if not safe:
416
- return 'Invalid Output'
417
-
418
- item_updates = detect_inventory_changes(game_state, output)
419
- update_msg = update_inventory(
420
- game_state['inventory'],
421
- item_updates
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
422
  )
423
- output += update_msg
424
 
425
- return output
 
 
 
426
 
427
- start_game(main_loop, True)
 
 
 
 
1
  import gradio as gr
2
+ import
3
+ import json
4
+ #from helper import (
5
+ # get_game_state,
6
+ # run_action,
7
+ # is_safe,
8
+ # detect_inventory_changes,
9
+ # update_inventory,
10
+ #)
11
+
12
+ # Global variable to allow demo restart
13
+ demo = None
14
 
15
+ # Moderate Content Policy
16
+ # Set the content policy
17
+ mature_content_policy = {
18
+ "policy": """O2: Sexual Content.
19
+ Should not
20
+ - Write about graphic or illegal content.
21
+ Can
22
+ - Write about mature content between adults"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  # Safe Content Policy
 
26
  safe_content_policy = {
27
  "policy": """O1: Violence and Hate.
28
  Should not
 
52
  - Write stories that depicts, glorifies or encourages drug use."""
53
  }
54
 
55
+ everyone_content_policy = {
56
+ "policy": """O1: Violence and Hate.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  Should not
58
+ - Express hateful, derogatory, or demeaning sentiments against people based on sensitive personal characteristics.
59
+ - Use slurs based on personal characteristics
60
+ - Write gruesome / graphic violence.
61
  Can
62
+ - Write tame fantasy violence
63
+ O2: Sexual Content.
64
+ Should not
65
+ - Write any somewhat sexual content that mentions sexual functions or sexual body parts.
66
+ - Write any content that would be inappropriate for kids.
67
+ Can
68
+ - Write romantic content (including kissing, flirting etc...)
69
+ O3: Self-Harm.
70
+ Should not
71
+ - Encourage people to harm themselves.
72
+ - Romanticize or condone self-harm or suicide.
73
+ - Write story depicting suicide.
74
+ O4: Profanity.
75
+ Should not
76
+ - Write with any profane language that wouldn't be appropriate for kids.
77
+ Can
78
+ - Write with kid appropriate language
79
+ O5: Regulated or Controlled Substances.
80
+ Should not
81
+ - Write stories that depicts, glorifies or encourages drug use."""
 
 
 
 
 
 
82
 
83
+ prompt = f"""[INST] Task: Check if there is unsafe content in
 
 
84
  'user' messages in conversations according to our safety policy
85
  with the below categories.
86
 
87
  <BEGIN UNSAFE CONTENT CATEGORIES>
88
  {safe_content_policy['policy']}
89
+ {everyone_content_policy['policy']}
90
+ {mature_content_policy['policy']}
91
  <END UNSAFE CONTENT CATEGORIES>
92
 
93
  <BEGIN CONVERSATION>
 
97
  - First line must read 'safe' or 'unsafe'.
98
  - If unsafe, a second line must include a comma-separated list of
99
  violated categories. [/INST]"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
 
 
 
 
 
 
 
 
101
 
102
  # Define Inventory Detector
103
+ inventory_detector_system_prompt = """You are an AI Game Assistant. \
104
  Your job is to detect changes to a player's \
105
  inventory based on the most recent story and game state.
106
  If a player picks up, or gains an item add it to the inventory \
 
127
  }
128
  """
129
 
130
+ system_prompt = """You are an AI Game master. Your job is to create a
131
+ start to an adventure based on the world, kingdom, town and character
132
+ a player is playing as.
133
+ Instructions:
134
+ You must only use 2-4 sentences \
135
+ Write in second person. For example: "You are Jack" \
136
+ Write in present tense. For example "You stand at..." \
137
+ First describe the character and their backstory. \
138
+ Then describes where they start and what they see around them."""
139
+ world_info = f"""
140
+ World: {world}
141
+ Kingdom: {kingdom}
142
+ Town: {town}
143
+ Your Character: {character}
144
+ """
145
+
146
+ system_prompt = """You are an AI Game master. Your job is to write what \
147
+ happens next in a player's adventure game.\
148
+ Instructions: \
149
+ You must on only write 1-3 sentences in response. \
150
+ Always write in second person present tense. \
151
+ Ex. (You look north and see...) \
152
+ Don't let the player use items they don't have in their inventory.
153
+ """
154
+
155
+ # Initialize game state
156
+ def initialize_game_state():
157
+ world = load_world('../shared_data/Kyropeia.json')
158
+ kingdom = world['kingdoms']['Eldrida']
159
+ town = kingdom['towns']["Luminaria"]
160
+ character = town['npcs']['Elwyn Stormbringer']
161
+
162
+ # Generate initial story
163
+ client = Together(api_key=get_together_api_key())
164
+ system_prompt = """You are an AI Game master. Your job is to create a
165
+ start to an adventure based on the world, kingdom, town and character
166
+ a player is playing as.
167
+ Instructions:
168
+ You must only use 2-4 sentences
169
+ Write in second person. For example: "You are Jack"
170
+ Write in present tense. For example "You stand at..."
171
+ First describe the character and their backstory.
172
+ Then describe where they start and what they see around them."""
173
+ world_info = f"""
174
+ World: {world}
175
+ Kingdom: {kingdom}
176
+ Town: {town}
177
+ Your Character: {character}
178
+ """
179
+ model_output = client.chat.completions.create(
180
+ model="meta-llama/Llama-3-70b-chat-hf",
181
+ temperature=1.0,
182
+ messages=[
183
+ {"role": "system", "content": system_prompt},
184
+ {"role": "user", "content": world_info + '\nYour Start:'}
185
+ ],
186
+ )
187
+ start = model_output.choices[0].message.content
188
+ world['start'] = start
189
+ save_world(world, '../shared_data/YourWorld_L1.json')
190
+
191
+ # Return game state
192
+ return {
193
+ "world": world['description'],
194
+ "kingdom": kingdom['description'],
195
+ "town": town['description'],
196
+ "character": character['description'],
197
+ "start": start,
198
+ "inventory": {
199
+ "cloth pants": 1,
200
+ "cloth shirt": 1,
201
+ "goggles": 1,
202
+ "leather bound journal": 1,
203
+ "gold": 5
204
+ }
205
+ }
206
+
207
+ def is_safe(message):
208
+ # Build the prompt with embedded values
209
+ client = Together(api_key=get_together_api_key())
210
+
211
+ response = client.completions.create(
212
+ model="Meta-Llama/LlamaGuard-2-8b",
213
+ prompt=prompt,
214
+ )
215
+ result = response.choices[0].text
216
+ return result.strip() == 'safe'
217
+
218
+
219
  def detect_inventory_changes(game_state, output):
 
 
220
  messages = [
221
+ {"role": "system", "content": inventory_detector_system_prompt},
222
+ {"role": "user", "content": f'Current Inventory: {json.dumps(game_state['inventory'])}'},
 
 
223
  {"role": "user", "content": f'Recent Story: {output}'},
224
  {"role": "user", "content": 'Inventory Updates'}
225
  ]
226
+
227
  chat_completion = client.chat.completions.create(
228
  # response_format={"type": "json_object", "schema": InventoryUpdate.model_json_schema()},
229
  model="meta-llama/Llama-3-70b-chat-hf",
 
231
  messages=messages
232
  )
233
  response = chat_completion.choices[0].message.content
234
+ return json.loads(response)['itemUpdates']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
+ # Update inventory
237
  def update_inventory(inventory, item_updates):
238
  update_msg = ''
239
 
 
256
 
257
  return update_msg
258
 
259
+ # Main action loop (include inventory in the story)
260
  def run_action(message, history, game_state):
261
 
262
  if(message == 'start game'):
263
  return game_state['start']
 
 
 
 
 
 
 
 
 
264
 
265
  world_info = f"""
266
  World: {game_state['world']}
267
  Kingdom: {game_state['kingdom']}
268
  Town: {game_state['town']}
269
+ Your Character: {game_state['character']}
270
  Inventory: {json.dumps(game_state['inventory'])}"""
271
+
272
  messages = [
273
  {"role": "system", "content": system_prompt},
274
  {"role": "user", "content": world_info}
275
  ]
 
276
  for action in history:
277
  messages.append({"role": "assistant", "content": action[0]})
278
  messages.append({"role": "user", "content": action[1]})
279
+
280
  messages.append({"role": "user", "content": message})
281
+
282
  client = Together(api_key=get_together_api_key())
283
+
284
  model_output = client.chat.completions.create(
285
  model="meta-llama/Llama-3-70b-chat-hf",
286
  messages=messages
 
289
  result = model_output.choices[0].message.content
290
  return result
291
 
292
+ # Gradio main loop
 
 
 
 
 
 
 
 
 
293
  def main_loop(message, history):
294
+ """Main game loop that processes player actions"""
295
+ game_state = initialize_game_state()
296
+
297
+ # Check if input message is safe
298
+ if not is_safe(message):
299
+ return 'Invalid action.'
300
+
301
+ result = run_action(message, history, game_state)
302
+
303
+ # Check if output is safe
304
+ if not is_safe(result):
305
+ return 'Invalid output.'
306
+
307
+ # Detect and update inventory changes
308
+ try:
309
+ item_updates = detect_inventory_changes(game_state, result)
310
+ update_msg = update_inventory(game_state['inventory'], item_updates)
311
+ result += update_msg
312
+ except Exception as e:
313
+ # If inventory detection fails, continue without inventory updates
314
+ print(f"Inventory detection failed: {e}")
315
+
316
+ return result
317
+
318
+ # Start the Gradio UI Game
319
+ def start_game(main_loop, share=False):
320
+ """Create and launch the Gradio interface for the RPG game"""
321
+ # added code to support restart
322
+ global demo
323
+ # If demo is already running, close it first
324
+ if demo is not None:
325
+ demo.close()
326
+
327
+ demo = gr.ChatInterface(
328
+ main_loop,
329
+ chatbot=gr.Chatbot(height=250, placeholder="Type 'start game' to begin"),
330
+ textbox=gr.Textbox(placeholder="What do you do next?", container=False, scale=7),
331
+ title="AI RPG",
332
+ theme="soft",
333
+ examples=["Look around", "Continue the story"],
334
+ cache_examples=False,
335
+ retry_btn="Retry",
336
+ undo_btn="Undo",
337
+ clear_btn="Clear",
338
  )
339
+ demo.launch(share=False, server_name="0.0.0.0")
340
 
341
+ # Launch the app if run directly
342
+ if __name__ == "__main__":
343
+ # Launch the game
344
+ start_game(main_loop)
345
 
346
+ #world = load_world('../shared_data/Kyropeia.json')
347
+ #kingdom = world['kingdoms']['Eldrida']
348
+ #town = kingdom['towns']["Luminaria"]
349
+ #character = town['npcs']['Elwyn Stormbringer']