llm_game_hackathon/L1.ipynb
Thomas van der Meer 0a9571de3d Initial commit
2024-11-22 14:20:37 +01:00

567 lines
18 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": "5ac6b5d5-fce7-4fcb-b1a8-c490ea5c5325",
"metadata": {
"id": "173e06c5-4b07-4e3b-a67a-5c3e141beb2c"
},
"source": [
"# L1: Hierarchical Content Generation"
]
},
{
"cell_type": "markdown",
"id": "8be81d7d-2c10-45c4-beb4-0e7d7910fa8a",
"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": "aa3e6edc-62d6-44ea-a7da-5863f11bf7a4",
"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": "ac19c917-fe0b-4140-abc4-33d6b3972aaa",
"metadata": {
"id": "173e06c5-4b07-4e3b-a67a-5c3e141beb2c"
},
"source": [
"## Creating a World"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "93056e48-cb80-46a8-8990-bc5b4ae9506b",
"metadata": {
"height": 149
},
"outputs": [],
"source": [
"system_prompt = f\"\"\"\n",
"Your job is to help create interesting fantasy worlds that \\\n",
"players would love to play in.\n",
"Instructions:\n",
"- Only generate in plain text without formatting.\n",
"- Use simple clear language without being flowery.\n",
"- You must stay below 3-5 sentences for each description.\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "330f3e78-9a20-45b1-afa5-a65289046a55",
"metadata": {
"height": 200
},
"outputs": [],
"source": [
"world_prompt = f\"\"\"\n",
"Generate a creative description for a unique fantasy world with an\n",
"interesting concept around cities build on the backs of massive beasts.\n",
"\n",
"Output content in the form:\n",
"World Name: <WORLD NAME>\n",
"World Description: <WORLD DESCRIPTION>\n",
"\n",
"World Name:\"\"\"\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "7f928bb3-c6e4-4891-a154-3b3f225e8d21",
"metadata": {
"height": 217
},
"outputs": [],
"source": [
"from together import Together\n",
"from helper import get_together_api_key,load_env \n",
"\n",
"client = Together(api_key=get_together_api_key())\n",
"\n",
"output = client.chat.completions.create(\n",
" model=\"meta-llama/Llama-3-70b-chat-hf\",\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": world_prompt}\n",
" ],\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "22d161d6-cb78-4c3d-b858-5659d5d16761",
"metadata": {
"height": 47
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"World Name: Kyropeia\n",
"\n",
"World Description: Kyropeia is a realm where ancient, gargantuan creatures known as the \"Colossi\" roam the land, their massive bodies serving as the foundation for sprawling metropolises. These beasts, born from the earth and infused with primal magic, have been domesticated by humans over centuries, allowing cities to be built upon their backs, shoulders, and even within their hollowed-out bodies. As the Colossi migrate across the landscape, their cities in tow, the inhabitants of Kyropeia must adapt to a life of constant motion and evolution.\n"
]
}
],
"source": [
"world_output =output.choices[0].message.content\n",
"print(world_output)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "b993a1df-7735-43da-9872-45bb2bdc9fb2",
"metadata": {
"height": 132
},
"outputs": [],
"source": [
"world_output = world_output.strip()\n",
"world = {\n",
" \"name\": world_output.split('\\n')[0].strip()\n",
" .replace('World Name: ', ''),\n",
" \"description\": '\\n'.join(world_output.split('\\n')[1:])\n",
" .replace('World Description:', '').strip()\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "5dbb561d-b115-4ba5-81f4-2ae3dfd4a71f",
"metadata": {},
"source": [
"## Generating Kingdoms"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "9531806c-8b56-4fe5-bb15-d7c8d9b1cef8",
"metadata": {
"height": 336
},
"outputs": [],
"source": [
"kingdom_prompt = f\"\"\"\n",
"Create 3 different kingdoms for a fantasy world.\n",
"For each kingdom generate a description based on the world it's in. \\\n",
"Describe important leaders, cultures, history of the kingdom.\\\n",
"\n",
"Output content in the form:\n",
"Kingdom 1 Name: <KINGDOM NAME>\n",
"Kingdom 1 Description: <KINGDOM DESCRIPTION>\n",
"Kingdom 2 Name: <KINGDOM NAME>\n",
"Kingdom 2 Description: <KINGDOM DESCRIPTION>\n",
"Kingdom 3 Name: <KINGDOM NAME>\n",
"Kingdom 3 Description: <KINGDOM DESCRIPTION>\n",
"\n",
"World Name: {world['name']}\n",
"World Description: {world['description']}\n",
"\n",
"Kingdom 1\"\"\"\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "f7c87417-695c-443a-baa1-b354a9664d14",
"metadata": {
"height": 132
},
"outputs": [],
"source": [
"output = client.chat.completions.create(\n",
" model=\"meta-llama/Llama-3-70b-chat-hf\",\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": kingdom_prompt}\n",
" ],\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "ca6d59b6-60f1-4241-8906-29be576d00e6",
"metadata": {
"height": 336
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Created kingdom \"Valtoria\" in Kyropeia\n",
"\n",
"Kingdom 1 Description: Valtoria is a kingdom built upon the back of the largest Colossus, the \"Earthshaker\". Its people, skilled engineers and architects, have developed a unique culture of mobility and adaptability. Led by the wise and cunning Queen Lyra, Valtoria is a hub of innovation, where inventors and tinkerers work tirelessly to improve the city's infrastructure and harness the primal magic of the Colossi.\n"
]
}
],
"source": [
"kingdoms = {}\n",
"kingdoms_output = output.choices[0].message.content\n",
"\n",
"for output in kingdoms_output.split('\\n\\n'):\n",
" kingdom_name = output.strip().split('\\n')[0] \\\n",
" .split('Name: ')[1].strip()\n",
" print(f'Created kingdom \"{kingdom_name}\" in {world[\"name\"]}')\n",
" kingdom_description = output.strip().split('\\n')[1] \\\n",
" .split('Description: ')[1].strip()\n",
" kingdom = {\n",
" \"name\": kingdom_name,\n",
" \"description\": kingdom_description,\n",
" \"world\": world['name']\n",
" }\n",
" kingdoms[kingdom_name] = kingdom\n",
"world['kingdoms'] = kingdoms\n",
"\n",
"print(f'\\nKingdom 1 Description: \\\n",
"{kingdom[\"description\"]}')"
]
},
{
"cell_type": "markdown",
"id": "e124ee9d-694b-4259-b38a-34ee106c5ca4",
"metadata": {},
"source": [
"## Generating Towns"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "8f111ae4-dc95-49e1-ae15-4b5fd515988e",
"metadata": {
"height": 387
},
"outputs": [],
"source": [
"def get_town_prompt(world, kingdom):\n",
" return f\"\"\"\n",
" Create 3 different towns for a fantasy kingdom abd world. \\\n",
" Describe the region it's in, important places of the town, \\\n",
" and interesting history about it. \\\n",
" \n",
" Output content in the form:\n",
" Town 1 Name: <TOWN NAME>\n",
" Town 1 Description: <TOWN DESCRIPTION>\n",
" Town 2 Name: <TOWN NAME>\n",
" Town 2 Description: <TOWN DESCRIPTION>\n",
" Town 3 Name: <TOWN NAME>\n",
" Town 3 Description: <TOWN DESCRIPTION>\n",
" \n",
" World Name: {world['name']}\n",
" World Description: {world['description']}\n",
" \n",
" Kingdom Name: {kingdom['name']}\n",
" Kingdom Description {kingdom['description']}\n",
" \n",
" Town 1 Name:\"\"\"\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "90d892c0-b74e-4c75-bcf7-b055fa6712cd",
"metadata": {
"height": 506
},
"outputs": [],
"source": [
"def create_towns(world, kingdom):\n",
" print(f'\\nCreating towns for kingdom: {kingdom[\"name\"]}...')\n",
" output = client.chat.completions.create(\n",
" model=\"meta-llama/Llama-3-70b-chat-hf\",\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": get_town_prompt(world, kingdom)}\n",
" ],\n",
" )\n",
" towns_output = output.choices[0].message.content\n",
" \n",
" towns = {}\n",
" for output in towns_output.split('\\n\\n'):\n",
" town_name = output.strip().split('\\n')[0]\\\n",
" .split('Name: ')[1].strip()\n",
" print(f'- {town_name} created')\n",
" \n",
" town_description = output.strip().split('\\n')[1]\\\n",
" .split('Description: ')[1].strip()\n",
" \n",
" town = {\n",
" \"name\": town_name,\n",
" \"description\": town_description,\n",
" \"world\": world['name'],\n",
" \"kingdom\": kingdom['name']\n",
" }\n",
" towns[town_name] = town\n",
" kingdom[\"towns\"] = towns"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "b534d860-5b6b-43f8-9c60-e345fbaf1d9e",
"metadata": {
"height": 115
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Creating towns for kingdom: Valtoria...\n",
"- Ironhaven created\n",
"- Skypoint created\n",
"- Emberwatch created\n",
"\n",
"Town 1 Description: Located on the Earthshaker's left shoulder, Ironhaven is a bustling industrial town where Valtoria's engineers and inventors craft innovative machinery and tools to aid the kingdom's constant migration. The town's central square features the famous Ironhaven Forge, a massive, Colossus-powered furnace that fuels the town's industry. Ironhaven's history is marked by a great fire that ravaged the town, prompting the development of advanced fire-resistant materials and safety measures.\n"
]
}
],
"source": [
"for kingdom in kingdoms.values():\n",
" create_towns(world, kingdom) \n",
"\n",
"town = list(kingdom['towns'].values())[0]\n",
"print(f'\\nTown 1 Description: \\\n",
"{town[\"description\"]}')"
]
},
{
"cell_type": "markdown",
"id": "fff397b4-3ac6-4737-a232-8e68df1471b0",
"metadata": {},
"source": [
"## Generating Non-Player Characters (NPC's)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "f31adacd-a37a-4de9-9be5-aadf56fff988",
"metadata": {
"height": 421
},
"outputs": [],
"source": [
"def get_npc_prompt(world, kingdom, town): \n",
" return f\"\"\"\n",
" Create 3 different characters based on the world, kingdom \\\n",
" and town they're in. Describe the character's appearance and \\\n",
" profession, as well as their deeper pains and desires. \\\n",
" \n",
" Output content in the form:\n",
" Character 1 Name: <CHARACTER NAME>\n",
" Character 1 Description: <CHARACTER DESCRIPTION>\n",
" Character 2 Name: <CHARACTER NAME>\n",
" Character 2 Description: <CHARACTER DESCRIPTION>\n",
" Character 3 Name: <CHARACTER NAME>\n",
" Character 3 Description: <CHARACTER DESCRIPTION>\n",
" \n",
" World Name: {world['name']}\n",
" World Description: {world['description']}\n",
" \n",
" Kingdom Name: {kingdom['name']}\n",
" Kingdom Description: {kingdom['description']}\n",
" \n",
" Town Name: {town['name']}\n",
" Town Description: {town['description']}\n",
" \n",
" Character 1 Name:\"\"\""
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "a301bf4d-1f99-475b-ae88-4a05e7537e3f",
"metadata": {
"height": 540
},
"outputs": [],
"source": [
"def create_npcs(world, kingdom, town):\n",
" print(f'\\nCreating characters for the town of: {town[\"name\"]}...')\n",
" output = client.chat.completions.create(\n",
" model=\"meta-llama/Llama-3-70b-chat-hf\",\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": get_npc_prompt(world, kingdom, town)}\n",
" ],\n",
" temperature=1 #added to generate unique names\n",
" )\n",
"\n",
" npcs_output = output.choices[0].message.content\n",
" npcs = {}\n",
" for output in npcs_output.split('\\n\\n'):\n",
" npc_name = output.strip().split('\\n')[0]\\\n",
" .split('Name: ')[1].strip()\n",
" print(f'- \"{npc_name}\" created')\n",
" \n",
" npc_description = output.strip().split('\\n')[1\\\n",
" ].split('Description: ')[1].strip()\n",
" \n",
" npc = {\n",
" \"name\": npc_name,\n",
" \"description\": npc_description,\n",
" \"world\": world['name'],\n",
" \"kingdom\": kingdom['name'],\n",
" \"town\": town['name']\n",
" }\n",
" npcs[npc_name] = npc\n",
" town[\"npcs\"] = npcs"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "36f0021d-41fa-4f3d-aed9-32d4fcb69dcb",
"metadata": {
"height": 98
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Creating characters for the town of: Ironhaven...\n",
"- \"Kaelin Darkhammer\" created\n",
"- \"Lyrien Stonefist\" created\n",
"- \"Aria Skypaw\" created\n",
"\n",
"Creating characters for the town of: Skypoint...\n",
"- \"Kaida Renn\" created\n",
"- \"Lyrien Frost\" created\n",
"- \"Arin Vexar\" created\n",
"\n",
"Creating characters for the town of: Emberwatch...\n",
"- \"Lyri kickoff\" created\n",
"- \"Kael Red nexus\" created\n",
"- \"background Adwasher<c Becket\" created\n"
]
}
],
"source": [
"for kingdom in kingdoms.values():\n",
" for town in kingdom['towns'].values():\n",
" create_npcs(world, kingdom, town)\n",
" # For now we'll only generate npcs for one kingdom\n",
" break"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "e95294cc-ee92-430d-ad48-e95852784851",
"metadata": {
"height": 81
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"NPC 1 in Emberwatch, Valtoria:\n",
"Lyri, the youngest daughter of Queen Lyrtl, is an ambitious inventor and engineer who wears elegant, intricately designed gloves embedded with tiny, glowing circuits. Her long, curly brown hair is tied back in a short ponytail, and her bright, inquisitive eyes are often peering into the workings of a new gadget. Despite her inborn enthusiasm for creation, Lyri harbors a deep pain - her mother's lack of acknowledgment of her own engineering prowess, fearing it's overshadowed by royal duties. Lyri yearns to create something revolutionary, proving her worth in the eyes of her mother and the kingdom.\n"
]
}
],
"source": [
"npc = list(town['npcs'].values())[0]\n",
"\n",
"print(f'\\nNPC 1 in {town[\"name\"]}, \\\n",
"{kingdom[\"name\"]}:\\n{npc[\"description\"]}')"
]
},
{
"cell_type": "markdown",
"id": "764a433b-5e04-4980-a9b0-4d336113f072",
"metadata": {},
"source": [
"## Save the World\n",
">Note: You will save your world state to a file different than the one shown in the video to allow future lessons to be consistent with the video. If later wish to build your own worlds, you will want to load your file rather than the saved file."
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "2dce3195-2c76-42da-9e49-c7a17e5ab08b",
"metadata": {
"height": 234
},
"outputs": [],
"source": [
"import json\n",
"\n",
"def save_world(world, filename):\n",
" with open(filename, 'w') as f:\n",
" json.dump(world, f)\n",
"\n",
"def load_world(filename):\n",
" with open(filename, 'r') as f:\n",
" return json.load(f)\n",
"\n",
"#save_world(world, '../shared_data/Kyropeia.json')\n",
"save_world(world, './shared_data/YourWorld_L1.json') #save to your version"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f64fc076-32b5-41ca-b755-6ccbd52347c0",
"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.12.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}