llm_game_hackathon/L4.ipynb
2024-11-22 16:55:08 +01:00

336 lines
10 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"id": "d0a04e3c-be0b-4551-bcd5-7265b5beeddd",
"metadata": {
"id": "173e06c5-4b07-4e3b-a67a-5c3e141beb2c"
},
"source": [
"# L4: JSON Game Mechanics"
]
},
{
"cell_type": "markdown",
"id": "fe186abb-1eb8-4f4b-972b-c0f4f5f555f2",
"metadata": {},
"source": [
"<p style=\"background-color:#f7fff8; padding:15px; border-width:3px; border-color:#e0f0e0; border-style:solid; border-radius:6px\"> 🚨\n",
"&nbsp; <b>Different Run Results:</b> The output generated by AI models can vary with each execution due to their dynamic, probabilistic nature. Don't be surprised if your results differ from those shown in the video.<br>\n",
"<span style=\"font-size: larger;\">To maintain consistency, the notebooks are run with a 'world state' consistent with the video at the start of each notebook.</span></p>"
]
},
{
"cell_type": "markdown",
"id": "f5a2bd48-5101-47d4-b359-b0a135968b62",
"metadata": {},
"source": [
"<div style=\"background-color:#fff6ff; padding:13px; border-width:3px; border-color:#efe6ef; border-style:solid; border-radius:6px\">\n",
"<p> 💻 &nbsp; <b>Access <code>requirements.txt</code> and <code>helper.py</code> files:</b> 1) click on the <em>\"File\"</em> option on the top menu of the notebook and then 2) click on <em>\"Open\"</em>.\n",
"\n",
"<p> ⬇ &nbsp; <b>Download Notebooks:</b> 1) click on the <em>\"File\"</em> option on the top menu of the notebook and then 2) click on <em>\"Download as\"</em> and select <em>\"Notebook (.ipynb)\"</em>.</p>\n",
"\n",
"<p> 📒 &nbsp; For more help, please see the <em>\"Appendix Tips, Help, and Download\"</em> Lesson.</p>\n",
"\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "668c3aa7-5594-4267-99f3-1d755477573d",
"metadata": {
"id": "173e06c5-4b07-4e3b-a67a-5c3e141beb2c"
},
"source": [
"## Define Inventory Detector"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bdddb477-7489-496c-ad99-e3def6691a63",
"metadata": {
"height": 489
},
"outputs": [],
"source": [
"system_prompt = \"\"\"You are an AI Game Assistant. \\\n",
"Your job is to detect changes to a player's \\\n",
"inventory based on the most recent story and game state.\n",
"If a player picks up, or gains an item add it to the inventory \\\n",
"with a positive change_amount.\n",
"If a player loses an item remove it from their inventory \\\n",
"with a negative change_amount.\n",
"Given a player name, inventory and story, return a list of json update\n",
"of the player's inventory in the following form.\n",
"Only take items that it's clear the player (you) lost.\n",
"Only give items that it's clear the player gained. \n",
"Don't make any other item updates.\n",
"If no items were changed return {\"itemUpdates\": []}\n",
"and nothing else.\n",
"\n",
"Response must be in Valid JSON\n",
"Don't add items that were already added in the inventory\n",
"\n",
"Inventory Updates:\n",
"{\n",
" \"itemUpdates\": [\n",
" {\"name\": <ITEM NAME>, \n",
" \"change_amount\": <CHANGE AMOUNT>}...\n",
" ]\n",
"}\n",
"\"\"\"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "88fbfee9-f217-459f-ae28-52e6155ddcca",
"metadata": {
"height": 115
},
"outputs": [],
"source": [
"import json\n",
"from helper import get_together_api_key, load_env\n",
"from together import Together\n",
"\n",
"client = Together(api_key=get_together_api_key())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2b040f28-d9dc-43ca-a7bb-f7a40447c235",
"metadata": {
"height": 387
},
"outputs": [],
"source": [
"\n",
"def detect_inventory_changes(game_state, output):\n",
" \n",
" inventory = game_state['inventory']\n",
" messages = [\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": \n",
" f'Current Inventory: {str(inventory)}'},\n",
" \n",
" {\"role\": \"user\", \"content\": f'Recent Story: {output}'},\n",
" {\"role\": \"user\", \"content\": 'Inventory Updates'}\n",
" ]\n",
" chat_completion = client.chat.completions.create(\n",
" # response_format={\"type\": \"json_object\", \"schema\": InventoryUpdate.model_json_schema()},\n",
" model=\"meta-llama/Llama-3-70b-chat-hf\",\n",
" temperature=0.0,\n",
" messages=messages\n",
" )\n",
" response = chat_completion.choices[0].message.content\n",
" result = json.loads(response)\n",
" return result['itemUpdates']"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "31558768-5d7a-4e7a-8c65-0e48ccdfe05e",
"metadata": {
"height": 251
},
"outputs": [],
"source": [
"from helper import get_game_state\n",
"\n",
"game_state = get_game_state()\n",
"game_state['inventory'] = {\n",
" \"cloth pants\": 1,\n",
" \"cloth shirt\": 1,\n",
" \"gold\": 5\n",
"}\n",
"\n",
"result = detect_inventory_changes(game_state, \n",
"\"You buy a sword from the merchant for 5 gold\")\n",
"\n",
"print(result)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e97e780f-2065-48a2-9a12-ee6ec8b12d91",
"metadata": {
"height": 404
},
"outputs": [],
"source": [
"def update_inventory(inventory, item_updates):\n",
" update_msg = ''\n",
" \n",
" for update in item_updates:\n",
" name = update['name']\n",
" change_amount = update['change_amount']\n",
" \n",
" if change_amount > 0:\n",
" if name not in inventory:\n",
" inventory[name] = change_amount\n",
" else:\n",
" inventory[name] += change_amount\n",
" update_msg += f'\\nInventory: {name} +{change_amount}'\n",
" elif name in inventory and change_amount < 0:\n",
" inventory[name] += change_amount\n",
" update_msg += f'\\nInventory: {name} {change_amount}'\n",
" \n",
" if name in inventory and inventory[name] < 0:\n",
" del inventory[name]\n",
" \n",
" return update_msg\n"
]
},
{
"cell_type": "markdown",
"id": "0d7ff980-3975-4672-bc39-d173105bd2a7",
"metadata": {},
"source": [
"#### Now include inventory in the story"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a4b1a67a-174b-467e-bc77-6b0e99e227b7",
"metadata": {
"height": 693
},
"outputs": [],
"source": [
"def run_action(message, history, game_state):\n",
" \n",
" if(message == 'start game'):\n",
" return game_state['start']\n",
" \n",
" system_prompt = \"\"\"You are an AI Game master. Your job is to write what \\\n",
"happens next in a player's adventure game.\\\n",
"Instructions: \\\n",
"You must on only write 1-3 sentences in response. \\\n",
"Always write in second person present tense. \\\n",
"Ex. (You look north and see...) \\\n",
"Don't let the player use items they don't have in their inventory.\n",
"\"\"\"\n",
"\n",
" world_info = f\"\"\"\n",
"World: {game_state['world']}\n",
"Kingdom: {game_state['kingdom']}\n",
"Town: {game_state['town']}\n",
"Your Character: {game_state['character']}\n",
"Inventory: {json.dumps(game_state['inventory'])}\"\"\"\n",
"\n",
" messages = [\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": world_info}\n",
" ]\n",
"\n",
" for action in history:\n",
" messages.append({\"role\": \"assistant\", \"content\": action[0]})\n",
" messages.append({\"role\": \"user\", \"content\": action[1]})\n",
" \n",
" messages.append({\"role\": \"user\", \"content\": message})\n",
" client = Together(api_key=get_together_api_key())\n",
" model_output = client.chat.completions.create(\n",
" model=\"meta-llama/Llama-3-70b-chat-hf\",\n",
" messages=messages\n",
" )\n",
" \n",
" result = model_output.choices[0].message.content\n",
" return result"
]
},
{
"cell_type": "markdown",
"id": "fadd8eb3-ac15-4cc4-8fc2-3591201241af",
"metadata": {},
"source": [
"## Integrate into the Game"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e8e66b52-8ca6-42aa-850c-3a6d3e5e2885",
"metadata": {
"height": 166
},
"outputs": [],
"source": [
"from helper import start_game, get_game_state, is_safe\n",
"game_state = get_game_state(inventory={\n",
" \"cloth pants\": 1,\n",
" \"cloth shirt\": 1,\n",
" \"goggles\": 1,\n",
" \"leather bound journal\": 1,\n",
" \"gold\": 5\n",
"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "47fb0923-6de9-49fa-b823-6ba03cb90ce4",
"metadata": {
"height": 336
},
"outputs": [],
"source": [
"\n",
"def main_loop(message, history):\n",
" output = run_action(message, history, game_state)\n",
" \n",
" safe = is_safe(output)\n",
" if not safe:\n",
" return 'Invalid Output'\n",
"\n",
" item_updates = detect_inventory_changes(game_state, output)\n",
" update_msg = update_inventory(\n",
" game_state['inventory'], \n",
" item_updates\n",
" )\n",
" output += update_msg\n",
"\n",
" return output\n",
"\n",
"start_game(main_loop, True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "58a58147-7832-494f-a00c-8a2e9c61c2a7",
"metadata": {
"height": 30
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}