commit cf882f1c01497513fc74feea2cdcdbbd8cdeca09 Author: Eric Ihli Date: Sun Nov 12 22:02:04 2023 -0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87620ac --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.ipynb_checkpoints/ diff --git a/customllm.py b/customllm.py new file mode 100644 index 0000000..e114e46 --- /dev/null +++ b/customllm.py @@ -0,0 +1,4 @@ +from typing import Any, List, Mapping, Optional + +from langchain.callbacks.manager import CallbackManagerForLLMRun +from langchain.llms.base import LLM diff --git a/langchain.ipynb b/langchain.ipynb new file mode 100644 index 0000000..08f2265 --- /dev/null +++ b/langchain.ipynb @@ -0,0 +1,550 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "0c03cbd4-861d-4e2d-b3f6-bd04d0d082cb", + "metadata": {}, + "outputs": [], + "source": [ + "from typing import Any, List, Mapping, Optional\n", + "\n", + "from langchain.callbacks.manager import CallbackManagerForLLMRun\n", + "from langchain.llms.base import LLM\n", + "import torch\n", + "from transformers import pipeline" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "8b7bed2e-9f16-4555-b6a4-e96fefda1ddf", + "metadata": {}, + "outputs": [], + "source": [ + "from transformers import AutoModel, AutoTokenizer" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "33720a1f-95e7-45d5-811b-0df34790edd0", + "metadata": {}, + "outputs": [], + "source": [ + "class CustomLLM(LLM):\n", + " model_name: str = \"mistralai/Mistral-7B-v0.1\"\n", + " model_pipeline: Any\n", + " device = torch.device(\"cuda\") if torch.cuda.is_available() else torch.device(\"cpu\")\n", + " \n", + " def init(self, *args, **kwargs):\n", + " t = AutoTokenizer.from_pretrained(\"mistralai/Mistral-7B-v0.1\")\n", + " t.add_special_tokens({\"pad_token\": t.eos_token})\n", + " m = AutoModel.from_pretrained(\"mistralai/Mistral-7B-v0.1\")\n", + " m.resize_token_embeddings(len(t))\n", + " self.model_pipeline = pipeline(\"text-generation\", model=\"mistralai/Mistral-7B-v0.1\", device_map='auto',\n", + " trust_remote_code=True, model_kwargs={\"torch_dtype\": torch.bfloat16, \"load_in_8bit\": True},\n", + " max_length=1500, tokenizer=t)\n", + "\n", + " def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:\n", + " print(prompt, type(prompt))\n", + " res = self.model_pipeline(str(prompt))\n", + " print(res, type(res))\n", + " if len(res) >= 1:\n", + " generated_text = res[0].get(\"generated_text\")[len(prompt):]\n", + " return generated_text\n", + " else:\n", + " return \"Don't know the answer\"\n", + "\n", + " @property\n", + " def _identifying_params(self) -> Mapping[str, Any]:\n", + " return {\"name_of_model\": self.model_name}\n", + "\n", + " @property\n", + " def _llm_type(self) -> str:\n", + " return \"custom\"" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "aa4eae46-fd3a-425b-8b10-0d06e756e179", + "metadata": {}, + "outputs": [], + "source": [ + "llm = CustomLLM()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "e1d0ebc5-5d3a-4401-982d-f46dea02532f", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "fa0f4b37d4ce4b049c84006d229e2b77", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Loading checkpoint shards: 0%| | 0/2 [00:00\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/eihli/.virtualenvs/system/lib/python3.10/site-packages/transformers/generation/utils.py:1281: UserWarning: Input length of input_ids is 1923, but `max_length` is set to 1500. This can lead to unexpected behavior. You should consider increasing `max_new_tokens`.\n", + " warnings.warn(\n", + "/home/eihli/.virtualenvs/system/lib/python3.10/site-packages/bitsandbytes/autograd/_functions.py:322: UserWarning: MatMul8bitLt: inputs will be cast from torch.bfloat16 to float16 during quantization\n", + " warnings.warn(f\"MatMul8bitLt: inputs will be cast from {A.dtype} to float16 during quantization\")\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[{'generated_text': \"Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.\\n\\nTo learn more about DeciCoder, check out the model on Hugging Face.\\n\\nDeciCoder’s architecture differs from SantaCoder’s in other ways as well. It has fewer layers (20 vs. 24 in Santa), more heads (32 vs 16) and the same embedding size, which means its head sizes are smaller (64 vs 128 in Santa).\\nDeciCoder’s Training Process\\n\\nBroad Use Rights: With a permissive license, DeciCoder grants you wide-ranging rights, alleviating typical legal concerns that can accompany the use of some models. You can seamlessly integrate DeciCoder into your projects with minimal restrictions.\\n\\nReady for Commercial Applications: Beyond just experimentation and personal projects, Deci’s permissive licensing means you can confidently deploy DeciCoder in commercial applications. Whether you’re looking to enhance your product, offer new services, or simply leverage the model for business growth, DeciCoder is ready to be your partner in innovation.\\n\\nCommunity\\nCompany\\n\\nAbout Us\\nPartners\\nCareers\\nNewsroom\\nContact Us\\n\\n\\n \\n\\n\\n\\n\\n\\n\\nLog in \\n\\n\\n\\n\\n\\n\\nBook a Demo\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n \\nBack to Blog\\n\\n\\n\\n\\n\\n\\n\\nAlgorithms \\n\\n\\n\\nIntroducing DeciCoder: The New Gold Standard in Efficient and Accurate Code Generation \\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n \\n\\n\\n\\n\\n\\n\\nBy\\nDeci \\n\\n\\n\\n \\n\\nProduct Team \\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\nAugust 15, 2023 \\n\\n\\n\\n \\n\\n6 min read\\n\\nSo, what drives DeciCoder’s impressive throughput? A combination of architectural efficiency and optimized implementation. Notably, DeciCoder is significantly more memory efficient, allowing it to manage larger batch sizes. This memory efficiency means that Deci’s throughput reaches its maximum when its batch size is at 128, whereas SantaCoder capped at 32. With larger batch sizes, without the worry of running out of memory, DeciCoder effectively processes more data at once, further augmenting\\n\\nDeci’s Edge\\nThroughout this blog, we’ve highlighted the robust capabilities of DeciCoder, showcasing its consistent superiority over models like SantaCoder. Our innovative use of AutoNAC allowed us to generate an architecture that’s both efficient and powerful.\\n\\nLooking to accelerate inference and cut your LLM inference costs?Book a Demo.\\n\\nDeciCoder’s Permissive Licensing\\nIn releasing DeciCoder to the open source community, we’re committed to ensuring ease of use and accessibility for all users. To that end, DeciCoder comes with a permissive license (Apache 2.0). What does this mean for developers and businesses alike? It’s simple:\\n\\nDeciCoder’s Architecture\\nThe use of AutoNAC resulted in a new and distinctive transformer architecture for DeciCoder. One notable feature is its implementation of Grouped Query Attention with 8 key-value heads. By grouping query heads and allowing them to share a key head and value head, computation becomes streamlined, and memory usage optimized.\\n\\nThe synergy with Infery LLM can’t be overlooked. This proprietary inference engine, built with compatibility for PyTorch Script, optimizes execution and bolsters any LLM’s speed, helping AI teams to dramatically cut their inference costs and deliver users with an enhanced experience.\\nDeciCoder is just a glimpse, into the upcoming release of our expansive suite of Generative AI foundation models, accompanied by the GenAI SDK. This is only the beginning—there’s a world of innovations awaiting.\\n\\nWhen integrated with Deci’s inference optimization tool, DeciCoder outperforms SantaCoder in efficiency, delivering higher throughput even on more affordable GPUs that are 4x less expensive.\\n\\nDeciCoder’s efficiency results in a significant reduction in inference cost and\\xa0 carbon emissions. When paired with Infery LLM, the model’s cost per 1k tokens is 71.4% lower than SantaCoder’s on HuggingFace Inference Endpoint. Moreover the yearly carbon emitted is reduced by 324 kg CO2 per model instance on A10G GPU.\\n\\nOnce the DeciCoder architecture was generated by AutoNAC, DeciCoder began its training phase. DeciCoder was trained on the Python, Java, and Javascript subsets of the Stack, an extensive dataset containing over 6TB of permissively-licensed source code from 358 programming languages.DeciCoder’s training employed the ‘Fill in the Middle’ training objective. This method challenges language models to complete missing or broken segments of text, aiming to produce coherent and contextually relevant\\n\\nDeciCoder’s unmatched throughput and low memory footprint enable applications to achieve extensive code generation with the same latency, even on more affordable GPUs, resulting in substantial cost savings.\\nAt Deci, we’re obsessed with AI efficiency. We’ve been empowering AI teams to achieve unparalleled inference speed and accuracy with our advanced tools and deep learning foundation models. Now, we’re extending our core technology and expertise into the realm of generative AI.\\n\\nDeciCoder’s Remarkable Inference Speed\\nWhen it comes to measuring the efficacy of AI models, throughput – the number of tokens processed per second – is a critical metric for the operational efficiency of any application powered by Generative AI models . DeciCoder consistently outperforms SantaCoder in head-to-head comparisons.\\n\\nJoin us as we delve into the outstanding capabilities of DeciCoder.\\nBridging the Gen AI Efficiency Gap\\nInefficient inference poses a substantial hurdle in the production and deployment of deep learning models, especially for generative AI. As these algorithms grow in size and complexity, their escalating computational requirements not only increase energy consumption but also drive up operational costs. Furthermore, this elevated energy usage carries significant environmental consequences.\\n\\nDeciCoder is just the beginning. As we prepare to unveil a new generation of high-efficiency foundation LLMs and text-to-image models, developers can also eagerly anticipate our upcoming generative AI SDK. This suite, loaded with advanced tools, promises to redefine Gen AI fine-tuning, optimization, and deployment, offering unparalleled performance and cost efficiency to small and large enterprises alike.\\n\\nDeciCoder was trained at a Bfloat16 precision.\\nDeciCoder’s Accuracy – Surpassing SantaCoder Across Multiple Languages\\nDeciCoder’s accuracy surpasses that of SantaCoder. On the HumanEval evaluation benchmark, a tool designed specifically for assessing large language model (LLM) expertise in code generation tasks, DeciCoder outperforms SantaCoder in every language they were trained on, namely Python, Javascript and Java.\\n\\nWhen combining DeciCoder with our LLM inference optimization tool, Infery LLM, you can achieve a throughput that’s a staggering 3.5 times greater than SantaCoder’s.\\n\\nIntroducing DeciCoder: The New Gold Standard in Efficient and Accurate Code Generation\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\nSkip to content\\n\\n\\n\\n\\n\\n\\n \\n \\n\\n\\n\\n\\n\\n\\n\\nPlatform\\n\\nPLATFORM MODULES\\nBuild Models\\nTrain\\nOptimize & Deploy\\n\\n\\nTechnology\\nSolutions\\n\\nUSE CASES\\nRun on Edge Devices\\nOptimize Generative AI Models\\nReduce Cloud Cost\\nShorten Development Time\\nMaximize Data Center Utilization\\nINDUSTRIES\\nAutomotive\\nSmart Retail\\nPublic Sector\\nSmart Manufacturing\\nVideo Analytics\\n\\n\\nPricing\\nResources\\n\\nQuestion: What is DeciCoder\\nHelpful Answer: Dec\"}] \n" + ] + } + ], + "source": [ + "response = qa_with_sources_chain({\"query\":\"What is DeciCoder\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc581097-a53e-4e09-bda5-ebde114e6c04", + "metadata": {}, + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pathfinder/adventures/fishery.txt b/pathfinder/adventures/fishery.txt new file mode 100644 index 0000000..2f2ee2a --- /dev/null +++ b/pathfinder/adventures/fishery.txt @@ -0,0 +1,13 @@ +Tamily, a one-legged eye-patch-wearing owner of the fishery, posted a notice on the job board about a thief that had been stealing from barrels of fish below the fishery. + +We, the Rising Guard, an adventurer's group with members Kestrel, Kyriela, Krogoth, Locke, and Gale, went down into the cellar to investigate. + +We encountered some large rats, broken barrels, and a hidden path to some tunnels beneath the fishery. + +We made our way through the barrier in the wall of the cellar and we eventually encountered a sarcophagus with an inscription: "Here lies Asophone Menhemes." On the wall of the room near the sarcophagus was a torch emanating a mysterious blue light. Gale took the torch, which we later learned was a magical source of unending light. + +Going deeper into the tunnels, we encountered spiders, a challenging fight against some undead, and we learned about a Kobold named Zolgran who is head of the Stone Scales kobolds. + +The kobolds were behind the missing fish. + +We captured a kobold, Pretz, and took him to Tamily where we collected our reward. We then took Pretz to Captain Longsaddle where Pretz was locked away in the garrison. diff --git a/pathfinder/kestrel_notes/kestrel.txt b/pathfinder/kestrel_notes/kestrel.txt new file mode 100644 index 0000000..e69de29 diff --git a/pathfinder/kestrel_notes/kestrel_background.txt b/pathfinder/kestrel_notes/kestrel_background.txt new file mode 100644 index 0000000..4ceb9c6 --- /dev/null +++ b/pathfinder/kestrel_notes/kestrel_background.txt @@ -0,0 +1,11 @@ +Kestrel was a scholar of all things healing and natural. + +She, her family, and their community were attacked by Drow — dark elves that use fleshwarp to attack and mutilate victims. + +Kestrel was the only survivor of the assault. She was left with lasting scars at the loss and horror of the event. + +She spent many years at the Dawnflower temple of Sarenrae. She learned about fleshwarp in hopes to eliminate it from Golarion. She spent a lot of time training and meditating, mostly in isolation. + +Kestrel has befriended Gale. His companionship helped her break free from her depression and isolation and return to the outside world. + +Kestrel moved from Absalom to study at the Dawnflower temple in Otari. That's where she met Gale, a monk at the Dawnflower. diff --git a/pathfinder/krogoth_notes/krogoth_background.txt b/pathfinder/krogoth_notes/krogoth_background.txt new file mode 100644 index 0000000..dc1c3f5 --- /dev/null +++ b/pathfinder/krogoth_notes/krogoth_background.txt @@ -0,0 +1,3 @@ +Krogoth hangs out at a bar called the Crow's Cask. The bar is run by a Tengu named Magilow. There's a low stakes gollum game (a card game) played at the Crow's Cask. That's where degenerates like Locke and Krogoth meet to discuss their hairbrained money-making schemes. + +Krogoth is a much better gollum player than Locke. Locke thinks he's good, but that's just because he gets drunk. diff --git a/pathfinder/kyriela_notes/kyriela_background.txt b/pathfinder/kyriela_notes/kyriela_background.txt new file mode 100644 index 0000000..8e0abd5 --- /dev/null +++ b/pathfinder/kyriela_notes/kyriela_background.txt @@ -0,0 +1,5 @@ +Kyriela, a wizard, traveled far — both attributes uncommon for a dwarf — to get to Otari. But Otari was founded by another dwarf wizard, Zarmibdean. And this is one of the things that attracted Kyriela to Otari. + +Kyriela likes to hang out at the bookstore in Otari. + +Her family is of a clan called the "Deathwarden"s. They defend a wall to the north from an onslaught of undead. diff --git a/pathfinder/locke_notes/locke_background.txt b/pathfinder/locke_notes/locke_background.txt new file mode 100644 index 0000000..e69de29 diff --git a/pathfinder/otari/bookstore.txt b/pathfinder/otari/bookstore.txt new file mode 100644 index 0000000..f6a8460 --- /dev/null +++ b/pathfinder/otari/bookstore.txt @@ -0,0 +1 @@ +The bookstore in Otari is named Odd Stories. It's run by the wizard Morlibint and his husband. diff --git a/pathfinder/otari/crows_cask.txt b/pathfinder/otari/crows_cask.txt new file mode 100644 index 0000000..4a4527e --- /dev/null +++ b/pathfinder/otari/crows_cask.txt @@ -0,0 +1,6 @@ +This brewery’s proprietor, Magiloy, creates magical potions in addition to +delicious (but sometimes questionable) beverages—your GM will have information +about what sorts of potions and dubious drinks might be for sale during any one +visit. Magiloy might reserve special potions or good deals for those who fetch +rare ingredients for her or for those who break up the tavern’s occasional bar +fights. diff --git a/pathfinder/otari/dawnflower.txt b/pathfinder/otari/dawnflower.txt new file mode 100644 index 0000000..28a91f8 --- /dev/null +++ b/pathfinder/otari/dawnflower.txt @@ -0,0 +1,4 @@ +Otari’s largest temple contains more than ordinary books; the clerics also sell +scrolls, wands, and magic weapons. True to her reputation of being unusually +knowledgeable, the high priestess Vandy Banderdash can often direct visitors to +exactly the scroll or weapon they need. diff --git a/pathfinder/otari/dawnflower_library.txt b/pathfinder/otari/dawnflower_library.txt new file mode 100644 index 0000000..b9eec0f --- /dev/null +++ b/pathfinder/otari/dawnflower_library.txt @@ -0,0 +1,8 @@ +Otari’s largest temple is built at the town’s westernmost edge, atop an upraised +shelf that’s nevertheless far below the clifftop. The library’s position allows +it to catch the rays of the rising sun, which transform its central dome into a +glowing testament to the sun goddess Sarenrae—at least when the sky is clear. +While principally dedicated to Sarenrae, the Dawnflower Library welcomes all +non-evil faiths. The building’s two wings each contain shrines, and the center +houses a wide range of books, including histories, satires, textbooks, and maps +to innumerable exciting locales. diff --git a/pathfinder/otari/graveyard.txt b/pathfinder/otari/graveyard.txt new file mode 100644 index 0000000..a171f00 --- /dev/null +++ b/pathfinder/otari/graveyard.txt @@ -0,0 +1,5 @@ +High on the cliff above the Dawnflower Library, the Otari Graveyard holds +crumbling mausoleums and groves of leafless trees. Few enter this ancient +cemetery other than the acolytes who tend it, as it’s hard to reach even though +it looms over the town. Rumors of undead roaming the cemetery at night persist +among Otari’s most superstitious townspeople. diff --git a/pathfinder/otari/guantlight_keep.txt b/pathfinder/otari/guantlight_keep.txt new file mode 100644 index 0000000..34c7aad --- /dev/null +++ b/pathfinder/otari/guantlight_keep.txt @@ -0,0 +1,8 @@ +About a half hour’s walk north of Otari is a sprawling swamp called Fogfen. +Ruined Gauntlight Keep lies within, overgrown with moss and overrun with vermin. +Over the last several generations, hopeful explorers have poked around the +ruins, but they’re generally considered unsafe and wholly picked over today. The +most mysterious feature of Gauntlight Keep is a lighthouse that towers above the +ruins, curiously far from the shore. The lighthouse hasn’t ever shone its light +in living memory, but there’s nevertheless a vague unease about the structure in +Otari—if its eerie light shines, sinister things must be afoot. diff --git a/pathfinder/otari/market.txt b/pathfinder/otari/market.txt new file mode 100644 index 0000000..c7ae080 --- /dev/null +++ b/pathfinder/otari/market.txt @@ -0,0 +1,5 @@ +Part open-air farmer’s market, part log-cabin trading post, the Otari Market is +a one-stop shop for basic goods. Available wares include all adventuring gear, +light armor, and simple weapons. The market’s owner is the dour, humorless +Keeleno Lathenar. Keeleno pays handsomely for wolf pelts, as a wolf-like monster +slew his wife years ago, and he hopes to one day acquire the skin of her killer. diff --git a/pathfinder/otari/otari_background.txt b/pathfinder/otari/otari_background.txt new file mode 100644 index 0000000..750573e --- /dev/null +++ b/pathfinder/otari/otari_background.txt @@ -0,0 +1,12 @@ +Otari is a town with two primary industries - fishing and lumber. + +The town was founded by adventures and still attracts a myriad of adventuring types. + +The mayor of the town is a man named Oseph Menhemes. + +There is a notice board in Otari with the following messages: + +- Death caused by a werewolf, Jal. 150 gold reward. +- Brelda is missing her son Lazda, a dwarf. +- Tamily has a note about a fish thief. +- diff --git a/pathfinder/otari/roseguard.txt b/pathfinder/otari/roseguard.txt new file mode 100644 index 0000000..ba66f76 --- /dev/null +++ b/pathfinder/otari/roseguard.txt @@ -0,0 +1,11 @@ +An adventuring party who made their name in Absalom, the Roseguard defeated the +villainous Belcorra Haruvex and founded the logging town of Otari. Today, the +people of Otari continue to respect and honor the Roseguard on Founder’s Day, 3 +Desnus. The Roseguard consisted of the following heroes. Aesephna Menhemes: +Aesephna was the party’s healer. She was a cleric of Erastil who was always more +comfortable in smaller towns than big cities like Absalom. Otari Ilvashti: +Otari, the group’s rogue, was a charming optimist who kept the others hopeful +with his charm and humor, even during their darkest hours. Vol Rajani: Vol was +the party’s fighter, a no‑nonsense swordswoman who claimed to be exiled royalty +from Nidal. Zarmavdian: The group’s wizard was a well‑educated diviner who +pursued outlandish conspiracy theories and occult lore. diff --git a/pathfinder/rising_guard.org b/pathfinder/rising_guard.org new file mode 100644 index 0000000..5e34531 --- /dev/null +++ b/pathfinder/rising_guard.org @@ -0,0 +1,5 @@ +#+title: Rising Guard + +* The Rising Guard + +** Kestrel diff --git a/pathfinder/rising_guard.tex b/pathfinder/rising_guard.tex new file mode 100644 index 0000000..e69de29 diff --git a/retrieval.ipynb b/retrieval.ipynb new file mode 100644 index 0000000..effa503 --- /dev/null +++ b/retrieval.ipynb @@ -0,0 +1,489 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "2bb27e2a-b568-4319-9a9c-24917d8e9d0e", + "metadata": {}, + "outputs": [], + "source": [ + "import re\n", + "from operator import itemgetter\n", + "import torch\n", + "from transformers import pipeline\n", + "from transformers import AutoModel, AutoTokenizer\n", + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "511b179c-fc8d-4aba-ab9d-fe0b8510d62a", + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"PYTORCH_CUDA_ALLOC_CONF\"] = \"max_split_size_mb:512\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a18de0f-93bf-4e4e-b24d-107f083aff8e", + "metadata": {}, + "outputs": [], + "source": [ + "import chromadb\n", + "chroma_client = chromadb.Client()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a25976c9-4b6c-40d7-914c-ad7840a06636", + "metadata": {}, + "outputs": [], + "source": [ + "collection = chroma_client.create_collection(\"pathfinder7\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8298e128-7c96-43a0-8d69-9c2d9fc3a7fd", + "metadata": {}, + "outputs": [], + "source": [ + "re.sub(r\"(\\d{8,}|Eric Ihli||paizo.com)\", \"\", \"paizo.com, Eric Ihli , Feb 13, 2023paizo.com, Eric Ihli , Feb 13, 2023\\n2365842023658420\\n236584204643808\\n46438084643808\\nAbility Score OverviewAbility Score Overview\\nEach ability score starts at 10, representing human Each ability score starts at 10, representing human \\naverage, but as you make character choices, you’ll adjust average, but as you make character choices, you’ll adjust \\nthese scores by applying ability boosts, which increase a these scores by applying ability boosts, which increase a \\nscore, and ability flaws, which decrease a score. As you score, and ability flaws,\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "293950e7-e1ac-4559-b8d4-617b6077f0c3", + "metadata": {}, + "outputs": [], + "source": [ + "def clean_page(page):\n", + " return re.sub(r\"(\\d{8,}|Eric Ihli||paizo.com)\", \"\", page).replace(r\" +\", \" \").replace(r\"\\n+\", \"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a5ba05c-65c8-42d7-943a-aabaa1c03f79", + "metadata": {}, + "outputs": [], + "source": [ + "import textract\n", + "import PyPDF2\n", + "world_guide = []\n", + "with open(\"/home/eihli/Downloads/Pathfinder 2e Lost Omens World Guide.pdf\", \"rb\") as f:\n", + " reader = PyPDF2.PdfReader(f)\n", + " for i, page in enumerate(reader.pages):\n", + " text = page.extract_text()\n", + " for j in range(0, len(text), len(text) // 10):\n", + " world_guide.append([f\"{i}.{j}\", clean_page(text[j:j+len(text)//10])])\n", + "\n", + "rulebook = []\n", + "with open(\"/home/eihli/Downloads/Pathfinder 2e Core Rulebook.pdf\", \"rb\") as f:\n", + " reader = PyPDF2.PdfReader(f)\n", + " for i, page in enumerate(reader.pages):\n", + " text = page.extract_text()\n", + " for j in range(0, len(text), len(text) // 10):\n", + " rulebook.append([f\"{i}.{j}\", clean_page(text[j:j+len(text)//10])])\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4811057-7d8c-4422-8491-d1bfd770b40e", + "metadata": {}, + "outputs": [], + "source": [ + "text = world_guide + rulebook" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf98cad9-2661-4eea-add6-e5bfb9bc54ea", + "metadata": {}, + "outputs": [], + "source": [ + "from tqdm.auto import tqdm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30bfb343-8b89-48a8-91d9-436aeff0c524", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "dataset = []\n", + "batch_size = 32\n", + "\n", + "for i in tqdm(range(0, len(rulebook), batch_size)):\n", + " start = i\n", + " end = i + batch_size\n", + " batch = rulebook[i:end]\n", + " collection.upsert(\n", + " ids=list(map(lambda x: str(x[0]) + \":rulebook\", batch)),\n", + " documents=list(map(itemgetter(1), batch)),\n", + " metadatas=list(map(lambda x: {\"source\": \"rulebook\", \"page\": x[0]}, batch)),\n", + " )\n", + "\n", + "for i in tqdm(range(0, len(world_guide), batch_size)):\n", + " start = i\n", + " end = i + batch_size\n", + " batch = world_guide[i:end]\n", + " collection.upsert(\n", + " ids=list(map(lambda x: str(x[0]) + \":world_guide\", batch)),\n", + " documents=list(map(itemgetter(1), batch)),\n", + " metadatas=list(map(lambda x: {\"source\": \"world_guide\", \"page\": x[0]}, batch)),\n", + " )\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48002fdf-460f-4f8c-b539-1cb32b3bef82", + "metadata": {}, + "outputs": [], + "source": [ + "results = collection.query(query_texts=[\"How can a goblin alchemist pair well with a human cleric?\"], n_results=2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e940fb3c-7d5d-4f97-9ff2-b423ba08a0a7", + "metadata": {}, + "outputs": [], + "source": [ + "results" + ] + }, + { + "cell_type": "markdown", + "id": "19c78008-2f5b-427a-9a80-b8942ec961df", + "metadata": {}, + "source": [ + "# Local data\n", + "\n", + "Reads from local files and inserts into the database." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "8a4eafc1-7d7d-4424-923e-fcf0b545b620", + "metadata": {}, + "outputs": [], + "source": [ + "for dirpath, dirnames, filenames in os.walk(\".\"):\n", + " for filename in filenames:\n", + " if filename.endswith(\".txt\"):\n", + " with open(os.path.join(dirpath, filename)) as f:\n", + " collection.upsert(\n", + " ids=[filename],\n", + " documents=[f.read()],\n", + " metadatas=[{\"source\": filename.split(\".txt\")[0], \"page\": \"0\"}],\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b7ab0341-e6f1-48e3-a76a-1606851e41f2", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d03391e-009a-4d21-a258-fe51b19109a2", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b78bf7c9-797d-4adf-94ad-dbf5e71783f5", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "abab6622-d805-4e70-b850-9b93b3003240", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "decd813a-0b44-47cb-a47d-09365e24058f", + "metadata": {}, + "outputs": [], + "source": [ + "from transformers import pipeline\n", + "from transformers import AutoModel, AutoTokenizer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe2c2a4c-b72e-48cf-a2e9-0ab4da32d397", + "metadata": {}, + "outputs": [], + "source": [ + "# t = AutoTokenizer.from_pretrained(\"mistralai/Mistral-7B-v0.1\", device_map=\"auto\")\n", + "# t.add_special_tokens({\"pad_token\": t.eos_token})\n", + "# m = AutoModel.from_pretrained(\"mistralai/Mistral-7B-v0.1\")\n", + "# m.resize_token_embeddings(len(t))\n", + "p = pipeline(\n", + " \"text-generation\", model=\"mistralai/Mistral-7B-Instruct-v0.1\", device_map='auto',\n", + " trust_remote_code=True, model_kwargs={\"torch_dtype\": torch.bfloat16, \"load_in_8bit\": True},\n", + " max_new_tokens=512, do_sample=True, temperature=0.6,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a52ef080-84ad-4391-9d1f-ea772d4546f6", + "metadata": {}, + "outputs": [], + "source": [ + "from string import Template\n", + "template = Template(\"\"\"\n", + "\n", + "[INST]\n", + "Answer questions about a fantasy role playing game like Dungeons and Dragons or Pathfinder.\n", + "[/INST]\n", + "Ok. I'll take into account the context of a fantasy role playing game.\n", + "\n", + "\n", + "\n", + "What follows are pages from the Pathfinder core rulebook and the Lost Omens world guide.\n", + "Lost Omens is in Pathfinder lore.\n", + "Each page is seperated by \"------\".\n", + "For example:\n", + "\n", + "------ Page 20 of the core rulebook.\n", + "Alchemist\n", + "You enjoy tinkering with alchemical formulas and \n", + "substances in your spare time, and your studies have \n", + "progressed beyond mere experimentation.\n", + "------\n", + "------ Page 38 of the world guide.\n", + "Cleric\n", + "You are an ordained priest of your deity and have even \n", + "learned how to cast a few divine spells. Though your main \n", + "training lies elsewhere, your religious calling provides \n", + "you divine gifts. \n", + "------\n", + "\n", + "[INST]\n", + "Describe what a Cleric is.\n", + "[/INST]\n", + "A cleric is a priest of a particular deity. They can cast a few divine spells, but their main training lies elsewhere.\n", + "See page 38 of the core world guide.\n", + "\n", + "\n", + "\n", + "What follows are pages from the Pathfinder core rulebook and the Lost Omens world guide.\n", + "Lost Omens is in Pathfinder lore.\n", + "Each page is seperated by \"------\".\n", + "For example:\n", + "\n", + "------ Page 203 of the core rulebook.\n", + "• Barbarian alchemists can mix mutagens with \n", + "their rage to ferocious effect. \n", + "• Champion alchemists can focus on alchemical \n", + "items that boost defenses and heal others, \n", + "allowing their champion’s reaction \n", + "and lay on hands to go further. \n", + "• Fighter alchemists can use their \n", + "alchemy to gain additional options \n", + "in situations where their usual \n", + "tactics don’t work. \n", + "• Ranger alchemists focus on alchemy \n", + "and snares, getting extra use out of \n", + "their Crafting skill and supplying \n", + "bombs for the bomb snare.\n", + "------\n", + "------ Page 102 of the world guide.\n", + "• Alchemist clerics work well with the chirurgeon \n", + "field, healing various ailments with either alchemy \n", + "or spells. \n", + "• Martial clerics are typically looking for a potent \n", + "domain spell or some healing to use in a pinch. \n", + "• Divine sorcerer clerics double down as the ultimate \n", + "divine spellcasters.\n", + "------\n", + "[INST]\n", + "What are some effective ways to play an alchemist?\n", + "[/INST]\n", + "There are many ways to be an effective alchemist. You could be a barbarian alchemist who mixes mutagens with rage to ferocious effect.\n", + "You could be a ranger alchemist who focuses on snares and getting bonuses to their crafting skill.\n", + "You could be a fighter alchemist who uses bombs, poisons, and traps to gain additional options when traditional tactics don't work.\n", + "\n", + "\n", + "\n", + "$pages\n", + "[INST]\n", + "$prompt\n", + "[/INST]\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12dddff0-a1af-4f4c-bee4-badb741f1885", + "metadata": {}, + "outputs": [], + "source": [ + "#list(zip(*list(*zip(results[\"ids\"], results[\"metadatas\"], results[\"documents\"]))))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4625ac89-9b0f-49af-a5ca-742b9b47db70", + "metadata": {}, + "outputs": [], + "source": [ + "def query(prompt):\n", + " results = collection.query(query_texts=[prompt], n_results=6)\n", + " result = \"\"\n", + " for id, md, doc in zip(*list(*zip(results[\"ids\"], results[\"metadatas\"], results[\"documents\"]))):\n", + " context = f\"------- Page {md['page']} of the {md['source']}\\n\"\n", + " context += doc + \"\\n\"\n", + " context += \"-------\\n\"\n", + " result += context\n", + " out = template.substitute(pages=result, prompt=prompt)\n", + " return out" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "255a2e8c-df5c-46c2-9ec5-56b638cb7a5a", + "metadata": { + "jupyter": { + "source_hidden": true + }, + "scrolled": true + }, + "outputs": [], + "source": [ + "print(query(\"I'm a goblin alchemist who likes fire. What alchemical bomb should I use? What other spells, armor, or items would help my bombs be most effective?\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "21b030a8-a104-43b4-a9cf-eae4ec1522d3", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Setting `pad_token_id` to `eos_token_id`:2 for open-end generation.\n" + ] + } + ], + "source": [ + "response = p(query(\"What spell should Kestrel use against undead?\"), return_full_text=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "e76b2e8f-45e6-4a99-ae58-9767799837e0", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Kestrel could use Disrupt Undead on an undead creature. It is a cantrip spell that deals 1d6 positive damage plus Kestrel's spellcasting ability modifier to the target. If the creature critically fails its Fortitude saving throw, it is stunned for 1 minute and becomes temporarily immune to any spell or other magical effect for 1 minute after that.\n", + "\n", + "If Kestrel wants to focus on dealing damage to undead creatures, they could use Necrotic Infusion. It is a feat that allows Kestrel to pour negative energy into their undead subject to empower its attacks. If the next action Kestrel uses is to cast Harm to restore Hit Points to a single undead creature, the target then deals an additional 1d6 negative damage with its melee weapons and unarmed attacks until the end of its next turn. If the Harm spell is a spell, Kestrel can choose to expend one of their Harm spells or one of their Heal spells to empower the undead creature instead.\n" + ] + } + ], + "source": [ + "print(response[0][\"generated_text\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "67cc80cb-1430-4183-9022-dd2c06ce70de", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Setting `pad_token_id` to `eos_token_id`:2 for open-end generation.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "It is said that Krogoth is a much better gollum player at the Crow's Cask than Locke. He gets drunk less often and is able to use his knowledge of the game to gain an advantage.\n" + ] + } + ], + "source": [ + "response = p(query(\"Tell me who the best gollum player is at the Crow's Cask.\"), return_full_text=False)\n", + "print(response[0][\"generated_text\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b6ed234-c72d-4505-abf8-52d5d3e2473e", + "metadata": {}, + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}