-
+
|
Other resources
diff --git a/SETUP-PC.pdf b/SETUP-PC.pdf
deleted file mode 100644
index 080346f..0000000
Binary files a/SETUP-PC.pdf and /dev/null differ
diff --git a/SETUP-linux.pdf b/SETUP-linux.pdf
deleted file mode 100644
index 35abb85..0000000
Binary files a/SETUP-linux.pdf and /dev/null differ
diff --git a/SETUP-mac.pdf b/SETUP-mac.pdf
deleted file mode 100644
index a9bc223..0000000
Binary files a/SETUP-mac.pdf and /dev/null differ
diff --git a/business.jpg b/assets/business.jpg
similarity index 100%
rename from business.jpg
rename to assets/business.jpg
diff --git a/important.jpg b/assets/important.jpg
similarity index 100%
rename from important.jpg
rename to assets/important.jpg
diff --git a/resources.jpg b/assets/resources.jpg
similarity index 100%
rename from resources.jpg
rename to assets/resources.jpg
diff --git a/thankyou.jpg b/assets/thankyou.jpg
similarity index 100%
rename from thankyou.jpg
rename to assets/thankyou.jpg
diff --git a/voyage.jpg b/assets/voyage.jpg
similarity index 100%
rename from voyage.jpg
rename to assets/voyage.jpg
diff --git a/guides/01_intro.ipynb b/guides/01_intro.ipynb
new file mode 100644
index 0000000..02ca9e2
--- /dev/null
+++ b/guides/01_intro.ipynb
@@ -0,0 +1,68 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Welcome to the Guides!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Introduction\n",
+ "\n",
+ "I've designed this course to be suitable for a wide range of backgrounds. For those of you relatively new to this, I've prepared some technical briefings to build your expertise.\n",
+ "\n",
+ "These are designed to be self-study; you work through them at your own pace, investigating and experimenting.\n",
+ "\n",
+ "I've heavily taken advantage of our AI friends to write some guides, and I've tried to frame them so they're as useful as possible and relevant to the course.\n",
+ "\n",
+ "There's only one requirement for the course: plenty of patience! Keep in mind that one of the best ways to learn is by solving problems - if you feel frustrated with a challenging puzzle, remember that this is where the learning happens! And, get in touch if I can help."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Contents (select from the sub-directory in the explorer on the left)\n",
+ "\n",
+ "1. Intro - this contents\n",
+ "2. The command line\n",
+ "3. Git and Github\n",
+ "4. Technical foundations (environment variables, networks, APIs, uv)\n",
+ "5. Notebooks\n",
+ "6. Python foundations\n",
+ "7. \"Vibe coding\" - successfully coding with the help of LLMs\n",
+ "8. Debugging techniques\n",
+ "9. APIs and Ollama\n",
+ "10. Intermediate level python, including decorators and async \n",
+ "11. Asynchronous Python\n",
+ "12. Starting your project - 3 crucial pieces of advice\n",
+ "13. Frontend Crash Course\n",
+ "14. Briefings on Docker and Terraform\n",
+ "\n",
+ "### Also see the community_contributions directory for some awesome Python cookbooks contributed by students! (Thank you!)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".venv",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.12.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/guides/02_command_line.ipynb b/guides/02_command_line.ipynb
new file mode 100644
index 0000000..863f621
--- /dev/null
+++ b/guides/02_command_line.ipynb
@@ -0,0 +1,63 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# The command line"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Welcome to the guide to build your confidence working at the command line.\n",
+ "\n",
+ "By the end of this guide, you should be able to confidently work at the command line, creating directories, moving files and more!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## For Windows PC users\n",
+ "\n",
+ "Please see this briefing:\n",
+ "\n",
+ "https://chatgpt.com/share/68064acf-4d3c-8012-86a1-fb09a7c6f923"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## For Mac users\n",
+ "\n",
+ "Please see this briefing:\n",
+ "\n",
+ "https://chatgpt.com/share/68064bfe-662c-8012-8073-479c32595459"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Please do experiment to build your confidence.\n",
+ "\n",
+ "ChatGPT, Claude, Gemini, DeepSeek and others are your friends! They are excellent at explaining any command line commands in detail. This will quickly become second nature."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/guides/03_git_and_github.ipynb b/guides/03_git_and_github.ipynb
new file mode 100644
index 0000000..0c814c8
--- /dev/null
+++ b/guides/03_git_and_github.ipynb
@@ -0,0 +1,81 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Git and Github"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This guide is all about using source code control: Git and Github.\n",
+ "\n",
+ "By the end of this, you should be confident with every day code control processes, including fetching the latest code and submitting a PR to merge your own changes."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Foundational briefing\n",
+ "\n",
+ "Here is Git and Github for a PC or Mac audience:\n",
+ "\n",
+ "https://chatgpt.com/share/68061486-08b8-8012-97bc-3264ad5ebcd4"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Pulling latest code\n",
+ "\n",
+ "I regularly add improvements to the course with new examples, exercises and materials.\n",
+ "\n",
+ "Here are instructions for how to bring in the latest - the easy way, and the rigorous way!\n",
+ "\n",
+ "https://chatgpt.com/share/6806178b-0700-8012-836f-7e87b2670b7b"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Contributing your changes to the repo to share your contributions with others\n",
+ "\n",
+ "Here are step by step instructions for submitting a PR.\n",
+ "\n",
+ "I'd be so grateful to include your contributions. It adds value for all other students, and I love to see it myself! As an added benefit, you get recognition in Github as a contributor to the repo. As this course involves building entire repos, I'd suggest that you create a Markdown file or Jupyter Notebook that links to your repo, and include it in community_contributions with a PR.\n",
+ "\n",
+ "Here are detailed instructions and explanations:\n",
+ "\n",
+ "https://chatgpt.com/share/6873c22b-2a1c-8012-bc9a-debdcf7c835b\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "vscode": {
+ "languageId": "plaintext"
+ }
+ },
+ "source": [
+ "### If you'd like to become a Git pro\n",
+ "\n",
+ "If you want to go deep on using Git, here is a brilliant guide. Read this and you will know much more than me!\n",
+ "\n",
+ "https://beej.us/guide/bggit/\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/guides/04_technical_foundations.ipynb b/guides/04_technical_foundations.ipynb
new file mode 100644
index 0000000..f59073f
--- /dev/null
+++ b/guides/04_technical_foundations.ipynb
@@ -0,0 +1,117 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Technical Foundations\n",
+ "\n",
+ "It's crucial that you feel comfortable with the basic technical concepts that we work with. This will make your experience of the entire course so much better - it can be very frustrating if you're not sure what's gong on.\n",
+ "\n",
+ "These guides should build confidence in the underlying technologies we work with."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Topic 1: ChatGPT versus OpenAI API\n",
+ "\n",
+ "### What’s the difference between ChatGPT and the GPT API, both offered by OpenAI?\n",
+ "\n",
+ "#### ChatGPT is an end-user tool. It’s a Chat product designed for consumers who are AI users.\n",
+ "- It has a free plan, and it also has paid subscription plans with more features.\n",
+ "- The subscription plans give the user near-unlimited access to use the Chat product.\n",
+ "\n",
+ "#### The API is a service provided for AI engineers - software engineers and data scientists - working on other commercial products.\n",
+ "- It allows technical people, like you and me, to access the underlying models (like “GPT4.1” and “o3”) so that we can build our own products.\n",
+ "- If we wanted to, we could build our own version of ChatGPT using the API, and charge our end-users for it.\n",
+ "- Like most APIs, OpenAI charges a small amount based on API usage. For most examples on the course using gpt-4o-mini, it’s of the order of $0.001 per API call.\n",
+ "\n",
+ "### I’m paying $20/month for ChatGPT - why do I need to pay more for the API?\n",
+ "\n",
+ "- Hopefully this is now clear. The API is not for consumers; it’s for engineers to build their own platforms that they can charge for.\n",
+ "- If you were to have access to the API based on your subscription, then you could offer ChatGPT tools to others at a cheaper price, and put OpenAI out of business!\n",
+ "- Keep in mind: each API call may require 10,000,000,000,000 floating point calculations - that compute uses electricity!\n",
+ "\n",
+ "Instead of calling the API, you can run open source models locally, but typically they have 1,000 times fewer calculations — and even though it’s tiny, that processing still hits your electricity bill.."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Topic 2: Taking a Screenshot\n",
+ "\n",
+ "You may already be familiar with \"taking a screenshot\" on your computer, but if not (or if you think this means taking a photo with your camera..), please review this tutorial:\n",
+ "\n",
+ "https://chatgpt.com/share/681f691b-6644-8012-b07d-207c68f259d5"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Topic 3: Environment Variables and the `.env` file\n",
+ "\n",
+ "This tutorial walks you through everything you need to know about .env files!\n",
+ "\n",
+ "Obiously you don't need to add the .env file to .gitignore, as I've already done that for you. But it hopefully explains the point well.\n",
+ "\n",
+ "https://chatgpt.com/share/68061e89-dd84-8012-829d-9f4506c7baaa"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Topic 4: Networking basics\n",
+ "\n",
+ "This tutorial covers networking and typical issues with certificates, VPNs, DNS and the like.\n",
+ "\n",
+ "The sections give a summary; you should ask ChatGPT to expand on any section if it's relevant to your situation.\n",
+ "\n",
+ "https://chatgpt.com/share/680620ec-3b30-8012-8c26-ca86693d0e3d\n",
+ "\n",
+ "This is a more in-depth guide to tackling SSL / certificate issues, which is common in corporate environments:\n",
+ "\n",
+ "https://chatgpt.com/share/68c2efc4-0280-8012-933b-5e89d7db6b58"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Topic 5: APIs and Client Libraries - foundational briefing\n",
+ "\n",
+ "We use APIs a lot in this course!\n",
+ "\n",
+ "It's essential to understand the fundamentals of what's going on when we make a call to an API, and to be comfortable with words like \"endpoint\" and \"client library\".\n",
+ "\n",
+ "Please review this guide:\n",
+ "\n",
+ "https://chatgpt.com/share/68062432-43c8-8012-ad91-6311d4ad5858"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Topic 6: uv, package management, environment management\n",
+ "\n",
+ "This lays out the Dependency Management situation and why we love uv! And a crash course in how to use it.\n",
+ "\n",
+ "https://chatgpt.com/share/68c34d46-18a0-8012-8d65-0a0cce615912\n",
+ "\n",
+ "Note that this guide suggests `uv run python xxx` which works fine, but simply `uv run xxx` works too and is more common."
+ ]
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/week1/Guide to Jupyter.ipynb b/guides/05_notebooks.ipynb
similarity index 76%
rename from week1/Guide to Jupyter.ipynb
rename to guides/05_notebooks.ipynb
index ebcc9f0..1e62c38 100644
--- a/week1/Guide to Jupyter.ipynb
+++ b/guides/05_notebooks.ipynb
@@ -5,26 +5,30 @@
"id": "5c291475-8c7c-461c-9b12-545a887b2432",
"metadata": {},
"source": [
- "# Jupyter Lab\n",
+ "# Notebooks in Cursor\n",
"\n",
- "## A Quick Start Guide\n",
+ "This course makes heavy use of a brilliant thing called Notebooks (also known as Jupyter Notebooks or Labs.) Those from a traditional software engineering background may feel discomfort with the \"hacky\" nature of Notebooks, but I must assure you: part of working with AI is being comfortable being a Scientist. As a Scientist, there's a lot of exploration and experimentation. And Notebooks are ideal for this kind of activity.\n",
"\n",
- "Welcome to the wonderful world of Jupyter lab! \n",
- "This is a Data Science playground where you can easily write code and investigate the results. It's an ideal environment for: \n",
+ "A notebook is a file with the extension \".ipynb\" which stands for IPython Notebook, an early name for these.\n",
+ "\n",
+ "## Briefing on Notebooks in Cursor\n",
+ "\n",
+ "First, here's a briefing on how this fits together, and how to create and run a notebook in Cursor:\n",
+ "\n",
+ "https://chatgpt.com/share/6806291a-25f0-8012-a08b-057acb5045ae\n",
+ "\n",
+ "\n",
+ "## A broader guide to Notebooks with examples\n",
+ "\n",
+ "The Notebook is a Data Science playground where you can easily write code and investigate the results. It's an ideal environment for: \n",
"- Research & Development\n",
"- Prototyping\n",
"- Learning (that's us!)\n",
"\n",
- "It's not typically used for shipping production code, and in Week 8 we'll explore the bridge between Jupyter and python code.\n",
- "\n",
- "A file in Jupyter Lab, like this one, is called a **Notebook**.\n",
- "\n",
- "A long time ago, Jupyter used to be called \"IPython\", and so the extensions of notebooks are \".ipynb\" which stands for \"IPython Notebook\".\n",
- "\n",
- "On the left is a File Browser that lets you navigate around the directories and choose different notebooks. But you probably know that already, or you wouldn't have got here!\n",
- "\n",
"The notebook consists of a series of square boxes called \"cells\". Some of them contain text, like this cell, and some of them contain code, like the cell below.\n",
"\n",
+ "First, you may need to click the `Select Kernel` button on the top right, and then pick `venv (Python 3.12.x)` or similar.\n",
+ "\n",
"Click in a cell with code and press `Shift + Return` (or `Shift + Enter`) to run the code and print the output.\n",
"\n",
"Do that now for the cell below this:"
@@ -54,7 +58,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 3,
"id": "585eb9c1-85ee-4c27-8dc2-b4d8d022eda0",
"metadata": {},
"outputs": [],
@@ -90,7 +94,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 6,
"id": "4c5a4e60-b7f4-4953-9e80-6d84ba4664ad",
"metadata": {},
"outputs": [],
@@ -111,7 +115,7 @@
"\n",
"The order that code appears in the notebook doesn't matter. What matters is the order that the code is **executed**. There's a python process sitting behind this notebook in which the variables are being changed.\n",
"\n",
- "This catches some people out when they first use Jupyter."
+ "This catches some people out when they first use notebooks."
]
},
{
@@ -137,7 +141,7 @@
"\n",
"Sitting behind this notebook is a Python process which executes each cell when you run it. That Python process is known as the Kernel. Each notebook has its own separate Kernel.\n",
"\n",
- "You can go to the Kernel menu and select \"Restart Kernel\".\n",
+ "You can click the button above \"Restart Kernel\".\n",
"\n",
"If you then try to run the next cell, you'll get an error, because favorite_fruit is no longer defined. You'll need to run the cells from the top of the notebook again. Then the next cell should run fine."
]
@@ -157,9 +161,9 @@
"id": "4d4188fc-d9cc-42be-8b4e-ae8630456764",
"metadata": {},
"source": [
- "# Adding and moving cells\n",
+ "# Adding and removing cells\n",
"\n",
- "Click in this cell, then click the \\[+\\] button in the toolbar above to create a new cell immediately below this one. Copy and paste in the code in the prior cell, then run it! There are also icons in the top right of the selected cell to delete it (bin), duplicate it, and move it up and down.\n"
+ "Click in this cell, then click the \\[+ Code\\] button in the toolbar above to create a new cell immediately below this one. Copy and paste in the code in the prior cell, then run it! There are also icons in the top right of the selected cell to delete it (bin).\n"
]
},
{
@@ -177,9 +181,9 @@
"source": [
"# Cell output\n",
"\n",
- "When you execute a cell, the standard output and the result of the last statement is written to the area immediately under the code, known as the 'cell output'. When you save a Notebook from the file menu (or command+S), the output is also saved, making it a useful record of what happened.\n",
+ "When you execute a cell, the standard output and the result of the last statement is written to the area immediately under the code, known as the 'cell output'. When you save a Notebook from the file menu (or ctrl+S or command+S), the output is also saved, making it a useful record of what happened.\n",
"\n",
- "You can clean this up by going to Edit menu >> Clear Outputs of All Cells, or Kernel menu >> Restart Kernel and Clear Outputs of All Cells."
+ "You can clean this up by clicking \"Clear All Outputs\" in the toolbar. It's a good idea to clear outputs before you push code to a repo like GitHub, otherwise the files can be large and harder to read."
]
},
{
@@ -202,7 +206,7 @@
"source": [
"# Using markdown\n",
"\n",
- "So what's going on with these areas with writing in them, like this one? Well, there's actually a different kind of cell called a 'Markdown' cell for adding explanations like this. Click the + button to add a cell. Then in the toolbar, click where it says 'Code' and change it to 'Markdown'.\n",
+ "So what's going on with these areas with writing in them, like this one? Well, there's actually a different kind of cell called a 'Markdown' cell for adding explanations like this. Click the [+ Markdown] button to add a new markdown cell.\n",
"\n",
"Add some comments using Markdown format, perhaps copying and pasting from here:\n",
"\n",
@@ -238,7 +242,8 @@
"\n",
"There's a super useful feature of jupyter labs; you can type a command with a ! in front of it in a code cell, like:\n",
"\n",
- "!pip install \\[some_package\\]\n",
+ "!ls \n",
+ "!pwd\n",
"\n",
"And it will run it at the command line (as if in Windows Powershell or Mac Terminal) and print the result"
]
@@ -262,25 +267,11 @@
"metadata": {},
"outputs": [],
"source": [
- "# ping cnn.com - press the stop button in the toolbar when you're bored\n",
+ "# ping cnn.com - press the stop / interrupt button in the toolbar when you're bored\n",
"\n",
"!ping cnn.com"
]
},
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "a58e9462-89a2-4b4f-b4aa-51c4bd9f796b",
- "metadata": {},
- "outputs": [],
- "source": [
- "# This is a useful command that ensures your Anaconda environment \n",
- "# is up to date with any new upgrades to packages;\n",
- "# But it might take a minute and will print a lot to output\n",
- "\n",
- "!conda env update -f ../environment.yml"
- ]
- },
{
"cell_type": "markdown",
"id": "4688baaf-a72c-41b5-90b6-474cb24790a7",
@@ -288,14 +279,14 @@
"source": [
"# Minor things we encounter on the course\n",
"\n",
- "This isn't necessarily a feature of Jupyter, but it's a nice package to know about that is useful in Jupyter Labs, and I use it in the course.\n",
+ "This isn't necessarily a feature of notebooks, but it's a nice package to know about that is useful in notebooks.\n",
"\n",
"The package `tqdm` will print a nice progress bar if you wrap any iterable."
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 12,
"id": "2646a4e5-3c23-4aee-a34d-d623815187d2",
"metadata": {},
"outputs": [],
@@ -348,17 +339,23 @@
"id": "9d14c1fb-3321-4387-b6ca-9af27676f980",
"metadata": {},
"source": [
- "# That's it! You're up to speed on Jupyter Lab.\n",
+ "# That's it! You're up to speed on Notebooks / Labs in Cursor.\n",
"\n",
"## Want to be even more advanced?\n",
"\n",
- "If you want to become a pro at Jupyter Lab, you can read their tutorial [here](https://jupyterlab.readthedocs.io/en/latest/). But this isn't required for our course; just a good technique for hitting Shift + Return and enjoying the result!"
+ "If you want to become a pro at Jupyter Lab (the technology behind this), you can read their tutorial [here](https://jupyterlab.readthedocs.io/en/latest/). But this isn't required for our course; just a good technique for hitting Shift + Return and enjoying the result!"
]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "db6e47b6",
+ "metadata": {},
+ "source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -372,7 +369,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.11"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/guides/06_python_foundations.ipynb b/guides/06_python_foundations.ipynb
new file mode 100644
index 0000000..155c5a9
--- /dev/null
+++ b/guides/06_python_foundations.ipynb
@@ -0,0 +1,97 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "5c291475-8c7c-461c-9b12-545a887b2432",
+ "metadata": {},
+ "source": [
+ "# Foundations of Python and fixing NameErrors\n",
+ "\n",
+ "## First, for a complete beginner\n",
+ "\n",
+ "This introductory tutorial gets you started with the basics.\n",
+ "\n",
+ "https://chatgpt.com/share/68063082-c2d8-8012-8d45-fa674aa1c1ed\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "542f0577-a826-4613-a5d7-4170e9666d04",
+ "metadata": {},
+ "source": [
+ "## Next: a comprehensive briefing on Python\n",
+ "\n",
+ "I'm going to defer to an AI friend for this, because these explanations are so well written with great examples. Copy and paste the code examples into a new cell to give them a try. Pick whichever section(s) you'd like to brush up on.\n",
+ "\n",
+ "**Python imports:** \n",
+ "https://chatgpt.com/share/672f9f31-8114-8012-be09-29ef0d0140fb\n",
+ "\n",
+ "**Python functions** including default arguments: \n",
+ "https://chatgpt.com/share/672f9f99-7060-8012-bfec-46d4cf77d672\n",
+ "\n",
+ "**Python strings**, including slicing, split/join, replace and literals: \n",
+ "https://chatgpt.com/share/672fb526-0aa0-8012-9e00-ad1687c04518\n",
+ "\n",
+ "**Python f-strings** including number and date formatting: \n",
+ "https://chatgpt.com/share/672fa125-0de0-8012-8e35-27918cbb481c\n",
+ "\n",
+ "**Python lists, dicts and sets**, including the `get()` method: \n",
+ "https://chatgpt.com/share/672fa225-3f04-8012-91af-f9c95287da8d\n",
+ "\n",
+ "**Python files** including modes, encoding, context managers, Path, glob.glob: \n",
+ "https://chatgpt.com/share/673b53b2-6d5c-8012-a344-221056c2f960\n",
+ "\n",
+ "**Python classes:** \n",
+ "https://chatgpt.com/share/672fa07a-1014-8012-b2ea-6dc679552715\n",
+ "\n",
+ "**Pickling Python objects and converting to JSON:** \n",
+ "https://chatgpt.com/share/673b553e-9d0c-8012-9919-f3bb5aa23e31"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f9e0f8e1-09b3-478b-ada7-c8c35003929b",
+ "metadata": {},
+ "source": [
+ "## With this in mind - understanding NameErrors in Python\n",
+ "\n",
+ "It's quite common to hit a NameError in python. With foundational knowledge, you should always feel equipped to debug a NameError and get to the bottom of it.\n",
+ "\n",
+ "The most common reason if you're working in a Notebook is that you haven't executed all the cells in order, so the Kernel does not have something defined.\n",
+ "\n",
+ "If you're unsure how to fix a NameError, please see this [initial guide](https://chatgpt.com/share/67958312-ada0-8012-a1d3-62b3a5fcbbfc) and this [second guide with exercises](https://chatgpt.com/share/67a57e0b-0194-8012-bb50-8ea76c5995b8), and work through them both until you have high confidence.\n",
+ "\n",
+ "There's some repetition here, so feel free to skip it if you're already confident.\n",
+ "\n",
+ "After this, a NameError should never give you problems again!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f465c23b",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".venv",
+ "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.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/guides/07_vibe_coding_and_debugging.ipynb b/guides/07_vibe_coding_and_debugging.ipynb
new file mode 100644
index 0000000..485405e
--- /dev/null
+++ b/guides/07_vibe_coding_and_debugging.ipynb
@@ -0,0 +1,65 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Vibe coding and debugging\n",
+ "\n",
+ "\"Vibe coding\" is the affectionate term for coding with the assistance of LLMs. It's particularly easy and wonderful to do with Cursor! But there are some good techniques to make it work well, which I cover on the course. Here are a few essential tips:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "1. If you're prompting an LLM like ChatGPT or Claude to write code, include the current date in your prompt, and instruct the LLM to generate code that uses the latest versions of APIs. This is particularly important with the OpenAI API! ChatGPT frequently tries to use outdated versions of its own API...\n",
+ "\n",
+ "2. Also in your prompts, ask LLMs to keep their code as short and simple as possible. LLMs seem to love to add lots of extra, unnecessary checks that clutters code and makes it hard to find problems.\n",
+ "\n",
+ "3. Ask the same question to multiple LLMs, and pick the answer that is clearest and simplest.\n",
+ "\n",
+ "4. Similar: take the answer from 1 LLM, and ask another LLM to verify it for correctness and whether it could be simpler or clearer.\n",
+ "\n",
+ "5. Ask an LLM to give you 3 variations for ways to solve a problem, and pick the one that is clearest."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Vibe Coding for a larger project"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Try to avoid having an LLM generate 100-200 lines of code or more; it will be so hard for you to debug and figure out what's going wrong (unless you're already knowledgable).\n",
+ "\n",
+ "Instead: start by breaking down your problem into small, independently testable steps, that are each relatively small. If you're not sure how to break down your problem - this is something you can ask the LLM to do!\n",
+ "\n",
+ "Then for each of these building blocks:\n",
+ "- Use the tips above to have the LLM build the code\n",
+ "- Also have the LLM write tests to test and verify the code\n",
+ "- Test it yourself and satisfy yourself that it's working correctly\n",
+ "\n",
+ "This will allow you to build a larger project with confidence.\n",
+ "\n",
+ "## The golden rule: start small, work incrementally!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/guides/08_debugging.ipynb b/guides/08_debugging.ipynb
new file mode 100644
index 0000000..d545446
--- /dev/null
+++ b/guides/08_debugging.ipynb
@@ -0,0 +1,72 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Debugging Survival Guide\n",
+ "\n",
+ "## The key is to consistently reproduce your problem in 5-10 lines of code\n",
+ "\n",
+ "Hitting an exception can sometimes feel quite frustrating, particularly if you're not sure how to approach it. But this is where the best learning happens! Getting to the bottom of hard problems is a great way to learn, and can be quite satisfying.\n",
+ "\n",
+ "But I'm here to help if you can't!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Preliminaries\n",
+ "\n",
+ "Here is a briefing on Exceptions, Stack Traces, Exception Handling and more:\n",
+ "\n",
+ "https://chatgpt.com/share/6806383c-ab38-8012-b21f-61af665bb900\n",
+ "\n",
+ "Also: see [this guide](https://chatgpt.com/share/681f691b-6644-8012-b07d-207c68f259d5) if you're unsure how to take screenshots."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Formula for debugging: recreate in 10 lines of code\n",
+ "\n",
+ "There is an art and a science to great debugging. The best way to pick it up is by practice! But here are the essentials:\n",
+ "\n",
+ "1. Recreate \n",
+ "Reproduce your problem, consistently\n",
+ "\n",
+ "2. Simplify \n",
+ "Reduce your problem down to the simplest possible way to reproduce it. I can't tell you how many people have sent me 100+ lines of code and said \"Ed, this isn't working, please fix it\". That's not how it works! The first thing I would try is to reduce this to the core problem - ideally in 10-20 lines of code or less. In one case, I showed a student how to reproduce it with 2 lines of code!\n",
+ "\n",
+ "_The thing is, it's much easier for **you** to do this than anybody else._ So while it can be tedious, this is almost always the best way to start. Reduce down to a few lines of code. And by the way, when you do that, you often figure out the problem yourself anyway!\n",
+ "\n",
+ "3. Get help \n",
+ "Once you've recreated the problem with just a few lines of code, if you can't see what's happening - you should get help! It's worth asking ChatGPT and friends of course; give them the short example and the full stack trace.\n",
+ "\n",
+ "And reach out to me! I'm here to make your learning experience as awesome as possible and if you are stuck, I will help you get unstuck.\n",
+ "\n",
+ "### The best way to work with me for fastest fixes...\n",
+ "\n",
+ "1. Simplify the problem as much as possible, with an easy way to reproduce\n",
+ "2. Include the full stack trace, and a screenshot not a photo (see [this guide](https://chatgpt.com/share/681f691b-6644-8012-b07d-207c68f259d5) if you're unsure how to take screenshots)\n",
+ "3. Email me at ed@edwarddonner.com. Or best of all: if you've used Google Colab before, this is a really terrific way to share an issue, because it will be identical for me to reproduce, and I can fix it and share the fix with you directly.\n",
+ "\n",
+ "I look forward to helping you!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/guides/09_ai_apis_and_ollama.ipynb b/guides/09_ai_apis_and_ollama.ipynb
new file mode 100644
index 0000000..e0b3c78
--- /dev/null
+++ b/guides/09_ai_apis_and_ollama.ipynb
@@ -0,0 +1,466 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# LLM APIs and Ollama - beyond OpenAI\n",
+ "\n",
+ "_IMPORTANT: If you're not as familiar with APIs in general, and with Environment Variables on your PC or Mac, please review the APIs section in Guide 4 Technical Foundations before proceeding with this guide (topics 3 and 5 in Guide 4)._\n",
+ "\n",
+ "## Crucial context for using models other than OpenAI - please read this first!\n",
+ "\n",
+ "Throughout the course, we use APIs for connecting with the strongest LLMs on the planet.\n",
+ "\n",
+ "The companies behind these LLMs, such as OpenAI, Anthropic, Google and DeepSeek, have built web endpoints. You call their models by making an HTTP request to a Web Address and passing in all the information about your prompts.\n",
+ "\n",
+ "But it would be painful if we needed to build HTTP requests every time we wanted to call an API.\n",
+ "\n",
+ "To make this simple, the team at OpenAI wrote a python utility known as a \"Python Client Library\" which wraps the HTTP call. So you write python code and it calls the web.\n",
+ "\n",
+ "And THAT is what the library `openai` is.\n",
+ "\n",
+ "### What is the `openai` python client library\n",
+ "\n",
+ "It is:\n",
+ "- A lightweight python utility\n",
+ "- Turns your python requests into an HTTP call\n",
+ "- Converts the results coming back from the HTTP call into python objects\n",
+ "\n",
+ "### What it is NOT\n",
+ "\n",
+ "- It's not got any code to actually run a Large Language Model! No GPT code! It just makes a web request\n",
+ "- There's no scientific computing code, and nothing particularly specialized for OpenAI\n",
+ "\n",
+ "### How to use it:\n",
+ "\n",
+ "```python\n",
+ "# Create an OpenAI python client for making web calls to OpenAI\n",
+ "openai = OpenAI()\n",
+ "\n",
+ "# Make the call\n",
+ "response = openai.chat.completions.create(model=\"gpt-4.1-mini\", messages=[{\"role\":\"user\", \"content\": \"what is 2+2?\"}])\n",
+ "\n",
+ "# Print the result\n",
+ "print(response.choices[0].message.content)\n",
+ "```\n",
+ "\n",
+ "### What does this do\n",
+ "\n",
+ "When you make the python call: `openai.chat.completions.create()` \n",
+ "It simply makes a web request to this url: `https://api.openai.com/v1/chat/completions` \n",
+ "And it converts the response to python objects.\n",
+ "\n",
+ "That's it.\n",
+ "\n",
+ "Here's the API documentation if you make [direct web HTTP calls](https://platform.openai.com/docs/guides/text?api-mode=chat&lang=curl) \n",
+ "And here's the same API documentation if you use the [Python Client Library](https://platform.openai.com/docs/guides/text?api-mode=chat&lang=python)\n",
+ "\n",
+ "## With that context - how do I use other LLMs?\n",
+ "\n",
+ "It turns out - it's super easy!\n",
+ "\n",
+ "All the other major LLMs have API endpoints that are compatible with OpenAI.\n",
+ "\n",
+ "And so OpenAI did everyone a favor: they said, hey look - you can all use our utility for converting python to web requests. We'll allow you to change the utility from calling `https://api.openai/com/v1` to calling any web address that you specify.\n",
+ "\n",
+ "And so you can use the OpenAI utility even for calling models that are NOT OpenAI, like this:\n",
+ "\n",
+ "`not_actually_openai = OpenAI(base_url=\"https://somewhere.completely.different/\", api_key=\"another_providers_key\")`\n",
+ "\n",
+ "It's important to appreciate that this OpenAI code is just a utility for making HTTP calls to endpoints. So even though we're using code from the OpenAI team, we can use it to call models other than OpenAI.\n",
+ "\n",
+ "Here are all the OpenAI-compatible endpoints from the major providers. It even includes using Ollama, locally. Ollama provides an endpoint on your local machine, and they made it OpenAI compatible too - very convenient.\n",
+ "\n",
+ "```python\n",
+ "ANTHROPIC_BASE_URL = \"https://api.anthropic.com/v1/\"\n",
+ "DEEPSEEK_BASE_URL = \"https://api.deepseek.com/v1\"\n",
+ "GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
+ "GROK_BASE_URL = \"https://api.x.ai/v1\"\n",
+ "GROQ_BASE_URL = \"https://api.groq.com/openai/v1\"\n",
+ "OPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\"\n",
+ "OLLAMA_BASE_URL = \"http://localhost:11434/v1\"\n",
+ "```\n",
+ "\n",
+ "## Here are examples for Gemini, DeepSeek, Ollama and OpenRouter\n",
+ "\n",
+ "### Example 1: Using Gemini instead of OpenAI\n",
+ "\n",
+ "1. Visit Google Studio to set up an account: https://aistudio.google.com/ \n",
+ "2. Add your key as GOOGLE_API_KEY to your `.env` \n",
+ "3. Also add it a second time as GEMINI_API_KEY to your `.env` - this will be helpful later.\n",
+ "\n",
+ "Then:\n",
+ "\n",
+ "```python\n",
+ "import os\n",
+ "from openai import OpenAI\n",
+ "from dotenv import load_dotenv\n",
+ "load_dotenv(override=True)\n",
+ "\n",
+ "GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
+ "google_api_key = os.getenv(\"GOOGLE_API_KEY\")\n",
+ "gemini = OpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)\n",
+ "response = gemini.chat.completions.create(model=\"gemini-2.5-flash-preview-05-20\", messages=[{\"role\":\"user\", \"content\": \"what is 2+2?\"}])\n",
+ "print(response.choices[0].message.content)\n",
+ "```\n",
+ "\n",
+ "### Example 2: Using DeepSeek API instead of OpenAI (cheap, and only $2 upfront)\n",
+ "\n",
+ "1. Visit DeepSeek API to set up an account: https://platform.deepseek.com/ \n",
+ "2. You will need to add an initial $2 minimum balance. \n",
+ "3. Add your key as DEEPSEEK_API_KEY to your `.env` \n",
+ "\n",
+ "Then:\n",
+ "\n",
+ "```python\n",
+ "import os\n",
+ "from openai import OpenAI\n",
+ "from dotenv import load_dotenv\n",
+ "load_dotenv(override=True)\n",
+ "\n",
+ "DEEPSEEK_BASE_URL = \"https://api.deepseek.com/v1\"\n",
+ "deepseek_api_key = os.getenv(\"DEEPSEEK_API_KEY\")\n",
+ "deepseek = OpenAI(base_url=DEEPSEEK_BASE_URL, api_key=deepseek_api_key)\n",
+ "response = deepseek.chat.completions.create(model=\"deepseek-chat\", messages=[{\"role\":\"user\", \"content\": \"what is 2+2?\"}])\n",
+ "print(response.choices[0].message.content)\n",
+ "```\n",
+ "\n",
+ "### Example 3: Using Ollama to be free and local instead of OpenAI\n",
+ "\n",
+ "Ollama allows you to run models locally; it provides an OpenAI compatible API on your machine. \n",
+ "There's no API key for Ollama; there's no third party with your credit card, so no need for any kind of key.\n",
+ "\n",
+ "1. If you're new to Ollama, install it by following the instructions here: https://ollama.com \n",
+ "2. Then in a Cursor Terminal, do `ollama run llama3.2` to chat with Llama 3.2 \n",
+ "BEWARE: do not use llama3.3 or llama4 - these are massive models not designed for home computing! They will fill up your disk. \n",
+ "\n",
+ "Then:\n",
+ "\n",
+ "```python\n",
+ "!ollama pull llama3.2\n",
+ "\n",
+ "from openai import OpenAI\n",
+ "\n",
+ "OLLAMA_BASE_URL = \"http://localhost:11434/v1\"\n",
+ "ollama = OpenAI(base_url=OLLAMA_BASE_URL, api_key=\"anything\")\n",
+ "response = ollama.chat.completions.create(model=\"llama3.2\", messages=[{\"role\":\"user\", \"content\": \"what is 2+2?\"}])\n",
+ "print(response.choices[0].message.content)\n",
+ "```\n",
+ "\n",
+ "### Example 4: Using the popular service [OpenRouter](https://openrouter.ai) which has an easier billing process instead of OpenAI\n",
+ "\n",
+ "OpenRouter is very convenient: it gives you free access to many models, and easy access with small upfront to paid models.\n",
+ "\n",
+ "1. Sign up at https://openrouter.ai\n",
+ "2. Add the minimum upfront balance as needed\n",
+ "3. Add your key as OPENROUTER_API_KEY to your `.env` file\n",
+ "\n",
+ "Then:\n",
+ "\n",
+ "```python\n",
+ "import os\n",
+ "from openai import OpenAI\n",
+ "from dotenv import load_dotenv\n",
+ "load_dotenv(override=True)\n",
+ "\n",
+ "OPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\"\n",
+ "openrouter_api_key = os.getenv(\"OPENROUTER_API_KEY\")\n",
+ "openrouter = OpenAI(base_url=OPENROUTER_BASE_URL, api_key=openrouter_api_key)\n",
+ "response = openrouter.chat.completions.create(model=\"openai/gpt-4.1-nano\", messages=[{\"role\":\"user\", \"content\": \"what is 2+2?\"}])\n",
+ "print(response.choices[0].message.content)\n",
+ "```\n",
+ "\n",
+ "\n",
+ "### Using different API providers with Agent Frameworks\n",
+ "\n",
+ "The Agent Frameworks make it easy to switch between these providers. You can switch LLMs and pick different ones at any point in the course. There are more notes below on each of them. For OpenAI Agents SDK, see a section later in this notebook. For CrewAI, we cover it on the course, but it's easy: just use the full path to the model that LiteLLM expects."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Costs of APIs\n",
+ "\n",
+ "The cost of each API call is very low indeed - most calls to models we use on this course are fractions of cents.\n",
+ "\n",
+ "But it's extremely important to note:\n",
+ "\n",
+ "1. A complex Agentic project could involve many LLM calls - perhaps 20-30 - and so it can add up. It's important to set limits and monitor usage.\n",
+ "\n",
+ "2. With Agentic AI, there is a risk of Agents getting into a loop or carrying out more processing than intended. You should monitor your API usage, and never put more budget than you are comfortable with. Some APIs have an \"auto-refill\" setting that can charge automatically to your card - I strongly recommend you keep this off.\n",
+ "\n",
+ "3. You should only spend what you are comfortable with. There is a free alternative in Ollama that you can use as a replacement if you wish. DeepSeek, Gemini 2.5 Flash and gpt-4.1-nano are significantly cheaper.\n",
+ "\n",
+ "Keep in mind that these LLM calls typically involve trillions of floating point calculations - someone has to pay the electricity bills!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Ollama: Free alternative to Paid APIs (but please see Warning about llama version)\n",
+ "\n",
+ "Ollama is a product that runs locally on your machine. It can run open-source models, and it provides an API endpoint on your computer that is compatible with OpenAI.\n",
+ "\n",
+ "First, download Ollama by visiting:\n",
+ "https://ollama.com\n",
+ "\n",
+ "Then from your Terminal in Cursor (View menu >> Terminal), run this command to download a model:\n",
+ "\n",
+ "```shell\n",
+ "ollama pull llama3.2\n",
+ "```\n",
+ "\n",
+ "WARNING: Be careful not to use llama3.3 or llama4 - these are much larger models that are not suitable for home computers.\n",
+ "\n",
+ "And now, any time that we have code like: \n",
+ "`openai = OpenAI()` \n",
+ "You can use this as a direct replacement: \n",
+ "`openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')` \n",
+ "And also replace model names like **gpt-4o-mini** with **llama3.2**. \n",
+ "\n",
+ "You don't need to put anything in your .env file for this; with Ollama, everything is running on your computer. You're not calling out to a third party on the cloud, nobody has your credit card details, so there's no need for a secret key! The code `api_key='ollama'` above is only required because the OpenAI client library expects an api_key to be passed in, but the value is ignored by Ollama.\n",
+ "\n",
+ "Below is a full example:\n",
+ "\n",
+ "```python\n",
+ "# You need to do this one time on your computer\n",
+ "!ollama pull llama3.2\n",
+ "\n",
+ "from openai import OpenAI\n",
+ "MODEL = \"llama3.2\"\n",
+ "openai = OpenAI(base_url=\"http://localhost:11434/v1\", api_key=\"ollama\")\n",
+ "\n",
+ "response = openai.chat.completions.create(\n",
+ " model=MODEL,\n",
+ " messages=[{\"role\": \"user\", \"content\": \"What is 2 + 2?\"}]\n",
+ ")\n",
+ "\n",
+ "print(response.choices[0].message.content)\n",
+ "```\n",
+ "\n",
+ "You will need to make similar changes to use Ollama within any of the Agent Frameworks - you should be able to google for an exact example, or ask me."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### OpenRouter: Convenient gateway platform for OpenAI and others\n",
+ "\n",
+ "OpenRouter is a third party service that allows you to connect to a wide range of LLMs, including OpenAI.\n",
+ "\n",
+ "It's known for having a simpler billing process that may be easier for some countries outside the US.\n",
+ "\n",
+ "First, check out their website: \n",
+ "https://openrouter.ai/\n",
+ "\n",
+ "Then, take a peak at their quickstart: \n",
+ "https://openrouter.ai/docs/quickstart\n",
+ "\n",
+ "And add your key to your .env file: \n",
+ "```shell\n",
+ "OPENROUTER_API_KEY=sk-or....\n",
+ "```\n",
+ "\n",
+ "And now, any time you have code like this: \n",
+ "```python\n",
+ "MODEL = \"gpt-4o-mini\"\n",
+ "openai = OpenAI()\n",
+ "```\n",
+ "\n",
+ "You can replace it with code like this:\n",
+ "\n",
+ "```python\n",
+ "MODEL = \"openai/gpt-4o-mini\"\n",
+ "openrouter_api_key = os.getenv(\"OPENROUTER_API_KEY\")\n",
+ "openai = OpenAI(base_url=\"https://openrouter.ai/api/v1\", api_key=openrouter_api_key)\n",
+ "\n",
+ "response = openai.chat.completions.create(\n",
+ " model=MODEL,\n",
+ " messages=[{\"role\": \"user\", \"content\": \"What is 2 + 2?\"}]\n",
+ ")\n",
+ "\n",
+ "print(response.choices[0].message.content)\n",
+ "```\n",
+ "\n",
+ "You will need to make similar changes to use OpenRouter within any of the Agent Frameworks - you should be able to google for an exact example, or ask me."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## OpenAI Agents SDK - specific instructions\n",
+ "\n",
+ "With OpenAI Agents SDK (weeks 2 and 6), it's particularly easy to use any model provided by OpenAI themselves. Simply pass in the model name:\n",
+ "\n",
+ "`agent = Agent(name=\"Jokester\", instructions=\"You are a joke teller\", model=\"gpt-4o-mini\")`\n",
+ "\n",
+ "You can also substitute in any other provider with an OpenAI compatible API. You do it in 3 steps like this:\n",
+ "\n",
+ "```python\n",
+ "DEEPSEEK_BASE_URL = \"https://api.deepseek.com/v1\"\n",
+ "deepseek_client = AsyncOpenAI(base_url=DEEPSEEK_BASE_URL, api_key=deepseek_api_key)\n",
+ "deepseek_model = OpenAIChatCompletionsModel(model=\"deepseek-chat\", openai_client=deepseek_client)\n",
+ "```\n",
+ "\n",
+ "And then you simply provide this model when you create an Agent.\n",
+ "\n",
+ "`agent = Agent(name=\"Jokester\", instructions=\"You are a joke teller\", model=deepseek_model)`\n",
+ "\n",
+ "And you can use a similar approach for any other OpenAI compatible API, with the same 3 steps:\n",
+ "\n",
+ "```python\n",
+ "# extra imports\n",
+ "from agents import OpenAIChatCompletionsModel\n",
+ "from openai import AsyncOpenAI\n",
+ "\n",
+ "# Step 1: specify the base URL endpoints where the provider offers an OpenAI compatible API\n",
+ "GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
+ "GROK_BASE_URL = \"https://api.x.ai/v1\"\n",
+ "GROQ_BASE_URL = \"https://api.groq.com/openai/v1\"\n",
+ "OPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\"\n",
+ "OLLAMA_BASE_URL = \"http://localhost:11434/v1\"\n",
+ "\n",
+ "# Step 2: Create an AsyncOpenAI object for that endpoint\n",
+ "gemini_client = AsyncOpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)\n",
+ "grok_client = AsyncOpenAI(base_url=GROK_BASE_URL, api_key=grok_api_key)\n",
+ "groq_client = AsyncOpenAI(base_url=GROQ_BASE_URL, api_key=groq_api_key)\n",
+ "openrouter_client = AsyncOpenAI(base_url=OPENROUTER_BASE_URL, api_key=openrouter_api_key)\n",
+ "ollama_client = AsyncOpenAI(base_url=OLLAMA_BASE_URL, api_key=\"ollama\")\n",
+ "\n",
+ "# Step 3: Create a model object to provide when creating an Agent\n",
+ "gemini_model = OpenAIChatCompletionsModel(model=\"gemini-2.5-flash\", openai_client=gemini_client)\n",
+ "grok_3_model = OpenAIChatCompletionsModel(model=\"grok-3-mini-beta\", openai_client=openrouter_client)\n",
+ "llama3_3_model = OpenAIChatCompletionsModel(model=\"llama-3.3-70b-versatile\", openai_client=groq_client)\n",
+ "grok_3_via_openrouter_model = OpenAIChatCompletionsModel(model=\"x-ai/grok-3-mini-beta\", openai_client=openrouter_client)\n",
+ "llama_3_2_local_model = OpenAIChatCompletionsModel(model=\"llama3.2\", openai_client=ollama_client)\n",
+ "```\n",
+ "\n",
+ "### To use Azure with OpenAI Agents SDK\n",
+ "\n",
+ "See instructions here: \n",
+ "https://techcommunity.microsoft.com/blog/azure-ai-services-blog/use-azure-openai-and-apim-with-the-openai-agents-sdk/4392537\n",
+ "\n",
+ "Such as this:\n",
+ "```python\n",
+ "from openai import AsyncAzureOpenAI\n",
+ "from agents import set_default_openai_client\n",
+ "from dotenv import load_dotenv\n",
+ "import os\n",
+ " \n",
+ "# Load environment variables\n",
+ "load_dotenv()\n",
+ " \n",
+ "# Create OpenAI client using Azure OpenAI\n",
+ "openai_client = AsyncAzureOpenAI(\n",
+ " api_key=os.getenv(\"AZURE_OPENAI_API_KEY\"),\n",
+ " api_version=os.getenv(\"AZURE_OPENAI_API_VERSION\"),\n",
+ " azure_endpoint=os.getenv(\"AZURE_OPENAI_ENDPOINT\"),\n",
+ " azure_deployment=os.getenv(\"AZURE_OPENAI_DEPLOYMENT\")\n",
+ ")\n",
+ " \n",
+ "# Set the default OpenAI client for the Agents SDK\n",
+ "set_default_openai_client(openai_client)\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## CrewAI setup\n",
+ "\n",
+ "Here's Crew's docs for LLM connections with the model names to use for all models. As student Sadan S. pointed out (thank you!), it's worth knowing that for Google you need to use the environment variable `GEMINI_API_KEY` instead of `GOOGLE_API_KEY`:\n",
+ "\n",
+ "https://docs.crewai.com/concepts/llms\n",
+ "\n",
+ "And here's their tutorial with some more info:\n",
+ "\n",
+ "https://docs.crewai.com/how-to/llm-connections"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## LangGraph setup\n",
+ "\n",
+ "To use LangGraph with Ollama (and follow similar for other models): \n",
+ "https://python.langchain.com/docs/integrations/chat/ollama/#installation\n",
+ "\n",
+ "First add the package: \n",
+ "`uv add langchain-ollama`\n",
+ "\n",
+ "Then in the lab, make this replacement: \n",
+ "```python\n",
+ "from langchain_ollama import ChatOllama\n",
+ "# llm = ChatOpenAI(model=\"gpt-4o-mini\")\n",
+ "llm = ChatOllama(model=\"gemma3:4b\")\n",
+ "```\n",
+ "\n",
+ "And obviously run `!ollama pull gemma3:4b` (or whichever model) beforehand.\n",
+ "\n",
+ "Many thanks to Miroslav P. for adding this, and to Arvin F. for the question!\n",
+ "\n",
+ "## LangGraph with other models\n",
+ "\n",
+ "Just follow the same recipe as above, but use any of the models from here: \n",
+ "https://python.langchain.com/docs/integrations/chat/\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## AutoGen with other models\n",
+ "\n",
+ "Here's another contribution from Miroslav P. (thank you!) for using Ollama + local models with AutoGen, and Miroslav has a great example showing gemma3 performing well.\n",
+ "\n",
+ "```python\n",
+ "# model_client = OpenAIChatCompletionClient(model=\"gpt-4o-mini\")\n",
+ " \n",
+ "from autogen_ext.models.ollama import OllamaChatCompletionClient\n",
+ " \n",
+ "model_client = OllamaChatCompletionClient(\n",
+ " model=\"gemma3:4b\",\n",
+ " model_info={\n",
+ " \"vision\": True,\n",
+ " \"function_calling\": False,\n",
+ " \"json_output\": True,\n",
+ " \"family\": \"unknown\",\n",
+ " },\n",
+ ")\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Worth keeping in mind\n",
+ "\n",
+ "1. If you wish to use Ollama to run models locally, you may find that smaller models struggle with the more advanced projects. You'll need to experiment with different model sizes and capabilities, and plenty of patience may be needed to find something that works well. I expect several of our projects are too challenging for llama3.2. As an alternative, consider the free models on openrouter.ai, or the very cheap models that are almost free - like DeepSeek.\n",
+ "\n",
+ "2. Chat models often do better than Reasoning models because Reasoning models can \"over-think\" some assignments. It's important to experiment. Bigger isn't always better...\n",
+ "\n",
+ "3. It's confusing, but there are 2 different providers that sound similar! \n",
+ "- Grok is the LLM from Elon Musk's X\n",
+ "- Groq is a platform for fast inference of open source models\n",
+ "\n",
+ "A student pointed out to me that \"Groq\" came first!\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/week1/Intermediate Python.ipynb b/guides/10_intermediate_python.ipynb
similarity index 81%
rename from week1/Intermediate Python.ipynb
rename to guides/10_intermediate_python.ipynb
index aaaa0e3..41ea63d 100644
--- a/week1/Intermediate Python.ipynb
+++ b/guides/10_intermediate_python.ipynb
@@ -7,63 +7,15 @@
"source": [
"# Intermediate Level Python\n",
"\n",
- "## Getting you up to speed\n",
+ "## A briefing on more advanced features of Python\n",
"\n",
- "This course assumes that you're at an intermediate level of python. For example, you should have a decent idea what something like this might do:\n",
+ "This section assumes you're up to speed on the foundations - and now we cover some important features of python that we use on the course.\n",
"\n",
- "`yield from {book.get(\"author\") for book in books if book.get(\"author\")}`\n",
- "\n",
- "If not - then you've come to the right place! Welcome to the crash course in intermediate level python. The best way to learn is by doing!\n"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "542f0577-a826-4613-a5d7-4170e9666d04",
- "metadata": {},
- "source": [
- "## First: if you need a refresher on the foundations\n",
- "\n",
- "I'm going to defer to an AI friend for this, because these explanations are so well written with great examples. Copy and paste the code examples into a new cell to give them a try. Pick whichever section(s) you'd like to brush up on.\n",
- "\n",
- "**Python imports:** \n",
- "https://chatgpt.com/share/672f9f31-8114-8012-be09-29ef0d0140fb\n",
- "\n",
- "**Python functions** including default arguments: \n",
- "https://chatgpt.com/share/672f9f99-7060-8012-bfec-46d4cf77d672\n",
- "\n",
- "**Python strings**, including slicing, split/join, replace and literals: \n",
- "https://chatgpt.com/share/672fb526-0aa0-8012-9e00-ad1687c04518\n",
- "\n",
- "**Python f-strings** including number and date formatting: \n",
- "https://chatgpt.com/share/672fa125-0de0-8012-8e35-27918cbb481c\n",
- "\n",
- "**Python lists, dicts and sets**, including the `get()` method: \n",
- "https://chatgpt.com/share/672fa225-3f04-8012-91af-f9c95287da8d\n",
- "\n",
- "**Python files** including modes, encoding, context managers, Path, glob.glob: \n",
- "https://chatgpt.com/share/673b53b2-6d5c-8012-a344-221056c2f960\n",
- "\n",
- "**Python classes:** \n",
- "https://chatgpt.com/share/672fa07a-1014-8012-b2ea-6dc679552715\n",
- "\n",
- "**Pickling Python objects and converting to JSON:** \n",
- "https://chatgpt.com/share/673b553e-9d0c-8012-9919-f3bb5aa23e31"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "f9e0f8e1-09b3-478b-ada7-c8c35003929b",
- "metadata": {},
- "source": [
- "## With this in mind - understanding NameErrors in Python\n",
- "\n",
- "It's quite common to hit a NameError in python. With foundational knowledge, you should always feel equipped to debug a NameError and get to the bottom of it.\n",
- "\n",
- "If you're unsure how to fix a NameError, please see this [initial guide](https://chatgpt.com/share/67958312-ada0-8012-a1d3-62b3a5fcbbfc) and this [second guide with exercises](https://chatgpt.com/share/67a57e0b-0194-8012-bb50-8ea76c5995b8), and work through them both until you have high confidence.\n",
- "\n",
- "There's some repetition here, so feel free to skip it if you're already confident.\n",
- "\n",
- "## And now, on to the code!"
+ "1. Comprehensions \n",
+ "2. Generators \n",
+ "3. Sub-classes, Type Hints, Pydantic \n",
+ "4. Decorators\n",
+ "5. Docker (not really python, but we use it to run python code!)\n"
]
},
{
@@ -454,17 +406,61 @@
"id": "35760406-fe6c-41f9-b0c0-3e8cf73aafd0",
"metadata": {},
"source": [
- "# Finally\n",
+ "# Part 3: Sub-classes, Type Hints, Pydantic\n",
"\n",
"Here are some intermediate level details of Classes from our AI friend, including use of type hints, inheritance and class methods. This includes a Book example.\n",
"\n",
- "https://chatgpt.com/share/67348aca-65fc-8012-a4a9-fd1b8f04ba59"
+ "https://chatgpt.com/share/67348aca-65fc-8012-a4a9-fd1b8f04ba59\n",
+ "\n",
+ "And here is a comprehensive tutorial on Pydantic classes covering everything you need to know about Pydantic.\n",
+ "\n",
+ "https://chatgpt.com/share/68064537-6cfc-8012-93e1-f7dd0932f321"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6bbc9c63",
+ "metadata": {},
+ "source": [
+ "## Part 4: Decorators\n",
+ "\n",
+ "Here is a briefing, with an example from OpenAI Agents SDK:\n",
+ "\n",
+ "https://chatgpt.com/share/6806474d-3880-8012-b2a2-87b3ee4489da"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0beef7e9",
+ "metadata": {},
+ "source": [
+ "## Part 5: Docker\n",
+ "\n",
+ "Here is a convenient tutorial to introduce Docker.\n",
+ "\n",
+ "In the last section, this also covers an answer to a question in Week 6 - what does it mean to run an MCP server in Docker? But you can ignore this question if you're not on week 6 yet.\n",
+ "\n",
+ "https://chatgpt.com/share/6814bc1d-2f3c-8012-9b18-dddc82ea421b"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "73e215b2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# You need to install docker to run this example\n",
+ "# This will download the Docker image for python 3.12, create a container,\n",
+ "# Run some python code and print the result\n",
+ "\n",
+ "!docker run --rm python:3.12 python -c \"print(2 + 2)\""
]
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -478,7 +474,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.11"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/guides/11_async_python.ipynb b/guides/11_async_python.ipynb
new file mode 100644
index 0000000..7860c5d
--- /dev/null
+++ b/guides/11_async_python.ipynb
@@ -0,0 +1,156 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "5c291475-8c7c-461c-9b12-545a887b2432",
+ "metadata": {},
+ "source": [
+ "# Async Python\n",
+ "\n",
+ "## A briefing on asynchronous python coding, essential in Agent engineering"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "538fa044",
+ "metadata": {},
+ "source": [
+ "Here is a masterful tutorial by you-know-who with exercises and comparisons.\n",
+ "\n",
+ "https://chatgpt.com/share/680648b1-b0a0-8012-8449-4f90b540886c\n",
+ "\n",
+ "This includes how to run async code from a python module.\n",
+ "\n",
+ "### And now some examples:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "09f5662a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Let's define an async function\n",
+ "\n",
+ "import asyncio\n",
+ "\n",
+ "async def do_some_work():\n",
+ " print(\"Starting work\")\n",
+ " await asyncio.sleep(1)\n",
+ " print(\"Work complete\")\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "07ab3abf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# What will this do?\n",
+ "\n",
+ "do_some_work()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6d681b6d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# OK let's try that again!\n",
+ "\n",
+ "await do_some_work()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ea867090",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# What's wrong with this?\n",
+ "\n",
+ "async def do_a_lot_of_work():\n",
+ " do_some_work()\n",
+ " do_some_work()\n",
+ " do_some_work()\n",
+ "\n",
+ "await do_a_lot_of_work()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e9c75c3f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Interesting warning! Let's fix it\n",
+ "\n",
+ "async def do_a_lot_of_work():\n",
+ " await do_some_work()\n",
+ " await do_some_work()\n",
+ " await do_some_work()\n",
+ "\n",
+ "await do_a_lot_of_work()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "720cf3f5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# And now let's do it in parallel\n",
+ "# It's important to recognize that this is not \"multi-threading\" in the way that you may be used to\n",
+ "# The asyncio library is running on a single thread, but it's using a loop to switch between tasks while one is waiting\n",
+ "\n",
+ "async def do_a_lot_of_work_in_parallel():\n",
+ " await asyncio.gather(do_some_work(), do_some_work(), do_some_work())\n",
+ "\n",
+ "await do_a_lot_of_work_in_parallel()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "230f85de",
+ "metadata": {},
+ "source": [
+ "### Finally - try writing a python module that calls do_a_lot_of_work_in_parallel\n",
+ "\n",
+ "See the link at the top; you'll need something like this in your module:\n",
+ "\n",
+ "```python\n",
+ "if __name__ == \"__main__\":\n",
+ " asyncio.run(do_a_lot_of_work_in_parallel())\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".venv",
+ "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.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/guides/12_starting_your_project.ipynb b/guides/12_starting_your_project.ipynb
new file mode 100644
index 0000000..eeea7e4
--- /dev/null
+++ b/guides/12_starting_your_project.ipynb
@@ -0,0 +1,97 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## How to start working on your idea\n",
+ "\n",
+ "So you've had an idea for something you'd like to build.\n",
+ "\n",
+ "CONGRATULATIONS! That's the most important part already done. The idea is everything!\n",
+ "\n",
+ "But now you're unsure where to begin. I get a lot of questions about this.\n",
+ "\n",
+ "I want to give you three essential pieces of advice.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Advice 1: Be a Scientist\n",
+ "\n",
+ "Being an AI Engineer involves wearing 2 hats: being a Software Engineer, and a Data Scientist.\n",
+ "\n",
+ "At the start of your project, it's crucial to take off your Software Engineering hat and firmly put on your Data Science hat.\n",
+ "\n",
+ "A lot of people from a software engineering background (myself included!) struggle with this. It's common for people to fall into their comfort zone, asking questions about architecture, design, data pipes, scalability, deployment.\n",
+ "\n",
+ "These are all great questions, but they are not the critical ones at this early stage. They are not the hard questions. They won't make or break your idea.\n",
+ "\n",
+ "For the critical questions, you need to be a Scientist.\n",
+ "\n",
+ "Ask yourself: \n",
+ "1. How will you evaluate success of your model? What will you measure? \n",
+ "2. What data do you have, and what data do you need? \n",
+ "3. How can you build small prototypes to test different techniques and understand model performance?\n",
+ "\n",
+ "Address the science questions first - what you can achieve with LLMs and how.\n",
+ "\n",
+ "And I recommend starting in a Notebook before you work in python modules, to force yourself to operate with this scientific mindset.\n",
+ "\n",
+ "This is even more crucial with Agent projects. It can be tempting to draw up a big Agent architecture diagram on how your agents will collaborate, like a technical diagram. But this is thinking like a Software Engineer. I recommend approaching it differently; experiment with different approaches, investigate what works well, test hypotheses and iterate."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Advice 2: Embrace R&D\n",
+ "\n",
+ "OK so this is pretty similar to Advice 1, but worth repeating!\n",
+ "\n",
+ "I often get asked questions like: \"Ed, I want to build the following solution. Should I use model A, B, or C? Should I use Agents, RAG or fine-tuning?\"\n",
+ "\n",
+ "My answer is almost always: \n",
+ "- You should do all of the above! The key is to experiment; (a) come up with an evaluation criteria, (b) develop a curated dataset, (c) test different ideas and see how they perform\n",
+ "- I often have an instinct for which will work best, but my instinct is often wrong! Don't trust me: try it yourself \n",
+ "- There's simply no substitute for experimentation."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Advice 3: Dream big but start SMALL!\n",
+ "\n",
+ "I also often have students send me 200-300 lines of code saying, \"Ed, this isn't performing, please fix it\". 😂\n",
+ "\n",
+ "As I say in the debugging guide - that's not how it works!\n",
+ "\n",
+ "When starting projects, it's crucial to start small and simple. Perfect every prompt; work in detail on every step. Satisfy yourself that each LLM call is performing as you wish, and iterate on the inputs until responses are consistent and reliable.\n",
+ "\n",
+ "If you always work incrementally and with small, testable building blocks, you should have complete clarity on what's going on.\n",
+ "\n",
+ "And of course, I love helping people with projects and it's great to help fix problems. But if you approach your project incrementally, you should always have clarity on exactly what isn't performing - and then it's super efficient for me to help you."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# In summary\n",
+ "\n",
+ "You probably noticed the common theme through these 3 pieces of advice. It can feel jarring for people from a non-Data Science background to approach problems in such an ad-hoc way; it feels \"hacky\" and unsatisfying. But in my opinion, this is the single most important skill to acquire to be a successful AI engineer: being comfortable with uncertainty, enjoying the experiments, and embracing being a Scientist."
+ ]
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/guides/13_frontend.ipynb b/guides/13_frontend.ipynb
new file mode 100644
index 0000000..55fa851
--- /dev/null
+++ b/guides/13_frontend.ipynb
@@ -0,0 +1,55 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "695d0c99",
+ "metadata": {},
+ "source": [
+ "# Your frontend crash course\n",
+ "\n",
+ "Here is a seven part series developed by you-know-who under my direction. It's very nicely done! You should take this in any direction you like.\n",
+ "\n",
+ "ChatGPT has written these in note form for someone who wants to experiment; you should ask it to rewrite in a more verbose way if you'd prefer deeper explanations.\n",
+ "\n",
+ "1. Refresher on modern HTML, CSS and JavaScript\n",
+ "\n",
+ "https://chatgpt.com/share/68c345ee-ae34-8012-9a05-0ce43a816f9c\n",
+ "\n",
+ "2. Modern JavaScript\n",
+ "\n",
+ "https://chatgpt.com/share/68c3495f-0c94-8012-b048-db1670aefa47\n",
+ "\n",
+ "3. From JavaScript to TypeScript\n",
+ "\n",
+ "https://chatgpt.com/share/68c34974-b768-8012-9926-5a9ed67d59c3\n",
+ "\n",
+ "4. React (TypeScript) basics\n",
+ "\n",
+ "https://chatgpt.com/share/68c3498d-e340-8012-b3a3-37a28802db6a\n",
+ "\n",
+ "5. React - state, props, hooks\n",
+ "\n",
+ "https://chatgpt.com/share/68c349c7-e75c-8012-b1e5-b4f51bb0e27c\n",
+ "\n",
+ "6. NextJS introduction\n",
+ "\n",
+ "https://chatgpt.com/share/68c349e7-e740-8012-8f0c-ba40ad7e148d\n",
+ "\n",
+ "7. NextJS rendering models and Tailwind\n",
+ "\n",
+ "https://chatgpt.com/share/68c34a13-3120-8012-9a67-f53d7a0cfc99\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/guides/14_docker_terraform.ipynb b/guides/14_docker_terraform.ipynb
new file mode 100644
index 0000000..c2dc469
--- /dev/null
+++ b/guides/14_docker_terraform.ipynb
@@ -0,0 +1,33 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "303a5c4f",
+ "metadata": {},
+ "source": [
+ "# Briefings on Docker and Terraform\n",
+ "\n",
+ "Here's a mutual friend giving an excellent self-study tutorial on Docker essentials:\n",
+ "\n",
+ "https://chatgpt.com/share/68c34f21-07bc-8012-b411-35cc97aff6ab\n",
+ "\n",
+ "And here is an equally excellent overview of Terraform to get you building infrastructure with code like a pro. No more AWS console!\n",
+ "\n",
+ "https://chatgpt.com/share/68c3513a-c194-8012-85c3-c0ea9143af5a"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6fe933fd",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..fc8112c
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,46 @@
+[project]
+name = "llm-engineering"
+version = "0.1.0"
+requires-python = ">=3.12"
+dependencies = [
+ "anthropic>=0.69.0",
+ "beautifulsoup4>=4.14.2",
+ "chromadb>=1.1.0",
+ "datasets==3.6.0",
+ "feedparser>=6.0.12",
+ "google-genai>=1.41.0",
+ "google-generativeai>=0.8.5",
+ "gradio>=5.47.2",
+ "ipykernel>=6.30.1",
+ "ipywidgets>=8.1.7",
+ "jupyter-dash>=0.4.2",
+ "langchain>=0.3.27",
+ "langchain-chroma>=0.2.6",
+ "langchain-community>=0.3.30",
+ "langchain-core>=0.3.76",
+ "langchain-openai>=0.3.33",
+ "langchain-text-splitters>=0.3.11",
+ "litellm>=1.77.5",
+ "matplotlib>=3.10.6",
+ "modal>=1.1.4",
+ "numpy>=2.3.3",
+ "ollama>=0.6.0",
+ "openai>=1.109.1",
+ "pandas>=2.3.3",
+ "plotly>=6.3.0",
+ "protobuf==3.20.2",
+ "psutil>=7.1.0",
+ "pydub>=0.25.1",
+ "python-dotenv>=1.1.1",
+ "requests>=2.32.5",
+ "scikit-learn>=1.7.2",
+ "scipy>=1.16.2",
+ "sentence-transformers>=5.1.1",
+ "setuptools>=80.9.0",
+ "speedtest-cli>=2.1.3",
+ "tiktoken>=0.11.0",
+ "torch>=2.8.0",
+ "tqdm>=4.67.1",
+ "transformers>=4.56.2",
+ "wandb>=0.22.1",
+]
diff --git a/requirements.txt b/requirements.txt
index 9d62d7d..f326741 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
python-dotenv
-jupyterlab
+ipykernel
ipywidgets
requests
numpy
@@ -7,7 +7,6 @@ pandas
scipy
scikit-learn
matplotlib
-gensim
torch
transformers
tqdm
diff --git a/SETUP-PC.md b/setup/SETUP-PC.md
similarity index 98%
rename from SETUP-PC.md
rename to setup/SETUP-PC.md
index 2ca8bbd..c1d2ee9 100644
--- a/SETUP-PC.md
+++ b/setup/SETUP-PC.md
@@ -2,6 +2,8 @@
## Setup instructions for Windows
+**These are the original instructions for the original version of the videos from before October 2025. For the new version, see [SETUP-new.md](SETUP-new.md).**
+
Welcome, PC people!
I should confess up-front: setting up a powerful environment to work at the forefront of AI is not as simple as I'd like. For most people these instructions will go great; but in some cases, for whatever reason, you'll hit a problem. Please don't hesitate to reach out - I am here to get you up and running quickly. There's nothing worse than feeling _stuck_. Message me, email me or LinkedIn message me and I will unstick you quickly!
diff --git a/SETUP-linux.md b/setup/SETUP-linux.md
similarity index 97%
rename from SETUP-linux.md
rename to setup/SETUP-linux.md
index 892a7f9..00424cc 100644
--- a/SETUP-linux.md
+++ b/setup/SETUP-linux.md
@@ -1,6 +1,8 @@
# LLM Engineering - Master AI and LLMs
-## Setup instructions for Linux
+## Original Setup instructions for Linux
+
+**These are the original instructions for the original version of the videos from before October 2025. For the new version, see [SETUP-new.md](SETUP-new.md).**
Welcome, Linux people!
diff --git a/SETUP-mac.md b/setup/SETUP-mac.md
similarity index 98%
rename from SETUP-mac.md
rename to setup/SETUP-mac.md
index ec65630..3d0932a 100644
--- a/SETUP-mac.md
+++ b/setup/SETUP-mac.md
@@ -1,6 +1,8 @@
# LLM Engineering - Master AI and LLMs
-## Setup instructions for Mac
+## Original Setup instructions for Mac
+
+**These are the original instructions for the original version of the videos from before October 2025. For the new version, see [SETUP-new.md](SETUP-new.md).**
Welcome, Mac people!
diff --git a/setup/SETUP-new.md b/setup/SETUP-new.md
new file mode 100644
index 0000000..605b148
--- /dev/null
+++ b/setup/SETUP-new.md
@@ -0,0 +1,213 @@
+# LLM Engineering - Master AI and LLMs
+
+## New Setup instructions for PC, Mac and Linux
+
+**These are the Setup instructions for the new version of the course as of October 2025. For the original versions (Anaconda) please see the other files in this directory for your platform.**
+
+_If you're looking at this in Cursor, please right click on the filename in the Explorer on the left, and select "Open preview", to view the formatted version._
+
+Welcome, LLM engineers in the making!
+
+I should confess up-front: setting up a powerful environment to work at the forefront of AI is not as simple as I'd like. For most people these instructions will go great; but in some cases, for whatever reason, you'll hit a problem. Please don't hesitate to reach out - I am here to get you up and running quickly. There's nothing worse than feeling _stuck_. Message me in Udemy or email me and I will unstick you quickly!
+
+Email: ed@edwarddonner.com
+LinkedIn: https://www.linkedin.com/in/eddonner/
+
+## Step 0 - Before we begin - addressing the "GOTCHAS" which trip up many people:
+
+Ignore this section at your peril! 80% of the questions I get about setup are solved by these very common system issues.
+
+1. PC people: Permissions. Please take a look at this [tutorial](https://chatgpt.com/share/67b0ae58-d1a8-8012-82ca-74762b0408b0) on permissions on Windows. If you ever have an error that you don't have the rights / permissions / ability to run a script or install software, then read this first. ChatGPT can tell you everything you need to know about Permissions on Windows.
+
+2. Anti-virus, Firewall, VPN. These can interfere with installations and network access; try temporarily disabling them as needed. Use a hotspot on your phone to prove whether it's a network issue.
+
+3. PC people: The evil Windows 260 character limit to filenames - here is a full [explanation and fix](https://chatgpt.com/share/67b0afb9-1b60-8012-a9f7-f968a5a910c7)!
+
+4. PC people: If you've not worked with Data Science packages on your computer before, you might need to install Microsoft Build Tools. Here are [instructions](https://chatgpt.com/share/67b0b762-327c-8012-b809-b4ec3b9e7be0). A student also mentioned that [these instructions](https://github.com/bycloudai/InstallVSBuildToolsWindows) might be helpful for people on Windows 11.
+
+5. Mac people: If you're new to developing on your Mac, you may need to install XCode developer tools. Here are [instructions](https://chatgpt.com/share/67b0b8d7-8eec-8012-9a37-6973b9db11f5).
+
+6. SSL and other network issues due to Corporate Security: if you ever get issues with SSL, such as an API Connection issue or any certificate issue, or an error trying to download files from Ollama (a Cloudflare error) then see Q15 [here](https://edwarddonner.com/faq)
+
+## STEP 1 - installing git, projects directory, Cursor
+
+This is the only section with separate steps for PC people and Mac/Linux people! Please pick your section below, then reconvene for Step 2...
+
+___
+
+**STEP 1 FOR PC people:**
+
+1. **Install Git** (if not already installed):
+
+- Open a new Powershell Prompt (start menu >> Powershell). If you ever have permissions errors, try opening the Powershell by right clicking and selecting "run as Administrator"
+- Run the command `git` and see if it responds with details of the command or an error
+- If you get an error, download Git from https://git-scm.com/download/win
+- Run the installer and follow the prompts, using default options (press OK lots of times!)
+
+2. **Create projects directory as needed**
+
+- Open a new Powershell prompt, as in prior step. You should be in your home directory, like `C:\Users\YourUserName`
+- Do you have a projects directory? Find out by typing `cd projects`
+- If that has an error, then create a projects directory: `mkdir projects` then `cd projects`
+- Now you should be in `C:\Users\YourUserName\projects`
+- You can locate this anywhere convenient for you, but avoid any directories that are on your OneDrive
+
+3. **Do a git clone:**
+
+Enter this in the command prompt in the Projects folder:
+
+`git clone https://github.com/ed-donner/llm_engineering.git`
+
+This creates a new directory `llm_engineering` within your projects folder and downloads the code for the class.
+Do `cd llm_engineering` to go into it. This `llm_engineering` directory is known as the "project root directory".
+
+4. **Cursor** Install Cursor if needed and open the project:
+
+Visit https://cursor.com
+
+Click Download for Windows. Then run the installer. Accept and pick defaults for everything..
+
+Then go to Start menu, enter cursor. Cursor will come up, and you might need to answer questions. Then you should see the 'new window' screen where you can click "Open Project". If not, go to File menu >> New Window. Then click "Open Project".
+
+Find your llm_engineering directory within your projects directory. Double click on llm_engineering so you're looking at the contents of llm_engineering. Then click Open or Open Folder.
+
+Cursor should then open up llm_engineering. You know you're in good shape if you see LLM_ENGINEERING in block caps on the top left.
+
+___
+
+**STEP 1 FOR MAC/LINUX PEOPLE**
+
+1. **Install Git** (if not already installed):
+
+Open a Terminal: on Mac, open a Finder window, go to Applications >> Utilities >> Terminal. On Linux, you people live in Terminals.. you hardly need instructions from me!
+
+- Run `git --version` and you should see a git version number. If not, you should get instructions on how to install it, or follow gotcha #5 at the top of this doc.
+
+2. **Create projects directory as needed**
+
+- Open a new Terminal window, as in prior step. Type `pwd` to see where you are. You should be in your home directory, like `/Users/username`
+- Do you have a projects directory? Find out by typing `cd projects`
+- If that has an error, then create a projects directory: `mkdir projects` then `cd projects`
+- If you now do `pwd` you should be in `/Users/username/projects`
+- You can locate this anywhere convenient for you, but avoid any directories that are on your icloud
+
+3. **Do a git clone:**
+
+Enter this in the command prompt in the Projects folder:
+
+`git clone https://github.com/ed-donner/llm_engineering.git`
+
+This creates a new directory `llm_engineering` within your projects folder and downloads the code for the class.
+Do `cd llm_engineering` to go into it. This `llm_engineering` directory is known as the "project root directory".
+
+4. **Cursor** Install Cursor if needed and open the project:
+
+Visit https://cursor.com
+
+Click Download for Mac OS. Or Linux. Then run the installer. Accept and pick defaults for everything..
+
+Then go to Start menu, enter cursor. Cursor will come up, and you might need to answer questions. Then you should see the 'new window' screen where you can click "Open Project". If not, go to File menu >> New Window. Then click "Open Project".
+
+Find your llm_engineering directory within your projects directory. Double click on llm_engineering so you're looking at the contents of llm_engineering. Then click Open.
+
+Cursor should then open up llm_engineering. You know you're in good shape if you see LLM_ENGINEERING in block caps on the top left.
+
+___
+
+## STEP 2: Installing the fabulous **uv** then doing a `uv sync`
+
+For this course, we're using uv, the blazingly fast package manager. It's really taken off in the Data Science world -- and for good reason.
+
+It's fast and reliable. You're going to love it!
+
+First, within Cursor, select View >> Terminal, to see a Terminal window within Cursor. Type `pwd` to check you're in the project root directory.
+
+Now type `uv --version` to see if uv is installed. If you get a version number, then terrific! But if you get an error, then follow the instructions here to install uv - I recommend using the Standalone Installer approach at the very top, but you can use any approach. Run commands in the Cursor installer. If one approach doesn't work for you, then try another.
+
+https://docs.astral.sh/uv/getting-started/installation/
+
+Once you've installed uv, you need to open a new terminal window in Cursor (the plus sign or Ctrl+shift+backtick) for `uv --version` to work. Please check!
+
+Mac people: if you hit a problem with not having permissions to edit your profile files, please see Q14 [here](https://edwarddonner.com/faq) for the fix to this common Mac configuration issue.
+
+### Now that it's installed:
+
+Run `uv self update` to make sure you're on the latest version of uv.
+
+One thing to watch for: if you've used Anaconda before, make sure that your Anaconda environment is deactivated
+`conda deactivate`
+And if you still have any problems with conda and python versions, it's possible that you will need to run this too:
+`conda config --set auto_activate_base false`
+
+And now simply run:
+`uv sync`
+And marvel at the speed and reliability! If necessary, uv should install python 3.12, and then it should install all the packages.
+If you get an error about "invalid certificate" while running `uv sync`, then please check Gotcha 6 above, and try this instead:
+`uv --native-tls sync`
+And also try this instead:
+`uv --allow-insecure-host github.com sync`
+
+And you now have a full spec environment!!
+
+___
+
+## STEP 3 - OPTIONAL - Set up OpenAI Account
+
+Alternative: see Guide 9 in the guides folder for free alternatives!
+
+Go to https://platform.openai.com
+
+- Click Sign Up to create an account if you don't have one. You might need to click some buttons to create an Organization first - just put in sensible defaults. See Guide 4 in the Guides folder if you're unsure about the differences between ChatGPT and the OpenAI API.
+- Click on the Settings icon on the top right, and then Billing on the left sidebar navigation.
+- Ensure Auto-Recharge is off. As needed, "Add to Credit Balance" and pick the $5 up-front payment amount, be sure that you add a proper payment method
+- Still in Settings, select API keys in the left sidebar (near the top)
+- Press "Create new secret key" - select "Owned by you", give it any name you want, for the project select "Default project", leave Permissions at All
+- Press "Create secret key" and you should see your new key. Press Copy to copy it into your clipboard.
+
+___
+
+## STEP 4 - needed for any model like OpenAI or Gemini, but not needed if you only use Ollama - create (and SAVE) your .env file
+
+**Be dilligent with this section!** - any mistakes with your key will be very hard to track down!! I get a huge volume of questions from students who make a mistake with one of these steps... Above all, remember to save the file after you change it.
+
+1. Create your `.env` file
+
+- Go back to Cursor
+- In the File Explorer on the left, right click in the blank space at the bottom of all your files, select "New File" and call your file `.env`
+- I can't stress this enough: the file needs to be called PRECISELY `.env` - those four characters, no more and no less. Not ".env.txt" and not "john.env" and not "openai.env" and not anything else! And it needs to be within the project root.
+
+If you're wondering why I rant about this: I get many, many frustrated people contacting me who (despite all my appeals) have named the file something else and think it's OK. It's not OK! It needs to be called `.env` in the llm_engineering directory 😂
+
+2. Populate your `.env` file and then Save it:
+
+Select the file on the left. You should see an empty blank file on the right. And type this into the contents of the file in the right:
+
+`OPENAI_API_KEY=`
+
+And then press paste! You should now see something like this:
+
+`OPENAI_API_KEY=sk-proj-lots-and-lots-of-digits`
+
+But obviously with your actual key there, not the words "sk-proj-lots-and-lots-of-digits"..
+
+Now be sure to SAVE the file! File >> Save or Ctrl+S (PC) or Command+S (Mac). Many people forget to Save. You need to Save the file!
+
+You should see a Stop sign by the .env file - don't be concerned.. this is a good thing! See Q7 [here](https://edwarddonner.com/faq) if you want to understand why.
+
+__
+
+## STEP 5 - Install Cursor Extensions, Open Day 1, Set the Kernel and GO!
+
+(If you are prompted in Cursor to install recommended extensions, just say yes! That is a nice shortcut for this step.)
+
+- Go to view menu and select Extensions.
+- Search for "python" to bring up the Python extensions. Select the Python extension made by "ms-python" or by "anysphere" and install it if not already installed.
+- Search for "jupyter" and select the extension made by "ms-toolsai" and install it if not already installed.
+
+Now go to View >> Explorer. Open the week1 folder, and click on `day1.ipynb`.
+
+- See where it says "Select Kernel" near the top right? Click that.. then pick "Python Environments"
+- Pick the top option with a star that should say something like `.venv (Python 3.12.x) .venv/bin/python Recommended`
+- If this doesn't come up, please go to the troubleshooting lab in the Setup folder.
+
+# CONGRATULATIONS!! You made it! The rest of the course is easy 😂
diff --git a/diagnostics.ipynb b/setup/diagnostics.ipynb
similarity index 100%
rename from diagnostics.ipynb
rename to setup/diagnostics.ipynb
diff --git a/diagnostics.py b/setup/diagnostics.py
similarity index 100%
rename from diagnostics.py
rename to setup/diagnostics.py
diff --git a/week1/troubleshooting.ipynb b/setup/troubleshooting.ipynb
similarity index 82%
rename from week1/troubleshooting.ipynb
rename to setup/troubleshooting.ipynb
index 23eca6f..71abd54 100644
--- a/week1/troubleshooting.ipynb
+++ b/setup/troubleshooting.ipynb
@@ -14,12 +14,61 @@
"And please remember - I'm standing by to help out. Message me or email ed@edwarddonner.com and I'll get on the case. The very last cell in this notebook has some diagnostics that will help me figure out what's happening.\n"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "8ebcd34f",
+ "metadata": {},
+ "source": [
+ "# If you are taking the new version of the course (using uv and Cursor, rather than Anaconda) then check this section first, otherwise jump ahead to the next section headed \"Starting with the basics\"\n",
+ "\n",
+ "## 1. Check Cursor extensions\n",
+ "\n",
+ "Just to confirm that the extensions are installed:\n",
+ "- Open extensions (View >> extensions)\n",
+ "- Search for python, and when the results show, click on the ms-python one, and Install it if not already installed\n",
+ "- Search for jupyter, and when the results show, click on the Microsoft one, and Install it if not already installed \n",
+ "Then View >> Explorer to bring back the File Explorer.\n",
+ "\n",
+ "## 2. Connect this Kernel:\n",
+ "\n",
+ "If you see the words `Select Kernel` in a button near the top right of this Window, then press the button!\n",
+ "\n",
+ "You should see a drop down titled \"Select kernel for..\" or you might need to pick \"Python environment\" first.\n",
+ "\n",
+ "Pick the one that begins `.venv python 3.12` - it should be the top choice. You might need to click \"Python Environments\" first.\n",
+ "\n",
+ "It should now say `.venv (Python 3.12.x)` where it used to say `Select Kernel`.\n",
+ "\n",
+ "After you click \"Select Kernel\", if there is no option like `.venv (Python 3.12.x)` then please do the following: \n",
+ "1. On Mac: From the Cursor menu, choose Settings >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`); \n",
+ "Or on Windows PC: From the File menu, choose Preferences >> VS Code Settings (NOTE: be sure to select `VSCode Settings` not `Cursor Settings`) \n",
+ "2. In the Settings search bar, type \"venv\" \n",
+ "3. In the field \"Path to folder with a list of Virtual Environments\" put the path to the project root, like C:\\Users\\username\\projects\\llm_engineering (on a Windows PC) or /Users/username/projects/llm_engineering (on Mac or Linux). \n",
+ "And then try again.\n",
+ "\n",
+ "## 3. Anaconda interference and Python version horrors\n",
+ "\n",
+ "Having problems with missing Python versions? Have you ever used Anaconda before? It might be interferring. Quit Cursor, bring up a new command line, and make sure that your Anaconda environment is deactivated: \n",
+ "`conda deactivate` \n",
+ "And if you still have any problems with conda and python versions, it's possible that you will need to run this too: \n",
+ "`conda config --set auto_activate_base false` \n",
+ "And then start a new Terminal / Powershell. \n",
+ "and then from within the agents directory, you should be able to run `uv python list` and see the Python 3.12 version. \n",
+ "And this shouldn't be required, but if you want to be absolutely careful, then now: \n",
+ "1. Delete the folder called '.venv' in the project root directory \n",
+ "2. `uv python uninstall 3.12`\n",
+ "3. `uv python install 3.12`\n",
+ "4. `uv python list`\n",
+ "5. `uv sync` \n",
+ "And surely that is bulletproof!"
+ ]
+ },
{
"cell_type": "markdown",
"id": "98787335-346f-4ee4-9cb7-6181b0e1b964",
"metadata": {},
"source": [
- "# Before we begin\n",
+ "# Starting with the basics\n",
"\n",
"## Checking your internet connection\n",
"\n",
@@ -126,8 +175,8 @@
" venv_name = os.path.basename(virtual_env)\n",
" print(f\"Environment Name: {venv_name}\")\n",
"\n",
- "if conda_name != \"llms\" and venv_name != \"llms\" and venv_name != \"venv\":\n",
- " print(\"Neither Anaconda nor Virtualenv seem to be activated with the expected name 'llms' or 'venv'\")\n",
+ "if conda_name != \"llms\" and venv_name != \"llms\" and venv_name != \"venv\" and venv_name != \".venv\":\n",
+ " print(\"Neither Anaconda nor Virtualenv seem to be activated with the expected name 'llms' or 'venv' or '.venv'\")\n",
" print(\"Did you run 'jupyter lab' from an activated environment with (llms) showing on the command line?\")\n",
" print(\"If in doubt, close down all jupyter lab, and follow Part 5 in the SETUP-PC or SETUP-mac guide.\")"
]
@@ -143,23 +192,22 @@
"\n",
"And now, this next cell should run with no output - no import errors. \n",
"\n",
- "Import errors might indicate that you started jupyter lab without your environment activated? See SETUP Part 5. \n",
+ "For people on the new version of the course (October 2025 on) - an error would suggest that you don't have the right kernel.\n",
"\n",
- "Or you might need to restart your Kernel and Jupyter Lab. \n",
+ "For people on the original course:\n",
"\n",
- "Or it's possible that something is wrong with Anaconda. \n",
- "If so, here are some recovery instructions: \n",
- "First, close everything down and restart your computer. \n",
- "Then in an Anaconda Prompt (PC) or Terminal (Mac), from an activated environment, with **(llms)** showing in the prompt, from the llm_engineering directory, run this: \n",
- "`python -m pip install --upgrade pip` \n",
- "`pip install --retries 5 --timeout 15 --no-cache-dir --force-reinstall -r requirements.txt` \n",
- "Watch carefully for any errors, and let me know. \n",
- "If you see instructions to install Microsoft Build Tools, or Apple XCode tools, then follow the instructions. \n",
- "Then try again!\n",
- "\n",
- "Finally, if that doesn't work, please try SETUP Part 2B, the alternative to Part 2 (with Python 3.11 or Python 3.12). \n",
- "\n",
- "If you're unsure, please run the diagnostics (last cell in this notebook) and then email me at ed@edwarddonner.com"
+ "> Import errors might indicate that you started jupyter lab without your environment activated? See SETUP Part 5. \n",
+ "> Or you might need to restart your Kernel and Jupyter Lab. \n",
+ "> Or it's possible that something is wrong with Anaconda. If so, here are some recovery instructions: \n",
+ "> First, close everything down and restart your computer. \n",
+ "> Then in an Anaconda Prompt (PC) or Terminal (Mac), from an activated environment, with **(llms)** showing in the prompt, from the llm_engineering directory, run this: \n",
+ "> `python -m pip install --upgrade pip` \n",
+ "> `pip install --retries 5 --timeout 15 --no-cache-dir --force-reinstall -r requirements.txt` \n",
+ "> Watch carefully for any errors, and let me know. \n",
+ "> If you see instructions to install Microsoft Build Tools, or Apple XCode tools, then follow the instructions. \n",
+ "> Then try again!\n",
+ "> Finally, if that doesn't work, please try SETUP Part 2B, the alternative to Part 2 (with Python 3.11 or Python 3.12). \n",
+ "> If you're unsure, please run the diagnostics (last cell in this notebook) and then email me at ed@edwarddonner.com"
]
},
{
@@ -487,7 +535,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -501,7 +549,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.11"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/uv.lock b/uv.lock
new file mode 100644
index 0000000..27cb024
--- /dev/null
+++ b/uv.lock
@@ -0,0 +1,4891 @@
+version = 1
+revision = 3
+requires-python = ">=3.12"
+resolution-markers = [
+ "python_full_version >= '3.13' and sys_platform == 'linux'",
+ "python_full_version >= '3.13' and sys_platform != 'linux'",
+ "python_full_version < '3.13' and sys_platform == 'linux'",
+ "python_full_version < '3.13' and sys_platform != 'linux'",
+]
+
+[[package]]
+name = "aiofiles"
+version = "24.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247, upload-time = "2024-06-24T11:02:03.584Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896, upload-time = "2024-06-24T11:02:01.529Z" },
+]
+
+[[package]]
+name = "aiohappyeyeballs"
+version = "2.6.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" },
+]
+
+[[package]]
+name = "aiohttp"
+version = "3.12.15"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohappyeyeballs" },
+ { name = "aiosignal" },
+ { name = "attrs" },
+ { name = "frozenlist" },
+ { name = "multidict" },
+ { name = "propcache" },
+ { name = "yarl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/63/97/77cb2450d9b35f517d6cf506256bf4f5bda3f93a66b4ad64ba7fc917899c/aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7", size = 702333, upload-time = "2025-07-29T05:50:46.507Z" },
+ { url = "https://files.pythonhosted.org/packages/83/6d/0544e6b08b748682c30b9f65640d006e51f90763b41d7c546693bc22900d/aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444", size = 476948, upload-time = "2025-07-29T05:50:48.067Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/1d/c8c40e611e5094330284b1aea8a4b02ca0858f8458614fa35754cab42b9c/aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d", size = 469787, upload-time = "2025-07-29T05:50:49.669Z" },
+ { url = "https://files.pythonhosted.org/packages/38/7d/b76438e70319796bfff717f325d97ce2e9310f752a267bfdf5192ac6082b/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c", size = 1716590, upload-time = "2025-07-29T05:50:51.368Z" },
+ { url = "https://files.pythonhosted.org/packages/79/b1/60370d70cdf8b269ee1444b390cbd72ce514f0d1cd1a715821c784d272c9/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0", size = 1699241, upload-time = "2025-07-29T05:50:53.628Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/2b/4968a7b8792437ebc12186db31523f541943e99bda8f30335c482bea6879/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab", size = 1754335, upload-time = "2025-07-29T05:50:55.394Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/c1/49524ed553f9a0bec1a11fac09e790f49ff669bcd14164f9fab608831c4d/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb", size = 1800491, upload-time = "2025-07-29T05:50:57.202Z" },
+ { url = "https://files.pythonhosted.org/packages/de/5e/3bf5acea47a96a28c121b167f5ef659cf71208b19e52a88cdfa5c37f1fcc/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545", size = 1719929, upload-time = "2025-07-29T05:50:59.192Z" },
+ { url = "https://files.pythonhosted.org/packages/39/94/8ae30b806835bcd1cba799ba35347dee6961a11bd507db634516210e91d8/aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c", size = 1635733, upload-time = "2025-07-29T05:51:01.394Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/46/06cdef71dd03acd9da7f51ab3a9107318aee12ad38d273f654e4f981583a/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd", size = 1696790, upload-time = "2025-07-29T05:51:03.657Z" },
+ { url = "https://files.pythonhosted.org/packages/02/90/6b4cfaaf92ed98d0ec4d173e78b99b4b1a7551250be8937d9d67ecb356b4/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f", size = 1718245, upload-time = "2025-07-29T05:51:05.911Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/e6/2593751670fa06f080a846f37f112cbe6f873ba510d070136a6ed46117c6/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d", size = 1658899, upload-time = "2025-07-29T05:51:07.753Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/28/c15bacbdb8b8eb5bf39b10680d129ea7410b859e379b03190f02fa104ffd/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519", size = 1738459, upload-time = "2025-07-29T05:51:09.56Z" },
+ { url = "https://files.pythonhosted.org/packages/00/de/c269cbc4faa01fb10f143b1670633a8ddd5b2e1ffd0548f7aa49cb5c70e2/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea", size = 1766434, upload-time = "2025-07-29T05:51:11.423Z" },
+ { url = "https://files.pythonhosted.org/packages/52/b0/4ff3abd81aa7d929b27d2e1403722a65fc87b763e3a97b3a2a494bfc63bc/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3", size = 1726045, upload-time = "2025-07-29T05:51:13.689Z" },
+ { url = "https://files.pythonhosted.org/packages/71/16/949225a6a2dd6efcbd855fbd90cf476052e648fb011aa538e3b15b89a57a/aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1", size = 423591, upload-time = "2025-07-29T05:51:15.452Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/d8/fa65d2a349fe938b76d309db1a56a75c4fb8cc7b17a398b698488a939903/aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34", size = 450266, upload-time = "2025-07-29T05:51:17.239Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/33/918091abcf102e39d15aba2476ad9e7bd35ddb190dcdd43a854000d3da0d/aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315", size = 696741, upload-time = "2025-07-29T05:51:19.021Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/2a/7495a81e39a998e400f3ecdd44a62107254803d1681d9189be5c2e4530cd/aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd", size = 474407, upload-time = "2025-07-29T05:51:21.165Z" },
+ { url = "https://files.pythonhosted.org/packages/49/fc/a9576ab4be2dcbd0f73ee8675d16c707cfc12d5ee80ccf4015ba543480c9/aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4", size = 466703, upload-time = "2025-07-29T05:51:22.948Z" },
+ { url = "https://files.pythonhosted.org/packages/09/2f/d4bcc8448cf536b2b54eed48f19682031ad182faa3a3fee54ebe5b156387/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7", size = 1705532, upload-time = "2025-07-29T05:51:25.211Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/f3/59406396083f8b489261e3c011aa8aee9df360a96ac8fa5c2e7e1b8f0466/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d", size = 1686794, upload-time = "2025-07-29T05:51:27.145Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/71/164d194993a8d114ee5656c3b7ae9c12ceee7040d076bf7b32fb98a8c5c6/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b", size = 1738865, upload-time = "2025-07-29T05:51:29.366Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/00/d198461b699188a93ead39cb458554d9f0f69879b95078dce416d3209b54/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d", size = 1788238, upload-time = "2025-07-29T05:51:31.285Z" },
+ { url = "https://files.pythonhosted.org/packages/85/b8/9e7175e1fa0ac8e56baa83bf3c214823ce250d0028955dfb23f43d5e61fd/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d", size = 1710566, upload-time = "2025-07-29T05:51:33.219Z" },
+ { url = "https://files.pythonhosted.org/packages/59/e4/16a8eac9df39b48ae102ec030fa9f726d3570732e46ba0c592aeeb507b93/aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645", size = 1624270, upload-time = "2025-07-29T05:51:35.195Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/f8/cd84dee7b6ace0740908fd0af170f9fab50c2a41ccbc3806aabcb1050141/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461", size = 1677294, upload-time = "2025-07-29T05:51:37.215Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/42/d0f1f85e50d401eccd12bf85c46ba84f947a84839c8a1c2c5f6e8ab1eb50/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9", size = 1708958, upload-time = "2025-07-29T05:51:39.328Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/6b/f6fa6c5790fb602538483aa5a1b86fcbad66244997e5230d88f9412ef24c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d", size = 1651553, upload-time = "2025-07-29T05:51:41.356Z" },
+ { url = "https://files.pythonhosted.org/packages/04/36/a6d36ad545fa12e61d11d1932eef273928b0495e6a576eb2af04297fdd3c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693", size = 1727688, upload-time = "2025-07-29T05:51:43.452Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/c8/f195e5e06608a97a4e52c5d41c7927301bf757a8e8bb5bbf8cef6c314961/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64", size = 1761157, upload-time = "2025-07-29T05:51:45.643Z" },
+ { url = "https://files.pythonhosted.org/packages/05/6a/ea199e61b67f25ba688d3ce93f63b49b0a4e3b3d380f03971b4646412fc6/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51", size = 1710050, upload-time = "2025-07-29T05:51:48.203Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/2e/ffeb7f6256b33635c29dbed29a22a723ff2dd7401fff42ea60cf2060abfb/aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0", size = 422647, upload-time = "2025-07-29T05:51:50.718Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/8e/78ee35774201f38d5e1ba079c9958f7629b1fd079459aea9467441dbfbf5/aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84", size = 449067, upload-time = "2025-07-29T05:51:52.549Z" },
+]
+
+[[package]]
+name = "aiosignal"
+version = "1.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "frozenlist" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
+]
+
+[[package]]
+name = "annotated-types"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
+]
+
+[[package]]
+name = "ansi2html"
+version = "1.9.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4b/d5/e3546dcd5e4a9566f4ed8708df5853e83ca627461a5b048a861c6f8e7a26/ansi2html-1.9.2.tar.gz", hash = "sha256:3453bf87535d37b827b05245faaa756dbab4ec3d69925e352b6319c3c955c0a5", size = 44300, upload-time = "2024-06-22T17:33:23.964Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/71/aee71b836e9ee2741d5694b80d74bfc7c8cd5dbdf7a9f3035fcf80d792b1/ansi2html-1.9.2-py3-none-any.whl", hash = "sha256:dccb75aa95fb018e5d299be2b45f802952377abfdce0504c17a6ee6ef0a420c5", size = 17614, upload-time = "2024-06-22T17:33:21.852Z" },
+]
+
+[[package]]
+name = "anthropic"
+version = "0.69.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "distro" },
+ { name = "docstring-parser" },
+ { name = "httpx" },
+ { name = "jiter" },
+ { name = "pydantic" },
+ { name = "sniffio" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c8/9d/9ad1778b95f15c5b04e7d328c1b5f558f1e893857b7c33cd288c19c0057a/anthropic-0.69.0.tar.gz", hash = "sha256:c604d287f4d73640f40bd2c0f3265a2eb6ce034217ead0608f6b07a8bc5ae5f2", size = 480622, upload-time = "2025-09-29T16:53:45.282Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9b/38/75129688de5637eb5b383e5f2b1570a5cc3aecafa4de422da8eea4b90a6c/anthropic-0.69.0-py3-none-any.whl", hash = "sha256:1f73193040f33f11e27c2cd6ec25f24fe7c3f193dc1c5cde6b7a08b18a16bcc5", size = 337265, upload-time = "2025-09-29T16:53:43.686Z" },
+]
+
+[[package]]
+name = "anyio"
+version = "4.11.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "idna" },
+ { name = "sniffio" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" },
+]
+
+[[package]]
+name = "appnope"
+version = "0.1.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" },
+]
+
+[[package]]
+name = "asttokens"
+version = "3.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" },
+]
+
+[[package]]
+name = "attrs"
+version = "25.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" },
+]
+
+[[package]]
+name = "audioop-lts"
+version = "0.2.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/38/53/946db57842a50b2da2e0c1e34bd37f36f5aadba1a929a3971c5d7841dbca/audioop_lts-0.2.2.tar.gz", hash = "sha256:64d0c62d88e67b98a1a5e71987b7aa7b5bcffc7dcee65b635823dbdd0a8dbbd0", size = 30686, upload-time = "2025-08-05T16:43:17.409Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/de/d4/94d277ca941de5a507b07f0b592f199c22454eeaec8f008a286b3fbbacd6/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd3d4602dc64914d462924a08c1a9816435a2155d74f325853c1f1ac3b2d9800", size = 46523, upload-time = "2025-08-05T16:42:20.836Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/5a/656d1c2da4b555920ce4177167bfeb8623d98765594af59702c8873f60ec/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:550c114a8df0aafe9a05442a1162dfc8fec37e9af1d625ae6060fed6e756f303", size = 27455, upload-time = "2025-08-05T16:42:22.283Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/83/ea581e364ce7b0d41456fb79d6ee0ad482beda61faf0cab20cbd4c63a541/audioop_lts-0.2.2-cp313-abi3-macosx_11_0_arm64.whl", hash = "sha256:9a13dc409f2564de15dd68be65b462ba0dde01b19663720c68c1140c782d1d75", size = 26997, upload-time = "2025-08-05T16:42:23.849Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/3b/e8964210b5e216e5041593b7d33e97ee65967f17c282e8510d19c666dab4/audioop_lts-0.2.2-cp313-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51c916108c56aa6e426ce611946f901badac950ee2ddaf302b7ed35d9958970d", size = 85844, upload-time = "2025-08-05T16:42:25.208Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/2e/0a1c52faf10d51def20531a59ce4c706cb7952323b11709e10de324d6493/audioop_lts-0.2.2-cp313-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47eba38322370347b1c47024defbd36374a211e8dd5b0dcbce7b34fdb6f8847b", size = 85056, upload-time = "2025-08-05T16:42:26.559Z" },
+ { url = "https://files.pythonhosted.org/packages/75/e8/cd95eef479656cb75ab05dfece8c1f8c395d17a7c651d88f8e6e291a63ab/audioop_lts-0.2.2-cp313-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba7c3a7e5f23e215cb271516197030c32aef2e754252c4c70a50aaff7031a2c8", size = 93892, upload-time = "2025-08-05T16:42:27.902Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/1e/a0c42570b74f83efa5cca34905b3eef03f7ab09fe5637015df538a7f3345/audioop_lts-0.2.2-cp313-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def246fe9e180626731b26e89816e79aae2276f825420a07b4a647abaa84becc", size = 96660, upload-time = "2025-08-05T16:42:28.9Z" },
+ { url = "https://files.pythonhosted.org/packages/50/d5/8a0ae607ca07dbb34027bac8db805498ee7bfecc05fd2c148cc1ed7646e7/audioop_lts-0.2.2-cp313-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e160bf9df356d841bb6c180eeeea1834085464626dc1b68fa4e1d59070affdc3", size = 79143, upload-time = "2025-08-05T16:42:29.929Z" },
+ { url = "https://files.pythonhosted.org/packages/12/17/0d28c46179e7910bfb0bb62760ccb33edb5de973052cb2230b662c14ca2e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4b4cd51a57b698b2d06cb9993b7ac8dfe89a3b2878e96bc7948e9f19ff51dba6", size = 84313, upload-time = "2025-08-05T16:42:30.949Z" },
+ { url = "https://files.pythonhosted.org/packages/84/ba/bd5d3806641564f2024e97ca98ea8f8811d4e01d9b9f9831474bc9e14f9e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4a53aa7c16a60a6857e6b0b165261436396ef7293f8b5c9c828a3a203147ed4a", size = 93044, upload-time = "2025-08-05T16:42:31.959Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/5e/435ce8d5642f1f7679540d1e73c1c42d933331c0976eb397d1717d7f01a3/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:3fc38008969796f0f689f1453722a0f463da1b8a6fbee11987830bfbb664f623", size = 78766, upload-time = "2025-08-05T16:42:33.302Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/3b/b909e76b606cbfd53875693ec8c156e93e15a1366a012f0b7e4fb52d3c34/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_s390x.whl", hash = "sha256:15ab25dd3e620790f40e9ead897f91e79c0d3ce65fe193c8ed6c26cffdd24be7", size = 87640, upload-time = "2025-08-05T16:42:34.854Z" },
+ { url = "https://files.pythonhosted.org/packages/30/e7/8f1603b4572d79b775f2140d7952f200f5e6c62904585d08a01f0a70393a/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:03f061a1915538fd96272bac9551841859dbb2e3bf73ebe4a23ef043766f5449", size = 86052, upload-time = "2025-08-05T16:42:35.839Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/96/c37846df657ccdda62ba1ae2b6534fa90e2e1b1742ca8dcf8ebd38c53801/audioop_lts-0.2.2-cp313-abi3-win32.whl", hash = "sha256:3bcddaaf6cc5935a300a8387c99f7a7fbbe212a11568ec6cf6e4bc458c048636", size = 26185, upload-time = "2025-08-05T16:42:37.04Z" },
+ { url = "https://files.pythonhosted.org/packages/34/a5/9d78fdb5b844a83da8a71226c7bdae7cc638861085fff7a1d707cb4823fa/audioop_lts-0.2.2-cp313-abi3-win_amd64.whl", hash = "sha256:a2c2a947fae7d1062ef08c4e369e0ba2086049a5e598fda41122535557012e9e", size = 30503, upload-time = "2025-08-05T16:42:38.427Z" },
+ { url = "https://files.pythonhosted.org/packages/34/25/20d8fde083123e90c61b51afb547bb0ea7e77bab50d98c0ab243d02a0e43/audioop_lts-0.2.2-cp313-abi3-win_arm64.whl", hash = "sha256:5f93a5db13927a37d2d09637ccca4b2b6b48c19cd9eda7b17a2e9f77edee6a6f", size = 24173, upload-time = "2025-08-05T16:42:39.704Z" },
+ { url = "https://files.pythonhosted.org/packages/58/a7/0a764f77b5c4ac58dc13c01a580f5d32ae8c74c92020b961556a43e26d02/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:73f80bf4cd5d2ca7814da30a120de1f9408ee0619cc75da87d0641273d202a09", size = 47096, upload-time = "2025-08-05T16:42:40.684Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/ed/ebebedde1a18848b085ad0fa54b66ceb95f1f94a3fc04f1cd1b5ccb0ed42/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:106753a83a25ee4d6f473f2be6b0966fc1c9af7e0017192f5531a3e7463dce58", size = 27748, upload-time = "2025-08-05T16:42:41.992Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/6e/11ca8c21af79f15dbb1c7f8017952ee8c810c438ce4e2b25638dfef2b02c/audioop_lts-0.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fbdd522624141e40948ab3e8cdae6e04c748d78710e9f0f8d4dae2750831de19", size = 27329, upload-time = "2025-08-05T16:42:42.987Z" },
+ { url = "https://files.pythonhosted.org/packages/84/52/0022f93d56d85eec5da6b9da6a958a1ef09e80c39f2cc0a590c6af81dcbb/audioop_lts-0.2.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:143fad0311e8209ece30a8dbddab3b65ab419cbe8c0dde6e8828da25999be911", size = 92407, upload-time = "2025-08-05T16:42:44.336Z" },
+ { url = "https://files.pythonhosted.org/packages/87/1d/48a889855e67be8718adbc7a01f3c01d5743c325453a5e81cf3717664aad/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dfbbc74ec68a0fd08cfec1f4b5e8cca3d3cd7de5501b01c4b5d209995033cde9", size = 91811, upload-time = "2025-08-05T16:42:45.325Z" },
+ { url = "https://files.pythonhosted.org/packages/98/a6/94b7213190e8077547ffae75e13ed05edc488653c85aa5c41472c297d295/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cfcac6aa6f42397471e4943e0feb2244549db5c5d01efcd02725b96af417f3fe", size = 100470, upload-time = "2025-08-05T16:42:46.468Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/e9/78450d7cb921ede0cfc33426d3a8023a3bda755883c95c868ee36db8d48d/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:752d76472d9804ac60f0078c79cdae8b956f293177acd2316cd1e15149aee132", size = 103878, upload-time = "2025-08-05T16:42:47.576Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/e2/cd5439aad4f3e34ae1ee852025dc6aa8f67a82b97641e390bf7bd9891d3e/audioop_lts-0.2.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:83c381767e2cc10e93e40281a04852facc4cd9334550e0f392f72d1c0a9c5753", size = 84867, upload-time = "2025-08-05T16:42:49.003Z" },
+ { url = "https://files.pythonhosted.org/packages/68/4b/9d853e9076c43ebba0d411e8d2aa19061083349ac695a7d082540bad64d0/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c0022283e9556e0f3643b7c3c03f05063ca72b3063291834cca43234f20c60bb", size = 90001, upload-time = "2025-08-05T16:42:50.038Z" },
+ { url = "https://files.pythonhosted.org/packages/58/26/4bae7f9d2f116ed5593989d0e521d679b0d583973d203384679323d8fa85/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a2d4f1513d63c795e82948e1305f31a6d530626e5f9f2605408b300ae6095093", size = 99046, upload-time = "2025-08-05T16:42:51.111Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/67/a9f4fb3e250dda9e9046f8866e9fa7d52664f8985e445c6b4ad6dfb55641/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:c9c8e68d8b4a56fda8c025e538e639f8c5953f5073886b596c93ec9b620055e7", size = 84788, upload-time = "2025-08-05T16:42:52.198Z" },
+ { url = "https://files.pythonhosted.org/packages/70/f7/3de86562db0121956148bcb0fe5b506615e3bcf6e63c4357a612b910765a/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:96f19de485a2925314f5020e85911fb447ff5fbef56e8c7c6927851b95533a1c", size = 94472, upload-time = "2025-08-05T16:42:53.59Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/32/fd772bf9078ae1001207d2df1eef3da05bea611a87dd0e8217989b2848fa/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e541c3ef484852ef36545f66209444c48b28661e864ccadb29daddb6a4b8e5f5", size = 92279, upload-time = "2025-08-05T16:42:54.632Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/41/affea7181592ab0ab560044632571a38edaf9130b84928177823fbf3176a/audioop_lts-0.2.2-cp313-cp313t-win32.whl", hash = "sha256:d5e73fa573e273e4f2e5ff96f9043858a5e9311e94ffefd88a3186a910c70917", size = 26568, upload-time = "2025-08-05T16:42:55.627Z" },
+ { url = "https://files.pythonhosted.org/packages/28/2b/0372842877016641db8fc54d5c88596b542eec2f8f6c20a36fb6612bf9ee/audioop_lts-0.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9191d68659eda01e448188f60364c7763a7ca6653ed3f87ebb165822153a8547", size = 30942, upload-time = "2025-08-05T16:42:56.674Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/ca/baf2b9cc7e96c179bb4a54f30fcd83e6ecb340031bde68f486403f943768/audioop_lts-0.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c174e322bb5783c099aaf87faeb240c8d210686b04bd61dfd05a8e5a83d88969", size = 24603, upload-time = "2025-08-05T16:42:57.571Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/73/413b5a2804091e2c7d5def1d618e4837f1cb82464e230f827226278556b7/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f9ee9b52f5f857fbaf9d605a360884f034c92c1c23021fb90b2e39b8e64bede6", size = 47104, upload-time = "2025-08-05T16:42:58.518Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/8c/daa3308dc6593944410c2c68306a5e217f5c05b70a12e70228e7dd42dc5c/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:49ee1a41738a23e98d98b937a0638357a2477bc99e61b0f768a8f654f45d9b7a", size = 27754, upload-time = "2025-08-05T16:43:00.132Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/86/c2e0f627168fcf61781a8f72cab06b228fe1da4b9fa4ab39cfb791b5836b/audioop_lts-0.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b00be98ccd0fc123dcfad31d50030d25fcf31488cde9e61692029cd7394733b", size = 27332, upload-time = "2025-08-05T16:43:01.666Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/bd/35dce665255434f54e5307de39e31912a6f902d4572da7c37582809de14f/audioop_lts-0.2.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6d2e0f9f7a69403e388894d4ca5ada5c47230716a03f2847cfc7bd1ecb589d6", size = 92396, upload-time = "2025-08-05T16:43:02.991Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/d2/deeb9f51def1437b3afa35aeb729d577c04bcd89394cb56f9239a9f50b6f/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b0b8a03ef474f56d1a842af1a2e01398b8f7654009823c6d9e0ecff4d5cfbf", size = 91811, upload-time = "2025-08-05T16:43:04.096Z" },
+ { url = "https://files.pythonhosted.org/packages/76/3b/09f8b35b227cee28cc8231e296a82759ed80c1a08e349811d69773c48426/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b267b70747d82125f1a021506565bdc5609a2b24bcb4773c16d79d2bb260bbd", size = 100483, upload-time = "2025-08-05T16:43:05.085Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/15/05b48a935cf3b130c248bfdbdea71ce6437f5394ee8533e0edd7cfd93d5e/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0337d658f9b81f4cd0fdb1f47635070cc084871a3d4646d9de74fdf4e7c3d24a", size = 103885, upload-time = "2025-08-05T16:43:06.197Z" },
+ { url = "https://files.pythonhosted.org/packages/83/80/186b7fce6d35b68d3d739f228dc31d60b3412105854edb975aa155a58339/audioop_lts-0.2.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:167d3b62586faef8b6b2275c3218796b12621a60e43f7e9d5845d627b9c9b80e", size = 84899, upload-time = "2025-08-05T16:43:07.291Z" },
+ { url = "https://files.pythonhosted.org/packages/49/89/c78cc5ac6cb5828f17514fb12966e299c850bc885e80f8ad94e38d450886/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0d9385e96f9f6da847f4d571ce3cb15b5091140edf3db97276872647ce37efd7", size = 89998, upload-time = "2025-08-05T16:43:08.335Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/4b/6401888d0c010e586c2ca50fce4c903d70a6bb55928b16cfbdfd957a13da/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:48159d96962674eccdca9a3df280e864e8ac75e40a577cc97c5c42667ffabfc5", size = 99046, upload-time = "2025-08-05T16:43:09.367Z" },
+ { url = "https://files.pythonhosted.org/packages/de/f8/c874ca9bb447dae0e2ef2e231f6c4c2b0c39e31ae684d2420b0f9e97ee68/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8fefe5868cd082db1186f2837d64cfbfa78b548ea0d0543e9b28935ccce81ce9", size = 84843, upload-time = "2025-08-05T16:43:10.749Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/c0/0323e66f3daebc13fd46b36b30c3be47e3fc4257eae44f1e77eb828c703f/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:58cf54380c3884fb49fdd37dfb7a772632b6701d28edd3e2904743c5e1773602", size = 94490, upload-time = "2025-08-05T16:43:12.131Z" },
+ { url = "https://files.pythonhosted.org/packages/98/6b/acc7734ac02d95ab791c10c3f17ffa3584ccb9ac5c18fd771c638ed6d1f5/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:088327f00488cdeed296edd9215ca159f3a5a5034741465789cad403fcf4bec0", size = 92297, upload-time = "2025-08-05T16:43:13.139Z" },
+ { url = "https://files.pythonhosted.org/packages/13/c3/c3dc3f564ce6877ecd2a05f8d751b9b27a8c320c2533a98b0c86349778d0/audioop_lts-0.2.2-cp314-cp314t-win32.whl", hash = "sha256:068aa17a38b4e0e7de771c62c60bbca2455924b67a8814f3b0dee92b5820c0b3", size = 27331, upload-time = "2025-08-05T16:43:14.19Z" },
+ { url = "https://files.pythonhosted.org/packages/72/bb/b4608537e9ffcb86449091939d52d24a055216a36a8bf66b936af8c3e7ac/audioop_lts-0.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a5bf613e96f49712073de86f20dbdd4014ca18efd4d34ed18c75bd808337851b", size = 31697, upload-time = "2025-08-05T16:43:15.193Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/22/91616fe707a5c5510de2cac9b046a30defe7007ba8a0c04f9c08f27df312/audioop_lts-0.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:b492c3b040153e68b9fdaff5913305aaaba5bb433d8a7f73d5cf6a64ed3cc1dd", size = 25206, upload-time = "2025-08-05T16:43:16.444Z" },
+]
+
+[[package]]
+name = "backoff"
+version = "2.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001, upload-time = "2022-10-05T19:19:32.061Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148, upload-time = "2022-10-05T19:19:30.546Z" },
+]
+
+[[package]]
+name = "bcrypt"
+version = "5.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d4/36/3329e2518d70ad8e2e5817d5a4cac6bba05a47767ec416c7d020a965f408/bcrypt-5.0.0.tar.gz", hash = "sha256:f748f7c2d6fd375cc93d3fba7ef4a9e3a092421b8dbf34d8d4dc06be9492dfdd", size = 25386, upload-time = "2025-09-25T19:50:47.829Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/13/85/3e65e01985fddf25b64ca67275bb5bdb4040bd1a53b66d355c6c37c8a680/bcrypt-5.0.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f3c08197f3039bec79cee59a606d62b96b16669cff3949f21e74796b6e3cd2be", size = 481806, upload-time = "2025-09-25T19:49:05.102Z" },
+ { url = "https://files.pythonhosted.org/packages/44/dc/01eb79f12b177017a726cbf78330eb0eb442fae0e7b3dfd84ea2849552f3/bcrypt-5.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:200af71bc25f22006f4069060c88ed36f8aa4ff7f53e67ff04d2ab3f1e79a5b2", size = 268626, upload-time = "2025-09-25T19:49:06.723Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/cf/e82388ad5959c40d6afd94fb4743cc077129d45b952d46bdc3180310e2df/bcrypt-5.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:baade0a5657654c2984468efb7d6c110db87ea63ef5a4b54732e7e337253e44f", size = 271853, upload-time = "2025-09-25T19:49:08.028Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/86/7134b9dae7cf0efa85671651341f6afa695857fae172615e960fb6a466fa/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c58b56cdfb03202b3bcc9fd8daee8e8e9b6d7e3163aa97c631dfcfcc24d36c86", size = 269793, upload-time = "2025-09-25T19:49:09.727Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/82/6296688ac1b9e503d034e7d0614d56e80c5d1a08402ff856a4549cb59207/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4bfd2a34de661f34d0bda43c3e4e79df586e4716ef401fe31ea39d69d581ef23", size = 289930, upload-time = "2025-09-25T19:49:11.204Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/18/884a44aa47f2a3b88dd09bc05a1e40b57878ecd111d17e5bba6f09f8bb77/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ed2e1365e31fc73f1825fa830f1c8f8917ca1b3ca6185773b349c20fd606cec2", size = 272194, upload-time = "2025-09-25T19:49:12.524Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/8f/371a3ab33c6982070b674f1788e05b656cfbf5685894acbfef0c65483a59/bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:83e787d7a84dbbfba6f250dd7a5efd689e935f03dd83b0f919d39349e1f23f83", size = 269381, upload-time = "2025-09-25T19:49:14.308Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/34/7e4e6abb7a8778db6422e88b1f06eb07c47682313997ee8a8f9352e5a6f1/bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:137c5156524328a24b9fac1cb5db0ba618bc97d11970b39184c1d87dc4bf1746", size = 271750, upload-time = "2025-09-25T19:49:15.584Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/1b/54f416be2499bd72123c70d98d36c6cd61a4e33d9b89562c22481c81bb30/bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:38cac74101777a6a7d3b3e3cfefa57089b5ada650dce2baf0cbdd9d65db22a9e", size = 303757, upload-time = "2025-09-25T19:49:17.244Z" },
+ { url = "https://files.pythonhosted.org/packages/13/62/062c24c7bcf9d2826a1a843d0d605c65a755bc98002923d01fd61270705a/bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:d8d65b564ec849643d9f7ea05c6d9f0cd7ca23bdd4ac0c2dbef1104ab504543d", size = 306740, upload-time = "2025-09-25T19:49:18.693Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/c8/1fdbfc8c0f20875b6b4020f3c7dc447b8de60aa0be5faaf009d24242aec9/bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:741449132f64b3524e95cd30e5cd3343006ce146088f074f31ab26b94e6c75ba", size = 334197, upload-time = "2025-09-25T19:49:20.523Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/c1/8b84545382d75bef226fbc6588af0f7b7d095f7cd6a670b42a86243183cd/bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:212139484ab3207b1f0c00633d3be92fef3c5f0af17cad155679d03ff2ee1e41", size = 352974, upload-time = "2025-09-25T19:49:22.254Z" },
+ { url = "https://files.pythonhosted.org/packages/10/a6/ffb49d4254ed085e62e3e5dd05982b4393e32fe1e49bb1130186617c29cd/bcrypt-5.0.0-cp313-cp313t-win32.whl", hash = "sha256:9d52ed507c2488eddd6a95bccee4e808d3234fa78dd370e24bac65a21212b861", size = 148498, upload-time = "2025-09-25T19:49:24.134Z" },
+ { url = "https://files.pythonhosted.org/packages/48/a9/259559edc85258b6d5fc5471a62a3299a6aa37a6611a169756bf4689323c/bcrypt-5.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f6984a24db30548fd39a44360532898c33528b74aedf81c26cf29c51ee47057e", size = 145853, upload-time = "2025-09-25T19:49:25.702Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/df/9714173403c7e8b245acf8e4be8876aac64a209d1b392af457c79e60492e/bcrypt-5.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9fffdb387abe6aa775af36ef16f55e318dcda4194ddbf82007a6f21da29de8f5", size = 139626, upload-time = "2025-09-25T19:49:26.928Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/14/c18006f91816606a4abe294ccc5d1e6f0e42304df5a33710e9e8e95416e1/bcrypt-5.0.0-cp314-cp314t-macosx_10_12_universal2.whl", hash = "sha256:4870a52610537037adb382444fefd3706d96d663ac44cbb2f37e3919dca3d7ef", size = 481862, upload-time = "2025-09-25T19:49:28.365Z" },
+ { url = "https://files.pythonhosted.org/packages/67/49/dd074d831f00e589537e07a0725cf0e220d1f0d5d8e85ad5bbff251c45aa/bcrypt-5.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48f753100931605686f74e27a7b49238122aa761a9aefe9373265b8b7aa43ea4", size = 268544, upload-time = "2025-09-25T19:49:30.39Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/91/50ccba088b8c474545b034a1424d05195d9fcbaaf802ab8bfe2be5a4e0d7/bcrypt-5.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f70aadb7a809305226daedf75d90379c397b094755a710d7014b8b117df1ebbf", size = 271787, upload-time = "2025-09-25T19:49:32.144Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/e7/d7dba133e02abcda3b52087a7eea8c0d4f64d3e593b4fffc10c31b7061f3/bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:744d3c6b164caa658adcb72cb8cc9ad9b4b75c7db507ab4bc2480474a51989da", size = 269753, upload-time = "2025-09-25T19:49:33.885Z" },
+ { url = "https://files.pythonhosted.org/packages/33/fc/5b145673c4b8d01018307b5c2c1fc87a6f5a436f0ad56607aee389de8ee3/bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a28bc05039bdf3289d757f49d616ab3efe8cf40d8e8001ccdd621cd4f98f4fc9", size = 289587, upload-time = "2025-09-25T19:49:35.144Z" },
+ { url = "https://files.pythonhosted.org/packages/27/d7/1ff22703ec6d4f90e62f1a5654b8867ef96bafb8e8102c2288333e1a6ca6/bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:7f277a4b3390ab4bebe597800a90da0edae882c6196d3038a73adf446c4f969f", size = 272178, upload-time = "2025-09-25T19:49:36.793Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/88/815b6d558a1e4d40ece04a2f84865b0fef233513bd85fd0e40c294272d62/bcrypt-5.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:79cfa161eda8d2ddf29acad370356b47f02387153b11d46042e93a0a95127493", size = 269295, upload-time = "2025-09-25T19:49:38.164Z" },
+ { url = "https://files.pythonhosted.org/packages/51/8c/e0db387c79ab4931fc89827d37608c31cc57b6edc08ccd2386139028dc0d/bcrypt-5.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a5393eae5722bcef046a990b84dff02b954904c36a194f6cfc817d7dca6c6f0b", size = 271700, upload-time = "2025-09-25T19:49:39.917Z" },
+ { url = "https://files.pythonhosted.org/packages/06/83/1570edddd150f572dbe9fc00f6203a89fc7d4226821f67328a85c330f239/bcrypt-5.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7f4c94dec1b5ab5d522750cb059bb9409ea8872d4494fd152b53cca99f1ddd8c", size = 334034, upload-time = "2025-09-25T19:49:41.227Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/f2/ea64e51a65e56ae7a8a4ec236c2bfbdd4b23008abd50ac33fbb2d1d15424/bcrypt-5.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0cae4cb350934dfd74c020525eeae0a5f79257e8a201c0c176f4b84fdbf2a4b4", size = 352766, upload-time = "2025-09-25T19:49:43.08Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/d4/1a388d21ee66876f27d1a1f41287897d0c0f1712ef97d395d708ba93004c/bcrypt-5.0.0-cp314-cp314t-win32.whl", hash = "sha256:b17366316c654e1ad0306a6858e189fc835eca39f7eb2cafd6aaca8ce0c40a2e", size = 152449, upload-time = "2025-09-25T19:49:44.971Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/61/3291c2243ae0229e5bca5d19f4032cecad5dfb05a2557169d3a69dc0ba91/bcrypt-5.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:92864f54fb48b4c718fc92a32825d0e42265a627f956bc0361fe869f1adc3e7d", size = 149310, upload-time = "2025-09-25T19:49:46.162Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/89/4b01c52ae0c1a681d4021e5dd3e45b111a8fb47254a274fa9a378d8d834b/bcrypt-5.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dd19cf5184a90c873009244586396a6a884d591a5323f0e8a5922560718d4993", size = 143761, upload-time = "2025-09-25T19:49:47.345Z" },
+ { url = "https://files.pythonhosted.org/packages/84/29/6237f151fbfe295fe3e074ecc6d44228faa1e842a81f6d34a02937ee1736/bcrypt-5.0.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:fc746432b951e92b58317af8e0ca746efe93e66555f1b40888865ef5bf56446b", size = 494553, upload-time = "2025-09-25T19:49:49.006Z" },
+ { url = "https://files.pythonhosted.org/packages/45/b6/4c1205dde5e464ea3bd88e8742e19f899c16fa8916fb8510a851fae985b5/bcrypt-5.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c2388ca94ffee269b6038d48747f4ce8df0ffbea43f31abfa18ac72f0218effb", size = 275009, upload-time = "2025-09-25T19:49:50.581Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/71/427945e6ead72ccffe77894b2655b695ccf14ae1866cd977e185d606dd2f/bcrypt-5.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:560ddb6ec730386e7b3b26b8b4c88197aaed924430e7b74666a586ac997249ef", size = 278029, upload-time = "2025-09-25T19:49:52.533Z" },
+ { url = "https://files.pythonhosted.org/packages/17/72/c344825e3b83c5389a369c8a8e58ffe1480b8a699f46c127c34580c4666b/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d79e5c65dcc9af213594d6f7f1fa2c98ad3fc10431e7aa53c176b441943efbdd", size = 275907, upload-time = "2025-09-25T19:49:54.709Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/7e/d4e47d2df1641a36d1212e5c0514f5291e1a956a7749f1e595c07a972038/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2b732e7d388fa22d48920baa267ba5d97cca38070b69c0e2d37087b381c681fd", size = 296500, upload-time = "2025-09-25T19:49:56.013Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/c3/0ae57a68be2039287ec28bc463b82e4b8dc23f9d12c0be331f4782e19108/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0c8e093ea2532601a6f686edbc2c6b2ec24131ff5c52f7610dd64fa4553b5464", size = 278412, upload-time = "2025-09-25T19:49:57.356Z" },
+ { url = "https://files.pythonhosted.org/packages/45/2b/77424511adb11e6a99e3a00dcc7745034bee89036ad7d7e255a7e47be7d8/bcrypt-5.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5b1589f4839a0899c146e8892efe320c0fa096568abd9b95593efac50a87cb75", size = 275486, upload-time = "2025-09-25T19:49:59.116Z" },
+ { url = "https://files.pythonhosted.org/packages/43/0a/405c753f6158e0f3f14b00b462d8bca31296f7ecfc8fc8bc7919c0c7d73a/bcrypt-5.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:89042e61b5e808b67daf24a434d89bab164d4de1746b37a8d173b6b14f3db9ff", size = 277940, upload-time = "2025-09-25T19:50:00.869Z" },
+ { url = "https://files.pythonhosted.org/packages/62/83/b3efc285d4aadc1fa83db385ec64dcfa1707e890eb42f03b127d66ac1b7b/bcrypt-5.0.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:e3cf5b2560c7b5a142286f69bde914494b6d8f901aaa71e453078388a50881c4", size = 310776, upload-time = "2025-09-25T19:50:02.393Z" },
+ { url = "https://files.pythonhosted.org/packages/95/7d/47ee337dacecde6d234890fe929936cb03ebc4c3a7460854bbd9c97780b8/bcrypt-5.0.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f632fd56fc4e61564f78b46a2269153122db34988e78b6be8b32d28507b7eaeb", size = 312922, upload-time = "2025-09-25T19:50:04.232Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/3a/43d494dfb728f55f4e1cf8fd435d50c16a2d75493225b54c8d06122523c6/bcrypt-5.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:801cad5ccb6b87d1b430f183269b94c24f248dddbbc5c1f78b6ed231743e001c", size = 341367, upload-time = "2025-09-25T19:50:05.559Z" },
+ { url = "https://files.pythonhosted.org/packages/55/ab/a0727a4547e383e2e22a630e0f908113db37904f58719dc48d4622139b5c/bcrypt-5.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3cf67a804fc66fc217e6914a5635000259fbbbb12e78a99488e4d5ba445a71eb", size = 359187, upload-time = "2025-09-25T19:50:06.916Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/bb/461f352fdca663524b4643d8b09e8435b4990f17fbf4fea6bc2a90aa0cc7/bcrypt-5.0.0-cp38-abi3-win32.whl", hash = "sha256:3abeb543874b2c0524ff40c57a4e14e5d3a66ff33fb423529c88f180fd756538", size = 153752, upload-time = "2025-09-25T19:50:08.515Z" },
+ { url = "https://files.pythonhosted.org/packages/41/aa/4190e60921927b7056820291f56fc57d00d04757c8b316b2d3c0d1d6da2c/bcrypt-5.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:35a77ec55b541e5e583eb3436ffbbf53b0ffa1fa16ca6782279daf95d146dcd9", size = 150881, upload-time = "2025-09-25T19:50:09.742Z" },
+ { url = "https://files.pythonhosted.org/packages/54/12/cd77221719d0b39ac0b55dbd39358db1cd1246e0282e104366ebbfb8266a/bcrypt-5.0.0-cp38-abi3-win_arm64.whl", hash = "sha256:cde08734f12c6a4e28dc6755cd11d3bdfea608d93d958fffbe95a7026ebe4980", size = 144931, upload-time = "2025-09-25T19:50:11.016Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/ba/2af136406e1c3839aea9ecadc2f6be2bcd1eff255bd451dd39bcf302c47a/bcrypt-5.0.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0c418ca99fd47e9c59a301744d63328f17798b5947b0f791e9af3c1c499c2d0a", size = 495313, upload-time = "2025-09-25T19:50:12.309Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/ee/2f4985dbad090ace5ad1f7dd8ff94477fe089b5fab2040bd784a3d5f187b/bcrypt-5.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddb4e1500f6efdd402218ffe34d040a1196c072e07929b9820f363a1fd1f4191", size = 275290, upload-time = "2025-09-25T19:50:13.673Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/6e/b77ade812672d15cf50842e167eead80ac3514f3beacac8902915417f8b7/bcrypt-5.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7aeef54b60ceddb6f30ee3db090351ecf0d40ec6e2abf41430997407a46d2254", size = 278253, upload-time = "2025-09-25T19:50:15.089Z" },
+ { url = "https://files.pythonhosted.org/packages/36/c4/ed00ed32f1040f7990dac7115f82273e3c03da1e1a1587a778d8cea496d8/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f0ce778135f60799d89c9693b9b398819d15f1921ba15fe719acb3178215a7db", size = 276084, upload-time = "2025-09-25T19:50:16.699Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/c4/fa6e16145e145e87f1fa351bbd54b429354fd72145cd3d4e0c5157cf4c70/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a71f70ee269671460b37a449f5ff26982a6f2ba493b3eabdd687b4bf35f875ac", size = 297185, upload-time = "2025-09-25T19:50:18.525Z" },
+ { url = "https://files.pythonhosted.org/packages/24/b4/11f8a31d8b67cca3371e046db49baa7c0594d71eb40ac8121e2fc0888db0/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8429e1c410b4073944f03bd778a9e066e7fad723564a52ff91841d278dfc822", size = 278656, upload-time = "2025-09-25T19:50:19.809Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/31/79f11865f8078e192847d2cb526e3fa27c200933c982c5b2869720fa5fce/bcrypt-5.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:edfcdcedd0d0f05850c52ba3127b1fce70b9f89e0fe5ff16517df7e81fa3cbb8", size = 275662, upload-time = "2025-09-25T19:50:21.567Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/8d/5e43d9584b3b3591a6f9b68f755a4da879a59712981ef5ad2a0ac1379f7a/bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:611f0a17aa4a25a69362dcc299fda5c8a3d4f160e2abb3831041feb77393a14a", size = 278240, upload-time = "2025-09-25T19:50:23.305Z" },
+ { url = "https://files.pythonhosted.org/packages/89/48/44590e3fc158620f680a978aafe8f87a4c4320da81ed11552f0323aa9a57/bcrypt-5.0.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:db99dca3b1fdc3db87d7c57eac0c82281242d1eabf19dcb8a6b10eb29a2e72d1", size = 311152, upload-time = "2025-09-25T19:50:24.597Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/85/e4fbfc46f14f47b0d20493669a625da5827d07e8a88ee460af6cd9768b44/bcrypt-5.0.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5feebf85a9cefda32966d8171f5db7e3ba964b77fdfe31919622256f80f9cf42", size = 313284, upload-time = "2025-09-25T19:50:26.268Z" },
+ { url = "https://files.pythonhosted.org/packages/25/ae/479f81d3f4594456a01ea2f05b132a519eff9ab5768a70430fa1132384b1/bcrypt-5.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3ca8a166b1140436e058298a34d88032ab62f15aae1c598580333dc21d27ef10", size = 341643, upload-time = "2025-09-25T19:50:28.02Z" },
+ { url = "https://files.pythonhosted.org/packages/df/d2/36a086dee1473b14276cd6ea7f61aef3b2648710b5d7f1c9e032c29b859f/bcrypt-5.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:61afc381250c3182d9078551e3ac3a41da14154fbff647ddf52a769f588c4172", size = 359698, upload-time = "2025-09-25T19:50:31.347Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/f6/688d2cd64bfd0b14d805ddb8a565e11ca1fb0fd6817175d58b10052b6d88/bcrypt-5.0.0-cp39-abi3-win32.whl", hash = "sha256:64d7ce196203e468c457c37ec22390f1a61c85c6f0b8160fd752940ccfb3a683", size = 153725, upload-time = "2025-09-25T19:50:34.384Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/b9/9d9a641194a730bda138b3dfe53f584d61c58cd5230e37566e83ec2ffa0d/bcrypt-5.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:64ee8434b0da054d830fa8e89e1c8bf30061d539044a39524ff7dec90481e5c2", size = 150912, upload-time = "2025-09-25T19:50:35.69Z" },
+ { url = "https://files.pythonhosted.org/packages/27/44/d2ef5e87509158ad2187f4dd0852df80695bb1ee0cfe0a684727b01a69e0/bcrypt-5.0.0-cp39-abi3-win_arm64.whl", hash = "sha256:f2347d3534e76bf50bca5500989d6c1d05ed64b440408057a37673282c654927", size = 144953, upload-time = "2025-09-25T19:50:37.32Z" },
+]
+
+[[package]]
+name = "beautifulsoup4"
+version = "4.14.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "soupsieve" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822, upload-time = "2025-09-29T10:05:42.613Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392, upload-time = "2025-09-29T10:05:43.771Z" },
+]
+
+[[package]]
+name = "blinker"
+version = "1.9.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" },
+]
+
+[[package]]
+name = "brotli"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2f/c2/f9e977608bdf958650638c3f1e28f85a1b075f075ebbe77db8555463787b/Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724", size = 7372270, upload-time = "2023-09-07T14:05:41.643Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5c/d0/5373ae13b93fe00095a58efcbce837fd470ca39f703a235d2a999baadfbc/Brotli-1.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28", size = 815693, upload-time = "2024-10-18T12:32:23.824Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/48/f6e1cdf86751300c288c1459724bfa6917a80e30dbfc326f92cea5d3683a/Brotli-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f", size = 422489, upload-time = "2024-10-18T12:32:25.641Z" },
+ { url = "https://files.pythonhosted.org/packages/06/88/564958cedce636d0f1bed313381dfc4b4e3d3f6015a63dae6146e1b8c65c/Brotli-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409", size = 873081, upload-time = "2023-09-07T14:03:57.967Z" },
+ { url = "https://files.pythonhosted.org/packages/58/79/b7026a8bb65da9a6bb7d14329fd2bd48d2b7f86d7329d5cc8ddc6a90526f/Brotli-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2", size = 446244, upload-time = "2023-09-07T14:03:59.319Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/18/c18c32ecea41b6c0004e15606e274006366fe19436b6adccc1ae7b2e50c2/Brotli-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451", size = 2906505, upload-time = "2023-09-07T14:04:01.327Z" },
+ { url = "https://files.pythonhosted.org/packages/08/c8/69ec0496b1ada7569b62d85893d928e865df29b90736558d6c98c2031208/Brotli-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91", size = 2944152, upload-time = "2023-09-07T14:04:03.033Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/fb/0517cea182219d6768113a38167ef6d4eb157a033178cc938033a552ed6d/Brotli-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408", size = 2919252, upload-time = "2023-09-07T14:04:04.675Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/53/73a3431662e33ae61a5c80b1b9d2d18f58dfa910ae8dd696e57d39f1a2f5/Brotli-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0", size = 2845955, upload-time = "2023-09-07T14:04:06.585Z" },
+ { url = "https://files.pythonhosted.org/packages/55/ac/bd280708d9c5ebdbf9de01459e625a3e3803cce0784f47d633562cf40e83/Brotli-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc", size = 2914304, upload-time = "2023-09-07T14:04:08.668Z" },
+ { url = "https://files.pythonhosted.org/packages/76/58/5c391b41ecfc4527d2cc3350719b02e87cb424ef8ba2023fb662f9bf743c/Brotli-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180", size = 2814452, upload-time = "2023-09-07T14:04:10.736Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/4e/91b8256dfe99c407f174924b65a01f5305e303f486cc7a2e8a5d43c8bec3/Brotli-1.1.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248", size = 2938751, upload-time = "2023-09-07T14:04:12.875Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/a6/e2a39a5d3b412938362bbbeba5af904092bf3f95b867b4a3eb856104074e/Brotli-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966", size = 2933757, upload-time = "2023-09-07T14:04:14.551Z" },
+ { url = "https://files.pythonhosted.org/packages/13/f0/358354786280a509482e0e77c1a5459e439766597d280f28cb097642fc26/Brotli-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9", size = 2936146, upload-time = "2024-10-18T12:32:27.257Z" },
+ { url = "https://files.pythonhosted.org/packages/80/f7/daf538c1060d3a88266b80ecc1d1c98b79553b3f117a485653f17070ea2a/Brotli-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb", size = 2848055, upload-time = "2024-10-18T12:32:29.376Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/cf/0eaa0585c4077d3c2d1edf322d8e97aabf317941d3a72d7b3ad8bce004b0/Brotli-1.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111", size = 3035102, upload-time = "2024-10-18T12:32:31.371Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/63/1c1585b2aa554fe6dbce30f0c18bdbc877fa9a1bf5ff17677d9cca0ac122/Brotli-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839", size = 2930029, upload-time = "2024-10-18T12:32:33.293Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/3b/4e3fd1893eb3bbfef8e5a80d4508bec17a57bb92d586c85c12d28666bb13/Brotli-1.1.0-cp312-cp312-win32.whl", hash = "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0", size = 333276, upload-time = "2023-09-07T14:04:16.49Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/d5/942051b45a9e883b5b6e98c041698b1eb2012d25e5948c58d6bf85b1bb43/Brotli-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951", size = 357255, upload-time = "2023-09-07T14:04:17.83Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/9f/fb37bb8ffc52a8da37b1c03c459a8cd55df7a57bdccd8831d500e994a0ca/Brotli-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5", size = 815681, upload-time = "2024-10-18T12:32:34.942Z" },
+ { url = "https://files.pythonhosted.org/packages/06/b3/dbd332a988586fefb0aa49c779f59f47cae76855c2d00f450364bb574cac/Brotli-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8", size = 422475, upload-time = "2024-10-18T12:32:36.485Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/80/6aaddc2f63dbcf2d93c2d204e49c11a9ec93a8c7c63261e2b4bd35198283/Brotli-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f", size = 2906173, upload-time = "2024-10-18T12:32:37.978Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/1d/e6ca79c96ff5b641df6097d299347507d39a9604bde8915e76bf026d6c77/Brotli-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648", size = 2943803, upload-time = "2024-10-18T12:32:39.606Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/a3/d98d2472e0130b7dd3acdbb7f390d478123dbf62b7d32bda5c830a96116d/Brotli-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0", size = 2918946, upload-time = "2024-10-18T12:32:41.679Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/a5/c69e6d272aee3e1423ed005d8915a7eaa0384c7de503da987f2d224d0721/Brotli-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089", size = 2845707, upload-time = "2024-10-18T12:32:43.478Z" },
+ { url = "https://files.pythonhosted.org/packages/58/9f/4149d38b52725afa39067350696c09526de0125ebfbaab5acc5af28b42ea/Brotli-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368", size = 2936231, upload-time = "2024-10-18T12:32:45.224Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/5a/145de884285611838a16bebfdb060c231c52b8f84dfbe52b852a15780386/Brotli-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c", size = 2848157, upload-time = "2024-10-18T12:32:46.894Z" },
+ { url = "https://files.pythonhosted.org/packages/50/ae/408b6bfb8525dadebd3b3dd5b19d631da4f7d46420321db44cd99dcf2f2c/Brotli-1.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284", size = 3035122, upload-time = "2024-10-18T12:32:48.844Z" },
+ { url = "https://files.pythonhosted.org/packages/af/85/a94e5cfaa0ca449d8f91c3d6f78313ebf919a0dbd55a100c711c6e9655bc/Brotli-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7", size = 2930206, upload-time = "2024-10-18T12:32:51.198Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/f0/a61d9262cd01351df22e57ad7c34f66794709acab13f34be2675f45bf89d/Brotli-1.1.0-cp313-cp313-win32.whl", hash = "sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0", size = 333804, upload-time = "2024-10-18T12:32:52.661Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/c1/ec214e9c94000d1c1974ec67ced1c970c148aa6b8d8373066123fc3dbf06/Brotli-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b", size = 358517, upload-time = "2024-10-18T12:32:54.066Z" },
+]
+
+[[package]]
+name = "build"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "os_name == 'nt' and sys_platform != 'linux'" },
+ { name = "packaging" },
+ { name = "pyproject-hooks" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/25/1c/23e33405a7c9eac261dff640926b8b5adaed6a6eb3e1767d441ed611d0c0/build-1.3.0.tar.gz", hash = "sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397", size = 48544, upload-time = "2025-08-01T21:27:09.268Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cb/8c/2b30c12155ad8de0cf641d76a8b396a16d2c36bc6d50b621a62b7c4567c1/build-1.3.0-py3-none-any.whl", hash = "sha256:7145f0b5061ba90a1500d60bd1b13ca0a8a4cebdd0cc16ed8adf1c0e739f43b4", size = 23382, upload-time = "2025-08-01T21:27:07.844Z" },
+]
+
+[[package]]
+name = "cachetools"
+version = "6.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9d/61/e4fad8155db4a04bfb4734c7c8ff0882f078f24294d42798b3568eb63bff/cachetools-6.2.0.tar.gz", hash = "sha256:38b328c0889450f05f5e120f56ab68c8abaf424e1275522b138ffc93253f7e32", size = 30988, upload-time = "2025-08-25T18:57:30.924Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6c/56/3124f61d37a7a4e7cc96afc5492c78ba0cb551151e530b54669ddd1436ef/cachetools-6.2.0-py3-none-any.whl", hash = "sha256:1c76a8960c0041fcc21097e357f882197c79da0dbff766e7317890a65d7d8ba6", size = 11276, upload-time = "2025-08-25T18:57:29.684Z" },
+]
+
+[[package]]
+name = "certifi"
+version = "2025.8.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" },
+]
+
+[[package]]
+name = "cffi"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pycparser", marker = "implementation_name != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
+ { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
+ { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
+ { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
+ { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
+ { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
+ { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
+ { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
+ { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
+ { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
+ { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
+ { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
+ { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
+ { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
+]
+
+[[package]]
+name = "charset-normalizer"
+version = "3.4.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" },
+ { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" },
+ { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" },
+ { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" },
+ { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" },
+ { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" },
+ { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" },
+ { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" },
+ { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" },
+ { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" },
+ { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" },
+ { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" },
+ { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" },
+ { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" },
+ { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" },
+ { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" },
+ { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" },
+]
+
+[[package]]
+name = "chromadb"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "bcrypt" },
+ { name = "build" },
+ { name = "grpcio" },
+ { name = "httpx" },
+ { name = "importlib-resources" },
+ { name = "jsonschema" },
+ { name = "kubernetes" },
+ { name = "mmh3" },
+ { name = "numpy" },
+ { name = "onnxruntime" },
+ { name = "opentelemetry-api" },
+ { name = "opentelemetry-exporter-otlp-proto-grpc" },
+ { name = "opentelemetry-sdk" },
+ { name = "orjson" },
+ { name = "overrides" },
+ { name = "posthog" },
+ { name = "pybase64" },
+ { name = "pydantic" },
+ { name = "pypika" },
+ { name = "pyyaml" },
+ { name = "rich" },
+ { name = "tenacity" },
+ { name = "tokenizers" },
+ { name = "tqdm" },
+ { name = "typer" },
+ { name = "typing-extensions" },
+ { name = "uvicorn", extra = ["standard"] },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c4/da/29ecec2b5609a8e4f6e93af01a95b716b3448fc94ab002efe421abef8e8e/chromadb-1.1.0.tar.gz", hash = "sha256:50be29e2ad45f1ac0b15f57e04f48766cf1e61de0fcc5e8d31dd738a5a773b48", size = 1311824, upload-time = "2025-09-16T21:23:08.273Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9f/63/7b02737d537aba017e464271fc0a94659b90862a9f8f6648942c00eb0541/chromadb-1.1.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:edfd17f5e04f762622d19969daffc255ae06cc3a63d8f9e5b04f291177f4bd5f", size = 19132671, upload-time = "2025-09-16T21:23:05.679Z" },
+ { url = "https://files.pythonhosted.org/packages/52/8a/33ff83d0eaaa83875aedbfa220f651ae0ad6f6c1d997515fd47e8ee4c4b9/chromadb-1.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:e847329f1e93252ae416478db54021cf7e86fe50bffc87e1429ead22d1ad0789", size = 18214077, upload-time = "2025-09-16T21:23:02.958Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/f0/a31bddc426b03a80286cc23480ace5e174c7b39f070b99967cd7bedb9a18/chromadb-1.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97dd7282fda79ef94ce20ee83b7cb62795231ecc657da5781bd2be4c55d9046", size = 18818050, upload-time = "2025-09-16T21:22:57.008Z" },
+ { url = "https://files.pythonhosted.org/packages/00/39/5969bec252d6b174eeb68a5b23c88cbe4913a1e20d6b313ec628e5079c74/chromadb-1.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:472d44f634e27b7b0ee42c17771c42af19a786f003500eb540add6f475791363", size = 19841393, upload-time = "2025-09-16T21:23:00.108Z" },
+ { url = "https://files.pythonhosted.org/packages/90/64/595af82790623f72ee8301fcbfca55192e8e1f2d65562a14bc549e596b06/chromadb-1.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:4f3eaad5817b81d9f90ba2727a8b956b5428db64c0350252b5d919f1fd74632e", size = 19789778, upload-time = "2025-09-16T21:23:10.657Z" },
+]
+
+[[package]]
+name = "click"
+version = "8.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" },
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
+]
+
+[[package]]
+name = "coloredlogs"
+version = "15.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "humanfriendly" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cc/c7/eed8f27100517e8c0e6b923d5f0845d0cb99763da6fdee00478f91db7325/coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0", size = 278520, upload-time = "2021-06-11T10:22:45.202Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", size = 46018, upload-time = "2021-06-11T10:22:42.561Z" },
+]
+
+[[package]]
+name = "comm"
+version = "0.2.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" },
+]
+
+[[package]]
+name = "contourpy"
+version = "1.3.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" },
+ { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" },
+ { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" },
+ { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" },
+ { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" },
+ { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" },
+ { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" },
+ { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" },
+ { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" },
+ { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" },
+ { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" },
+ { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" },
+ { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" },
+ { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" },
+ { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" },
+ { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" },
+ { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" },
+ { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" },
+ { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" },
+ { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" },
+ { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" },
+ { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" },
+ { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" },
+ { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" },
+ { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" },
+ { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" },
+]
+
+[[package]]
+name = "cycler"
+version = "0.12.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" },
+]
+
+[[package]]
+name = "dash"
+version = "3.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "flask" },
+ { name = "importlib-metadata" },
+ { name = "nest-asyncio" },
+ { name = "plotly" },
+ { name = "requests" },
+ { name = "retrying" },
+ { name = "setuptools" },
+ { name = "typing-extensions" },
+ { name = "werkzeug" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/80/37/8b5621e0a0b3c6e81a8b6cd3f033aa4b750f53e288dd1a494a887a8a06e9/dash-3.2.0.tar.gz", hash = "sha256:93300b9b99498f8b8ed267e61c455b4ee1282c7e4d4b518600eec87ce6ddea55", size = 7558708, upload-time = "2025-07-31T19:18:59.014Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d3/36/e0010483ca49b9bf6f389631ccea07b3ff6b678d14d8c7a0a4357860c36a/dash-3.2.0-py3-none-any.whl", hash = "sha256:4c1819588d83bed2cbcf5807daa5c2380c8c85789a6935a733f018f04ad8a6a2", size = 7900661, upload-time = "2025-07-31T19:18:50.679Z" },
+]
+
+[[package]]
+name = "dataclasses-json"
+version = "0.6.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "marshmallow" },
+ { name = "typing-inspect" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227, upload-time = "2024-06-09T16:20:19.103Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686, upload-time = "2024-06-09T16:20:16.715Z" },
+]
+
+[[package]]
+name = "datasets"
+version = "3.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "dill" },
+ { name = "filelock" },
+ { name = "fsspec", extra = ["http"] },
+ { name = "huggingface-hub" },
+ { name = "multiprocess" },
+ { name = "numpy" },
+ { name = "packaging" },
+ { name = "pandas" },
+ { name = "pyarrow" },
+ { name = "pyyaml" },
+ { name = "requests" },
+ { name = "tqdm" },
+ { name = "xxhash" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1a/89/d3d6fef58a488f8569c82fd293ab7cbd4250244d67f425dcae64c63800ea/datasets-3.6.0.tar.gz", hash = "sha256:1b2bf43b19776e2787e181cfd329cb0ca1a358ea014780c3581e0f276375e041", size = 569336, upload-time = "2025-05-07T15:15:02.659Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/20/34/a08b0ee99715eaba118cbe19a71f7b5e2425c2718ef96007c325944a1152/datasets-3.6.0-py3-none-any.whl", hash = "sha256:25000c4a2c0873a710df127d08a202a06eab7bf42441a6bc278b499c2f72cd1b", size = 491546, upload-time = "2025-05-07T15:14:59.742Z" },
+]
+
+[[package]]
+name = "debugpy"
+version = "1.8.17"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/15/ad/71e708ff4ca377c4230530d6a7aa7992592648c122a2cd2b321cf8b35a76/debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e", size = 1644129, upload-time = "2025-09-17T16:33:20.633Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/08/2b/9d8e65beb2751876c82e1aceb32f328c43ec872711fa80257c7674f45650/debugpy-1.8.17-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:f14467edef672195c6f6b8e27ce5005313cb5d03c9239059bc7182b60c176e2d", size = 2549522, upload-time = "2025-09-17T16:33:38.466Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/78/eb0d77f02971c05fca0eb7465b18058ba84bd957062f5eec82f941ac792a/debugpy-1.8.17-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:24693179ef9dfa20dca8605905a42b392be56d410c333af82f1c5dff807a64cc", size = 4309417, upload-time = "2025-09-17T16:33:41.299Z" },
+ { url = "https://files.pythonhosted.org/packages/37/42/c40f1d8cc1fed1e75ea54298a382395b8b937d923fcf41ab0797a554f555/debugpy-1.8.17-cp312-cp312-win32.whl", hash = "sha256:6a4e9dacf2cbb60d2514ff7b04b4534b0139facbf2abdffe0639ddb6088e59cf", size = 5277130, upload-time = "2025-09-17T16:33:43.554Z" },
+ { url = "https://files.pythonhosted.org/packages/72/22/84263b205baad32b81b36eac076de0cdbe09fe2d0637f5b32243dc7c925b/debugpy-1.8.17-cp312-cp312-win_amd64.whl", hash = "sha256:e8f8f61c518952fb15f74a302e068b48d9c4691768ade433e4adeea961993464", size = 5319053, upload-time = "2025-09-17T16:33:53.033Z" },
+ { url = "https://files.pythonhosted.org/packages/50/76/597e5cb97d026274ba297af8d89138dfd9e695767ba0e0895edb20963f40/debugpy-1.8.17-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:857c1dd5d70042502aef1c6d1c2801211f3ea7e56f75e9c335f434afb403e464", size = 2538386, upload-time = "2025-09-17T16:33:54.594Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/60/ce5c34fcdfec493701f9d1532dba95b21b2f6394147234dce21160bd923f/debugpy-1.8.17-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:3bea3b0b12f3946e098cce9b43c3c46e317b567f79570c3f43f0b96d00788088", size = 4292100, upload-time = "2025-09-17T16:33:56.353Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/95/7873cf2146577ef71d2a20bf553f12df865922a6f87b9e8ee1df04f01785/debugpy-1.8.17-cp313-cp313-win32.whl", hash = "sha256:e34ee844c2f17b18556b5bbe59e1e2ff4e86a00282d2a46edab73fd7f18f4a83", size = 5277002, upload-time = "2025-09-17T16:33:58.231Z" },
+ { url = "https://files.pythonhosted.org/packages/46/11/18c79a1cee5ff539a94ec4aa290c1c069a5580fd5cfd2fb2e282f8e905da/debugpy-1.8.17-cp313-cp313-win_amd64.whl", hash = "sha256:6c5cd6f009ad4fca8e33e5238210dc1e5f42db07d4b6ab21ac7ffa904a196420", size = 5319047, upload-time = "2025-09-17T16:34:00.586Z" },
+ { url = "https://files.pythonhosted.org/packages/de/45/115d55b2a9da6de812696064ceb505c31e952c5d89c4ed1d9bb983deec34/debugpy-1.8.17-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:045290c010bcd2d82bc97aa2daf6837443cd52f6328592698809b4549babcee1", size = 2536899, upload-time = "2025-09-17T16:34:02.657Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/73/2aa00c7f1f06e997ef57dc9b23d61a92120bec1437a012afb6d176585197/debugpy-1.8.17-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:b69b6bd9dba6a03632534cdf67c760625760a215ae289f7489a452af1031fe1f", size = 4268254, upload-time = "2025-09-17T16:34:04.486Z" },
+ { url = "https://files.pythonhosted.org/packages/86/b5/ed3e65c63c68a6634e3ba04bd10255c8e46ec16ebed7d1c79e4816d8a760/debugpy-1.8.17-cp314-cp314-win32.whl", hash = "sha256:5c59b74aa5630f3a5194467100c3b3d1c77898f9ab27e3f7dc5d40fc2f122670", size = 5277203, upload-time = "2025-09-17T16:34:06.65Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/26/394276b71c7538445f29e792f589ab7379ae70fd26ff5577dfde71158e96/debugpy-1.8.17-cp314-cp314-win_amd64.whl", hash = "sha256:893cba7bb0f55161de4365584b025f7064e1f88913551bcd23be3260b231429c", size = 5318493, upload-time = "2025-09-17T16:34:08.483Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/d0/89247ec250369fc76db477720a26b2fce7ba079ff1380e4ab4529d2fe233/debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef", size = 5283210, upload-time = "2025-09-17T16:34:25.835Z" },
+]
+
+[[package]]
+name = "decorator"
+version = "5.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" },
+]
+
+[[package]]
+name = "dill"
+version = "0.3.8"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/17/4d/ac7ffa80c69ea1df30a8aa11b3578692a5118e7cd1aa157e3ef73b092d15/dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca", size = 184847, upload-time = "2024-01-27T23:42:16.145Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c9/7a/cef76fd8438a42f96db64ddaa85280485a9c395e7df3db8158cfec1eee34/dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7", size = 116252, upload-time = "2024-01-27T23:42:14.239Z" },
+]
+
+[[package]]
+name = "distro"
+version = "1.9.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" },
+]
+
+[[package]]
+name = "docstring-parser"
+version = "0.17.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" },
+]
+
+[[package]]
+name = "durationpy"
+version = "0.10"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9d/a4/e44218c2b394e31a6dd0d6b095c4e1f32d0be54c2a4b250032d717647bab/durationpy-0.10.tar.gz", hash = "sha256:1fa6893409a6e739c9c72334fc65cca1f355dbdd93405d30f726deb5bde42fba", size = 3335, upload-time = "2025-05-17T13:52:37.26Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b0/0d/9feae160378a3553fa9a339b0e9c1a048e147a4127210e286ef18b730f03/durationpy-0.10-py3-none-any.whl", hash = "sha256:3b41e1b601234296b4fb368338fdcd3e13e0b4fb5b67345948f4f2bf9868b286", size = 3922, upload-time = "2025-05-17T13:52:36.463Z" },
+]
+
+[[package]]
+name = "executing"
+version = "2.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" },
+]
+
+[[package]]
+name = "fastapi"
+version = "0.118.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pydantic" },
+ { name = "starlette" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/28/3c/2b9345a6504e4055eaa490e0b41c10e338ad61d9aeaae41d97807873cdf2/fastapi-0.118.0.tar.gz", hash = "sha256:5e81654d98c4d2f53790a7d32d25a7353b30c81441be7d0958a26b5d761fa1c8", size = 310536, upload-time = "2025-09-29T03:37:23.126Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/54/20/54e2bdaad22ca91a59455251998d43094d5c3d3567c52c7c04774b3f43f2/fastapi-0.118.0-py3-none-any.whl", hash = "sha256:705137a61e2ef71019d2445b123aa8845bd97273c395b744d5a7dfe559056855", size = 97694, upload-time = "2025-09-29T03:37:21.338Z" },
+]
+
+[[package]]
+name = "fastuuid"
+version = "0.13.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/15/80/3c16a1edad2e6cd82fbd15ac998cc1b881f478bf1f80ca717d941c441874/fastuuid-0.13.5.tar.gz", hash = "sha256:d4976821ab424d41542e1ea39bc828a9d454c3f8a04067c06fca123c5b95a1a1", size = 18255, upload-time = "2025-09-26T09:05:38.281Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/21/36/434f137c5970cac19e57834e1f7680e85301619d49891618c00666700c61/fastuuid-0.13.5-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:35fe8045e866bc6846f8de6fa05acb1de0c32478048484a995e96d31e21dff2a", size = 494638, upload-time = "2025-09-26T09:14:58.695Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/3c/083de2ac007b2b305523b9c006dba5051e5afd87a626ef1a39f76e2c6b82/fastuuid-0.13.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:02a460333f52d731a006d18a52ef6fcb2d295a1f5b1a5938d30744191b2f77b7", size = 253138, upload-time = "2025-09-26T09:13:33.283Z" },
+ { url = "https://files.pythonhosted.org/packages/73/5e/630cffa1c8775db526e39e9e4c5c7db0c27be0786bb21ba82c912ae19f63/fastuuid-0.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:74b0e4f8c307b9f477a5d7284db4431ce53a3c1e3f4173db7a97db18564a6202", size = 244521, upload-time = "2025-09-26T09:14:40.682Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/51/55d78705f4fbdadf88fb40f382f508d6c7a4941ceddd7825fafebb4cc778/fastuuid-0.13.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6955a99ef455c2986f3851f4e0ccc35dec56ac1a7720f2b92e88a75d6684512e", size = 271557, upload-time = "2025-09-26T09:15:09.75Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/2b/1b89e90a8635e5587ccdbbeb169c590672ce7637880f2c047482a0359950/fastuuid-0.13.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f10c77b826738c1a27dcdaa92ea4dc1ec9d869748a99e1fde54f1379553d4854", size = 272334, upload-time = "2025-09-26T09:07:48.865Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/06/4c8207894eeb30414999e5c3f66ac039bc4003437eb4060d8a1bceb4cc6f/fastuuid-0.13.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb25dccbeb249d16d5e664f65f17ebec05136821d5ef462c4110e3f76b86fb86", size = 290594, upload-time = "2025-09-26T09:12:54.124Z" },
+ { url = "https://files.pythonhosted.org/packages/50/69/96d221931a31d77a47cc2487bdfacfb3091edfc2e7a04b1795df1aec05df/fastuuid-0.13.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a5becc646a3eeafb76ce0a6783ba190cd182e3790a8b2c78ca9db2b5e87af952", size = 452835, upload-time = "2025-09-26T09:14:00.994Z" },
+ { url = "https://files.pythonhosted.org/packages/25/ef/bf045f0a47dcec96247497ef3f7a31d86ebc074330e2dccc34b8dbc0468a/fastuuid-0.13.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:69b34363752d06e9bb0dbdf02ae391ec56ac948c6f2eb00be90dad68e80774b9", size = 468225, upload-time = "2025-09-26T09:13:38.585Z" },
+ { url = "https://files.pythonhosted.org/packages/30/46/4817ab5a3778927155a4bde92540d4c4fa996161ec8b8e080c8928b0984e/fastuuid-0.13.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57d0768afcad0eab8770c9b8cf904716bd3c547e8b9a4e755ee8a673b060a3a3", size = 444907, upload-time = "2025-09-26T09:14:30.163Z" },
+ { url = "https://files.pythonhosted.org/packages/80/27/ab284117ce4dc9b356a7196bdbf220510285f201d27f1f078592cdc8187b/fastuuid-0.13.5-cp312-cp312-win32.whl", hash = "sha256:8ac6c6f5129d52eaa6ef9ea4b6e2f7c69468a053f3ab8e439661186b9c06bb85", size = 145415, upload-time = "2025-09-26T09:08:59.494Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/0c/f970a4222773b248931819f8940800b760283216ca3dda173ed027e94bdd/fastuuid-0.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:ad630e97715beefef07ec37c9c162336e500400774e2c1cbe1a0df6f80d15b9a", size = 150840, upload-time = "2025-09-26T09:13:46.115Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/62/74fc53f6e04a4dc5b36c34e4e679f85a4c14eec800dcdb0f2c14b5442217/fastuuid-0.13.5-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:ea17dfd35e0e91920a35d91e65e5f9c9d1985db55ac4ff2f1667a0f61189cefa", size = 494678, upload-time = "2025-09-26T09:14:30.908Z" },
+ { url = "https://files.pythonhosted.org/packages/09/ba/f28b9b7045738a8bfccfb9cd6aff4b91fce2669e6b383a48b0694ee9b3ff/fastuuid-0.13.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:be6ad91e5fefbcc2a4b478858a2715e386d405834ea3ae337c3b6b95cc0e47d6", size = 253162, upload-time = "2025-09-26T09:13:35.879Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/18/13fac89cb4c9f0cd7e81a9154a77ecebcc95d2b03477aa91d4d50f7227ee/fastuuid-0.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ea6df13a306aab3e0439d58c312ff1e6f4f07f09f667579679239b4a6121f64a", size = 244546, upload-time = "2025-09-26T09:14:58.13Z" },
+ { url = "https://files.pythonhosted.org/packages/04/bf/9691167804d59411cc4269841df949f6dd5e76452ab10dcfcd1dbe04c5bc/fastuuid-0.13.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2354c1996d3cf12dc2ba3752e2c4d6edc46e1a38c63893146777b1939f3062d4", size = 271528, upload-time = "2025-09-26T09:14:48.996Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/b5/7a75a03d1c7aa0b6d573032fcca39391f0aef7f2caabeeb45a672bc0bd3c/fastuuid-0.13.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6cf9b7469fc26d1f9b1c43ac4b192e219e85b88fdf81d71aa755a6c08c8a817", size = 272292, upload-time = "2025-09-26T09:14:42.82Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/db/fa0f16cbf76e6880599533af4ef01bb586949c5320612e9d884eff13e603/fastuuid-0.13.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92ba539170097b9047551375f1ca09d8d2b4aefcc79eeae3e1c43fe49b42072e", size = 290466, upload-time = "2025-09-26T09:08:33.161Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/02/6b8c45bfbc8500994dd94edba7f59555f9683c4d8c9a164ae1d25d03c7c7/fastuuid-0.13.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:dbb81d05617bc2970765c1ad82db7e8716f6a2b7a361a14b83de5b9240ade448", size = 452838, upload-time = "2025-09-26T09:13:44.747Z" },
+ { url = "https://files.pythonhosted.org/packages/27/12/85d95a84f265b888e8eb9f9e2b5aaf331e8be60c0a7060146364b3544b6a/fastuuid-0.13.5-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:d973bd6bf9d754d3cca874714ac0a6b22a47f239fb3d3c8687569db05aac3471", size = 468149, upload-time = "2025-09-26T09:13:18.712Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/da/dd9a137e9ea707e883c92470113a432233482ec9ad3e9b99c4defc4904e6/fastuuid-0.13.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e725ceef79486423f05ee657634d4b4c1ca5fb2c8a94e0708f5d6356a83f2a83", size = 444933, upload-time = "2025-09-26T09:14:09.494Z" },
+ { url = "https://files.pythonhosted.org/packages/12/f4/ab363d7f4ac3989691e2dc5ae2d8391cfb0b4169e52ef7fa0ac363e936f0/fastuuid-0.13.5-cp313-cp313-win32.whl", hash = "sha256:a1c430a332ead0b2674f1ef71b17f43b8139ec5a4201182766a21f131a31e021", size = 145462, upload-time = "2025-09-26T09:14:15.105Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/8a/52eb77d9c294a54caa0d2d8cc9f906207aa6d916a22de963687ab6db8b86/fastuuid-0.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:241fdd362fd96e6b337db62a65dd7cb3dfac20adf854573247a47510e192db6f", size = 150923, upload-time = "2025-09-26T09:13:03.923Z" },
+]
+
+[[package]]
+name = "feedparser"
+version = "6.0.12"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "sgmllib3k" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/dc/79/db7edb5e77d6dfbc54d7d9df72828be4318275b2e580549ff45a962f6461/feedparser-6.0.12.tar.gz", hash = "sha256:64f76ce90ae3e8ef5d1ede0f8d3b50ce26bcce71dd8ae5e82b1cd2d4a5f94228", size = 286579, upload-time = "2025-09-10T13:33:59.486Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4e/eb/c96d64137e29ae17d83ad2552470bafe3a7a915e85434d9942077d7fd011/feedparser-6.0.12-py3-none-any.whl", hash = "sha256:6bbff10f5a52662c00a2e3f86a38928c37c48f77b3c511aedcd51de933549324", size = 81480, upload-time = "2025-09-10T13:33:58.022Z" },
+]
+
+[[package]]
+name = "ffmpy"
+version = "0.6.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0b/f6/67cadf1686030be511004e75fa1c1397f8f193cd4d15d4788edef7c28621/ffmpy-0.6.1.tar.gz", hash = "sha256:b5830fd05f72bace05b8fb28724d54a7a63c5119d7f74ca36a75df33f749142d", size = 4958, upload-time = "2025-07-22T12:08:22.276Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/74/d4/1806897b31c480efc4e97c22506ac46c716084f573aef780bb7fb7a16e8a/ffmpy-0.6.1-py3-none-any.whl", hash = "sha256:69a37e2d7d6feb840e233d5640f3499a8b0a8657336774c86e4c52a3219222d4", size = 5512, upload-time = "2025-07-22T12:08:21.176Z" },
+]
+
+[[package]]
+name = "filelock"
+version = "3.19.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" },
+]
+
+[[package]]
+name = "flask"
+version = "3.1.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "blinker" },
+ { name = "click" },
+ { name = "itsdangerous" },
+ { name = "jinja2" },
+ { name = "markupsafe" },
+ { name = "werkzeug" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/dc/6d/cfe3c0fcc5e477df242b98bfe186a4c34357b4847e87ecaef04507332dab/flask-3.1.2.tar.gz", hash = "sha256:bf656c15c80190ed628ad08cdfd3aaa35beb087855e2f494910aa3774cc4fd87", size = 720160, upload-time = "2025-08-19T21:03:21.205Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ec/f9/7f9263c5695f4bd0023734af91bedb2ff8209e8de6ead162f35d8dc762fd/flask-3.1.2-py3-none-any.whl", hash = "sha256:ca1d8112ec8a6158cc29ea4858963350011b5c846a414cdb7a954aa9e967d03c", size = 103308, upload-time = "2025-08-19T21:03:19.499Z" },
+]
+
+[[package]]
+name = "flatbuffers"
+version = "25.9.23"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9d/1f/3ee70b0a55137442038f2a33469cc5fddd7e0ad2abf83d7497c18a2b6923/flatbuffers-25.9.23.tar.gz", hash = "sha256:676f9fa62750bb50cf531b42a0a2a118ad8f7f797a511eda12881c016f093b12", size = 22067, upload-time = "2025-09-24T05:25:30.106Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ee/1b/00a78aa2e8fbd63f9af08c9c19e6deb3d5d66b4dda677a0f61654680ee89/flatbuffers-25.9.23-py2.py3-none-any.whl", hash = "sha256:255538574d6cb6d0a79a17ec8bc0d30985913b87513a01cce8bcdb6b4c44d0e2", size = 30869, upload-time = "2025-09-24T05:25:28.912Z" },
+]
+
+[[package]]
+name = "fonttools"
+version = "4.60.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4b/42/97a13e47a1e51a5a7142475bbcf5107fe3a68fc34aef331c897d5fb98ad0/fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9", size = 3559823, upload-time = "2025-09-29T21:13:27.129Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e3/f7/a10b101b7a6f8836a5adb47f2791f2075d044a6ca123f35985c42edc82d8/fonttools-4.60.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7b0c6d57ab00dae9529f3faf187f2254ea0aa1e04215cf2f1a8ec277c96661bc", size = 2832953, upload-time = "2025-09-29T21:11:39.616Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/fe/7bd094b59c926acf2304d2151354ddbeb74b94812f3dc943c231db09cb41/fonttools-4.60.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:839565cbf14645952d933853e8ade66a463684ed6ed6c9345d0faf1f0e868877", size = 2352706, upload-time = "2025-09-29T21:11:41.826Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/ca/4bb48a26ed95a1e7eba175535fe5805887682140ee0a0d10a88e1de84208/fonttools-4.60.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8177ec9676ea6e1793c8a084a90b65a9f778771998eb919d05db6d4b1c0b114c", size = 4923716, upload-time = "2025-09-29T21:11:43.893Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/9f/2cb82999f686c1d1ddf06f6ae1a9117a880adbec113611cc9d22b2fdd465/fonttools-4.60.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:996a4d1834524adbb423385d5a629b868ef9d774670856c63c9a0408a3063401", size = 4968175, upload-time = "2025-09-29T21:11:46.439Z" },
+ { url = "https://files.pythonhosted.org/packages/18/79/be569699e37d166b78e6218f2cde8c550204f2505038cdd83b42edc469b9/fonttools-4.60.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a46b2f450bc79e06ef3b6394f0c68660529ed51692606ad7f953fc2e448bc903", size = 4911031, upload-time = "2025-09-29T21:11:48.977Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/9f/89411cc116effaec5260ad519162f64f9c150e5522a27cbb05eb62d0c05b/fonttools-4.60.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ec722ee589e89a89f5b7574f5c45604030aa6ae24cb2c751e2707193b466fed", size = 5062966, upload-time = "2025-09-29T21:11:54.344Z" },
+ { url = "https://files.pythonhosted.org/packages/62/a1/f888221934b5731d46cb9991c7a71f30cb1f97c0ef5fcf37f8da8fce6c8e/fonttools-4.60.1-cp312-cp312-win32.whl", hash = "sha256:b2cf105cee600d2de04ca3cfa1f74f1127f8455b71dbad02b9da6ec266e116d6", size = 2218750, upload-time = "2025-09-29T21:11:56.601Z" },
+ { url = "https://files.pythonhosted.org/packages/88/8f/a55b5550cd33cd1028601df41acd057d4be20efa5c958f417b0c0613924d/fonttools-4.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:992775c9fbe2cf794786fa0ffca7f09f564ba3499b8fe9f2f80bd7197db60383", size = 2267026, upload-time = "2025-09-29T21:11:58.852Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/5b/cdd2c612277b7ac7ec8c0c9bc41812c43dc7b2d5f2b0897e15fdf5a1f915/fonttools-4.60.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb", size = 2825777, upload-time = "2025-09-29T21:12:01.22Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/8a/de9cc0540f542963ba5e8f3a1f6ad48fa211badc3177783b9d5cadf79b5d/fonttools-4.60.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4", size = 2348080, upload-time = "2025-09-29T21:12:03.785Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/8b/371ab3cec97ee3fe1126b3406b7abd60c8fec8975fd79a3c75cdea0c3d83/fonttools-4.60.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c", size = 4903082, upload-time = "2025-09-29T21:12:06.382Z" },
+ { url = "https://files.pythonhosted.org/packages/04/05/06b1455e4bc653fcb2117ac3ef5fa3a8a14919b93c60742d04440605d058/fonttools-4.60.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77", size = 4960125, upload-time = "2025-09-29T21:12:09.314Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/37/f3b840fcb2666f6cb97038793606bdd83488dca2d0b0fc542ccc20afa668/fonttools-4.60.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199", size = 4901454, upload-time = "2025-09-29T21:12:11.931Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/9e/eb76f77e82f8d4a46420aadff12cec6237751b0fb9ef1de373186dcffb5f/fonttools-4.60.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c", size = 5044495, upload-time = "2025-09-29T21:12:15.241Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/b3/cede8f8235d42ff7ae891bae8d619d02c8ac9fd0cfc450c5927a6200c70d/fonttools-4.60.1-cp313-cp313-win32.whl", hash = "sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272", size = 2217028, upload-time = "2025-09-29T21:12:17.96Z" },
+ { url = "https://files.pythonhosted.org/packages/75/4d/b022c1577807ce8b31ffe055306ec13a866f2337ecee96e75b24b9b753ea/fonttools-4.60.1-cp313-cp313-win_amd64.whl", hash = "sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac", size = 2266200, upload-time = "2025-09-29T21:12:20.14Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/83/752ca11c1aa9a899b793a130f2e466b79ea0cf7279c8d79c178fc954a07b/fonttools-4.60.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3", size = 2822830, upload-time = "2025-09-29T21:12:24.406Z" },
+ { url = "https://files.pythonhosted.org/packages/57/17/bbeab391100331950a96ce55cfbbff27d781c1b85ebafb4167eae50d9fe3/fonttools-4.60.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85", size = 2345524, upload-time = "2025-09-29T21:12:26.819Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/2e/d4831caa96d85a84dd0da1d9f90d81cec081f551e0ea216df684092c6c97/fonttools-4.60.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537", size = 4843490, upload-time = "2025-09-29T21:12:29.123Z" },
+ { url = "https://files.pythonhosted.org/packages/49/13/5e2ea7c7a101b6fc3941be65307ef8df92cbbfa6ec4804032baf1893b434/fonttools-4.60.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003", size = 4944184, upload-time = "2025-09-29T21:12:31.414Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/2b/cf9603551c525b73fc47c52ee0b82a891579a93d9651ed694e4e2cd08bb8/fonttools-4.60.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08", size = 4890218, upload-time = "2025-09-29T21:12:33.936Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/2f/933d2352422e25f2376aae74f79eaa882a50fb3bfef3c0d4f50501267101/fonttools-4.60.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99", size = 4999324, upload-time = "2025-09-29T21:12:36.637Z" },
+ { url = "https://files.pythonhosted.org/packages/38/99/234594c0391221f66216bc2c886923513b3399a148defaccf81dc3be6560/fonttools-4.60.1-cp314-cp314-win32.whl", hash = "sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6", size = 2220861, upload-time = "2025-09-29T21:12:39.108Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/1d/edb5b23726dde50fc4068e1493e4fc7658eeefcaf75d4c5ffce067d07ae5/fonttools-4.60.1-cp314-cp314-win_amd64.whl", hash = "sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987", size = 2270934, upload-time = "2025-09-29T21:12:41.339Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/da/1392aaa2170adc7071fe7f9cfd181a5684a7afcde605aebddf1fb4d76df5/fonttools-4.60.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299", size = 2894340, upload-time = "2025-09-29T21:12:43.774Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/a7/3b9f16e010d536ce567058b931a20b590d8f3177b2eda09edd92e392375d/fonttools-4.60.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01", size = 2375073, upload-time = "2025-09-29T21:12:46.437Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/b5/e9bcf51980f98e59bb5bb7c382a63c6f6cac0eec5f67de6d8f2322382065/fonttools-4.60.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801", size = 4849758, upload-time = "2025-09-29T21:12:48.694Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/dc/1d2cf7d1cba82264b2f8385db3f5960e3d8ce756b4dc65b700d2c496f7e9/fonttools-4.60.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc", size = 5085598, upload-time = "2025-09-29T21:12:51.081Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/4d/279e28ba87fb20e0c69baf72b60bbf1c4d873af1476806a7b5f2b7fac1ff/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc", size = 4957603, upload-time = "2025-09-29T21:12:53.423Z" },
+ { url = "https://files.pythonhosted.org/packages/78/d4/ff19976305e0c05aa3340c805475abb00224c954d3c65e82c0a69633d55d/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed", size = 4974184, upload-time = "2025-09-29T21:12:55.962Z" },
+ { url = "https://files.pythonhosted.org/packages/63/22/8553ff6166f5cd21cfaa115aaacaa0dc73b91c079a8cfd54a482cbc0f4f5/fonttools-4.60.1-cp314-cp314t-win32.whl", hash = "sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259", size = 2282241, upload-time = "2025-09-29T21:12:58.179Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/cb/fa7b4d148e11d5a72761a22e595344133e83a9507a4c231df972e657579b/fonttools-4.60.1-cp314-cp314t-win_amd64.whl", hash = "sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c", size = 2345760, upload-time = "2025-09-29T21:13:00.375Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/93/0dd45cd283c32dea1545151d8c3637b4b8c53cdb3a625aeb2885b184d74d/fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb", size = 1143175, upload-time = "2025-09-29T21:13:24.134Z" },
+]
+
+[[package]]
+name = "frozenlist"
+version = "1.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" },
+ { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" },
+ { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" },
+ { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" },
+ { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" },
+ { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" },
+ { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" },
+ { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" },
+ { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" },
+ { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" },
+ { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" },
+ { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" },
+ { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" },
+ { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" },
+ { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" },
+ { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" },
+ { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" },
+ { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" },
+ { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" },
+ { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" },
+ { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" },
+ { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" },
+]
+
+[[package]]
+name = "fsspec"
+version = "2025.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/34/f4/5721faf47b8c499e776bc34c6a8fc17efdf7fdef0b00f398128bc5dcb4ac/fsspec-2025.3.0.tar.gz", hash = "sha256:a935fd1ea872591f2b5148907d103488fc523295e6c64b835cfad8c3eca44972", size = 298491, upload-time = "2025-03-07T21:47:56.461Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/56/53/eb690efa8513166adef3e0669afd31e95ffde69fb3c52ec2ac7223ed6018/fsspec-2025.3.0-py3-none-any.whl", hash = "sha256:efb87af3efa9103f94ca91a7f8cb7a4df91af9f74fc106c9c7ea0efd7277c1b3", size = 193615, upload-time = "2025-03-07T21:47:54.809Z" },
+]
+
+[package.optional-dependencies]
+http = [
+ { name = "aiohttp" },
+]
+
+[[package]]
+name = "gitdb"
+version = "4.0.12"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "smmap" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" },
+]
+
+[[package]]
+name = "gitpython"
+version = "3.1.45"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "gitdb" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9a/c8/dd58967d119baab745caec2f9d853297cec1989ec1d63f677d3880632b88/gitpython-3.1.45.tar.gz", hash = "sha256:85b0ee964ceddf211c41b9f27a49086010a190fd8132a24e21f362a4b36a791c", size = 215076, upload-time = "2025-07-24T03:45:54.871Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/01/61/d4b89fec821f72385526e1b9d9a3a0385dda4a72b206d28049e2c7cd39b8/gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77", size = 208168, upload-time = "2025-07-24T03:45:52.517Z" },
+]
+
+[[package]]
+name = "google-ai-generativelanguage"
+version = "0.6.15"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "google-api-core", extra = ["grpc"] },
+ { name = "google-auth" },
+ { name = "proto-plus" },
+ { name = "protobuf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/11/d1/48fe5d7a43d278e9f6b5ada810b0a3530bbeac7ed7fcbcd366f932f05316/google_ai_generativelanguage-0.6.15.tar.gz", hash = "sha256:8f6d9dc4c12b065fe2d0289026171acea5183ebf2d0b11cefe12f3821e159ec3", size = 1375443, upload-time = "2025-01-13T21:50:47.459Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7c/a3/67b8a6ff5001a1d8864922f2d6488dc2a14367ceb651bc3f09a947f2f306/google_ai_generativelanguage-0.6.15-py3-none-any.whl", hash = "sha256:5a03ef86377aa184ffef3662ca28f19eeee158733e45d7947982eb953c6ebb6c", size = 1327356, upload-time = "2025-01-13T21:50:44.174Z" },
+]
+
+[[package]]
+name = "google-api-core"
+version = "1.34.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "google-auth" },
+ { name = "googleapis-common-protos" },
+ { name = "protobuf" },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c8/b0/7c8d4a03960da803a4c471545fd7b3404d2819f1585ba3f3d97e887aa91d/google-api-core-1.34.1.tar.gz", hash = "sha256:3399c92887a97d33038baa4bfd3bf07acc05d474b0171f333e1f641c1364e552", size = 129177, upload-time = "2024-02-14T15:18:26.166Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/11/51/1d325e9b7358f15dca82e1ed91413c5cecb9d4665da6c44cb8dd348deeaa/google_api_core-1.34.1-py3-none-any.whl", hash = "sha256:52bcc9d9937735f8a3986fa0bbf9135ae9cf5393a722387e5eced520e39c774a", size = 120355, upload-time = "2024-02-14T15:18:23.907Z" },
+]
+
+[package.optional-dependencies]
+grpc = [
+ { name = "grpcio" },
+ { name = "grpcio-status" },
+]
+
+[[package]]
+name = "google-api-python-client"
+version = "2.183.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "google-api-core" },
+ { name = "google-auth" },
+ { name = "google-auth-httplib2" },
+ { name = "httplib2" },
+ { name = "uritemplate" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fa/1f/49a2c83fc6dcd8b127cc9efbecf7d5fc36109c2028ba22ed6cb4d072fca4/google_api_python_client-2.183.0.tar.gz", hash = "sha256:abae37e04fecf719388e5c02f707ed9cdf952f10b217c79a3e76c636762e3ea9", size = 13645623, upload-time = "2025-09-23T22:27:00.854Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ab/06/1974f937172854bc7622eff5c2390f33542ceb843f305922922c8f5f7f17/google_api_python_client-2.183.0-py3-none-any.whl", hash = "sha256:2005b6e86c27be1db1a43f43e047a0f8e004159f3cceddecb08cf1624bddba31", size = 14214837, upload-time = "2025-09-23T22:26:57.758Z" },
+]
+
+[[package]]
+name = "google-auth"
+version = "2.41.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cachetools" },
+ { name = "pyasn1-modules" },
+ { name = "rsa" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/07/c5/87742f5b5f055514c67f970f7174a876fccff2289a69d460b0614cc7ccfb/google_auth-2.41.0.tar.gz", hash = "sha256:c9d7b534ea4a5d9813c552846797fafb080312263cd4994d6622dd50992ae101", size = 292282, upload-time = "2025-09-29T21:36:35.791Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/ff/a1c426fc9bea7268230bf92340da7d112fae18cf946cafe13ab17d14e6ee/google_auth-2.41.0-py2.py3-none-any.whl", hash = "sha256:d8bed9b53ab63b7b0374656b8e1bef051f95bb14ecc0cf21ba49de7911d62e09", size = 221168, upload-time = "2025-09-29T21:36:33.925Z" },
+]
+
+[[package]]
+name = "google-auth-httplib2"
+version = "0.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "google-auth" },
+ { name = "httplib2" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/56/be/217a598a818567b28e859ff087f347475c807a5649296fb5a817c58dacef/google-auth-httplib2-0.2.0.tar.gz", hash = "sha256:38aa7badf48f974f1eb9861794e9c0cb2a0511a4ec0679b1f886d108f5640e05", size = 10842, upload-time = "2023-12-12T17:40:30.722Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/be/8a/fe34d2f3f9470a27b01c9e76226965863f153d5fbe276f83608562e49c04/google_auth_httplib2-0.2.0-py2.py3-none-any.whl", hash = "sha256:b65a0a2123300dd71281a7bf6e64d65a0759287df52729bdd1ae2e47dc311a3d", size = 9253, upload-time = "2023-12-12T17:40:13.055Z" },
+]
+
+[[package]]
+name = "google-genai"
+version = "1.41.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "google-auth" },
+ { name = "httpx" },
+ { name = "pydantic" },
+ { name = "requests" },
+ { name = "tenacity" },
+ { name = "typing-extensions" },
+ { name = "websockets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/72/8b/ee20bcf707769b3b0e1106c3b5c811507736af7e8a60f29a70af1750ba19/google_genai-1.41.0.tar.gz", hash = "sha256:134f861bb0ace4e34af0501ecb75ceee15f7662fd8120698cd185e8cb39f2800", size = 245812, upload-time = "2025-10-02T22:30:29.699Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/15/14/e5e8fbca8863fee718208566c4e927b8e9f45fd46ec5cf89e24759da545b/google_genai-1.41.0-py3-none-any.whl", hash = "sha256:111a3ee64c1a0927d3879faddb368234594432479a40c311e5fe4db338ca8778", size = 245931, upload-time = "2025-10-02T22:30:27.885Z" },
+]
+
+[[package]]
+name = "google-generativeai"
+version = "0.8.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "google-ai-generativelanguage" },
+ { name = "google-api-core" },
+ { name = "google-api-python-client" },
+ { name = "google-auth" },
+ { name = "protobuf" },
+ { name = "pydantic" },
+ { name = "tqdm" },
+ { name = "typing-extensions" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6e/40/c42ff9ded9f09ec9392879a8e6538a00b2dc185e834a3392917626255419/google_generativeai-0.8.5-py3-none-any.whl", hash = "sha256:22b420817fb263f8ed520b33285f45976d5b21e904da32b80d4fd20c055123a2", size = 155427, upload-time = "2025-04-17T00:40:00.67Z" },
+]
+
+[[package]]
+name = "googleapis-common-protos"
+version = "1.70.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "protobuf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/39/24/33db22342cf4a2ea27c9955e6713140fedd51e8b141b5ce5260897020f1a/googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257", size = 145903, upload-time = "2025-04-14T10:17:02.924Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530, upload-time = "2025-04-14T10:17:01.271Z" },
+]
+
+[[package]]
+name = "gradio"
+version = "5.47.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiofiles" },
+ { name = "anyio" },
+ { name = "audioop-lts", marker = "python_full_version >= '3.13'" },
+ { name = "brotli" },
+ { name = "fastapi" },
+ { name = "ffmpy" },
+ { name = "gradio-client" },
+ { name = "groovy" },
+ { name = "httpx" },
+ { name = "huggingface-hub" },
+ { name = "jinja2" },
+ { name = "markupsafe" },
+ { name = "numpy" },
+ { name = "orjson" },
+ { name = "packaging" },
+ { name = "pandas" },
+ { name = "pillow" },
+ { name = "pydantic" },
+ { name = "pydub" },
+ { name = "python-multipart" },
+ { name = "pyyaml" },
+ { name = "ruff" },
+ { name = "safehttpx" },
+ { name = "semantic-version" },
+ { name = "starlette" },
+ { name = "tomlkit" },
+ { name = "typer" },
+ { name = "typing-extensions" },
+ { name = "uvicorn" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/68/df/b792699b386c91aac38f5f844f92703a9fdd37aa4d2193c37de2cd4fa007/gradio-5.47.2.tar.gz", hash = "sha256:2e1cc00421da159ed9e9e2c8760e792ca2d8fa9bc610f3da0ec5cfa3fa6ca0be", size = 72289342, upload-time = "2025-09-26T19:51:10.355Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/71/44/7fed1186a9c289dad190011c1d86be761aeef968e856d653efa2f1d48dc9/gradio-5.47.2-py3-none-any.whl", hash = "sha256:e5cdf106b27bdb321284f327537682f3060ef0c62d9c70236eeaa8b1917a6803", size = 60369896, upload-time = "2025-09-26T19:51:05.636Z" },
+]
+
+[[package]]
+name = "gradio-client"
+version = "1.13.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "fsspec" },
+ { name = "httpx" },
+ { name = "huggingface-hub" },
+ { name = "packaging" },
+ { name = "typing-extensions" },
+ { name = "websockets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/3e/a9/a3beb0ece8c05c33e6376b790fa42e0dd157abca8220cf639b249a597467/gradio_client-1.13.3.tar.gz", hash = "sha256:869b3e67e0f7a0f40df8c48c94de99183265cf4b7b1d9bd4623e336d219ffbe7", size = 323253, upload-time = "2025-09-26T19:51:21.7Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6e/0b/337b74504681b5dde39f20d803bb09757f9973ecdc65fd4e819d4b11faf7/gradio_client-1.13.3-py3-none-any.whl", hash = "sha256:3f63e4d33a2899c1a12b10fe3cf77b82a6919ff1a1fb6391f6aa225811aa390c", size = 325350, upload-time = "2025-09-26T19:51:20.288Z" },
+]
+
+[[package]]
+name = "greenlet"
+version = "3.2.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/44/69/9b804adb5fd0671f367781560eb5eb586c4d495277c93bde4307b9e28068/greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", size = 274079, upload-time = "2025-08-07T13:15:45.033Z" },
+ { url = "https://files.pythonhosted.org/packages/46/e9/d2a80c99f19a153eff70bc451ab78615583b8dac0754cfb942223d2c1a0d/greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", size = 640997, upload-time = "2025-08-07T13:42:56.234Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/16/035dcfcc48715ccd345f3a93183267167cdd162ad123cd93067d86f27ce4/greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968", size = 655185, upload-time = "2025-08-07T13:45:27.624Z" },
+ { url = "https://files.pythonhosted.org/packages/31/da/0386695eef69ffae1ad726881571dfe28b41970173947e7c558d9998de0f/greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9", size = 649926, upload-time = "2025-08-07T13:53:15.251Z" },
+ { url = "https://files.pythonhosted.org/packages/68/88/69bf19fd4dc19981928ceacbc5fd4bb6bc2215d53199e367832e98d1d8fe/greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6", size = 651839, upload-time = "2025-08-07T13:18:30.281Z" },
+ { url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586, upload-time = "2025-08-07T13:18:28.544Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281, upload-time = "2025-08-07T13:42:39.858Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142, upload-time = "2025-08-07T13:18:22.981Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899, upload-time = "2025-08-07T13:38:53.448Z" },
+ { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" },
+ { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516, upload-time = "2025-08-07T13:53:16.314Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" },
+ { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" },
+ { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" },
+ { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" },
+]
+
+[[package]]
+name = "groovy"
+version = "0.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/52/36/bbdede67400277bef33d3ec0e6a31750da972c469f75966b4930c753218f/groovy-0.1.2.tar.gz", hash = "sha256:25c1dc09b3f9d7e292458aa762c6beb96ea037071bf5e917fc81fb78d2231083", size = 17325, upload-time = "2025-02-28T20:24:56.068Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/28/27/3d6dcadc8a3214d8522c1e7f6a19554e33659be44546d44a2f7572ac7d2a/groovy-0.1.2-py3-none-any.whl", hash = "sha256:7f7975bab18c729a257a8b1ae9dcd70b7cafb1720481beae47719af57c35fa64", size = 14090, upload-time = "2025-02-28T20:24:55.152Z" },
+]
+
+[[package]]
+name = "grpcio"
+version = "1.75.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9d/f7/8963848164c7604efb3a3e6ee457fdb3a469653e19002bd24742473254f8/grpcio-1.75.1.tar.gz", hash = "sha256:3e81d89ece99b9ace23a6916880baca613c03a799925afb2857887efa8b1b3d2", size = 12731327, upload-time = "2025-09-26T09:03:36.887Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3a/81/42be79e73a50aaa20af66731c2defeb0e8c9008d9935a64dd8ea8e8c44eb/grpcio-1.75.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:7b888b33cd14085d86176b1628ad2fcbff94cfbbe7809465097aa0132e58b018", size = 5668314, upload-time = "2025-09-26T09:01:55.424Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/a7/3686ed15822fedc58c22f82b3a7403d9faf38d7c33de46d4de6f06e49426/grpcio-1.75.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:8775036efe4ad2085975531d221535329f5dac99b6c2a854a995456098f99546", size = 11476125, upload-time = "2025-09-26T09:01:57.927Z" },
+ { url = "https://files.pythonhosted.org/packages/14/85/21c71d674f03345ab183c634ecd889d3330177e27baea8d5d247a89b6442/grpcio-1.75.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb658f703468d7fbb5dcc4037c65391b7dc34f808ac46ed9136c24fc5eeb041d", size = 6246335, upload-time = "2025-09-26T09:02:00.76Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/db/3beb661bc56a385ae4fa6b0e70f6b91ac99d47afb726fe76aaff87ebb116/grpcio-1.75.1-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4b7177a1cdb3c51b02b0c0a256b0a72fdab719600a693e0e9037949efffb200b", size = 6916309, upload-time = "2025-09-26T09:02:02.894Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/9c/eda9fe57f2b84343d44c1b66cf3831c973ba29b078b16a27d4587a1fdd47/grpcio-1.75.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7d4fa6ccc3ec2e68a04f7b883d354d7fea22a34c44ce535a2f0c0049cf626ddf", size = 6435419, upload-time = "2025-09-26T09:02:05.055Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/b8/090c98983e0a9d602e3f919a6e2d4e470a8b489452905f9a0fa472cac059/grpcio-1.75.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3d86880ecaeb5b2f0a8afa63824de93adb8ebe4e49d0e51442532f4e08add7d6", size = 7064893, upload-time = "2025-09-26T09:02:07.275Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/c0/6d53d4dbbd00f8bd81571f5478d8a95528b716e0eddb4217cc7cb45aae5f/grpcio-1.75.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a8041d2f9e8a742aeae96f4b047ee44e73619f4f9d24565e84d5446c623673b6", size = 8011922, upload-time = "2025-09-26T09:02:09.527Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/7c/48455b2d0c5949678d6982c3e31ea4d89df4e16131b03f7d5c590811cbe9/grpcio-1.75.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3652516048bf4c314ce12be37423c79829f46efffb390ad64149a10c6071e8de", size = 7466181, upload-time = "2025-09-26T09:02:12.279Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/12/04a0e79081e3170b6124f8cba9b6275871276be06c156ef981033f691880/grpcio-1.75.1-cp312-cp312-win32.whl", hash = "sha256:44b62345d8403975513af88da2f3d5cc76f73ca538ba46596f92a127c2aea945", size = 3938543, upload-time = "2025-09-26T09:02:14.77Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/d7/11350d9d7fb5adc73d2b0ebf6ac1cc70135577701e607407fe6739a90021/grpcio-1.75.1-cp312-cp312-win_amd64.whl", hash = "sha256:b1e191c5c465fa777d4cafbaacf0c01e0d5278022082c0abbd2ee1d6454ed94d", size = 4641938, upload-time = "2025-09-26T09:02:16.927Z" },
+ { url = "https://files.pythonhosted.org/packages/46/74/bac4ab9f7722164afdf263ae31ba97b8174c667153510322a5eba4194c32/grpcio-1.75.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:3bed22e750d91d53d9e31e0af35a7b0b51367e974e14a4ff229db5b207647884", size = 5672779, upload-time = "2025-09-26T09:02:19.11Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/52/d0483cfa667cddaa294e3ab88fd2c2a6e9dc1a1928c0e5911e2e54bd5b50/grpcio-1.75.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:5b8f381eadcd6ecaa143a21e9e80a26424c76a0a9b3d546febe6648f3a36a5ac", size = 11470623, upload-time = "2025-09-26T09:02:22.117Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/e4/d1954dce2972e32384db6a30273275e8c8ea5a44b80347f9055589333b3f/grpcio-1.75.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5bf4001d3293e3414d0cf99ff9b1139106e57c3a66dfff0c5f60b2a6286ec133", size = 6248838, upload-time = "2025-09-26T09:02:26.426Z" },
+ { url = "https://files.pythonhosted.org/packages/06/43/073363bf63826ba8077c335d797a8d026f129dc0912b69c42feaf8f0cd26/grpcio-1.75.1-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f82ff474103e26351dacfe8d50214e7c9322960d8d07ba7fa1d05ff981c8b2d", size = 6922663, upload-time = "2025-09-26T09:02:28.724Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/6f/076ac0df6c359117676cacfa8a377e2abcecec6a6599a15a672d331f6680/grpcio-1.75.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0ee119f4f88d9f75414217823d21d75bfe0e6ed40135b0cbbfc6376bc9f7757d", size = 6436149, upload-time = "2025-09-26T09:02:30.971Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/27/1d08824f1d573fcb1fa35ede40d6020e68a04391709939e1c6f4193b445f/grpcio-1.75.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:664eecc3abe6d916fa6cf8dd6b778e62fb264a70f3430a3180995bf2da935446", size = 7067989, upload-time = "2025-09-26T09:02:33.233Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/98/98594cf97b8713feb06a8cb04eeef60b4757e3e2fb91aa0d9161da769843/grpcio-1.75.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c32193fa08b2fbebf08fe08e84f8a0aad32d87c3ad42999c65e9449871b1c66e", size = 8010717, upload-time = "2025-09-26T09:02:36.011Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/7e/bb80b1bba03c12158f9254762cdf5cced4a9bc2e8ed51ed335915a5a06ef/grpcio-1.75.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5cebe13088b9254f6e615bcf1da9131d46cfa4e88039454aca9cb65f639bd3bc", size = 7463822, upload-time = "2025-09-26T09:02:38.26Z" },
+ { url = "https://files.pythonhosted.org/packages/23/1c/1ea57fdc06927eb5640f6750c697f596f26183573069189eeaf6ef86ba2d/grpcio-1.75.1-cp313-cp313-win32.whl", hash = "sha256:4b4c678e7ed50f8ae8b8dbad15a865ee73ce12668b6aaf411bf3258b5bc3f970", size = 3938490, upload-time = "2025-09-26T09:02:40.268Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/24/fbb8ff1ccadfbf78ad2401c41aceaf02b0d782c084530d8871ddd69a2d49/grpcio-1.75.1-cp313-cp313-win_amd64.whl", hash = "sha256:5573f51e3f296a1bcf71e7a690c092845fb223072120f4bdb7a5b48e111def66", size = 4642538, upload-time = "2025-09-26T09:02:42.519Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/1b/9a0a5cecd24302b9fdbcd55d15ed6267e5f3d5b898ff9ac8cbe17ee76129/grpcio-1.75.1-cp314-cp314-linux_armv7l.whl", hash = "sha256:c05da79068dd96723793bffc8d0e64c45f316248417515f28d22204d9dae51c7", size = 5673319, upload-time = "2025-09-26T09:02:44.742Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/ec/9d6959429a83fbf5df8549c591a8a52bb313976f6646b79852c4884e3225/grpcio-1.75.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06373a94fd16ec287116a825161dca179a0402d0c60674ceeec8c9fba344fe66", size = 11480347, upload-time = "2025-09-26T09:02:47.539Z" },
+ { url = "https://files.pythonhosted.org/packages/09/7a/26da709e42c4565c3d7bf999a9569da96243ce34a8271a968dee810a7cf1/grpcio-1.75.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4484f4b7287bdaa7a5b3980f3c7224c3c622669405d20f69549f5fb956ad0421", size = 6254706, upload-time = "2025-09-26T09:02:50.4Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/08/dcb26a319d3725f199c97e671d904d84ee5680de57d74c566a991cfab632/grpcio-1.75.1-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:2720c239c1180eee69f7883c1d4c83fc1a495a2535b5fa322887c70bf02b16e8", size = 6922501, upload-time = "2025-09-26T09:02:52.711Z" },
+ { url = "https://files.pythonhosted.org/packages/78/66/044d412c98408a5e23cb348845979a2d17a2e2b6c3c34c1ec91b920f49d0/grpcio-1.75.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:07a554fa31c668cf0e7a188678ceeca3cb8fead29bbe455352e712ec33ca701c", size = 6437492, upload-time = "2025-09-26T09:02:55.542Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/9d/5e3e362815152aa1afd8b26ea613effa005962f9da0eec6e0e4527e7a7d1/grpcio-1.75.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3e71a2105210366bfc398eef7f57a664df99194f3520edb88b9c3a7e46ee0d64", size = 7081061, upload-time = "2025-09-26T09:02:58.261Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/1a/46615682a19e100f46e31ddba9ebc297c5a5ab9ddb47b35443ffadb8776c/grpcio-1.75.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8679aa8a5b67976776d3c6b0521e99d1c34db8a312a12bcfd78a7085cb9b604e", size = 8010849, upload-time = "2025-09-26T09:03:00.548Z" },
+ { url = "https://files.pythonhosted.org/packages/67/8e/3204b94ac30b0f675ab1c06540ab5578660dc8b690db71854d3116f20d00/grpcio-1.75.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:aad1c774f4ebf0696a7f148a56d39a3432550612597331792528895258966dc0", size = 7464478, upload-time = "2025-09-26T09:03:03.096Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/97/2d90652b213863b2cf466d9c1260ca7e7b67a16780431b3eb1d0420e3d5b/grpcio-1.75.1-cp314-cp314-win32.whl", hash = "sha256:62ce42d9994446b307649cb2a23335fa8e927f7ab2cbf5fcb844d6acb4d85f9c", size = 4012672, upload-time = "2025-09-26T09:03:05.477Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/df/e2e6e9fc1c985cd1a59e6996a05647c720fe8a03b92f5ec2d60d366c531e/grpcio-1.75.1-cp314-cp314-win_amd64.whl", hash = "sha256:f86e92275710bea3000cb79feca1762dc0ad3b27830dd1a74e82ab321d4ee464", size = 4772475, upload-time = "2025-09-26T09:03:07.661Z" },
+]
+
+[[package]]
+name = "grpcio-status"
+version = "1.48.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "googleapis-common-protos" },
+ { name = "grpcio" },
+ { name = "protobuf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/22/62/a86443ec8f7bf635fe0b48abe56cd699816bdc0b29d24e0bcb5cada42d4a/grpcio-status-1.48.2.tar.gz", hash = "sha256:53695f45da07437b7c344ee4ef60d370fd2850179f5a28bb26d8e2aa1102ec11", size = 13485, upload-time = "2022-09-22T02:50:32.913Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/14/32/754cd4474790239c7436a7a9490bc0c4a0a2ed604cb9a940151a3b1055b9/grpcio_status-1.48.2-py3-none-any.whl", hash = "sha256:2c33bbdbe20188b2953f46f31af669263b6ee2a9b2d38fa0d36ee091532e21bf", size = 14441, upload-time = "2022-09-22T02:47:51.828Z" },
+]
+
+[[package]]
+name = "grpclib"
+version = "0.4.8"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "h2" },
+ { name = "multidict" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/19/75/0f0d3524b38b35e5cd07334b754aa9bd0570140ad982131b04ebfa3b0374/grpclib-0.4.8.tar.gz", hash = "sha256:d8823763780ef94fed8b2c562f7485cf0bbee15fc7d065a640673667f7719c9a", size = 62793, upload-time = "2025-05-04T16:27:30.051Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/03/8b/ad381ec1b8195fa4a9a693cb8087e031b99530c0d6b8ad036dcb99e144c4/grpclib-0.4.8-py3-none-any.whl", hash = "sha256:a5047733a7acc1c1cee6abf3c841c7c6fab67d2844a45a853b113fa2e6cd2654", size = 76311, upload-time = "2025-05-04T16:27:22.818Z" },
+]
+
+[[package]]
+name = "h11"
+version = "0.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
+]
+
+[[package]]
+name = "h2"
+version = "4.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "hpack" },
+ { name = "hyperframe" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" },
+]
+
+[[package]]
+name = "hf-xet"
+version = "1.1.10"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/74/31/feeddfce1748c4a233ec1aa5b7396161c07ae1aa9b7bdbc9a72c3c7dd768/hf_xet-1.1.10.tar.gz", hash = "sha256:408aef343800a2102374a883f283ff29068055c111f003ff840733d3b715bb97", size = 487910, upload-time = "2025-09-12T20:10:27.12Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f7/a2/343e6d05de96908366bdc0081f2d8607d61200be2ac802769c4284cc65bd/hf_xet-1.1.10-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:686083aca1a6669bc85c21c0563551cbcdaa5cf7876a91f3d074a030b577231d", size = 2761466, upload-time = "2025-09-12T20:10:22.836Z" },
+ { url = "https://files.pythonhosted.org/packages/31/f9/6215f948ac8f17566ee27af6430ea72045e0418ce757260248b483f4183b/hf_xet-1.1.10-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:71081925383b66b24eedff3013f8e6bbd41215c3338be4b94ba75fd75b21513b", size = 2623807, upload-time = "2025-09-12T20:10:21.118Z" },
+ { url = "https://files.pythonhosted.org/packages/15/07/86397573efefff941e100367bbda0b21496ffcdb34db7ab51912994c32a2/hf_xet-1.1.10-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6bceb6361c80c1cc42b5a7b4e3efd90e64630bcf11224dcac50ef30a47e435", size = 3186960, upload-time = "2025-09-12T20:10:19.336Z" },
+ { url = "https://files.pythonhosted.org/packages/01/a7/0b2e242b918cc30e1f91980f3c4b026ff2eedaf1e2ad96933bca164b2869/hf_xet-1.1.10-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eae7c1fc8a664e54753ffc235e11427ca61f4b0477d757cc4eb9ae374b69f09c", size = 3087167, upload-time = "2025-09-12T20:10:17.255Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/25/3e32ab61cc7145b11eee9d745988e2f0f4fafda81b25980eebf97d8cff15/hf_xet-1.1.10-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0a0005fd08f002180f7a12d4e13b22be277725bc23ed0529f8add5c7a6309c06", size = 3248612, upload-time = "2025-09-12T20:10:24.093Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/3d/ab7109e607ed321afaa690f557a9ada6d6d164ec852fd6bf9979665dc3d6/hf_xet-1.1.10-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f900481cf6e362a6c549c61ff77468bd59d6dd082f3170a36acfef2eb6a6793f", size = 3353360, upload-time = "2025-09-12T20:10:25.563Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/0e/471f0a21db36e71a2f1752767ad77e92d8cde24e974e03d662931b1305ec/hf_xet-1.1.10-cp37-abi3-win_amd64.whl", hash = "sha256:5f54b19cc347c13235ae7ee98b330c26dd65ef1df47e5316ffb1e87713ca7045", size = 2804691, upload-time = "2025-09-12T20:10:28.433Z" },
+]
+
+[[package]]
+name = "hpack"
+version = "4.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" },
+]
+
+[[package]]
+name = "httpcore"
+version = "1.0.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
+]
+
+[[package]]
+name = "httplib2"
+version = "0.31.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyparsing" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/52/77/6653db69c1f7ecfe5e3f9726fdadc981794656fcd7d98c4209fecfea9993/httplib2-0.31.0.tar.gz", hash = "sha256:ac7ab497c50975147d4f7b1ade44becc7df2f8954d42b38b3d69c515f531135c", size = 250759, upload-time = "2025-09-11T12:16:03.403Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8c/a2/0d269db0f6163be503775dc8b6a6fa15820cc9fdc866f6ba608d86b721f2/httplib2-0.31.0-py3-none-any.whl", hash = "sha256:b9cd78abea9b4e43a7714c6e0f8b6b8561a6fc1e95d5dbd367f5bf0ef35f5d24", size = 91148, upload-time = "2025-09-11T12:16:01.803Z" },
+]
+
+[[package]]
+name = "httptools"
+version = "0.6.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" },
+ { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" },
+ { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" },
+ { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" },
+ { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" },
+ { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" },
+]
+
+[[package]]
+name = "httpx"
+version = "0.28.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "certifi" },
+ { name = "httpcore" },
+ { name = "idna" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
+]
+
+[[package]]
+name = "httpx-sse"
+version = "0.4.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6e/fa/66bd985dd0b7c109a3bcb89272ee0bfb7e2b4d06309ad7b38ff866734b2a/httpx_sse-0.4.1.tar.gz", hash = "sha256:8f44d34414bc7b21bf3602713005c5df4917884f76072479b21f68befa4ea26e", size = 12998, upload-time = "2025-06-24T13:21:05.71Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/25/0a/6269e3473b09aed2dab8aa1a600c70f31f00ae1349bee30658f7e358a159/httpx_sse-0.4.1-py3-none-any.whl", hash = "sha256:cba42174344c3a5b06f255ce65b350880f962d99ead85e776f23c6618a377a37", size = 8054, upload-time = "2025-06-24T13:21:04.772Z" },
+]
+
+[[package]]
+name = "huggingface-hub"
+version = "0.35.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "filelock" },
+ { name = "fsspec" },
+ { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" },
+ { name = "packaging" },
+ { name = "pyyaml" },
+ { name = "requests" },
+ { name = "tqdm" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/10/7e/a0a97de7c73671863ca6b3f61fa12518caf35db37825e43d63a70956738c/huggingface_hub-0.35.3.tar.gz", hash = "sha256:350932eaa5cc6a4747efae85126ee220e4ef1b54e29d31c3b45c5612ddf0b32a", size = 461798, upload-time = "2025-09-29T14:29:58.625Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/31/a0/651f93d154cb72323358bf2bbae3e642bdb5d2f1bfc874d096f7cb159fa0/huggingface_hub-0.35.3-py3-none-any.whl", hash = "sha256:0e3a01829c19d86d03793e4577816fe3bdfc1602ac62c7fb220d593d351224ba", size = 564262, upload-time = "2025-09-29T14:29:55.813Z" },
+]
+
+[[package]]
+name = "humanfriendly"
+version = "10.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyreadline3", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cc/3f/2c29224acb2e2df4d2046e4c73ee2662023c58ff5b113c4c1adac0886c43/humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc", size = 360702, upload-time = "2021-09-17T21:40:43.31Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", size = 86794, upload-time = "2021-09-17T21:40:39.897Z" },
+]
+
+[[package]]
+name = "hyperframe"
+version = "6.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" },
+]
+
+[[package]]
+name = "idna"
+version = "3.10"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
+]
+
+[[package]]
+name = "importlib-metadata"
+version = "8.7.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "zipp" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" },
+]
+
+[[package]]
+name = "importlib-resources"
+version = "6.5.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" },
+]
+
+[[package]]
+name = "ipykernel"
+version = "6.30.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "appnope", marker = "sys_platform == 'darwin'" },
+ { name = "comm" },
+ { name = "debugpy" },
+ { name = "ipython" },
+ { name = "jupyter-client" },
+ { name = "jupyter-core" },
+ { name = "matplotlib-inline" },
+ { name = "nest-asyncio" },
+ { name = "packaging" },
+ { name = "psutil" },
+ { name = "pyzmq" },
+ { name = "tornado" },
+ { name = "traitlets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bb/76/11082e338e0daadc89c8ff866185de11daf67d181901038f9e139d109761/ipykernel-6.30.1.tar.gz", hash = "sha256:6abb270161896402e76b91394fcdce5d1be5d45f456671e5080572f8505be39b", size = 166260, upload-time = "2025-08-04T15:47:35.018Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fc/c7/b445faca8deb954fe536abebff4ece5b097b923de482b26e78448c89d1dd/ipykernel-6.30.1-py3-none-any.whl", hash = "sha256:aa6b9fb93dca949069d8b85b6c79b2518e32ac583ae9c7d37c51d119e18b3fb4", size = 117484, upload-time = "2025-08-04T15:47:32.622Z" },
+]
+
+[[package]]
+name = "ipython"
+version = "9.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "decorator" },
+ { name = "ipython-pygments-lexers" },
+ { name = "jedi" },
+ { name = "matplotlib-inline" },
+ { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+ { name = "prompt-toolkit" },
+ { name = "pygments" },
+ { name = "stack-data" },
+ { name = "traitlets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2a/34/29b18c62e39ee2f7a6a3bba7efd952729d8aadd45ca17efc34453b717665/ipython-9.6.0.tar.gz", hash = "sha256:5603d6d5d356378be5043e69441a072b50a5b33b4503428c77b04cb8ce7bc731", size = 4396932, upload-time = "2025-09-29T10:55:53.948Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/48/c5/d5e07995077e48220269c28a221e168c91123ad5ceee44d548f54a057fc0/ipython-9.6.0-py3-none-any.whl", hash = "sha256:5f77efafc886d2f023442479b8149e7d86547ad0a979e9da9f045d252f648196", size = 616170, upload-time = "2025-09-29T10:55:47.676Z" },
+]
+
+[[package]]
+name = "ipython-pygments-lexers"
+version = "1.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" },
+]
+
+[[package]]
+name = "ipywidgets"
+version = "8.1.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "comm" },
+ { name = "ipython" },
+ { name = "jupyterlab-widgets" },
+ { name = "traitlets" },
+ { name = "widgetsnbextension" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/3e/48/d3dbac45c2814cb73812f98dd6b38bbcc957a4e7bb31d6ea9c03bf94ed87/ipywidgets-8.1.7.tar.gz", hash = "sha256:15f1ac050b9ccbefd45dccfbb2ef6bed0029d8278682d569d71b8dd96bee0376", size = 116721, upload-time = "2025-05-05T12:42:03.489Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/58/6a/9166369a2f092bd286d24e6307de555d63616e8ddb373ebad2b5635ca4cd/ipywidgets-8.1.7-py3-none-any.whl", hash = "sha256:764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb", size = 139806, upload-time = "2025-05-05T12:41:56.833Z" },
+]
+
+[[package]]
+name = "itsdangerous"
+version = "2.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" },
+]
+
+[[package]]
+name = "jedi"
+version = "0.19.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "parso" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" },
+]
+
+[[package]]
+name = "jinja2"
+version = "3.1.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markupsafe" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
+]
+
+[[package]]
+name = "jiter"
+version = "0.11.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9d/c0/a3bb4cc13aced219dd18191ea66e874266bd8aa7b96744e495e1c733aa2d/jiter-0.11.0.tar.gz", hash = "sha256:1d9637eaf8c1d6a63d6562f2a6e5ab3af946c66037eb1b894e8fad75422266e4", size = 167094, upload-time = "2025-09-15T09:20:38.212Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ba/b5/3009b112b8f673e568ef79af9863d8309a15f0a8cdcc06ed6092051f377e/jiter-0.11.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:2fb7b377688cc3850bbe5c192a6bd493562a0bc50cbc8b047316428fbae00ada", size = 305510, upload-time = "2025-09-15T09:19:25.893Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/82/15514244e03b9e71e086bbe2a6de3e4616b48f07d5f834200c873956fb8c/jiter-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a1b7cbe3f25bd0d8abb468ba4302a5d45617ee61b2a7a638f63fee1dc086be99", size = 316521, upload-time = "2025-09-15T09:19:27.525Z" },
+ { url = "https://files.pythonhosted.org/packages/92/94/7a2e905f40ad2d6d660e00b68d818f9e29fb87ffe82774f06191e93cbe4a/jiter-0.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0a7f0ec81d5b7588c5cade1eb1925b91436ae6726dc2df2348524aeabad5de6", size = 338214, upload-time = "2025-09-15T09:19:28.727Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/9c/5791ed5bdc76f12110158d3316a7a3ec0b1413d018b41c5ed399549d3ad5/jiter-0.11.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07630bb46ea2a6b9c6ed986c6e17e35b26148cce2c535454b26ee3f0e8dcaba1", size = 361280, upload-time = "2025-09-15T09:19:30.013Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/7f/b7d82d77ff0d2cb06424141000176b53a9e6b16a1125525bb51ea4990c2e/jiter-0.11.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7764f27d28cd4a9cbc61704dfcd80c903ce3aad106a37902d3270cd6673d17f4", size = 487895, upload-time = "2025-09-15T09:19:31.424Z" },
+ { url = "https://files.pythonhosted.org/packages/42/44/10a1475d46f1fc1fd5cc2e82c58e7bca0ce5852208e0fa5df2f949353321/jiter-0.11.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d4a6c4a737d486f77f842aeb22807edecb4a9417e6700c7b981e16d34ba7c72", size = 378421, upload-time = "2025-09-15T09:19:32.746Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/5f/0dc34563d8164d31d07bc09d141d3da08157a68dcd1f9b886fa4e917805b/jiter-0.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf408d2a0abd919b60de8c2e7bc5eeab72d4dafd18784152acc7c9adc3291591", size = 347932, upload-time = "2025-09-15T09:19:34.612Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/de/b68f32a4fcb7b4a682b37c73a0e5dae32180140cd1caf11aef6ad40ddbf2/jiter-0.11.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cdef53eda7d18e799625023e1e250dbc18fbc275153039b873ec74d7e8883e09", size = 386959, upload-time = "2025-09-15T09:19:35.994Z" },
+ { url = "https://files.pythonhosted.org/packages/76/0a/c08c92e713b6e28972a846a81ce374883dac2f78ec6f39a0dad9f2339c3a/jiter-0.11.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:53933a38ef7b551dd9c7f1064f9d7bb235bb3168d0fa5f14f0798d1b7ea0d9c5", size = 517187, upload-time = "2025-09-15T09:19:37.426Z" },
+ { url = "https://files.pythonhosted.org/packages/89/b5/4a283bec43b15aad54fcae18d951f06a2ec3f78db5708d3b59a48e9c3fbd/jiter-0.11.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:11840d2324c9ab5162fc1abba23bc922124fedcff0d7b7f85fffa291e2f69206", size = 509461, upload-time = "2025-09-15T09:19:38.761Z" },
+ { url = "https://files.pythonhosted.org/packages/34/a5/f8bad793010534ea73c985caaeef8cc22dfb1fedb15220ecdf15c623c07a/jiter-0.11.0-cp312-cp312-win32.whl", hash = "sha256:4f01a744d24a5f2bb4a11657a1b27b61dc038ae2e674621a74020406e08f749b", size = 206664, upload-time = "2025-09-15T09:19:40.096Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/42/5823ec2b1469395a160b4bf5f14326b4a098f3b6898fbd327366789fa5d3/jiter-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:29fff31190ab3a26de026da2f187814f4b9c6695361e20a9ac2123e4d4378a4c", size = 203520, upload-time = "2025-09-15T09:19:41.798Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c4/d530e514d0f4f29b2b68145e7b389cbc7cac7f9c8c23df43b04d3d10fa3e/jiter-0.11.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:4441a91b80a80249f9a6452c14b2c24708f139f64de959943dfeaa6cb915e8eb", size = 305021, upload-time = "2025-09-15T09:19:43.523Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/77/796a19c567c5734cbfc736a6f987affc0d5f240af8e12063c0fb93990ffa/jiter-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ff85fc6d2a431251ad82dbd1ea953affb5a60376b62e7d6809c5cd058bb39471", size = 314384, upload-time = "2025-09-15T09:19:44.849Z" },
+ { url = "https://files.pythonhosted.org/packages/14/9c/824334de0b037b91b6f3fa9fe5a191c83977c7ec4abe17795d3cb6d174cf/jiter-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5e86126d64706fd28dfc46f910d496923c6f95b395138c02d0e252947f452bd", size = 337389, upload-time = "2025-09-15T09:19:46.094Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/95/ed4feab69e6cf9b2176ea29d4ef9d01a01db210a3a2c8a31a44ecdc68c38/jiter-0.11.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad8bd82165961867a10f52010590ce0b7a8c53da5ddd8bbb62fef68c181b921", size = 360519, upload-time = "2025-09-15T09:19:47.494Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/0c/2ad00f38d3e583caba3909d95b7da1c3a7cd82c0aa81ff4317a8016fb581/jiter-0.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b42c2cd74273455ce439fd9528db0c6e84b5623cb74572305bdd9f2f2961d3df", size = 487198, upload-time = "2025-09-15T09:19:49.116Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/8b/919b64cf3499b79bdfba6036da7b0cac5d62d5c75a28fb45bad7819e22f0/jiter-0.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0062dab98172dd0599fcdbf90214d0dcde070b1ff38a00cc1b90e111f071982", size = 377835, upload-time = "2025-09-15T09:19:50.468Z" },
+ { url = "https://files.pythonhosted.org/packages/29/7f/8ebe15b6e0a8026b0d286c083b553779b4dd63db35b43a3f171b544de91d/jiter-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb948402821bc76d1f6ef0f9e19b816f9b09f8577844ba7140f0b6afe994bc64", size = 347655, upload-time = "2025-09-15T09:19:51.726Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/64/332127cef7e94ac75719dda07b9a472af6158ba819088d87f17f3226a769/jiter-0.11.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25a5b1110cca7329fd0daf5060faa1234be5c11e988948e4f1a1923b6a457fe1", size = 386135, upload-time = "2025-09-15T09:19:53.075Z" },
+ { url = "https://files.pythonhosted.org/packages/20/c8/557b63527442f84c14774159948262a9d4fabb0d61166f11568f22fc60d2/jiter-0.11.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:bf11807e802a214daf6c485037778843fadd3e2ec29377ae17e0706ec1a25758", size = 516063, upload-time = "2025-09-15T09:19:54.447Z" },
+ { url = "https://files.pythonhosted.org/packages/86/13/4164c819df4a43cdc8047f9a42880f0ceef5afeb22e8b9675c0528ebdccd/jiter-0.11.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:dbb57da40631c267861dd0090461222060960012d70fd6e4c799b0f62d0ba166", size = 508139, upload-time = "2025-09-15T09:19:55.764Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/70/6e06929b401b331d41ddb4afb9f91cd1168218e3371972f0afa51c9f3c31/jiter-0.11.0-cp313-cp313-win32.whl", hash = "sha256:8e36924dad32c48d3c5e188d169e71dc6e84d6cb8dedefea089de5739d1d2f80", size = 206369, upload-time = "2025-09-15T09:19:57.048Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/0d/8185b8e15de6dce24f6afae63380e16377dd75686d56007baa4f29723ea1/jiter-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:452d13e4fd59698408087235259cebe67d9d49173b4dacb3e8d35ce4acf385d6", size = 202538, upload-time = "2025-09-15T09:19:58.35Z" },
+ { url = "https://files.pythonhosted.org/packages/13/3a/d61707803260d59520721fa326babfae25e9573a88d8b7b9cb54c5423a59/jiter-0.11.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:089f9df9f69532d1339e83142438668f52c97cd22ee2d1195551c2b1a9e6cf33", size = 313737, upload-time = "2025-09-15T09:19:59.638Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/cc/c9f0eec5d00f2a1da89f6bdfac12b8afdf8d5ad974184863c75060026457/jiter-0.11.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29ed1fe69a8c69bf0f2a962d8d706c7b89b50f1332cd6b9fbda014f60bd03a03", size = 346183, upload-time = "2025-09-15T09:20:01.442Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/87/fc632776344e7aabbab05a95a0075476f418c5d29ab0f2eec672b7a1f0ac/jiter-0.11.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a4d71d7ea6ea8786291423fe209acf6f8d398a0759d03e7f24094acb8ab686ba", size = 204225, upload-time = "2025-09-15T09:20:03.102Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/3b/e7f45be7d3969bdf2e3cd4b816a7a1d272507cd0edd2d6dc4b07514f2d9a/jiter-0.11.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9a6dff27eca70930bdbe4cbb7c1a4ba8526e13b63dc808c0670083d2d51a4a72", size = 304414, upload-time = "2025-09-15T09:20:04.357Z" },
+ { url = "https://files.pythonhosted.org/packages/06/32/13e8e0d152631fcc1907ceb4943711471be70496d14888ec6e92034e2caf/jiter-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ae2a7593a62132c7d4c2abbee80bbbb94fdc6d157e2c6cc966250c564ef774", size = 314223, upload-time = "2025-09-15T09:20:05.631Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/7e/abedd5b5a20ca083f778d96bba0d2366567fcecb0e6e34ff42640d5d7a18/jiter-0.11.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b13a431dba4b059e9e43019d3022346d009baf5066c24dcdea321a303cde9f0", size = 337306, upload-time = "2025-09-15T09:20:06.917Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/e2/30d59bdc1204c86aa975ec72c48c482fee6633120ee9c3ab755e4dfefea8/jiter-0.11.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:af62e84ca3889604ebb645df3b0a3f3bcf6b92babbff642bd214616f57abb93a", size = 360565, upload-time = "2025-09-15T09:20:08.283Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/88/567288e0d2ed9fa8f7a3b425fdaf2cb82b998633c24fe0d98f5417321aa8/jiter-0.11.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6f3b32bb723246e6b351aecace52aba78adb8eeb4b2391630322dc30ff6c773", size = 486465, upload-time = "2025-09-15T09:20:09.613Z" },
+ { url = "https://files.pythonhosted.org/packages/18/6e/7b72d09273214cadd15970e91dd5ed9634bee605176107db21e1e4205eb1/jiter-0.11.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:adcab442f4a099a358a7f562eaa54ed6456fb866e922c6545a717be51dbed7d7", size = 377581, upload-time = "2025-09-15T09:20:10.884Z" },
+ { url = "https://files.pythonhosted.org/packages/58/52/4db456319f9d14deed325f70102577492e9d7e87cf7097bda9769a1fcacb/jiter-0.11.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9967c2ab338ee2b2c0102fd379ec2693c496abf71ffd47e4d791d1f593b68e2", size = 347102, upload-time = "2025-09-15T09:20:12.175Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/b4/433d5703c38b26083aec7a733eb5be96f9c6085d0e270a87ca6482cbf049/jiter-0.11.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e7d0bed3b187af8b47a981d9742ddfc1d9b252a7235471ad6078e7e4e5fe75c2", size = 386477, upload-time = "2025-09-15T09:20:13.428Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/7a/a60bfd9c55b55b07c5c441c5085f06420b6d493ce9db28d069cc5b45d9f3/jiter-0.11.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:f6fe0283e903ebc55f1a6cc569b8c1f3bf4abd026fed85e3ff8598a9e6f982f0", size = 516004, upload-time = "2025-09-15T09:20:14.848Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/46/f8363e5ecc179b4ed0ca6cb0a6d3bfc266078578c71ff30642ea2ce2f203/jiter-0.11.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:4ee5821e3d66606b29ae5b497230b304f1376f38137d69e35f8d2bd5f310ff73", size = 507855, upload-time = "2025-09-15T09:20:16.176Z" },
+ { url = "https://files.pythonhosted.org/packages/90/33/396083357d51d7ff0f9805852c288af47480d30dd31d8abc74909b020761/jiter-0.11.0-cp314-cp314-win32.whl", hash = "sha256:c2d13ba7567ca8799f17c76ed56b1d49be30df996eb7fa33e46b62800562a5e2", size = 205802, upload-time = "2025-09-15T09:20:17.661Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/ab/eb06ca556b2551d41de7d03bf2ee24285fa3d0c58c5f8d95c64c9c3281b1/jiter-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fb4790497369d134a07fc763cc88888c46f734abdd66f9fdf7865038bf3a8f40", size = 313405, upload-time = "2025-09-15T09:20:18.918Z" },
+ { url = "https://files.pythonhosted.org/packages/af/22/7ab7b4ec3a1c1f03aef376af11d23b05abcca3fb31fbca1e7557053b1ba2/jiter-0.11.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e2bbf24f16ba5ad4441a9845e40e4ea0cb9eed00e76ba94050664ef53ef4406", size = 347102, upload-time = "2025-09-15T09:20:20.16Z" },
+]
+
+[[package]]
+name = "joblib"
+version = "1.5.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" },
+]
+
+[[package]]
+name = "jsonpatch"
+version = "1.33"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "jsonpointer" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade", size = 12898, upload-time = "2023-06-16T21:01:28.466Z" },
+]
+
+[[package]]
+name = "jsonpointer"
+version = "3.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" },
+]
+
+[[package]]
+name = "jsonschema"
+version = "4.25.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "jsonschema-specifications" },
+ { name = "referencing" },
+ { name = "rpds-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" },
+]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2025.9.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "referencing" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" },
+]
+
+[[package]]
+name = "jupyter-client"
+version = "8.6.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "jupyter-core" },
+ { name = "python-dateutil" },
+ { name = "pyzmq" },
+ { name = "tornado" },
+ { name = "traitlets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105, upload-time = "2024-09-17T10:44:15.218Z" },
+]
+
+[[package]]
+name = "jupyter-core"
+version = "5.8.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "platformdirs" },
+ { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" },
+ { name = "traitlets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/99/1b/72906d554acfeb588332eaaa6f61577705e9ec752ddb486f302dafa292d9/jupyter_core-5.8.1.tar.gz", hash = "sha256:0a5f9706f70e64786b75acba995988915ebd4601c8a52e534a40b51c95f59941", size = 88923, upload-time = "2025-05-27T07:38:16.655Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2f/57/6bffd4b20b88da3800c5d691e0337761576ee688eb01299eae865689d2df/jupyter_core-5.8.1-py3-none-any.whl", hash = "sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0", size = 28880, upload-time = "2025-05-27T07:38:15.137Z" },
+]
+
+[[package]]
+name = "jupyter-dash"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "ansi2html" },
+ { name = "dash" },
+ { name = "flask" },
+ { name = "ipykernel" },
+ { name = "ipython" },
+ { name = "nest-asyncio" },
+ { name = "requests" },
+ { name = "retrying" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d6/49/1f99474c4d22c7bc05a96ee9d1301ed5eda6aee27f0bce0d9761f3759e49/jupyter-dash-0.4.2.tar.gz", hash = "sha256:d546c7c25a2867c14c95a48af0ad572803b26915a5ce6052158c9dede4dbf48c", size = 17888, upload-time = "2022-04-01T20:05:10.464Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/38/62/2c51aeb18c6d765c03c911e4d70f029ccb9de1a991d88cf30e362d2433c9/jupyter_dash-0.4.2-py3-none-any.whl", hash = "sha256:b07d90ccf38d4dfb04efd630a2b2627f367b79fa4296ee3912d0c4e21e73e9b2", size = 23566, upload-time = "2022-04-01T20:05:08.382Z" },
+]
+
+[[package]]
+name = "jupyterlab-widgets"
+version = "3.0.15"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b9/7d/160595ca88ee87ac6ba95d82177d29ec60aaa63821d3077babb22ce031a5/jupyterlab_widgets-3.0.15.tar.gz", hash = "sha256:2920888a0c2922351a9202817957a68c07d99673504d6cd37345299e971bb08b", size = 213149, upload-time = "2025-05-05T12:32:31.004Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl", hash = "sha256:d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c", size = 216571, upload-time = "2025-05-05T12:32:29.534Z" },
+]
+
+[[package]]
+name = "kiwisolver"
+version = "1.4.9"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/86/c9/13573a747838aeb1c76e3267620daa054f4152444d1f3d1a2324b78255b5/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999", size = 123686, upload-time = "2025-08-10T21:26:10.034Z" },
+ { url = "https://files.pythonhosted.org/packages/51/ea/2ecf727927f103ffd1739271ca19c424d0e65ea473fbaeea1c014aea93f6/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2", size = 66460, upload-time = "2025-08-10T21:26:11.083Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/5a/51f5464373ce2aeb5194508298a508b6f21d3867f499556263c64c621914/kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14", size = 64952, upload-time = "2025-08-10T21:26:12.058Z" },
+ { url = "https://files.pythonhosted.org/packages/70/90/6d240beb0f24b74371762873e9b7f499f1e02166a2d9c5801f4dbf8fa12e/kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04", size = 1474756, upload-time = "2025-08-10T21:26:13.096Z" },
+ { url = "https://files.pythonhosted.org/packages/12/42/f36816eaf465220f683fb711efdd1bbf7a7005a2473d0e4ed421389bd26c/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752", size = 1276404, upload-time = "2025-08-10T21:26:14.457Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/64/bc2de94800adc830c476dce44e9b40fd0809cddeef1fde9fcf0f73da301f/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77", size = 1294410, upload-time = "2025-08-10T21:26:15.73Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/42/2dc82330a70aa8e55b6d395b11018045e58d0bb00834502bf11509f79091/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198", size = 1343631, upload-time = "2025-08-10T21:26:17.045Z" },
+ { url = "https://files.pythonhosted.org/packages/22/fd/f4c67a6ed1aab149ec5a8a401c323cee7a1cbe364381bb6c9c0d564e0e20/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d", size = 2224963, upload-time = "2025-08-10T21:26:18.737Z" },
+ { url = "https://files.pythonhosted.org/packages/45/aa/76720bd4cb3713314677d9ec94dcc21ced3f1baf4830adde5bb9b2430a5f/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab", size = 2321295, upload-time = "2025-08-10T21:26:20.11Z" },
+ { url = "https://files.pythonhosted.org/packages/80/19/d3ec0d9ab711242f56ae0dc2fc5d70e298bb4a1f9dfab44c027668c673a1/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2", size = 2487987, upload-time = "2025-08-10T21:26:21.49Z" },
+ { url = "https://files.pythonhosted.org/packages/39/e9/61e4813b2c97e86b6fdbd4dd824bf72d28bcd8d4849b8084a357bc0dd64d/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145", size = 2291817, upload-time = "2025-08-10T21:26:22.812Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/41/85d82b0291db7504da3c2defe35c9a8a5c9803a730f297bd823d11d5fb77/kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54", size = 73895, upload-time = "2025-08-10T21:26:24.37Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/92/5f3068cf15ee5cb624a0c7596e67e2a0bb2adee33f71c379054a491d07da/kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60", size = 64992, upload-time = "2025-08-10T21:26:25.732Z" },
+ { url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" },
+ { url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" },
+ { url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" },
+ { url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" },
+ { url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" },
+ { url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" },
+ { url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" },
+ { url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" },
+ { url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" },
+ { url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" },
+ { url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" },
+ { url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806, upload-time = "2025-08-10T21:27:01.537Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605, upload-time = "2025-08-10T21:27:03.335Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925, upload-time = "2025-08-10T21:27:04.339Z" },
+ { url = "https://files.pythonhosted.org/packages/43/dc/51acc6791aa14e5cb6d8a2e28cefb0dc2886d8862795449d021334c0df20/kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58", size = 1472414, upload-time = "2025-08-10T21:27:05.437Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/bb/93fa64a81db304ac8a246f834d5094fae4b13baf53c839d6bb6e81177129/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4", size = 1281272, upload-time = "2025-08-10T21:27:07.063Z" },
+ { url = "https://files.pythonhosted.org/packages/70/e6/6df102916960fb8d05069d4bd92d6d9a8202d5a3e2444494e7cd50f65b7a/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df", size = 1298578, upload-time = "2025-08-10T21:27:08.452Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/47/e142aaa612f5343736b087864dbaebc53ea8831453fb47e7521fa8658f30/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6", size = 1345607, upload-time = "2025-08-10T21:27:10.125Z" },
+ { url = "https://files.pythonhosted.org/packages/54/89/d641a746194a0f4d1a3670fb900d0dbaa786fb98341056814bc3f058fa52/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5", size = 2230150, upload-time = "2025-08-10T21:27:11.484Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/6b/5ee1207198febdf16ac11f78c5ae40861b809cbe0e6d2a8d5b0b3044b199/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf", size = 2325979, upload-time = "2025-08-10T21:27:12.917Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/ff/b269eefd90f4ae14dcc74973d5a0f6d28d3b9bb1afd8c0340513afe6b39a/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5", size = 2491456, upload-time = "2025-08-10T21:27:14.353Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/d4/10303190bd4d30de547534601e259a4fbf014eed94aae3e5521129215086/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce", size = 2294621, upload-time = "2025-08-10T21:27:15.808Z" },
+ { url = "https://files.pythonhosted.org/packages/28/e0/a9a90416fce5c0be25742729c2ea52105d62eda6c4be4d803c2a7be1fa50/kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7", size = 75417, upload-time = "2025-08-10T21:27:17.436Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/10/6949958215b7a9a264299a7db195564e87900f709db9245e4ebdd3c70779/kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c", size = 66582, upload-time = "2025-08-10T21:27:18.436Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/79/60e53067903d3bc5469b369fe0dfc6b3482e2133e85dae9daa9527535991/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548", size = 126514, upload-time = "2025-08-10T21:27:19.465Z" },
+ { url = "https://files.pythonhosted.org/packages/25/d1/4843d3e8d46b072c12a38c97c57fab4608d36e13fe47d47ee96b4d61ba6f/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d", size = 67905, upload-time = "2025-08-10T21:27:20.51Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/ae/29ffcbd239aea8b93108de1278271ae764dfc0d803a5693914975f200596/kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c", size = 66399, upload-time = "2025-08-10T21:27:21.496Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/ae/d7ba902aa604152c2ceba5d352d7b62106bedbccc8e95c3934d94472bfa3/kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122", size = 1582197, upload-time = "2025-08-10T21:27:22.604Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/41/27c70d427eddb8bc7e4f16420a20fefc6f480312122a59a959fdfe0445ad/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64", size = 1390125, upload-time = "2025-08-10T21:27:24.036Z" },
+ { url = "https://files.pythonhosted.org/packages/41/42/b3799a12bafc76d962ad69083f8b43b12bf4fe78b097b12e105d75c9b8f1/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134", size = 1402612, upload-time = "2025-08-10T21:27:25.773Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/b5/a210ea073ea1cfaca1bb5c55a62307d8252f531beb364e18aa1e0888b5a0/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370", size = 1453990, upload-time = "2025-08-10T21:27:27.089Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/ce/a829eb8c033e977d7ea03ed32fb3c1781b4fa0433fbadfff29e39c676f32/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21", size = 2331601, upload-time = "2025-08-10T21:27:29.343Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/4b/b5e97eb142eb9cd0072dacfcdcd31b1c66dc7352b0f7c7255d339c0edf00/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a", size = 2422041, upload-time = "2025-08-10T21:27:30.754Z" },
+ { url = "https://files.pythonhosted.org/packages/40/be/8eb4cd53e1b85ba4edc3a9321666f12b83113a178845593307a3e7891f44/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f", size = 2594897, upload-time = "2025-08-10T21:27:32.803Z" },
+ { url = "https://files.pythonhosted.org/packages/99/dd/841e9a66c4715477ea0abc78da039832fbb09dac5c35c58dc4c41a407b8a/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369", size = 2391835, upload-time = "2025-08-10T21:27:34.23Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/28/4b2e5c47a0da96896fdfdb006340ade064afa1e63675d01ea5ac222b6d52/kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891", size = 79988, upload-time = "2025-08-10T21:27:35.587Z" },
+ { url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260, upload-time = "2025-08-10T21:27:36.606Z" },
+]
+
+[[package]]
+name = "kubernetes"
+version = "34.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "durationpy" },
+ { name = "google-auth" },
+ { name = "python-dateutil" },
+ { name = "pyyaml" },
+ { name = "requests" },
+ { name = "requests-oauthlib" },
+ { name = "six" },
+ { name = "urllib3" },
+ { name = "websocket-client" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ef/55/3f880ef65f559cbed44a9aa20d3bdbc219a2c3a3bac4a30a513029b03ee9/kubernetes-34.1.0.tar.gz", hash = "sha256:8fe8edb0b5d290a2f3ac06596b23f87c658977d46b5f8df9d0f4ea83d0003912", size = 1083771, upload-time = "2025-09-29T20:23:49.283Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ca/ec/65f7d563aa4a62dd58777e8f6aa882f15db53b14eb29aba0c28a20f7eb26/kubernetes-34.1.0-py2.py3-none-any.whl", hash = "sha256:bffba2272534e224e6a7a74d582deb0b545b7c9879d2cd9e4aae9481d1f2cc2a", size = 2008380, upload-time = "2025-09-29T20:23:47.684Z" },
+]
+
+[[package]]
+name = "langchain"
+version = "0.3.27"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "langchain-core" },
+ { name = "langchain-text-splitters" },
+ { name = "langsmith" },
+ { name = "pydantic" },
+ { name = "pyyaml" },
+ { name = "requests" },
+ { name = "sqlalchemy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/83/f6/f4f7f3a56626fe07e2bb330feb61254dbdf06c506e6b59a536a337da51cf/langchain-0.3.27.tar.gz", hash = "sha256:aa6f1e6274ff055d0fd36254176770f356ed0a8994297d1df47df341953cec62", size = 10233809, upload-time = "2025-07-24T14:42:32.959Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f6/d5/4861816a95b2f6993f1360cfb605aacb015506ee2090433a71de9cca8477/langchain-0.3.27-py3-none-any.whl", hash = "sha256:7b20c4f338826acb148d885b20a73a16e410ede9ee4f19bb02011852d5f98798", size = 1018194, upload-time = "2025-07-24T14:42:30.23Z" },
+]
+
+[[package]]
+name = "langchain-chroma"
+version = "0.2.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "chromadb" },
+ { name = "langchain-core" },
+ { name = "numpy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/dd/94/93ab8f6e96429a60da50eea2d3f3ac988852f6b8da4e817d73ec026a0bd3/langchain_chroma-0.2.6.tar.gz", hash = "sha256:ec5ca0f6f7692ac053741e076ea086c4be0cfcb5846c8693b1bcc3089c88b65e", size = 17296, upload-time = "2025-09-11T19:54:47.991Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/08/bc/591e416a134f9fb766579d1ca9739f32b9d79c607a5053d34ad2b8fa7246/langchain_chroma-0.2.6-py3-none-any.whl", hash = "sha256:d7e10101b0942cd990eedb798c3d85ed3e8415a992c8a388843196f6ab97b41b", size = 12512, upload-time = "2025-09-11T19:54:46.72Z" },
+]
+
+[[package]]
+name = "langchain-community"
+version = "0.3.30"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohttp" },
+ { name = "dataclasses-json" },
+ { name = "httpx-sse" },
+ { name = "langchain" },
+ { name = "langchain-core" },
+ { name = "langsmith" },
+ { name = "numpy" },
+ { name = "pydantic-settings" },
+ { name = "pyyaml" },
+ { name = "requests" },
+ { name = "sqlalchemy" },
+ { name = "tenacity" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d7/32/852facdba14140bbfc9b02e6dcb00fe2e0c5f50901d512a473351cf013e2/langchain_community-0.3.30.tar.gz", hash = "sha256:df68fbde7f7fa5142ab93b0cbc104916b12ab4163e200edd933ee93e67956ee9", size = 33240417, upload-time = "2025-09-26T05:52:49.588Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7f/1b/3c7930361567825a473da10deacf261e029258eb450c9fa8cb98368548ce/langchain_community-0.3.30-py3-none-any.whl", hash = "sha256:a49dcedbf8f320d9868d5944d0991c7bcc9f2182a602e5d5e872d315183c11c3", size = 2532469, upload-time = "2025-09-26T05:52:47.037Z" },
+]
+
+[[package]]
+name = "langchain-core"
+version = "0.3.76"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "jsonpatch" },
+ { name = "langsmith" },
+ { name = "packaging" },
+ { name = "pydantic" },
+ { name = "pyyaml" },
+ { name = "tenacity" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4f/4d/5e2ea7754ee0a1f524c412801c6ba9ad49318ecb58b0d524903c3d9efe0a/langchain_core-0.3.76.tar.gz", hash = "sha256:71136a122dd1abae2c289c5809d035cf12b5f2bb682d8a4c1078cd94feae7419", size = 573568, upload-time = "2025-09-10T14:49:39.863Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/77/b5/501c0ffcb09c734457ceaa86bc7b1dd37b6a261147bd653add03b838aacb/langchain_core-0.3.76-py3-none-any.whl", hash = "sha256:46e0eb48c7ac532432d51f8ca1ece1804c82afe9ae3dcf027b867edadf82b3ec", size = 447508, upload-time = "2025-09-10T14:49:38.179Z" },
+]
+
+[[package]]
+name = "langchain-openai"
+version = "0.3.33"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "langchain-core" },
+ { name = "openai" },
+ { name = "tiktoken" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ff/66/4245ffe1fed8cd3812be9d228be50baa406cbb0ef5bd7cb1d98d82dcfe37/langchain_openai-0.3.33.tar.gz", hash = "sha256:2dec058332ea9e8977cd91df6515b95952e187ac7484f349c3fe91d936a92375", size = 784533, upload-time = "2025-09-10T16:03:12.965Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/67/31/af0486b7ad8a49f3c5c852ca2b3a7f6d8526cc71a405045dd959c36ec5db/langchain_openai-0.3.33-py3-none-any.whl", hash = "sha256:2d52aab6d2af61da9bb9470616ce782128f4be59df965caee3dece30ae6b2bc4", size = 74961, upload-time = "2025-09-10T16:03:11.732Z" },
+]
+
+[[package]]
+name = "langchain-text-splitters"
+version = "0.3.11"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "langchain-core" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/11/43/dcda8fd25f0b19cb2835f2f6bb67f26ad58634f04ac2d8eae00526b0fa55/langchain_text_splitters-0.3.11.tar.gz", hash = "sha256:7a50a04ada9a133bbabb80731df7f6ddac51bc9f1b9cab7fa09304d71d38a6cc", size = 46458, upload-time = "2025-08-31T23:02:58.316Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl", hash = "sha256:cf079131166a487f1372c8ab5d0bfaa6c0a4291733d9c43a34a16ac9bcd6a393", size = 33845, upload-time = "2025-08-31T23:02:57.195Z" },
+]
+
+[[package]]
+name = "langsmith"
+version = "0.4.31"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "httpx" },
+ { name = "orjson", marker = "platform_python_implementation != 'PyPy'" },
+ { name = "packaging" },
+ { name = "pydantic" },
+ { name = "requests" },
+ { name = "requests-toolbelt" },
+ { name = "zstandard" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/55/f5/edbdf89a162ee025348b3b2080fb3b88f4a1040a5a186f32d34aca913994/langsmith-0.4.31.tar.gz", hash = "sha256:5fb3729e22bd9a225391936cb9d1080322e6c375bb776514af06b56d6c46ed3e", size = 959698, upload-time = "2025-09-25T04:18:19.55Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3e/8e/e7a43d907a147e1f87eebdd6737483f9feba52a5d4b20f69d0bd6f2fa22f/langsmith-0.4.31-py3-none-any.whl", hash = "sha256:64f340bdead21defe5f4a6ca330c11073e35444989169f669508edf45a19025f", size = 386347, upload-time = "2025-09-25T04:18:16.69Z" },
+]
+
+[[package]]
+name = "litellm"
+version = "1.77.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohttp" },
+ { name = "click" },
+ { name = "fastuuid" },
+ { name = "httpx" },
+ { name = "importlib-metadata" },
+ { name = "jinja2" },
+ { name = "jsonschema" },
+ { name = "openai" },
+ { name = "pydantic" },
+ { name = "python-dotenv" },
+ { name = "tiktoken" },
+ { name = "tokenizers" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e1/a3/85fc92d998ec9645c9fac108618681ef411ca4b338cc7544d6b3aad57699/litellm-1.77.5.tar.gz", hash = "sha256:8e8a83b49c4a6ae044b1a1c01adfbdef72b0031b86f1463dd743e267fa1d7b99", size = 10351819, upload-time = "2025-09-28T07:17:39.393Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/4c/89553f7e375ef39497d86f2266a0cdb37371a07e9e0aa8949f33c15a4198/litellm-1.77.5-py3-none-any.whl", hash = "sha256:07f53964c08d555621d4376cc42330458301ae889bfb6303155dcabc51095fbf", size = 9165458, upload-time = "2025-09-28T07:17:35.474Z" },
+]
+
+[[package]]
+name = "llm-engineering"
+version = "0.1.0"
+source = { virtual = "." }
+dependencies = [
+ { name = "anthropic" },
+ { name = "beautifulsoup4" },
+ { name = "chromadb" },
+ { name = "datasets" },
+ { name = "feedparser" },
+ { name = "google-genai" },
+ { name = "google-generativeai" },
+ { name = "gradio" },
+ { name = "ipykernel" },
+ { name = "ipywidgets" },
+ { name = "jupyter-dash" },
+ { name = "langchain" },
+ { name = "langchain-chroma" },
+ { name = "langchain-community" },
+ { name = "langchain-core" },
+ { name = "langchain-openai" },
+ { name = "langchain-text-splitters" },
+ { name = "litellm" },
+ { name = "matplotlib" },
+ { name = "modal" },
+ { name = "numpy" },
+ { name = "ollama" },
+ { name = "openai" },
+ { name = "pandas" },
+ { name = "plotly" },
+ { name = "protobuf" },
+ { name = "psutil" },
+ { name = "pydub" },
+ { name = "python-dotenv" },
+ { name = "requests" },
+ { name = "scikit-learn" },
+ { name = "scipy" },
+ { name = "sentence-transformers" },
+ { name = "setuptools" },
+ { name = "speedtest-cli" },
+ { name = "tiktoken" },
+ { name = "torch" },
+ { name = "tqdm" },
+ { name = "transformers" },
+ { name = "wandb" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "anthropic", specifier = ">=0.69.0" },
+ { name = "beautifulsoup4", specifier = ">=4.14.2" },
+ { name = "chromadb", specifier = ">=1.1.0" },
+ { name = "datasets", specifier = "==3.6.0" },
+ { name = "feedparser", specifier = ">=6.0.12" },
+ { name = "google-genai", specifier = ">=1.41.0" },
+ { name = "google-generativeai", specifier = ">=0.8.5" },
+ { name = "gradio", specifier = ">=5.47.2" },
+ { name = "ipykernel", specifier = ">=6.30.1" },
+ { name = "ipywidgets", specifier = ">=8.1.7" },
+ { name = "jupyter-dash", specifier = ">=0.4.2" },
+ { name = "langchain", specifier = ">=0.3.27" },
+ { name = "langchain-chroma", specifier = ">=0.2.6" },
+ { name = "langchain-community", specifier = ">=0.3.30" },
+ { name = "langchain-core", specifier = ">=0.3.76" },
+ { name = "langchain-openai", specifier = ">=0.3.33" },
+ { name = "langchain-text-splitters", specifier = ">=0.3.11" },
+ { name = "litellm", specifier = ">=1.77.5" },
+ { name = "matplotlib", specifier = ">=3.10.6" },
+ { name = "modal", specifier = ">=1.1.4" },
+ { name = "numpy", specifier = ">=2.3.3" },
+ { name = "ollama", specifier = ">=0.6.0" },
+ { name = "openai", specifier = ">=1.109.1" },
+ { name = "pandas", specifier = ">=2.3.3" },
+ { name = "plotly", specifier = ">=6.3.0" },
+ { name = "protobuf", specifier = "==3.20.2" },
+ { name = "psutil", specifier = ">=7.1.0" },
+ { name = "pydub", specifier = ">=0.25.1" },
+ { name = "python-dotenv", specifier = ">=1.1.1" },
+ { name = "requests", specifier = ">=2.32.5" },
+ { name = "scikit-learn", specifier = ">=1.7.2" },
+ { name = "scipy", specifier = ">=1.16.2" },
+ { name = "sentence-transformers", specifier = ">=5.1.1" },
+ { name = "setuptools", specifier = ">=80.9.0" },
+ { name = "speedtest-cli", specifier = ">=2.1.3" },
+ { name = "tiktoken", specifier = ">=0.11.0" },
+ { name = "torch", specifier = ">=2.8.0" },
+ { name = "tqdm", specifier = ">=4.67.1" },
+ { name = "transformers", specifier = ">=4.56.2" },
+ { name = "wandb", specifier = ">=0.22.1" },
+]
+
+[[package]]
+name = "markdown-it-py"
+version = "4.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mdurl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
+]
+
+[[package]]
+name = "markupsafe"
+version = "3.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" },
+ { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" },
+ { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" },
+ { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" },
+ { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" },
+ { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" },
+ { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" },
+ { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" },
+ { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" },
+ { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" },
+ { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" },
+ { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" },
+ { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" },
+ { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" },
+ { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" },
+ { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" },
+ { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" },
+ { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" },
+ { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" },
+ { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" },
+ { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" },
+ { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" },
+ { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" },
+]
+
+[[package]]
+name = "marshmallow"
+version = "3.26.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "packaging" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ab/5e/5e53d26b42ab75491cda89b871dab9e97c840bf12c63ec58a1919710cd06/marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6", size = 221825, upload-time = "2025-02-03T15:32:25.093Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/34/75/51952c7b2d3873b44a0028b1bd26a25078c18f92f256608e8d1dc61b39fd/marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c", size = 50878, upload-time = "2025-02-03T15:32:22.295Z" },
+]
+
+[[package]]
+name = "matplotlib"
+version = "3.10.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "contourpy" },
+ { name = "cycler" },
+ { name = "fonttools" },
+ { name = "kiwisolver" },
+ { name = "numpy" },
+ { name = "packaging" },
+ { name = "pillow" },
+ { name = "pyparsing" },
+ { name = "python-dateutil" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a0/59/c3e6453a9676ffba145309a73c462bb407f4400de7de3f2b41af70720a3c/matplotlib-3.10.6.tar.gz", hash = "sha256:ec01b645840dd1996df21ee37f208cd8ba57644779fa20464010638013d3203c", size = 34804264, upload-time = "2025-08-30T00:14:25.137Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ea/1a/7042f7430055d567cc3257ac409fcf608599ab27459457f13772c2d9778b/matplotlib-3.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31ca662df6a80bd426f871105fdd69db7543e28e73a9f2afe80de7e531eb2347", size = 8272404, upload-time = "2025-08-30T00:12:59.112Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/5d/1d5f33f5b43f4f9e69e6a5fe1fb9090936ae7bc8e2ff6158e7a76542633b/matplotlib-3.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1678bb61d897bb4ac4757b5ecfb02bfb3fddf7f808000fb81e09c510712fda75", size = 8128262, upload-time = "2025-08-30T00:13:01.141Z" },
+ { url = "https://files.pythonhosted.org/packages/67/c3/135fdbbbf84e0979712df58e5e22b4f257b3f5e52a3c4aacf1b8abec0d09/matplotlib-3.10.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:56cd2d20842f58c03d2d6e6c1f1cf5548ad6f66b91e1e48f814e4fb5abd1cb95", size = 8697008, upload-time = "2025-08-30T00:13:03.24Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/be/c443ea428fb2488a3ea7608714b1bd85a82738c45da21b447dc49e2f8e5d/matplotlib-3.10.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:662df55604a2f9a45435566d6e2660e41efe83cd94f4288dfbf1e6d1eae4b0bb", size = 9530166, upload-time = "2025-08-30T00:13:05.951Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/35/48441422b044d74034aea2a3e0d1a49023f12150ebc58f16600132b9bbaf/matplotlib-3.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:08f141d55148cd1fc870c3387d70ca4df16dee10e909b3b038782bd4bda6ea07", size = 9593105, upload-time = "2025-08-30T00:13:08.356Z" },
+ { url = "https://files.pythonhosted.org/packages/45/c3/994ef20eb4154ab84cc08d033834555319e4af970165e6c8894050af0b3c/matplotlib-3.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:590f5925c2d650b5c9d813c5b3b5fc53f2929c3f8ef463e4ecfa7e052044fb2b", size = 8122784, upload-time = "2025-08-30T00:13:10.367Z" },
+ { url = "https://files.pythonhosted.org/packages/57/b8/5c85d9ae0e40f04e71bedb053aada5d6bab1f9b5399a0937afb5d6b02d98/matplotlib-3.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:f44c8d264a71609c79a78d50349e724f5d5fc3684ead7c2a473665ee63d868aa", size = 7992823, upload-time = "2025-08-30T00:13:12.24Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/db/18380e788bb837e724358287b08e223b32bc8dccb3b0c12fa8ca20bc7f3b/matplotlib-3.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:819e409653c1106c8deaf62e6de6b8611449c2cd9939acb0d7d4e57a3d95cc7a", size = 8273231, upload-time = "2025-08-30T00:13:13.881Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/0f/38dd49445b297e0d4f12a322c30779df0d43cb5873c7847df8a82e82ec67/matplotlib-3.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:59c8ac8382fefb9cb71308dde16a7c487432f5255d8f1fd32473523abecfecdf", size = 8128730, upload-time = "2025-08-30T00:13:15.556Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/b8/9eea6630198cb303d131d95d285a024b3b8645b1763a2916fddb44ca8760/matplotlib-3.10.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84e82d9e0fd70c70bc55739defbd8055c54300750cbacf4740c9673a24d6933a", size = 8698539, upload-time = "2025-08-30T00:13:17.297Z" },
+ { url = "https://files.pythonhosted.org/packages/71/34/44c7b1f075e1ea398f88aeabcc2907c01b9cc99e2afd560c1d49845a1227/matplotlib-3.10.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25f7a3eb42d6c1c56e89eacd495661fc815ffc08d9da750bca766771c0fd9110", size = 9529702, upload-time = "2025-08-30T00:13:19.248Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/7f/e5c2dc9950c7facaf8b461858d1b92c09dd0cf174fe14e21953b3dda06f7/matplotlib-3.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f9c862d91ec0b7842920a4cfdaaec29662195301914ea54c33e01f1a28d014b2", size = 9593742, upload-time = "2025-08-30T00:13:21.181Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/1d/70c28528794f6410ee2856cd729fa1f1756498b8d3126443b0a94e1a8695/matplotlib-3.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:1b53bd6337eba483e2e7d29c5ab10eee644bc3a2491ec67cc55f7b44583ffb18", size = 8122753, upload-time = "2025-08-30T00:13:23.44Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/74/0e1670501fc7d02d981564caf7c4df42974464625935424ca9654040077c/matplotlib-3.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:cbd5eb50b7058b2892ce45c2f4e92557f395c9991f5c886d1bb74a1582e70fd6", size = 7992973, upload-time = "2025-08-30T00:13:26.632Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/4e/60780e631d73b6b02bd7239f89c451a72970e5e7ec34f621eda55cd9a445/matplotlib-3.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:acc86dd6e0e695c095001a7fccff158c49e45e0758fdf5dcdbb0103318b59c9f", size = 8316869, upload-time = "2025-08-30T00:13:28.262Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/15/baa662374a579413210fc2115d40c503b7360a08e9cc254aa0d97d34b0c1/matplotlib-3.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e228cd2ffb8f88b7d0b29e37f68ca9aaf83e33821f24a5ccc4f082dd8396bc27", size = 8178240, upload-time = "2025-08-30T00:13:30.007Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/3f/3c38e78d2aafdb8829fcd0857d25aaf9e7dd2dfcf7ec742765b585774931/matplotlib-3.10.6-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:658bc91894adeab669cf4bb4a186d049948262987e80f0857216387d7435d833", size = 8711719, upload-time = "2025-08-30T00:13:31.72Z" },
+ { url = "https://files.pythonhosted.org/packages/96/4b/2ec2bbf8cefaa53207cc56118d1fa8a0f9b80642713ea9390235d331ede4/matplotlib-3.10.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8913b7474f6dd83ac444c9459c91f7f0f2859e839f41d642691b104e0af056aa", size = 9541422, upload-time = "2025-08-30T00:13:33.611Z" },
+ { url = "https://files.pythonhosted.org/packages/83/7d/40255e89b3ef11c7871020563b2dd85f6cb1b4eff17c0f62b6eb14c8fa80/matplotlib-3.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:091cea22e059b89f6d7d1a18e2c33a7376c26eee60e401d92a4d6726c4e12706", size = 9594068, upload-time = "2025-08-30T00:13:35.833Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/a9/0213748d69dc842537a113493e1c27daf9f96bd7cc316f933dc8ec4de985/matplotlib-3.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:491e25e02a23d7207629d942c666924a6b61e007a48177fdd231a0097b7f507e", size = 8200100, upload-time = "2025-08-30T00:13:37.668Z" },
+ { url = "https://files.pythonhosted.org/packages/be/15/79f9988066ce40b8a6f1759a934ea0cde8dc4adc2262255ee1bc98de6ad0/matplotlib-3.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3d80d60d4e54cda462e2cd9a086d85cd9f20943ead92f575ce86885a43a565d5", size = 8042142, upload-time = "2025-08-30T00:13:39.426Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/58/e7b6d292beae6fb4283ca6fb7fa47d7c944a68062d6238c07b497dd35493/matplotlib-3.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:70aaf890ce1d0efd482df969b28a5b30ea0b891224bb315810a3940f67182899", size = 8273802, upload-time = "2025-08-30T00:13:41.006Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/f6/7882d05aba16a8cdd594fb9a03a9d3cca751dbb6816adf7b102945522ee9/matplotlib-3.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1565aae810ab79cb72e402b22facfa6501365e73ebab70a0fdfb98488d2c3c0c", size = 8131365, upload-time = "2025-08-30T00:13:42.664Z" },
+ { url = "https://files.pythonhosted.org/packages/94/bf/ff32f6ed76e78514e98775a53715eca4804b12bdcf35902cdd1cf759d324/matplotlib-3.10.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3b23315a01981689aa4e1a179dbf6ef9fbd17143c3eea77548c2ecfb0499438", size = 9533961, upload-time = "2025-08-30T00:13:44.372Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/c3/6bf88c2fc2da7708a2ff8d2eeb5d68943130f50e636d5d3dcf9d4252e971/matplotlib-3.10.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:30fdd37edf41a4e6785f9b37969de57aea770696cb637d9946eb37470c94a453", size = 9804262, upload-time = "2025-08-30T00:13:46.614Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/7a/e05e6d9446d2d577b459427ad060cd2de5742d0e435db3191fea4fcc7e8b/matplotlib-3.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bc31e693da1c08012c764b053e702c1855378e04102238e6a5ee6a7117c53a47", size = 9595508, upload-time = "2025-08-30T00:13:48.731Z" },
+ { url = "https://files.pythonhosted.org/packages/39/fb/af09c463ced80b801629fd73b96f726c9f6124c3603aa2e480a061d6705b/matplotlib-3.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:05be9bdaa8b242bc6ff96330d18c52f1fc59c6fb3a4dd411d953d67e7e1baf98", size = 8252742, upload-time = "2025-08-30T00:13:50.539Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/f9/b682f6db9396d9ab8f050c0a3bfbb5f14fb0f6518f08507c04cc02f8f229/matplotlib-3.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:f56a0d1ab05d34c628592435781d185cd99630bdfd76822cd686fb5a0aecd43a", size = 8124237, upload-time = "2025-08-30T00:13:54.3Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/d2/b69b4a0923a3c05ab90527c60fdec899ee21ca23ede7f0fb818e6620d6f2/matplotlib-3.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:94f0b4cacb23763b64b5dace50d5b7bfe98710fed5f0cef5c08135a03399d98b", size = 8316956, upload-time = "2025-08-30T00:13:55.932Z" },
+ { url = "https://files.pythonhosted.org/packages/28/e9/dc427b6f16457ffaeecb2fc4abf91e5adb8827861b869c7a7a6d1836fa73/matplotlib-3.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cc332891306b9fb39462673d8225d1b824c89783fee82840a709f96714f17a5c", size = 8178260, upload-time = "2025-08-30T00:14:00.942Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/89/1fbd5ad611802c34d1c7ad04607e64a1350b7fb9c567c4ec2c19e066ed35/matplotlib-3.10.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee1d607b3fb1590deb04b69f02ea1d53ed0b0bf75b2b1a5745f269afcbd3cdd3", size = 9541422, upload-time = "2025-08-30T00:14:02.664Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/3b/65fec8716025b22c1d72d5a82ea079934c76a547696eaa55be6866bc89b1/matplotlib-3.10.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:376a624a218116461696b27b2bbf7a8945053e6d799f6502fc03226d077807bf", size = 9803678, upload-time = "2025-08-30T00:14:04.741Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/b0/40fb2b3a1ab9381bb39a952e8390357c8be3bdadcf6d5055d9c31e1b35ae/matplotlib-3.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:83847b47f6524c34b4f2d3ce726bb0541c48c8e7692729865c3df75bfa0f495a", size = 9594077, upload-time = "2025-08-30T00:14:07.012Z" },
+ { url = "https://files.pythonhosted.org/packages/76/34/c4b71b69edf5b06e635eee1ed10bfc73cf8df058b66e63e30e6a55e231d5/matplotlib-3.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:c7e0518e0d223683532a07f4b512e2e0729b62674f1b3a1a69869f98e6b1c7e3", size = 8342822, upload-time = "2025-08-30T00:14:09.041Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/62/aeabeef1a842b6226a30d49dd13e8a7a1e81e9ec98212c0b5169f0a12d83/matplotlib-3.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:4dd83e029f5b4801eeb87c64efd80e732452781c16a9cf7415b7b63ec8f374d7", size = 8172588, upload-time = "2025-08-30T00:14:11.166Z" },
+]
+
+[[package]]
+name = "matplotlib-inline"
+version = "0.1.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "traitlets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" },
+]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
+]
+
+[[package]]
+name = "mmh3"
+version = "5.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a7/af/f28c2c2f51f31abb4725f9a64bc7863d5f491f6539bd26aee2a1d21a649e/mmh3-5.2.0.tar.gz", hash = "sha256:1efc8fec8478e9243a78bb993422cf79f8ff85cb4cf6b79647480a31e0d950a8", size = 33582, upload-time = "2025-07-29T07:43:48.49Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bf/6a/d5aa7edb5c08e0bd24286c7d08341a0446f9a2fbbb97d96a8a6dd81935ee/mmh3-5.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:384eda9361a7bf83a85e09447e1feafe081034af9dd428893701b959230d84be", size = 56141, upload-time = "2025-07-29T07:42:13.456Z" },
+ { url = "https://files.pythonhosted.org/packages/08/49/131d0fae6447bc4a7299ebdb1a6fb9d08c9f8dcf97d75ea93e8152ddf7ab/mmh3-5.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c9da0d568569cc87315cb063486d761e38458b8ad513fedd3dc9263e1b81bcd", size = 40681, upload-time = "2025-07-29T07:42:14.306Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/6f/9221445a6bcc962b7f5ff3ba18ad55bba624bacdc7aa3fc0a518db7da8ec/mmh3-5.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86d1be5d63232e6eb93c50881aea55ff06eb86d8e08f9b5417c8c9b10db9db96", size = 40062, upload-time = "2025-07-29T07:42:15.08Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/d4/6bb2d0fef81401e0bb4c297d1eb568b767de4ce6fc00890bc14d7b51ecc4/mmh3-5.2.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bf7bee43e17e81671c447e9c83499f53d99bf440bc6d9dc26a841e21acfbe094", size = 97333, upload-time = "2025-07-29T07:42:16.436Z" },
+ { url = "https://files.pythonhosted.org/packages/44/e0/ccf0daff8134efbb4fbc10a945ab53302e358c4b016ada9bf97a6bdd50c1/mmh3-5.2.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7aa18cdb58983ee660c9c400b46272e14fa253c675ed963d3812487f8ca42037", size = 103310, upload-time = "2025-07-29T07:42:17.796Z" },
+ { url = "https://files.pythonhosted.org/packages/02/63/1965cb08a46533faca0e420e06aff8bbaf9690a6f0ac6ae6e5b2e4544687/mmh3-5.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9d032488fcec32d22be6542d1a836f00247f40f320844dbb361393b5b22773", size = 106178, upload-time = "2025-07-29T07:42:19.281Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/41/c883ad8e2c234013f27f92061200afc11554ea55edd1bcf5e1accd803a85/mmh3-5.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1861fb6b1d0453ed7293200139c0a9011eeb1376632e048e3766945b13313c5", size = 113035, upload-time = "2025-07-29T07:42:20.356Z" },
+ { url = "https://files.pythonhosted.org/packages/df/b5/1ccade8b1fa625d634a18bab7bf08a87457e09d5ec8cf83ca07cbea9d400/mmh3-5.2.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:99bb6a4d809aa4e528ddfe2c85dd5239b78b9dd14be62cca0329db78505e7b50", size = 120784, upload-time = "2025-07-29T07:42:21.377Z" },
+ { url = "https://files.pythonhosted.org/packages/77/1c/919d9171fcbdcdab242e06394464ccf546f7d0f3b31e0d1e3a630398782e/mmh3-5.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1f8d8b627799f4e2fcc7c034fed8f5f24dc7724ff52f69838a3d6d15f1ad4765", size = 99137, upload-time = "2025-07-29T07:42:22.344Z" },
+ { url = "https://files.pythonhosted.org/packages/66/8a/1eebef5bd6633d36281d9fc83cf2e9ba1ba0e1a77dff92aacab83001cee4/mmh3-5.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b5995088dd7023d2d9f310a0c67de5a2b2e06a570ecfd00f9ff4ab94a67cde43", size = 98664, upload-time = "2025-07-29T07:42:23.269Z" },
+ { url = "https://files.pythonhosted.org/packages/13/41/a5d981563e2ee682b21fb65e29cc0f517a6734a02b581359edd67f9d0360/mmh3-5.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1a5f4d2e59d6bba8ef01b013c472741835ad961e7c28f50c82b27c57748744a4", size = 106459, upload-time = "2025-07-29T07:42:24.238Z" },
+ { url = "https://files.pythonhosted.org/packages/24/31/342494cd6ab792d81e083680875a2c50fa0c5df475ebf0b67784f13e4647/mmh3-5.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fd6e6c3d90660d085f7e73710eab6f5545d4854b81b0135a3526e797009dbda3", size = 110038, upload-time = "2025-07-29T07:42:25.629Z" },
+ { url = "https://files.pythonhosted.org/packages/28/44/efda282170a46bb4f19c3e2b90536513b1d821c414c28469a227ca5a1789/mmh3-5.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c4a2f3d83879e3de2eb8cbf562e71563a8ed15ee9b9c2e77ca5d9f73072ac15c", size = 97545, upload-time = "2025-07-29T07:42:27.04Z" },
+ { url = "https://files.pythonhosted.org/packages/68/8f/534ae319c6e05d714f437e7206f78c17e66daca88164dff70286b0e8ea0c/mmh3-5.2.0-cp312-cp312-win32.whl", hash = "sha256:2421b9d665a0b1ad724ec7332fb5a98d075f50bc51a6ff854f3a1882bd650d49", size = 40805, upload-time = "2025-07-29T07:42:28.032Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/f6/f6abdcfefcedab3c964868048cfe472764ed358c2bf6819a70dd4ed4ed3a/mmh3-5.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:72d80005b7634a3a2220f81fbeb94775ebd12794623bb2e1451701ea732b4aa3", size = 41597, upload-time = "2025-07-29T07:42:28.894Z" },
+ { url = "https://files.pythonhosted.org/packages/15/fd/f7420e8cbce45c259c770cac5718badf907b302d3a99ec587ba5ce030237/mmh3-5.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:3d6bfd9662a20c054bc216f861fa330c2dac7c81e7fb8307b5e32ab5b9b4d2e0", size = 39350, upload-time = "2025-07-29T07:42:29.794Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/fa/27f6ab93995ef6ad9f940e96593c5dd24744d61a7389532b0fec03745607/mmh3-5.2.0-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:e79c00eba78f7258e5b354eccd4d7907d60317ced924ea4a5f2e9d83f5453065", size = 40874, upload-time = "2025-07-29T07:42:30.662Z" },
+ { url = "https://files.pythonhosted.org/packages/11/9c/03d13bcb6a03438bc8cac3d2e50f80908d159b31a4367c2e1a7a077ded32/mmh3-5.2.0-cp313-cp313-android_21_x86_64.whl", hash = "sha256:956127e663d05edbeec54df38885d943dfa27406594c411139690485128525de", size = 42012, upload-time = "2025-07-29T07:42:31.539Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/78/0865d9765408a7d504f1789944e678f74e0888b96a766d578cb80b040999/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:c3dca4cb5b946ee91b3d6bb700d137b1cd85c20827f89fdf9c16258253489044", size = 39197, upload-time = "2025-07-29T07:42:32.374Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/12/76c3207bd186f98b908b6706c2317abb73756d23a4e68ea2bc94825b9015/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e651e17bfde5840e9e4174b01e9e080ce49277b70d424308b36a7969d0d1af73", size = 39840, upload-time = "2025-07-29T07:42:33.227Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/0d/574b6cce5555c9f2b31ea189ad44986755eb14e8862db28c8b834b8b64dc/mmh3-5.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:9f64bf06f4bf623325fda3a6d02d36cd69199b9ace99b04bb2d7fd9f89688504", size = 40644, upload-time = "2025-07-29T07:42:34.099Z" },
+ { url = "https://files.pythonhosted.org/packages/52/82/3731f8640b79c46707f53ed72034a58baad400be908c87b0088f1f89f986/mmh3-5.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ddc63328889bcaee77b743309e5c7d2d52cee0d7d577837c91b6e7cc9e755e0b", size = 56153, upload-time = "2025-07-29T07:42:35.031Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/34/e02dca1d4727fd9fdeaff9e2ad6983e1552804ce1d92cc796e5b052159bb/mmh3-5.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bb0fdc451fb6d86d81ab8f23d881b8d6e37fc373a2deae1c02d27002d2ad7a05", size = 40684, upload-time = "2025-07-29T07:42:35.914Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/36/3dee40767356e104967e6ed6d102ba47b0b1ce2a89432239b95a94de1b89/mmh3-5.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b29044e1ffdb84fe164d0a7ea05c7316afea93c00f8ed9449cf357c36fc4f814", size = 40057, upload-time = "2025-07-29T07:42:36.755Z" },
+ { url = "https://files.pythonhosted.org/packages/31/58/228c402fccf76eb39a0a01b8fc470fecf21965584e66453b477050ee0e99/mmh3-5.2.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:58981d6ea9646dbbf9e59a30890cbf9f610df0e4a57dbfe09215116fd90b0093", size = 97344, upload-time = "2025-07-29T07:42:37.675Z" },
+ { url = "https://files.pythonhosted.org/packages/34/82/fc5ce89006389a6426ef28e326fc065b0fbaaed230373b62d14c889f47ea/mmh3-5.2.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e5634565367b6d98dc4aa2983703526ef556b3688ba3065edb4b9b90ede1c54", size = 103325, upload-time = "2025-07-29T07:42:38.591Z" },
+ { url = "https://files.pythonhosted.org/packages/09/8c/261e85777c6aee1ebd53f2f17e210e7481d5b0846cd0b4a5c45f1e3761b8/mmh3-5.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0271ac12415afd3171ab9a3c7cbfc71dee2c68760a7dc9d05bf8ed6ddfa3a7a", size = 106240, upload-time = "2025-07-29T07:42:39.563Z" },
+ { url = "https://files.pythonhosted.org/packages/70/73/2f76b3ad8a3d431824e9934403df36c0ddacc7831acf82114bce3c4309c8/mmh3-5.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:45b590e31bc552c6f8e2150ff1ad0c28dd151e9f87589e7eaf508fbdd8e8e908", size = 113060, upload-time = "2025-07-29T07:42:40.585Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/b9/7ea61a34e90e50a79a9d87aa1c0b8139a7eaf4125782b34b7d7383472633/mmh3-5.2.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bdde97310d59604f2a9119322f61b31546748499a21b44f6715e8ced9308a6c5", size = 120781, upload-time = "2025-07-29T07:42:41.618Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/5b/ae1a717db98c7894a37aeedbd94b3f99e6472a836488f36b6849d003485b/mmh3-5.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc9c5f280438cf1c1a8f9abb87dc8ce9630a964120cfb5dd50d1e7ce79690c7a", size = 99174, upload-time = "2025-07-29T07:42:42.587Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/de/000cce1d799fceebb6d4487ae29175dd8e81b48e314cba7b4da90bcf55d7/mmh3-5.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c903e71fd8debb35ad2a4184c1316b3cb22f64ce517b4e6747f25b0a34e41266", size = 98734, upload-time = "2025-07-29T07:42:43.996Z" },
+ { url = "https://files.pythonhosted.org/packages/79/19/0dc364391a792b72fbb22becfdeacc5add85cc043cd16986e82152141883/mmh3-5.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:eed4bba7ff8a0d37106ba931ab03bdd3915fbb025bcf4e1f0aa02bc8114960c5", size = 106493, upload-time = "2025-07-29T07:42:45.07Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/b1/bc8c28e4d6e807bbb051fefe78e1156d7f104b89948742ad310612ce240d/mmh3-5.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1fdb36b940e9261aff0b5177c5b74a36936b902f473180f6c15bde26143681a9", size = 110089, upload-time = "2025-07-29T07:42:46.122Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/a2/d20f3f5c95e9c511806686c70d0a15479cc3941c5f322061697af1c1ff70/mmh3-5.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7303aab41e97adcf010a09efd8f1403e719e59b7705d5e3cfed3dd7571589290", size = 97571, upload-time = "2025-07-29T07:42:47.18Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/23/665296fce4f33488deec39a750ffd245cfc07aafb0e3ef37835f91775d14/mmh3-5.2.0-cp313-cp313-win32.whl", hash = "sha256:03e08c6ebaf666ec1e3d6ea657a2d363bb01effd1a9acfe41f9197decaef0051", size = 40806, upload-time = "2025-07-29T07:42:48.166Z" },
+ { url = "https://files.pythonhosted.org/packages/59/b0/92e7103f3b20646e255b699e2d0327ce53a3f250e44367a99dc8be0b7c7a/mmh3-5.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:7fddccd4113e7b736706e17a239a696332360cbaddf25ae75b57ba1acce65081", size = 41600, upload-time = "2025-07-29T07:42:49.371Z" },
+ { url = "https://files.pythonhosted.org/packages/99/22/0b2bd679a84574647de538c5b07ccaa435dbccc37815067fe15b90fe8dad/mmh3-5.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa0c966ee727aad5406d516375593c5f058c766b21236ab8985693934bb5085b", size = 39349, upload-time = "2025-07-29T07:42:50.268Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/ca/a20db059a8a47048aaf550da14a145b56e9c7386fb8280d3ce2962dcebf7/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:e5015f0bb6eb50008bed2d4b1ce0f2a294698a926111e4bb202c0987b4f89078", size = 39209, upload-time = "2025-07-29T07:42:51.559Z" },
+ { url = "https://files.pythonhosted.org/packages/98/dd/e5094799d55c7482d814b979a0fd608027d0af1b274bfb4c3ea3e950bfd5/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e0f3ed828d709f5b82d8bfe14f8856120718ec4bd44a5b26102c3030a1e12501", size = 39843, upload-time = "2025-07-29T07:42:52.536Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/6b/7844d7f832c85400e7cc89a1348e4e1fdd38c5a38415bb5726bbb8fcdb6c/mmh3-5.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:f35727c5118aba95f0397e18a1a5b8405425581bfe53e821f0fb444cbdc2bc9b", size = 40648, upload-time = "2025-07-29T07:42:53.392Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/bf/71f791f48a21ff3190ba5225807cbe4f7223360e96862c376e6e3fb7efa7/mmh3-5.2.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bc244802ccab5220008cb712ca1508cb6a12f0eb64ad62997156410579a1770", size = 56164, upload-time = "2025-07-29T07:42:54.267Z" },
+ { url = "https://files.pythonhosted.org/packages/70/1f/f87e3d34d83032b4f3f0f528c6d95a98290fcacf019da61343a49dccfd51/mmh3-5.2.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ff3d50dc3fe8a98059f99b445dfb62792b5d006c5e0b8f03c6de2813b8376110", size = 40692, upload-time = "2025-07-29T07:42:55.234Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/e2/db849eaed07117086f3452feca8c839d30d38b830ac59fe1ce65af8be5ad/mmh3-5.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:37a358cc881fe796e099c1db6ce07ff757f088827b4e8467ac52b7a7ffdca647", size = 40068, upload-time = "2025-07-29T07:42:56.158Z" },
+ { url = "https://files.pythonhosted.org/packages/df/6b/209af927207af77425b044e32f77f49105a0b05d82ff88af6971d8da4e19/mmh3-5.2.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b9a87025121d1c448f24f27ff53a5fe7b6ef980574b4a4f11acaabe702420d63", size = 97367, upload-time = "2025-07-29T07:42:57.037Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/e0/78adf4104c425606a9ce33fb351f790c76a6c2314969c4a517d1ffc92196/mmh3-5.2.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ba55d6ca32eeef8b2625e1e4bfc3b3db52bc63014bd7e5df8cc11bf2b036b12", size = 103306, upload-time = "2025-07-29T07:42:58.522Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/79/c2b89f91b962658b890104745b1b6c9ce38d50a889f000b469b91eeb1b9e/mmh3-5.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9ff37ba9f15637e424c2ab57a1a590c52897c845b768e4e0a4958084ec87f22", size = 106312, upload-time = "2025-07-29T07:42:59.552Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/14/659d4095528b1a209be90934778c5ffe312177d51e365ddcbca2cac2ec7c/mmh3-5.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a094319ec0db52a04af9fdc391b4d39a1bc72bc8424b47c4411afb05413a44b5", size = 113135, upload-time = "2025-07-29T07:43:00.745Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/6f/cd7734a779389a8a467b5c89a48ff476d6f2576e78216a37551a97e9e42a/mmh3-5.2.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5584061fd3da584659b13587f26c6cad25a096246a481636d64375d0c1f6c07", size = 120775, upload-time = "2025-07-29T07:43:02.124Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/ca/8256e3b96944408940de3f9291d7e38a283b5761fe9614d4808fcf27bd62/mmh3-5.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecbfc0437ddfdced5e7822d1ce4855c9c64f46819d0fdc4482c53f56c707b935", size = 99178, upload-time = "2025-07-29T07:43:03.182Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/32/39e2b3cf06b6e2eb042c984dab8680841ac2a0d3ca6e0bea30db1f27b565/mmh3-5.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7b986d506a8e8ea345791897ba5d8ba0d9d8820cd4fc3e52dbe6de19388de2e7", size = 98738, upload-time = "2025-07-29T07:43:04.207Z" },
+ { url = "https://files.pythonhosted.org/packages/61/d3/7bbc8e0e8cf65ebbe1b893ffa0467b7ecd1bd07c3bbf6c9db4308ada22ec/mmh3-5.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:38d899a156549da8ef6a9f1d6f7ef231228d29f8f69bce2ee12f5fba6d6fd7c5", size = 106510, upload-time = "2025-07-29T07:43:05.656Z" },
+ { url = "https://files.pythonhosted.org/packages/10/99/b97e53724b52374e2f3859046f0eb2425192da356cb19784d64bc17bb1cf/mmh3-5.2.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d86651fa45799530885ba4dab3d21144486ed15285e8784181a0ab37a4552384", size = 110053, upload-time = "2025-07-29T07:43:07.204Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/62/3688c7d975ed195155671df68788c83fed6f7909b6ec4951724c6860cb97/mmh3-5.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c463d7c1c4cfc9d751efeaadd936bbba07b5b0ed81a012b3a9f5a12f0872bd6e", size = 97546, upload-time = "2025-07-29T07:43:08.226Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/3b/c6153250f03f71a8b7634cded82939546cdfba02e32f124ff51d52c6f991/mmh3-5.2.0-cp314-cp314-win32.whl", hash = "sha256:bb4fe46bdc6104fbc28db7a6bacb115ee6368ff993366bbd8a2a7f0076e6f0c0", size = 41422, upload-time = "2025-07-29T07:43:09.216Z" },
+ { url = "https://files.pythonhosted.org/packages/74/01/a27d98bab083a435c4c07e9d1d720d4c8a578bf4c270bae373760b1022be/mmh3-5.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c7f0b342fd06044bedd0b6e72177ddc0076f54fd89ee239447f8b271d919d9b", size = 42135, upload-time = "2025-07-29T07:43:10.183Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/c9/dbba5507e95429b8b380e2ba091eff5c20a70a59560934dff0ad8392b8c8/mmh3-5.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:3193752fc05ea72366c2b63ff24b9a190f422e32d75fdeae71087c08fff26115", size = 39879, upload-time = "2025-07-29T07:43:11.106Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/d1/c8c0ef839c17258b9de41b84f663574fabcf8ac2007b7416575e0f65ff6e/mmh3-5.2.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:69fc339d7202bea69ef9bd7c39bfdf9fdabc8e6822a01eba62fb43233c1b3932", size = 57696, upload-time = "2025-07-29T07:43:11.989Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/55/95e2b9ff201e89f9fe37036037ab61a6c941942b25cdb7b6a9df9b931993/mmh3-5.2.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:12da42c0a55c9d86ab566395324213c319c73ecb0c239fad4726324212b9441c", size = 41421, upload-time = "2025-07-29T07:43:13.269Z" },
+ { url = "https://files.pythonhosted.org/packages/77/79/9be23ad0b7001a4b22752e7693be232428ecc0a35068a4ff5c2f14ef8b20/mmh3-5.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f7f9034c7cf05ddfaac8d7a2e63a3c97a840d4615d0a0e65ba8bdf6f8576e3be", size = 40853, upload-time = "2025-07-29T07:43:14.888Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/1b/96b32058eda1c1dee8264900c37c359a7325c1f11f5ff14fd2be8e24eff9/mmh3-5.2.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11730eeb16dfcf9674fdea9bb6b8e6dd9b40813b7eb839bc35113649eef38aeb", size = 109694, upload-time = "2025-07-29T07:43:15.816Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/6f/a2ae44cd7dad697b6dea48390cbc977b1e5ca58fda09628cbcb2275af064/mmh3-5.2.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:932a6eec1d2e2c3c9e630d10f7128d80e70e2d47fe6b8c7ea5e1afbd98733e65", size = 117438, upload-time = "2025-07-29T07:43:16.865Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/08/bfb75451c83f05224a28afeaf3950c7b793c0b71440d571f8e819cfb149a/mmh3-5.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca975c51c5028947bbcfc24966517aac06a01d6c921e30f7c5383c195f87991", size = 120409, upload-time = "2025-07-29T07:43:18.207Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/ea/8b118b69b2ff8df568f742387d1a159bc654a0f78741b31437dd047ea28e/mmh3-5.2.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5b0b58215befe0f0e120b828f7645e97719bbba9f23b69e268ed0ac7adde8645", size = 125909, upload-time = "2025-07-29T07:43:19.39Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/11/168cc0b6a30650032e351a3b89b8a47382da541993a03af91e1ba2501234/mmh3-5.2.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29c2b9ce61886809d0492a274a5a53047742dea0f703f9c4d5d223c3ea6377d3", size = 135331, upload-time = "2025-07-29T07:43:20.435Z" },
+ { url = "https://files.pythonhosted.org/packages/31/05/e3a9849b1c18a7934c64e831492c99e67daebe84a8c2f2c39a7096a830e3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a367d4741ac0103f8198c82f429bccb9359f543ca542b06a51f4f0332e8de279", size = 110085, upload-time = "2025-07-29T07:43:21.92Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/d5/a96bcc306e3404601418b2a9a370baec92af84204528ba659fdfe34c242f/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5a5dba98e514fb26241868f6eb90a7f7ca0e039aed779342965ce24ea32ba513", size = 111195, upload-time = "2025-07-29T07:43:23.066Z" },
+ { url = "https://files.pythonhosted.org/packages/af/29/0fd49801fec5bff37198684e0849b58e0dab3a2a68382a357cfffb0fafc3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:941603bfd75a46023807511c1ac2f1b0f39cccc393c15039969806063b27e6db", size = 116919, upload-time = "2025-07-29T07:43:24.178Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/04/4f3c32b0a2ed762edca45d8b46568fc3668e34f00fb1e0a3b5451ec1281c/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:132dd943451a7c7546978863d2f5a64977928410782e1a87d583cb60eb89e667", size = 123160, upload-time = "2025-07-29T07:43:25.26Z" },
+ { url = "https://files.pythonhosted.org/packages/91/76/3d29eaa38821730633d6a240d36fa8ad2807e9dfd432c12e1a472ed211eb/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f698733a8a494466432d611a8f0d1e026f5286dee051beea4b3c3146817e35d5", size = 110206, upload-time = "2025-07-29T07:43:26.699Z" },
+ { url = "https://files.pythonhosted.org/packages/44/1c/ccf35892684d3a408202e296e56843743e0b4fb1629e59432ea88cdb3909/mmh3-5.2.0-cp314-cp314t-win32.whl", hash = "sha256:6d541038b3fc360ec538fc116de87462627944765a6750308118f8b509a8eec7", size = 41970, upload-time = "2025-07-29T07:43:27.666Z" },
+ { url = "https://files.pythonhosted.org/packages/75/b2/b9e4f1e5adb5e21eb104588fcee2cd1eaa8308255173481427d5ecc4284e/mmh3-5.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e912b19cf2378f2967d0c08e86ff4c6c360129887f678e27e4dde970d21b3f4d", size = 43063, upload-time = "2025-07-29T07:43:28.582Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/fc/0e61d9a4e29c8679356795a40e48f647b4aad58d71bfc969f0f8f56fb912/mmh3-5.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e7884931fe5e788163e7b3c511614130c2c59feffdc21112290a194487efb2e9", size = 40455, upload-time = "2025-07-29T07:43:29.563Z" },
+]
+
+[[package]]
+name = "modal"
+version = "1.1.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohttp" },
+ { name = "certifi" },
+ { name = "click" },
+ { name = "grpclib" },
+ { name = "protobuf" },
+ { name = "rich" },
+ { name = "synchronicity" },
+ { name = "toml" },
+ { name = "typer" },
+ { name = "types-certifi" },
+ { name = "types-toml" },
+ { name = "typing-extensions" },
+ { name = "watchfiles" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ba/96/6696e536e7d0063eab645c11330e2daa5b87dbccc12c719307079b362050/modal-1.1.4.tar.gz", hash = "sha256:67f612f41ef6091e24a92fb9bb158fabf5e8f6ff7351a2c7ae2140bb112b871b", size = 594653, upload-time = "2025-09-03T22:25:38.44Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3d/cf/6b3988de454d65e6f5b6471400dbb1f28ad4784f24abd5d3f392a39df782/modal-1.1.4-py3-none-any.whl", hash = "sha256:fcacbc22c5db59b76239f54e16e35c5a4a24cda10b465f1e4750311418939212", size = 685859, upload-time = "2025-09-03T22:25:35.477Z" },
+]
+
+[[package]]
+name = "mpmath"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" },
+]
+
+[[package]]
+name = "multidict"
+version = "6.6.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/69/7f/0652e6ed47ab288e3756ea9c0df8b14950781184d4bd7883f4d87dd41245/multidict-6.6.4.tar.gz", hash = "sha256:d2d4e4787672911b48350df02ed3fa3fffdc2f2e8ca06dd6afdf34189b76a9dd", size = 101843, upload-time = "2025-08-11T12:08:48.217Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/f6/512ffd8fd8b37fb2680e5ac35d788f1d71bbaf37789d21a820bdc441e565/multidict-6.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0ffb87be160942d56d7b87b0fdf098e81ed565add09eaa1294268c7f3caac4c8", size = 76516, upload-time = "2025-08-11T12:06:53.393Z" },
+ { url = "https://files.pythonhosted.org/packages/99/58/45c3e75deb8855c36bd66cc1658007589662ba584dbf423d01df478dd1c5/multidict-6.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d191de6cbab2aff5de6c5723101705fd044b3e4c7cfd587a1929b5028b9714b3", size = 45394, upload-time = "2025-08-11T12:06:54.555Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/ca/e8c4472a93a26e4507c0b8e1f0762c0d8a32de1328ef72fd704ef9cc5447/multidict-6.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38a0956dd92d918ad5feff3db8fcb4a5eb7dba114da917e1a88475619781b57b", size = 43591, upload-time = "2025-08-11T12:06:55.672Z" },
+ { url = "https://files.pythonhosted.org/packages/05/51/edf414f4df058574a7265034d04c935aa84a89e79ce90fcf4df211f47b16/multidict-6.6.4-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6865f6d3b7900ae020b495d599fcf3765653bc927951c1abb959017f81ae8287", size = 237215, upload-time = "2025-08-11T12:06:57.213Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/45/8b3d6dbad8cf3252553cc41abea09ad527b33ce47a5e199072620b296902/multidict-6.6.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a2088c126b6f72db6c9212ad827d0ba088c01d951cee25e758c450da732c138", size = 258299, upload-time = "2025-08-11T12:06:58.946Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/e8/8ca2e9a9f5a435fc6db40438a55730a4bf4956b554e487fa1b9ae920f825/multidict-6.6.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f37bed7319b848097085d7d48116f545985db988e2256b2e6f00563a3416ee6", size = 242357, upload-time = "2025-08-11T12:07:00.301Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/84/80c77c99df05a75c28490b2af8f7cba2a12621186e0a8b0865d8e745c104/multidict-6.6.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:01368e3c94032ba6ca0b78e7ccb099643466cf24f8dc8eefcfdc0571d56e58f9", size = 268369, upload-time = "2025-08-11T12:07:01.638Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/e9/920bfa46c27b05fb3e1ad85121fd49f441492dca2449c5bcfe42e4565d8a/multidict-6.6.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fe323540c255db0bffee79ad7f048c909f2ab0edb87a597e1c17da6a54e493c", size = 269341, upload-time = "2025-08-11T12:07:02.943Z" },
+ { url = "https://files.pythonhosted.org/packages/af/65/753a2d8b05daf496f4a9c367fe844e90a1b2cac78e2be2c844200d10cc4c/multidict-6.6.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8eb3025f17b0a4c3cd08cda49acf312a19ad6e8a4edd9dbd591e6506d999402", size = 256100, upload-time = "2025-08-11T12:07:04.564Z" },
+ { url = "https://files.pythonhosted.org/packages/09/54/655be13ae324212bf0bc15d665a4e34844f34c206f78801be42f7a0a8aaa/multidict-6.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bbc14f0365534d35a06970d6a83478b249752e922d662dc24d489af1aa0d1be7", size = 253584, upload-time = "2025-08-11T12:07:05.914Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/74/ab2039ecc05264b5cec73eb018ce417af3ebb384ae9c0e9ed42cb33f8151/multidict-6.6.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:75aa52fba2d96bf972e85451b99d8e19cc37ce26fd016f6d4aa60da9ab2b005f", size = 251018, upload-time = "2025-08-11T12:07:08.301Z" },
+ { url = "https://files.pythonhosted.org/packages/af/0a/ccbb244ac848e56c6427f2392741c06302bbfba49c0042f1eb3c5b606497/multidict-6.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fefd4a815e362d4f011919d97d7b4a1e566f1dde83dc4ad8cfb5b41de1df68d", size = 251477, upload-time = "2025-08-11T12:07:10.248Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/b0/0ed49bba775b135937f52fe13922bc64a7eaf0a3ead84a36e8e4e446e096/multidict-6.6.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:db9801fe021f59a5b375ab778973127ca0ac52429a26e2fd86aa9508f4d26eb7", size = 263575, upload-time = "2025-08-11T12:07:11.928Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/d9/7fb85a85e14de2e44dfb6a24f03c41e2af8697a6df83daddb0e9b7569f73/multidict-6.6.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a650629970fa21ac1fb06ba25dabfc5b8a2054fcbf6ae97c758aa956b8dba802", size = 259649, upload-time = "2025-08-11T12:07:13.244Z" },
+ { url = "https://files.pythonhosted.org/packages/03/9e/b3a459bcf9b6e74fa461a5222a10ff9b544cb1cd52fd482fb1b75ecda2a2/multidict-6.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:452ff5da78d4720d7516a3a2abd804957532dd69296cb77319c193e3ffb87e24", size = 251505, upload-time = "2025-08-11T12:07:14.57Z" },
+ { url = "https://files.pythonhosted.org/packages/86/a2/8022f78f041dfe6d71e364001a5cf987c30edfc83c8a5fb7a3f0974cff39/multidict-6.6.4-cp312-cp312-win32.whl", hash = "sha256:8c2fcb12136530ed19572bbba61b407f655e3953ba669b96a35036a11a485793", size = 41888, upload-time = "2025-08-11T12:07:15.904Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/eb/d88b1780d43a56db2cba24289fa744a9d216c1a8546a0dc3956563fd53ea/multidict-6.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:047d9425860a8c9544fed1b9584f0c8bcd31bcde9568b047c5e567a1025ecd6e", size = 46072, upload-time = "2025-08-11T12:07:17.045Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/16/b929320bf5750e2d9d4931835a4c638a19d2494a5b519caaaa7492ebe105/multidict-6.6.4-cp312-cp312-win_arm64.whl", hash = "sha256:14754eb72feaa1e8ae528468f24250dd997b8e2188c3d2f593f9eba259e4b364", size = 43222, upload-time = "2025-08-11T12:07:18.328Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/5d/e1db626f64f60008320aab00fbe4f23fc3300d75892a3381275b3d284580/multidict-6.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f46a6e8597f9bd71b31cc708195d42b634c8527fecbcf93febf1052cacc1f16e", size = 75848, upload-time = "2025-08-11T12:07:19.912Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/aa/8b6f548d839b6c13887253af4e29c939af22a18591bfb5d0ee6f1931dae8/multidict-6.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:22e38b2bc176c5eb9c0a0e379f9d188ae4cd8b28c0f53b52bce7ab0a9e534657", size = 45060, upload-time = "2025-08-11T12:07:21.163Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/c6/f5e97e5d99a729bc2aa58eb3ebfa9f1e56a9b517cc38c60537c81834a73f/multidict-6.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5df8afd26f162da59e218ac0eefaa01b01b2e6cd606cffa46608f699539246da", size = 43269, upload-time = "2025-08-11T12:07:22.392Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/31/d54eb0c62516776f36fe67f84a732f97e0b0e12f98d5685bebcc6d396910/multidict-6.6.4-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:49517449b58d043023720aa58e62b2f74ce9b28f740a0b5d33971149553d72aa", size = 237158, upload-time = "2025-08-11T12:07:23.636Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/1c/8a10c1c25b23156e63b12165a929d8eb49a6ed769fdbefb06e6f07c1e50d/multidict-6.6.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9408439537c5afdca05edd128a63f56a62680f4b3c234301055d7a2000220f", size = 257076, upload-time = "2025-08-11T12:07:25.049Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/86/90e20b5771d6805a119e483fd3d1e8393e745a11511aebca41f0da38c3e2/multidict-6.6.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87a32d20759dc52a9e850fe1061b6e41ab28e2998d44168a8a341b99ded1dba0", size = 240694, upload-time = "2025-08-11T12:07:26.458Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/49/484d3e6b535bc0555b52a0a26ba86e4d8d03fd5587d4936dc59ba7583221/multidict-6.6.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:52e3c8d43cdfff587ceedce9deb25e6ae77daba560b626e97a56ddcad3756879", size = 266350, upload-time = "2025-08-11T12:07:27.94Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/b4/aa4c5c379b11895083d50021e229e90c408d7d875471cb3abf721e4670d6/multidict-6.6.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ad8850921d3a8d8ff6fbef790e773cecfc260bbfa0566998980d3fa8f520bc4a", size = 267250, upload-time = "2025-08-11T12:07:29.303Z" },
+ { url = "https://files.pythonhosted.org/packages/80/e5/5e22c5bf96a64bdd43518b1834c6d95a4922cc2066b7d8e467dae9b6cee6/multidict-6.6.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:497a2954adc25c08daff36f795077f63ad33e13f19bfff7736e72c785391534f", size = 254900, upload-time = "2025-08-11T12:07:30.764Z" },
+ { url = "https://files.pythonhosted.org/packages/17/38/58b27fed927c07035abc02befacab42491e7388ca105e087e6e0215ead64/multidict-6.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:024ce601f92d780ca1617ad4be5ac15b501cc2414970ffa2bb2bbc2bd5a68fa5", size = 252355, upload-time = "2025-08-11T12:07:32.205Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/a1/dad75d23a90c29c02b5d6f3d7c10ab36c3197613be5d07ec49c7791e186c/multidict-6.6.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a693fc5ed9bdd1c9e898013e0da4dcc640de7963a371c0bd458e50e046bf6438", size = 250061, upload-time = "2025-08-11T12:07:33.623Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/1a/ac2216b61c7f116edab6dc3378cca6c70dc019c9a457ff0d754067c58b20/multidict-6.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:190766dac95aab54cae5b152a56520fd99298f32a1266d66d27fdd1b5ac00f4e", size = 249675, upload-time = "2025-08-11T12:07:34.958Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/79/1916af833b800d13883e452e8e0977c065c4ee3ab7a26941fbfdebc11895/multidict-6.6.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:34d8f2a5ffdceab9dcd97c7a016deb2308531d5f0fced2bb0c9e1df45b3363d7", size = 261247, upload-time = "2025-08-11T12:07:36.588Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/65/d1f84fe08ac44a5fc7391cbc20a7cedc433ea616b266284413fd86062f8c/multidict-6.6.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:59e8d40ab1f5a8597abcef00d04845155a5693b5da00d2c93dbe88f2050f2812", size = 257960, upload-time = "2025-08-11T12:07:39.735Z" },
+ { url = "https://files.pythonhosted.org/packages/13/b5/29ec78057d377b195ac2c5248c773703a6b602e132a763e20ec0457e7440/multidict-6.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:467fe64138cfac771f0e949b938c2e1ada2b5af22f39692aa9258715e9ea613a", size = 250078, upload-time = "2025-08-11T12:07:41.525Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/0e/7e79d38f70a872cae32e29b0d77024bef7834b0afb406ddae6558d9e2414/multidict-6.6.4-cp313-cp313-win32.whl", hash = "sha256:14616a30fe6d0a48d0a48d1a633ab3b8bec4cf293aac65f32ed116f620adfd69", size = 41708, upload-time = "2025-08-11T12:07:43.405Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/34/746696dffff742e97cd6a23da953e55d0ea51fa601fa2ff387b3edcfaa2c/multidict-6.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:40cd05eaeb39e2bc8939451f033e57feaa2ac99e07dbca8afe2be450a4a3b6cf", size = 45912, upload-time = "2025-08-11T12:07:45.082Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/87/3bac136181e271e29170d8d71929cdeddeb77f3e8b6a0c08da3a8e9da114/multidict-6.6.4-cp313-cp313-win_arm64.whl", hash = "sha256:f6eb37d511bfae9e13e82cb4d1af36b91150466f24d9b2b8a9785816deb16605", size = 43076, upload-time = "2025-08-11T12:07:46.746Z" },
+ { url = "https://files.pythonhosted.org/packages/64/94/0a8e63e36c049b571c9ae41ee301ada29c3fee9643d9c2548d7d558a1d99/multidict-6.6.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6c84378acd4f37d1b507dfa0d459b449e2321b3ba5f2338f9b085cf7a7ba95eb", size = 82812, upload-time = "2025-08-11T12:07:48.402Z" },
+ { url = "https://files.pythonhosted.org/packages/25/1a/be8e369dfcd260d2070a67e65dd3990dd635cbd735b98da31e00ea84cd4e/multidict-6.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0e0558693063c75f3d952abf645c78f3c5dfdd825a41d8c4d8156fc0b0da6e7e", size = 48313, upload-time = "2025-08-11T12:07:49.679Z" },
+ { url = "https://files.pythonhosted.org/packages/26/5a/dd4ade298674b2f9a7b06a32c94ffbc0497354df8285f27317c66433ce3b/multidict-6.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3f8e2384cb83ebd23fd07e9eada8ba64afc4c759cd94817433ab8c81ee4b403f", size = 46777, upload-time = "2025-08-11T12:07:51.318Z" },
+ { url = "https://files.pythonhosted.org/packages/89/db/98aa28bc7e071bfba611ac2ae803c24e96dd3a452b4118c587d3d872c64c/multidict-6.6.4-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f996b87b420995a9174b2a7c1a8daf7db4750be6848b03eb5e639674f7963773", size = 229321, upload-time = "2025-08-11T12:07:52.965Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/bc/01ddda2a73dd9d167bd85d0e8ef4293836a8f82b786c63fb1a429bc3e678/multidict-6.6.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc356250cffd6e78416cf5b40dc6a74f1edf3be8e834cf8862d9ed5265cf9b0e", size = 249954, upload-time = "2025-08-11T12:07:54.423Z" },
+ { url = "https://files.pythonhosted.org/packages/06/78/6b7c0f020f9aa0acf66d0ab4eb9f08375bac9a50ff5e3edb1c4ccd59eafc/multidict-6.6.4-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:dadf95aa862714ea468a49ad1e09fe00fcc9ec67d122f6596a8d40caf6cec7d0", size = 228612, upload-time = "2025-08-11T12:07:55.914Z" },
+ { url = "https://files.pythonhosted.org/packages/00/44/3faa416f89b2d5d76e9d447296a81521e1c832ad6e40b92f990697b43192/multidict-6.6.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dd57515bebffd8ebd714d101d4c434063322e4fe24042e90ced41f18b6d3395", size = 257528, upload-time = "2025-08-11T12:07:57.371Z" },
+ { url = "https://files.pythonhosted.org/packages/05/5f/77c03b89af0fcb16f018f668207768191fb9dcfb5e3361a5e706a11db2c9/multidict-6.6.4-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:967af5f238ebc2eb1da4e77af5492219fbd9b4b812347da39a7b5f5c72c0fa45", size = 256329, upload-time = "2025-08-11T12:07:58.844Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/e9/ed750a2a9afb4f8dc6f13dc5b67b514832101b95714f1211cd42e0aafc26/multidict-6.6.4-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a4c6875c37aae9794308ec43e3530e4aa0d36579ce38d89979bbf89582002bb", size = 247928, upload-time = "2025-08-11T12:08:01.037Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/b5/e0571bc13cda277db7e6e8a532791d4403dacc9850006cb66d2556e649c0/multidict-6.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7f683a551e92bdb7fac545b9c6f9fa2aebdeefa61d607510b3533286fcab67f5", size = 245228, upload-time = "2025-08-11T12:08:02.96Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/a3/69a84b0eccb9824491f06368f5b86e72e4af54c3067c37c39099b6687109/multidict-6.6.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:3ba5aaf600edaf2a868a391779f7a85d93bed147854925f34edd24cc70a3e141", size = 235869, upload-time = "2025-08-11T12:08:04.746Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/9d/28802e8f9121a6a0804fa009debf4e753d0a59969ea9f70be5f5fdfcb18f/multidict-6.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:580b643b7fd2c295d83cad90d78419081f53fd532d1f1eb67ceb7060f61cff0d", size = 243446, upload-time = "2025-08-11T12:08:06.332Z" },
+ { url = "https://files.pythonhosted.org/packages/38/ea/6c98add069b4878c1d66428a5f5149ddb6d32b1f9836a826ac764b9940be/multidict-6.6.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:37b7187197da6af3ee0b044dbc9625afd0c885f2800815b228a0e70f9a7f473d", size = 252299, upload-time = "2025-08-11T12:08:07.931Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/09/8fe02d204473e14c0af3affd50af9078839dfca1742f025cca765435d6b4/multidict-6.6.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e1b93790ed0bc26feb72e2f08299691ceb6da5e9e14a0d13cc74f1869af327a0", size = 246926, upload-time = "2025-08-11T12:08:09.467Z" },
+ { url = "https://files.pythonhosted.org/packages/37/3d/7b1e10d774a6df5175ecd3c92bff069e77bed9ec2a927fdd4ff5fe182f67/multidict-6.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a506a77ddee1efcca81ecbeae27ade3e09cdf21a8ae854d766c2bb4f14053f92", size = 243383, upload-time = "2025-08-11T12:08:10.981Z" },
+ { url = "https://files.pythonhosted.org/packages/50/b0/a6fae46071b645ae98786ab738447de1ef53742eaad949f27e960864bb49/multidict-6.6.4-cp313-cp313t-win32.whl", hash = "sha256:f93b2b2279883d1d0a9e1bd01f312d6fc315c5e4c1f09e112e4736e2f650bc4e", size = 47775, upload-time = "2025-08-11T12:08:12.439Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/0a/2436550b1520091af0600dff547913cb2d66fbac27a8c33bc1b1bccd8d98/multidict-6.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:6d46a180acdf6e87cc41dc15d8f5c2986e1e8739dc25dbb7dac826731ef381a4", size = 53100, upload-time = "2025-08-11T12:08:13.823Z" },
+ { url = "https://files.pythonhosted.org/packages/97/ea/43ac51faff934086db9c072a94d327d71b7d8b40cd5dcb47311330929ef0/multidict-6.6.4-cp313-cp313t-win_arm64.whl", hash = "sha256:756989334015e3335d087a27331659820d53ba432befdef6a718398b0a8493ad", size = 45501, upload-time = "2025-08-11T12:08:15.173Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/69/b547032297c7e63ba2af494edba695d781af8a0c6e89e4d06cf848b21d80/multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c", size = 12313, upload-time = "2025-08-11T12:08:46.891Z" },
+]
+
+[[package]]
+name = "multiprocess"
+version = "0.70.16"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "dill" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b5/ae/04f39c5d0d0def03247c2893d6f2b83c136bf3320a2154d7b8858f2ba72d/multiprocess-0.70.16.tar.gz", hash = "sha256:161af703d4652a0e1410be6abccecde4a7ddffd19341be0a7011b94aeb171ac1", size = 1772603, upload-time = "2024-01-28T18:52:34.85Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bc/f7/7ec7fddc92e50714ea3745631f79bd9c96424cb2702632521028e57d3a36/multiprocess-0.70.16-py310-none-any.whl", hash = "sha256:c4a9944c67bd49f823687463660a2d6daae94c289adff97e0f9d696ba6371d02", size = 134824, upload-time = "2024-01-28T18:52:26.062Z" },
+ { url = "https://files.pythonhosted.org/packages/50/15/b56e50e8debaf439f44befec5b2af11db85f6e0f344c3113ae0be0593a91/multiprocess-0.70.16-py311-none-any.whl", hash = "sha256:af4cabb0dac72abfb1e794fa7855c325fd2b55a10a44628a3c1ad3311c04127a", size = 143519, upload-time = "2024-01-28T18:52:28.115Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/7d/a988f258104dcd2ccf1ed40fdc97e26c4ac351eeaf81d76e266c52d84e2f/multiprocess-0.70.16-py312-none-any.whl", hash = "sha256:fc0544c531920dde3b00c29863377f87e1632601092ea2daca74e4beb40faa2e", size = 146741, upload-time = "2024-01-28T18:52:29.395Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/89/38df130f2c799090c978b366cfdf5b96d08de5b29a4a293df7f7429fa50b/multiprocess-0.70.16-py38-none-any.whl", hash = "sha256:a71d82033454891091a226dfc319d0cfa8019a4e888ef9ca910372a446de4435", size = 132628, upload-time = "2024-01-28T18:52:30.853Z" },
+ { url = "https://files.pythonhosted.org/packages/da/d9/f7f9379981e39b8c2511c9e0326d212accacb82f12fbfdc1aa2ce2a7b2b6/multiprocess-0.70.16-py39-none-any.whl", hash = "sha256:a0bafd3ae1b732eac64be2e72038231c1ba97724b60b09400d68f229fcc2fbf3", size = 133351, upload-time = "2024-01-28T18:52:31.981Z" },
+]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
+]
+
+[[package]]
+name = "narwhals"
+version = "2.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/00/dd/40ff412dabf90ef6b99266b0b74f217bb88733541733849e0153a108c750/narwhals-2.6.0.tar.gz", hash = "sha256:5c9e2ba923e6a0051017e146184e49fb793548936f978ce130c9f55a9a81240e", size = 561649, upload-time = "2025-09-29T09:08:56.482Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/50/3b/0e2c535c3e6970cfc5763b67f6cc31accaab35a7aa3e322fb6a12830450f/narwhals-2.6.0-py3-none-any.whl", hash = "sha256:3215ea42afb452c6c8527e79cefbe542b674aa08d7e2e99d46b2c9708870e0d4", size = 408435, upload-time = "2025-09-29T09:08:54.503Z" },
+]
+
+[[package]]
+name = "nest-asyncio"
+version = "1.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" },
+]
+
+[[package]]
+name = "networkx"
+version = "3.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" },
+]
+
+[[package]]
+name = "numpy"
+version = "2.3.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d0/19/95b3d357407220ed24c139018d2518fab0a61a948e68286a25f1a4d049ff/numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029", size = 20576648, upload-time = "2025-09-09T16:54:12.543Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/51/5d/bb7fc075b762c96329147799e1bcc9176ab07ca6375ea976c475482ad5b3/numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf", size = 20957014, upload-time = "2025-09-09T15:56:29.966Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/0e/c6211bb92af26517acd52125a237a92afe9c3124c6a68d3b9f81b62a0568/numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25", size = 14185220, upload-time = "2025-09-09T15:56:32.175Z" },
+ { url = "https://files.pythonhosted.org/packages/22/f2/07bb754eb2ede9073f4054f7c0286b0d9d2e23982e090a80d478b26d35ca/numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe", size = 5113918, upload-time = "2025-09-09T15:56:34.175Z" },
+ { url = "https://files.pythonhosted.org/packages/81/0a/afa51697e9fb74642f231ea36aca80fa17c8fb89f7a82abd5174023c3960/numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b", size = 6647922, upload-time = "2025-09-09T15:56:36.149Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/f5/122d9cdb3f51c520d150fef6e87df9279e33d19a9611a87c0d2cf78a89f4/numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8", size = 14281991, upload-time = "2025-09-09T15:56:40.548Z" },
+ { url = "https://files.pythonhosted.org/packages/51/64/7de3c91e821a2debf77c92962ea3fe6ac2bc45d0778c1cbe15d4fce2fd94/numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20", size = 16641643, upload-time = "2025-09-09T15:56:43.343Z" },
+ { url = "https://files.pythonhosted.org/packages/30/e4/961a5fa681502cd0d68907818b69f67542695b74e3ceaa513918103b7e80/numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea", size = 16056787, upload-time = "2025-09-09T15:56:46.141Z" },
+ { url = "https://files.pythonhosted.org/packages/99/26/92c912b966e47fbbdf2ad556cb17e3a3088e2e1292b9833be1dfa5361a1a/numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7", size = 18579598, upload-time = "2025-09-09T15:56:49.844Z" },
+ { url = "https://files.pythonhosted.org/packages/17/b6/fc8f82cb3520768718834f310c37d96380d9dc61bfdaf05fe5c0b7653e01/numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf", size = 6320800, upload-time = "2025-09-09T15:56:52.499Z" },
+ { url = "https://files.pythonhosted.org/packages/32/ee/de999f2625b80d043d6d2d628c07d0d5555a677a3cf78fdf868d409b8766/numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb", size = 12786615, upload-time = "2025-09-09T15:56:54.422Z" },
+ { url = "https://files.pythonhosted.org/packages/49/6e/b479032f8a43559c383acb20816644f5f91c88f633d9271ee84f3b3a996c/numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5", size = 10195936, upload-time = "2025-09-09T15:56:56.541Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/b9/984c2b1ee61a8b803bf63582b4ac4242cf76e2dbd663efeafcb620cc0ccb/numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf", size = 20949588, upload-time = "2025-09-09T15:56:59.087Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/e4/07970e3bed0b1384d22af1e9912527ecbeb47d3b26e9b6a3bced068b3bea/numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7", size = 14177802, upload-time = "2025-09-09T15:57:01.73Z" },
+ { url = "https://files.pythonhosted.org/packages/35/c7/477a83887f9de61f1203bad89cf208b7c19cc9fef0cebef65d5a1a0619f2/numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6", size = 5106537, upload-time = "2025-09-09T15:57:03.765Z" },
+ { url = "https://files.pythonhosted.org/packages/52/47/93b953bd5866a6f6986344d045a207d3f1cfbad99db29f534ea9cee5108c/numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7", size = 6640743, upload-time = "2025-09-09T15:57:07.921Z" },
+ { url = "https://files.pythonhosted.org/packages/23/83/377f84aaeb800b64c0ef4de58b08769e782edcefa4fea712910b6f0afd3c/numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c", size = 14278881, upload-time = "2025-09-09T15:57:11.349Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/a5/bf3db6e66c4b160d6ea10b534c381a1955dfab34cb1017ea93aa33c70ed3/numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93", size = 16636301, upload-time = "2025-09-09T15:57:14.245Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/59/1287924242eb4fa3f9b3a2c30400f2e17eb2707020d1c5e3086fe7330717/numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae", size = 16053645, upload-time = "2025-09-09T15:57:16.534Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/93/b3d47ed882027c35e94ac2320c37e452a549f582a5e801f2d34b56973c97/numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86", size = 18578179, upload-time = "2025-09-09T15:57:18.883Z" },
+ { url = "https://files.pythonhosted.org/packages/20/d9/487a2bccbf7cc9d4bfc5f0f197761a5ef27ba870f1e3bbb9afc4bbe3fcc2/numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8", size = 6312250, upload-time = "2025-09-09T15:57:21.296Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/b5/263ebbbbcede85028f30047eab3d58028d7ebe389d6493fc95ae66c636ab/numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf", size = 12783269, upload-time = "2025-09-09T15:57:23.034Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/75/67b8ca554bbeaaeb3fac2e8bce46967a5a06544c9108ec0cf5cece559b6c/numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5", size = 10195314, upload-time = "2025-09-09T15:57:25.045Z" },
+ { url = "https://files.pythonhosted.org/packages/11/d0/0d1ddec56b162042ddfafeeb293bac672de9b0cfd688383590090963720a/numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc", size = 21048025, upload-time = "2025-09-09T15:57:27.257Z" },
+ { url = "https://files.pythonhosted.org/packages/36/9e/1996ca6b6d00415b6acbdd3c42f7f03ea256e2c3f158f80bd7436a8a19f3/numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc", size = 14301053, upload-time = "2025-09-09T15:57:30.077Z" },
+ { url = "https://files.pythonhosted.org/packages/05/24/43da09aa764c68694b76e84b3d3f0c44cb7c18cdc1ba80e48b0ac1d2cd39/numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b", size = 5229444, upload-time = "2025-09-09T15:57:32.733Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/14/50ffb0f22f7218ef8af28dd089f79f68289a7a05a208db9a2c5dcbe123c1/numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19", size = 6738039, upload-time = "2025-09-09T15:57:34.328Z" },
+ { url = "https://files.pythonhosted.org/packages/55/52/af46ac0795e09657d45a7f4db961917314377edecf66db0e39fa7ab5c3d3/numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30", size = 14352314, upload-time = "2025-09-09T15:57:36.255Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/b1/dc226b4c90eb9f07a3fff95c2f0db3268e2e54e5cce97c4ac91518aee71b/numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e", size = 16701722, upload-time = "2025-09-09T15:57:38.622Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/9d/9d8d358f2eb5eced14dba99f110d83b5cd9a4460895230f3b396ad19a323/numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3", size = 16132755, upload-time = "2025-09-09T15:57:41.16Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/27/b3922660c45513f9377b3fb42240bec63f203c71416093476ec9aa0719dc/numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea", size = 18651560, upload-time = "2025-09-09T15:57:43.459Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/8e/3ab61a730bdbbc201bb245a71102aa609f0008b9ed15255500a99cd7f780/numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd", size = 6442776, upload-time = "2025-09-09T15:57:45.793Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/3a/e22b766b11f6030dc2decdeff5c2fb1610768055603f9f3be88b6d192fb2/numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d", size = 12927281, upload-time = "2025-09-09T15:57:47.492Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/42/c2e2bc48c5e9b2a83423f99733950fbefd86f165b468a3d85d52b30bf782/numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1", size = 10265275, upload-time = "2025-09-09T15:57:49.647Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/01/342ad585ad82419b99bcf7cebe99e61da6bedb89e213c5fd71acc467faee/numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593", size = 20951527, upload-time = "2025-09-09T15:57:52.006Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/d8/204e0d73fc1b7a9ee80ab1fe1983dd33a4d64a4e30a05364b0208e9a241a/numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652", size = 14186159, upload-time = "2025-09-09T15:57:54.407Z" },
+ { url = "https://files.pythonhosted.org/packages/22/af/f11c916d08f3a18fb8ba81ab72b5b74a6e42ead4c2846d270eb19845bf74/numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7", size = 5114624, upload-time = "2025-09-09T15:57:56.5Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/11/0ed919c8381ac9d2ffacd63fd1f0c34d27e99cab650f0eb6f110e6ae4858/numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a", size = 6642627, upload-time = "2025-09-09T15:57:58.206Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/83/deb5f77cb0f7ba6cb52b91ed388b47f8f3c2e9930d4665c600408d9b90b9/numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe", size = 14296926, upload-time = "2025-09-09T15:58:00.035Z" },
+ { url = "https://files.pythonhosted.org/packages/77/cc/70e59dcb84f2b005d4f306310ff0a892518cc0c8000a33d0e6faf7ca8d80/numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421", size = 16638958, upload-time = "2025-09-09T15:58:02.738Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/5a/b2ab6c18b4257e099587d5b7f903317bd7115333ad8d4ec4874278eafa61/numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021", size = 16071920, upload-time = "2025-09-09T15:58:05.029Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/f1/8b3fdc44324a259298520dd82147ff648979bed085feeacc1250ef1656c0/numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf", size = 18577076, upload-time = "2025-09-09T15:58:07.745Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/a1/b87a284fb15a42e9274e7fcea0dad259d12ddbf07c1595b26883151ca3b4/numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0", size = 6366952, upload-time = "2025-09-09T15:58:10.096Z" },
+ { url = "https://files.pythonhosted.org/packages/70/5f/1816f4d08f3b8f66576d8433a66f8fa35a5acfb3bbd0bf6c31183b003f3d/numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8", size = 12919322, upload-time = "2025-09-09T15:58:12.138Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/de/072420342e46a8ea41c324a555fa90fcc11637583fb8df722936aed1736d/numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe", size = 10478630, upload-time = "2025-09-09T15:58:14.64Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/df/ee2f1c0a9de7347f14da5dd3cd3c3b034d1b8607ccb6883d7dd5c035d631/numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00", size = 21047987, upload-time = "2025-09-09T15:58:16.889Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/92/9453bdc5a4e9e69cf4358463f25e8260e2ffc126d52e10038b9077815989/numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a", size = 14301076, upload-time = "2025-09-09T15:58:20.343Z" },
+ { url = "https://files.pythonhosted.org/packages/13/77/1447b9eb500f028bb44253105bd67534af60499588a5149a94f18f2ca917/numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d", size = 5229491, upload-time = "2025-09-09T15:58:22.481Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/f9/d72221b6ca205f9736cb4b2ce3b002f6e45cd67cd6a6d1c8af11a2f0b649/numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a", size = 6737913, upload-time = "2025-09-09T15:58:24.569Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/5f/d12834711962ad9c46af72f79bb31e73e416ee49d17f4c797f72c96b6ca5/numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54", size = 14352811, upload-time = "2025-09-09T15:58:26.416Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/0d/fdbec6629d97fd1bebed56cd742884e4eead593611bbe1abc3eb40d304b2/numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e", size = 16702689, upload-time = "2025-09-09T15:58:28.831Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/09/0a35196dc5575adde1eb97ddfbc3e1687a814f905377621d18ca9bc2b7dd/numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097", size = 16133855, upload-time = "2025-09-09T15:58:31.349Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/ca/c9de3ea397d576f1b6753eaa906d4cdef1bf97589a6d9825a349b4729cc2/numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970", size = 18652520, upload-time = "2025-09-09T15:58:33.762Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/c2/e5ed830e08cd0196351db55db82f65bc0ab05da6ef2b72a836dcf1936d2f/numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5", size = 6515371, upload-time = "2025-09-09T15:58:36.04Z" },
+ { url = "https://files.pythonhosted.org/packages/47/c7/b0f6b5b67f6788a0725f744496badbb604d226bf233ba716683ebb47b570/numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f", size = 13112576, upload-time = "2025-09-09T15:58:37.927Z" },
+ { url = "https://files.pythonhosted.org/packages/06/b9/33bba5ff6fb679aa0b1f8a07e853f002a6b04b9394db3069a1270a7784ca/numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b", size = 10545953, upload-time = "2025-09-09T15:58:40.576Z" },
+]
+
+[[package]]
+name = "nvidia-cublas-cu12"
+version = "12.8.4.1"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" },
+]
+
+[[package]]
+name = "nvidia-cuda-cupti-cu12"
+version = "12.8.90"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" },
+]
+
+[[package]]
+name = "nvidia-cuda-nvrtc-cu12"
+version = "12.8.93"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" },
+]
+
+[[package]]
+name = "nvidia-cuda-runtime-cu12"
+version = "12.8.90"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" },
+]
+
+[[package]]
+name = "nvidia-cudnn-cu12"
+version = "9.10.2.21"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" },
+]
+
+[[package]]
+name = "nvidia-cufft-cu12"
+version = "11.3.3.83"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" },
+]
+
+[[package]]
+name = "nvidia-cufile-cu12"
+version = "1.13.1.3"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" },
+]
+
+[[package]]
+name = "nvidia-curand-cu12"
+version = "10.3.9.90"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" },
+]
+
+[[package]]
+name = "nvidia-cusolver-cu12"
+version = "11.7.3.90"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux'" },
+ { name = "nvidia-cusparse-cu12", marker = "sys_platform == 'linux'" },
+ { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" },
+]
+
+[[package]]
+name = "nvidia-cusparse-cu12"
+version = "12.5.8.93"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" },
+]
+
+[[package]]
+name = "nvidia-cusparselt-cu12"
+version = "0.7.1"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" },
+]
+
+[[package]]
+name = "nvidia-nccl-cu12"
+version = "2.27.3"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5c/5b/4e4fff7bad39adf89f735f2bc87248c81db71205b62bcc0d5ca5b606b3c3/nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adf27ccf4238253e0b826bce3ff5fa532d65fc42322c8bfdfaf28024c0fbe039", size = 322364134, upload-time = "2025-06-03T21:58:04.013Z" },
+]
+
+[[package]]
+name = "nvidia-nvjitlink-cu12"
+version = "12.8.93"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" },
+]
+
+[[package]]
+name = "nvidia-nvtx-cu12"
+version = "12.8.90"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" },
+]
+
+[[package]]
+name = "oauthlib"
+version = "3.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" },
+]
+
+[[package]]
+name = "ollama"
+version = "0.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "httpx" },
+ { name = "pydantic" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d6/47/f9ee32467fe92744474a8c72e138113f3b529fc266eea76abfdec9a33f3b/ollama-0.6.0.tar.gz", hash = "sha256:da2b2d846b5944cfbcee1ca1e6ee0585f6c9d45a2fe9467cbcd096a37383da2f", size = 50811, upload-time = "2025-09-24T22:46:02.417Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b5/c1/edc9f41b425ca40b26b7c104c5f6841a4537bb2552bfa6ca66e81405bb95/ollama-0.6.0-py3-none-any.whl", hash = "sha256:534511b3ccea2dff419ae06c3b58d7f217c55be7897c8ce5868dfb6b219cf7a0", size = 14130, upload-time = "2025-09-24T22:46:01.19Z" },
+]
+
+[[package]]
+name = "onnxruntime"
+version = "1.23.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "coloredlogs" },
+ { name = "flatbuffers" },
+ { name = "numpy" },
+ { name = "packaging" },
+ { name = "protobuf" },
+ { name = "sympy" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/33/ec5395c9539423246e4976d6ec7c4e7a4624ad8bcbe783fea5c629d7980a/onnxruntime-1.23.0-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:5921f2e106f5faf2b32095b2ecdfae047e445c3bce063e439dadc75c212e7be7", size = 17081368, upload-time = "2025-09-25T19:16:46.585Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/3c/d1976a9933e075291a3d67f4e949c667ff36a3e3a4a0cbd883af3c4eae5a/onnxruntime-1.23.0-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:053df2f9c6522b258055bce4b776aa9ea3adb4b28d2530ab07b204a3d4b04bf9", size = 19028636, upload-time = "2025-09-25T18:56:34.457Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/1f/5b76864a970a23dc85f8745d045b81a9151aa101bbb426af6fa489f59364/onnxruntime-1.23.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:974e327ca3b6d43da404b9a45df1f61e2503667fde46843ee7ad1567a98f3f0b", size = 15140544, upload-time = "2025-09-25T18:56:15.9Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/62/84f23952d01e07ce8aa02e657e3a0c8fa40aba0d5e11a0e9904a9063af76/onnxruntime-1.23.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f67edb93678cab5cd77eda89b65bb1b58f3d4c0742058742cfad8b172cfa83", size = 17274126, upload-time = "2025-09-25T19:16:11.21Z" },
+ { url = "https://files.pythonhosted.org/packages/19/90/d5b4ea0bd6805f3f21aac2fe549a5b58ee10d1c99c499d867539620a002b/onnxruntime-1.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:e100f3869da4c12b17a9b942934a96a542406f860eb8beb74a68342ea43aaa55", size = 13392437, upload-time = "2025-09-25T19:16:36.066Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/59/dbd5731f2188c65c22f65e5b9dde45cf68510a14ecb1eb6fabd272da94c3/onnxruntime-1.23.0-cp313-cp313-macosx_13_0_arm64.whl", hash = "sha256:b6659f17326e64f2902cd31aa5efc1af41d0e0e3bd1357a75985e358412c35ca", size = 17081033, upload-time = "2025-09-25T18:56:27.426Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/fd/6a95d7ab505517192966da8df5aec491eff1b32559ce8981299192194ca3/onnxruntime-1.23.0-cp313-cp313-macosx_13_0_x86_64.whl", hash = "sha256:9ef62369a0261aa15b1399addaaf17ed398e4e2128c8548fafcd73aac13820fd", size = 19029223, upload-time = "2025-09-25T18:56:36.85Z" },
+ { url = "https://files.pythonhosted.org/packages/11/51/673cf86f574a87a4fb9d4fb2cd1ccfcf362bc7c3f2ecb1919325e7fd0fd4/onnxruntime-1.23.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edee45d4119f7a6f187dc1b63e177e3e6c76932446006fd4f3e81540f260dfa", size = 15140613, upload-time = "2025-09-25T18:56:22.824Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/ab/898f87a633f3063269fcee2f94b1e8349223f1f14fa730822d2cf6021c76/onnxruntime-1.23.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2dc1993aa91d665faf2b17772e4e29a2999821e110c0e3d17e2b1c00d0e7f48", size = 17274274, upload-time = "2025-09-25T19:16:13.603Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/69/070eae0d0369562d1dec0046ec2e3dd7c523adfae0f30b3887f81ef98c3b/onnxruntime-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:e52c8603c4cc74746ece9966102e4fc6c2b355efc0102a9deb107f3ff86680af", size = 13392787, upload-time = "2025-09-25T19:16:38.871Z" },
+ { url = "https://files.pythonhosted.org/packages/42/8c/6f1d8ec63c887a855f65648b1c743f673191da94703b5fd207d21f17c292/onnxruntime-1.23.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24ac2a8b2c6dd00a152a08a9cf1ba3f06b38915f6cb6cf1adbe714e16e5ff460", size = 15148462, upload-time = "2025-09-25T18:56:25.11Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/59/0db51308fa479f9325ade08c343a5164153ad01dbb83b62ff661e1129d2e/onnxruntime-1.23.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ed85686e08cfb29ee96365b9a49e8a350aff7557c13d63d9f07ca3ad68975074", size = 17281939, upload-time = "2025-09-25T19:16:16.16Z" },
+]
+
+[[package]]
+name = "openai"
+version = "1.109.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "distro" },
+ { name = "httpx" },
+ { name = "jiter" },
+ { name = "pydantic" },
+ { name = "sniffio" },
+ { name = "tqdm" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c6/a1/a303104dc55fc546a3f6914c842d3da471c64eec92043aef8f652eb6c524/openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869", size = 564133, upload-time = "2025-09-24T13:00:53.075Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627, upload-time = "2025-09-24T13:00:50.754Z" },
+]
+
+[[package]]
+name = "opentelemetry-api"
+version = "1.37.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "importlib-metadata" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/63/04/05040d7ce33a907a2a02257e601992f0cdf11c73b33f13c4492bf6c3d6d5/opentelemetry_api-1.37.0.tar.gz", hash = "sha256:540735b120355bd5112738ea53621f8d5edb35ebcd6fe21ada3ab1c61d1cd9a7", size = 64923, upload-time = "2025-09-11T10:29:01.662Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/91/48/28ed9e55dcf2f453128df738210a980e09f4e468a456fa3c763dbc8be70a/opentelemetry_api-1.37.0-py3-none-any.whl", hash = "sha256:accf2024d3e89faec14302213bc39550ec0f4095d1cf5ca688e1bfb1c8612f47", size = 65732, upload-time = "2025-09-11T10:28:41.826Z" },
+]
+
+[[package]]
+name = "opentelemetry-exporter-otlp-proto-grpc"
+version = "1.15.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "backoff" },
+ { name = "googleapis-common-protos" },
+ { name = "grpcio" },
+ { name = "opentelemetry-api" },
+ { name = "opentelemetry-proto" },
+ { name = "opentelemetry-sdk" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e4/ab/1be294b194af410f350f867a54621b4f33b7551adce2ae795e907148fc1e/opentelemetry_exporter_otlp_proto_grpc-1.15.0.tar.gz", hash = "sha256:844f2a4bb9bcda34e4eb6fe36765e5031aacb36dc60ed88c90fc246942ea26e7", size = 27262, upload-time = "2022-12-09T22:28:44.359Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dd/8f/73ad108bcfd61b4169be5ad8b76acaf9158f224740da10ab9ea3469d551a/opentelemetry_exporter_otlp_proto_grpc-1.15.0-py3-none-any.whl", hash = "sha256:c2a5492ba7d140109968135d641d06ce3c5bd73c50665f787526065d57d7fd1d", size = 20378, upload-time = "2022-12-09T22:28:14.623Z" },
+]
+
+[[package]]
+name = "opentelemetry-proto"
+version = "1.15.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "protobuf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1e/80/b3b2a98039574e57b6b15982219ae025d55f8c46d50dde258865ce5601b4/opentelemetry_proto-1.15.0.tar.gz", hash = "sha256:9c4008e40ac8cab359daac283fbe7002c5c29c77ea2674ad5626a249e64e0101", size = 35713, upload-time = "2022-12-09T22:28:55.409Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3a/56/8343d94af8f32594f6b0bd273f72a40e430fb5970a353237af53af5d3031/opentelemetry_proto-1.15.0-py3-none-any.whl", hash = "sha256:044b6d044b4d10530f250856f933442b8753a17f94ae37c207607f733fb9a844", size = 52616, upload-time = "2022-12-09T22:28:30.03Z" },
+]
+
+[[package]]
+name = "opentelemetry-sdk"
+version = "1.37.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "opentelemetry-api" },
+ { name = "opentelemetry-semantic-conventions" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f4/62/2e0ca80d7fe94f0b193135375da92c640d15fe81f636658d2acf373086bc/opentelemetry_sdk-1.37.0.tar.gz", hash = "sha256:cc8e089c10953ded765b5ab5669b198bbe0af1b3f89f1007d19acd32dc46dda5", size = 170404, upload-time = "2025-09-11T10:29:11.779Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9f/62/9f4ad6a54126fb00f7ed4bb5034964c6e4f00fcd5a905e115bd22707e20d/opentelemetry_sdk-1.37.0-py3-none-any.whl", hash = "sha256:8f3c3c22063e52475c5dbced7209495c2c16723d016d39287dfc215d1771257c", size = 131941, upload-time = "2025-09-11T10:28:57.83Z" },
+]
+
+[[package]]
+name = "opentelemetry-semantic-conventions"
+version = "0.58b0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "opentelemetry-api" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/aa/1b/90701d91e6300d9f2fb352153fb1721ed99ed1f6ea14fa992c756016e63a/opentelemetry_semantic_conventions-0.58b0.tar.gz", hash = "sha256:6bd46f51264279c433755767bb44ad00f1c9e2367e1b42af563372c5a6fa0c25", size = 129867, upload-time = "2025-09-11T10:29:12.597Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/07/90/68152b7465f50285d3ce2481b3aec2f82822e3f52e5152eeeaf516bab841/opentelemetry_semantic_conventions-0.58b0-py3-none-any.whl", hash = "sha256:5564905ab1458b96684db1340232729fce3b5375a06e140e8904c78e4f815b28", size = 207954, upload-time = "2025-09-11T10:28:59.218Z" },
+]
+
+[[package]]
+name = "orjson"
+version = "3.11.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/be/4d/8df5f83256a809c22c4d6792ce8d43bb503be0fb7a8e4da9025754b09658/orjson-3.11.3.tar.gz", hash = "sha256:1c0603b1d2ffcd43a411d64797a19556ef76958aef1c182f22dc30860152a98a", size = 5482394, upload-time = "2025-08-26T17:46:43.171Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3d/b0/a7edab2a00cdcb2688e1c943401cb3236323e7bfd2839815c6131a3742f4/orjson-3.11.3-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8c752089db84333e36d754c4baf19c0e1437012242048439c7e80eb0e6426e3b", size = 238259, upload-time = "2025-08-26T17:45:15.093Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/c6/ff4865a9cc398a07a83342713b5932e4dc3cb4bf4bc04e8f83dedfc0d736/orjson-3.11.3-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:9b8761b6cf04a856eb544acdd82fc594b978f12ac3602d6374a7edb9d86fd2c2", size = 127633, upload-time = "2025-08-26T17:45:16.417Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/e6/e00bea2d9472f44fe8794f523e548ce0ad51eb9693cf538a753a27b8bda4/orjson-3.11.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b13974dc8ac6ba22feaa867fc19135a3e01a134b4f7c9c28162fed4d615008a", size = 123061, upload-time = "2025-08-26T17:45:17.673Z" },
+ { url = "https://files.pythonhosted.org/packages/54/31/9fbb78b8e1eb3ac605467cb846e1c08d0588506028b37f4ee21f978a51d4/orjson-3.11.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f83abab5bacb76d9c821fd5c07728ff224ed0e52d7a71b7b3de822f3df04e15c", size = 127956, upload-time = "2025-08-26T17:45:19.172Z" },
+ { url = "https://files.pythonhosted.org/packages/36/88/b0604c22af1eed9f98d709a96302006915cfd724a7ebd27d6dd11c22d80b/orjson-3.11.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6fbaf48a744b94091a56c62897b27c31ee2da93d826aa5b207131a1e13d4064", size = 130790, upload-time = "2025-08-26T17:45:20.586Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/9d/1c1238ae9fffbfed51ba1e507731b3faaf6b846126a47e9649222b0fd06f/orjson-3.11.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc779b4f4bba2847d0d2940081a7b6f7b5877e05408ffbb74fa1faf4a136c424", size = 132385, upload-time = "2025-08-26T17:45:22.036Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/b5/c06f1b090a1c875f337e21dd71943bc9d84087f7cdf8c6e9086902c34e42/orjson-3.11.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd4b909ce4c50faa2192da6bb684d9848d4510b736b0611b6ab4020ea6fd2d23", size = 135305, upload-time = "2025-08-26T17:45:23.4Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/26/5f028c7d81ad2ebbf84414ba6d6c9cac03f22f5cd0d01eb40fb2d6a06b07/orjson-3.11.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:524b765ad888dc5518bbce12c77c2e83dee1ed6b0992c1790cc5fb49bb4b6667", size = 132875, upload-time = "2025-08-26T17:45:25.182Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/d4/b8df70d9cfb56e385bf39b4e915298f9ae6c61454c8154a0f5fd7efcd42e/orjson-3.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:84fd82870b97ae3cdcea9d8746e592b6d40e1e4d4527835fc520c588d2ded04f", size = 130940, upload-time = "2025-08-26T17:45:27.209Z" },
+ { url = "https://files.pythonhosted.org/packages/da/5e/afe6a052ebc1a4741c792dd96e9f65bf3939d2094e8b356503b68d48f9f5/orjson-3.11.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fbecb9709111be913ae6879b07bafd4b0785b44c1eb5cac8ac76da048b3885a1", size = 403852, upload-time = "2025-08-26T17:45:28.478Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/90/7bbabafeb2ce65915e9247f14a56b29c9334003536009ef5b122783fe67e/orjson-3.11.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9dba358d55aee552bd868de348f4736ca5a4086d9a62e2bfbbeeb5629fe8b0cc", size = 146293, upload-time = "2025-08-26T17:45:29.86Z" },
+ { url = "https://files.pythonhosted.org/packages/27/b3/2d703946447da8b093350570644a663df69448c9d9330e5f1d9cce997f20/orjson-3.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eabcf2e84f1d7105f84580e03012270c7e97ecb1fb1618bda395061b2a84a049", size = 135470, upload-time = "2025-08-26T17:45:31.243Z" },
+ { url = "https://files.pythonhosted.org/packages/38/70/b14dcfae7aff0e379b0119c8a812f8396678919c431efccc8e8a0263e4d9/orjson-3.11.3-cp312-cp312-win32.whl", hash = "sha256:3782d2c60b8116772aea8d9b7905221437fdf53e7277282e8d8b07c220f96cca", size = 136248, upload-time = "2025-08-26T17:45:32.567Z" },
+ { url = "https://files.pythonhosted.org/packages/35/b8/9e3127d65de7fff243f7f3e53f59a531bf6bb295ebe5db024c2503cc0726/orjson-3.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:79b44319268af2eaa3e315b92298de9a0067ade6e6003ddaef72f8e0bedb94f1", size = 131437, upload-time = "2025-08-26T17:45:34.949Z" },
+ { url = "https://files.pythonhosted.org/packages/51/92/a946e737d4d8a7fd84a606aba96220043dcc7d6988b9e7551f7f6d5ba5ad/orjson-3.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:0e92a4e83341ef79d835ca21b8bd13e27c859e4e9e4d7b63defc6e58462a3710", size = 125978, upload-time = "2025-08-26T17:45:36.422Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/79/8932b27293ad35919571f77cb3693b5906cf14f206ef17546052a241fdf6/orjson-3.11.3-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:af40c6612fd2a4b00de648aa26d18186cd1322330bd3a3cc52f87c699e995810", size = 238127, upload-time = "2025-08-26T17:45:38.146Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/82/cb93cd8cf132cd7643b30b6c5a56a26c4e780c7a145db6f83de977b540ce/orjson-3.11.3-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:9f1587f26c235894c09e8b5b7636a38091a9e6e7fe4531937534749c04face43", size = 127494, upload-time = "2025-08-26T17:45:39.57Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/b8/2d9eb181a9b6bb71463a78882bcac1027fd29cf62c38a40cc02fc11d3495/orjson-3.11.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61dcdad16da5bb486d7227a37a2e789c429397793a6955227cedbd7252eb5a27", size = 123017, upload-time = "2025-08-26T17:45:40.876Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/14/a0e971e72d03b509190232356d54c0f34507a05050bd026b8db2bf2c192c/orjson-3.11.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11c6d71478e2cbea0a709e8a06365fa63da81da6498a53e4c4f065881d21ae8f", size = 127898, upload-time = "2025-08-26T17:45:42.188Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/af/dc74536722b03d65e17042cc30ae586161093e5b1f29bccda24765a6ae47/orjson-3.11.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff94112e0098470b665cb0ed06efb187154b63649403b8d5e9aedeb482b4548c", size = 130742, upload-time = "2025-08-26T17:45:43.511Z" },
+ { url = "https://files.pythonhosted.org/packages/62/e6/7a3b63b6677bce089fe939353cda24a7679825c43a24e49f757805fc0d8a/orjson-3.11.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b756575aaa2a855a75192f356bbda11a89169830e1439cfb1a3e1a6dde7be", size = 132377, upload-time = "2025-08-26T17:45:45.525Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/cd/ce2ab93e2e7eaf518f0fd15e3068b8c43216c8a44ed82ac2b79ce5cef72d/orjson-3.11.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9416cc19a349c167ef76135b2fe40d03cea93680428efee8771f3e9fb66079d", size = 135313, upload-time = "2025-08-26T17:45:46.821Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/b4/f98355eff0bd1a38454209bbc73372ce351ba29933cb3e2eba16c04b9448/orjson-3.11.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b822caf5b9752bc6f246eb08124c3d12bf2175b66ab74bac2ef3bbf9221ce1b2", size = 132908, upload-time = "2025-08-26T17:45:48.126Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/92/8f5182d7bc2a1bed46ed960b61a39af8389f0ad476120cd99e67182bfb6d/orjson-3.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:414f71e3bdd5573893bf5ecdf35c32b213ed20aa15536fe2f588f946c318824f", size = 130905, upload-time = "2025-08-26T17:45:49.414Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/60/c41ca753ce9ffe3d0f67b9b4c093bdd6e5fdb1bc53064f992f66bb99954d/orjson-3.11.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:828e3149ad8815dc14468f36ab2a4b819237c155ee1370341b91ea4c8672d2ee", size = 403812, upload-time = "2025-08-26T17:45:51.085Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/13/e4a4f16d71ce1868860db59092e78782c67082a8f1dc06a3788aef2b41bc/orjson-3.11.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac9e05f25627ffc714c21f8dfe3a579445a5c392a9c8ae7ba1d0e9fb5333f56e", size = 146277, upload-time = "2025-08-26T17:45:52.851Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/8b/bafb7f0afef9344754a3a0597a12442f1b85a048b82108ef2c956f53babd/orjson-3.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e44fbe4000bd321d9f3b648ae46e0196d21577cf66ae684a96ff90b1f7c93633", size = 135418, upload-time = "2025-08-26T17:45:54.806Z" },
+ { url = "https://files.pythonhosted.org/packages/60/d4/bae8e4f26afb2c23bea69d2f6d566132584d1c3a5fe89ee8c17b718cab67/orjson-3.11.3-cp313-cp313-win32.whl", hash = "sha256:2039b7847ba3eec1f5886e75e6763a16e18c68a63efc4b029ddf994821e2e66b", size = 136216, upload-time = "2025-08-26T17:45:57.182Z" },
+ { url = "https://files.pythonhosted.org/packages/88/76/224985d9f127e121c8cad882cea55f0ebe39f97925de040b75ccd4b33999/orjson-3.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:29be5ac4164aa8bdcba5fa0700a3c9c316b411d8ed9d39ef8a882541bd452fae", size = 131362, upload-time = "2025-08-26T17:45:58.56Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/cf/0dce7a0be94bd36d1346be5067ed65ded6adb795fdbe3abd234c8d576d01/orjson-3.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:18bd1435cb1f2857ceb59cfb7de6f92593ef7b831ccd1b9bfb28ca530e539dce", size = 125989, upload-time = "2025-08-26T17:45:59.95Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/77/d3b1fef1fc6aaeed4cbf3be2b480114035f4df8fa1a99d2dac1d40d6e924/orjson-3.11.3-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cf4b81227ec86935568c7edd78352a92e97af8da7bd70bdfdaa0d2e0011a1ab4", size = 238115, upload-time = "2025-08-26T17:46:01.669Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/6d/468d21d49bb12f900052edcfbf52c292022d0a323d7828dc6376e6319703/orjson-3.11.3-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:bc8bc85b81b6ac9fc4dae393a8c159b817f4c2c9dee5d12b773bddb3b95fc07e", size = 127493, upload-time = "2025-08-26T17:46:03.466Z" },
+ { url = "https://files.pythonhosted.org/packages/67/46/1e2588700d354aacdf9e12cc2d98131fb8ac6f31ca65997bef3863edb8ff/orjson-3.11.3-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:88dcfc514cfd1b0de038443c7b3e6a9797ffb1b3674ef1fd14f701a13397f82d", size = 122998, upload-time = "2025-08-26T17:46:04.803Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/94/11137c9b6adb3779f1b34fd98be51608a14b430dbc02c6d41134fbba484c/orjson-3.11.3-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d61cd543d69715d5fc0a690c7c6f8dcc307bc23abef9738957981885f5f38229", size = 132915, upload-time = "2025-08-26T17:46:06.237Z" },
+ { url = "https://files.pythonhosted.org/packages/10/61/dccedcf9e9bcaac09fdabe9eaee0311ca92115699500efbd31950d878833/orjson-3.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2b7b153ed90ababadbef5c3eb39549f9476890d339cf47af563aea7e07db2451", size = 130907, upload-time = "2025-08-26T17:46:07.581Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/fd/0e935539aa7b08b3ca0f817d73034f7eb506792aae5ecc3b7c6e679cdf5f/orjson-3.11.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:7909ae2460f5f494fecbcd10613beafe40381fd0316e35d6acb5f3a05bfda167", size = 403852, upload-time = "2025-08-26T17:46:08.982Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/2b/50ae1a5505cd1043379132fdb2adb8a05f37b3e1ebffe94a5073321966fd/orjson-3.11.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2030c01cbf77bc67bee7eef1e7e31ecf28649353987775e3583062c752da0077", size = 146309, upload-time = "2025-08-26T17:46:10.576Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/1d/a473c158e380ef6f32753b5f39a69028b25ec5be331c2049a2201bde2e19/orjson-3.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a0169ebd1cbd94b26c7a7ad282cf5c2744fce054133f959e02eb5265deae1872", size = 135424, upload-time = "2025-08-26T17:46:12.386Z" },
+ { url = "https://files.pythonhosted.org/packages/da/09/17d9d2b60592890ff7382e591aa1d9afb202a266b180c3d4049b1ec70e4a/orjson-3.11.3-cp314-cp314-win32.whl", hash = "sha256:0c6d7328c200c349e3a4c6d8c83e0a5ad029bdc2d417f234152bf34842d0fc8d", size = 136266, upload-time = "2025-08-26T17:46:13.853Z" },
+ { url = "https://files.pythonhosted.org/packages/15/58/358f6846410a6b4958b74734727e582ed971e13d335d6c7ce3e47730493e/orjson-3.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:317bbe2c069bbc757b1a2e4105b64aacd3bc78279b66a6b9e51e846e4809f804", size = 131351, upload-time = "2025-08-26T17:46:15.27Z" },
+ { url = "https://files.pythonhosted.org/packages/28/01/d6b274a0635be0468d4dbd9cafe80c47105937a0d42434e805e67cd2ed8b/orjson-3.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:e8f6a7a27d7b7bec81bd5924163e9af03d49bbb63013f107b48eb5d16db711bc", size = 125985, upload-time = "2025-08-26T17:46:16.67Z" },
+]
+
+[[package]]
+name = "overrides"
+version = "7.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" },
+]
+
+[[package]]
+name = "packaging"
+version = "25.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
+]
+
+[[package]]
+name = "pandas"
+version = "2.3.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+ { name = "python-dateutil" },
+ { name = "pytz" },
+ { name = "tzdata" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" },
+ { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" },
+ { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" },
+ { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" },
+ { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" },
+ { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" },
+ { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" },
+ { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" },
+ { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" },
+ { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" },
+ { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" },
+ { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" },
+ { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" },
+ { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" },
+ { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" },
+ { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" },
+ { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" },
+]
+
+[[package]]
+name = "parso"
+version = "0.8.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" },
+]
+
+[[package]]
+name = "pexpect"
+version = "4.9.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "ptyprocess" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" },
+]
+
+[[package]]
+name = "pillow"
+version = "11.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" },
+ { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" },
+ { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" },
+ { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" },
+ { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" },
+ { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" },
+ { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" },
+ { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" },
+ { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" },
+ { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" },
+ { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" },
+ { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" },
+ { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" },
+ { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" },
+ { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" },
+ { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" },
+ { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" },
+ { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" },
+ { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" },
+ { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" },
+ { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" },
+ { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" },
+]
+
+[[package]]
+name = "platformdirs"
+version = "4.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" },
+]
+
+[[package]]
+name = "plotly"
+version = "6.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "narwhals" },
+ { name = "packaging" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a0/64/850de5076f4436410e1ce4f6a69f4313ef6215dfea155f3f6559335cad29/plotly-6.3.0.tar.gz", hash = "sha256:8840a184d18ccae0f9189c2b9a2943923fd5cae7717b723f36eef78f444e5a73", size = 6923926, upload-time = "2025-08-12T20:22:14.127Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/95/a9/12e2dc726ba1ba775a2c6922d5d5b4488ad60bdab0888c337c194c8e6de8/plotly-6.3.0-py3-none-any.whl", hash = "sha256:7ad806edce9d3cdd882eaebaf97c0c9e252043ed1ed3d382c3e3520ec07806d4", size = 9791257, upload-time = "2025-08-12T20:22:09.205Z" },
+]
+
+[[package]]
+name = "posthog"
+version = "5.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "backoff" },
+ { name = "distro" },
+ { name = "python-dateutil" },
+ { name = "requests" },
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/48/20/60ae67bb9d82f00427946218d49e2e7e80fb41c15dc5019482289ec9ce8d/posthog-5.4.0.tar.gz", hash = "sha256:701669261b8d07cdde0276e5bc096b87f9e200e3b9589c5ebff14df658c5893c", size = 88076, upload-time = "2025-06-20T23:19:23.485Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4f/98/e480cab9a08d1c09b1c59a93dade92c1bb7544826684ff2acbfd10fcfbd4/posthog-5.4.0-py3-none-any.whl", hash = "sha256:284dfa302f64353484420b52d4ad81ff5c2c2d1d607c4e2db602ac72761831bd", size = 105364, upload-time = "2025-06-20T23:19:22.001Z" },
+]
+
+[[package]]
+name = "prompt-toolkit"
+version = "3.0.52"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "wcwidth" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" },
+]
+
+[[package]]
+name = "propcache"
+version = "0.3.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" },
+ { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" },
+ { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" },
+ { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" },
+ { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" },
+ { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" },
+ { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" },
+ { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" },
+ { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" },
+ { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" },
+ { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" },
+ { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" },
+ { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" },
+ { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" },
+ { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" },
+]
+
+[[package]]
+name = "proto-plus"
+version = "1.26.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "protobuf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f4/ac/87285f15f7cce6d4a008f33f1757fb5a13611ea8914eb58c3d0d26243468/proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012", size = 56142, upload-time = "2025-03-10T15:54:38.843Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163, upload-time = "2025-03-10T15:54:37.335Z" },
+]
+
+[[package]]
+name = "protobuf"
+version = "3.20.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/3d/79/34fbcce8666c74ec6729e2844143fd066d9708eecb89ecd2037fc6cfe9a9/protobuf-3.20.2.tar.gz", hash = "sha256:712dca319eee507a1e7df3591e639a2b112a2f4a62d40fe7832a16fd19151750", size = 216716, upload-time = "2022-09-13T21:56:49.375Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8b/e6/2a47ce2eba1aaf287380a44270da897ada03d118a55c19595ec7b4f0831f/protobuf-3.20.2-py2.py3-none-any.whl", hash = "sha256:c9cdf251c582c16fd6a9f5e95836c90828d51b0069ad22f463761d27c6c19019", size = 162128, upload-time = "2022-09-13T21:56:47.5Z" },
+]
+
+[[package]]
+name = "psutil"
+version = "7.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b3/31/4723d756b59344b643542936e37a31d1d3204bcdc42a7daa8ee9eb06fb50/psutil-7.1.0.tar.gz", hash = "sha256:655708b3c069387c8b77b072fc429a57d0e214221d01c0a772df7dfedcb3bcd2", size = 497660, upload-time = "2025-09-17T20:14:52.902Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/46/62/ce4051019ee20ce0ed74432dd73a5bb087a6704284a470bb8adff69a0932/psutil-7.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76168cef4397494250e9f4e73eb3752b146de1dd950040b29186d0cce1d5ca13", size = 245242, upload-time = "2025-09-17T20:14:56.126Z" },
+ { url = "https://files.pythonhosted.org/packages/38/61/f76959fba841bf5b61123fbf4b650886dc4094c6858008b5bf73d9057216/psutil-7.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:5d007560c8c372efdff9e4579c2846d71de737e4605f611437255e81efcca2c5", size = 246682, upload-time = "2025-09-17T20:14:58.25Z" },
+ { url = "https://files.pythonhosted.org/packages/88/7a/37c99d2e77ec30d63398ffa6a660450b8a62517cabe44b3e9bae97696e8d/psutil-7.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22e4454970b32472ce7deaa45d045b34d3648ce478e26a04c7e858a0a6e75ff3", size = 287994, upload-time = "2025-09-17T20:14:59.901Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/de/04c8c61232f7244aa0a4b9a9fbd63a89d5aeaf94b2fc9d1d16e2faa5cbb0/psutil-7.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c70e113920d51e89f212dd7be06219a9b88014e63a4cec69b684c327bc474e3", size = 291163, upload-time = "2025-09-17T20:15:01.481Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/58/c4f976234bf6d4737bc8c02a81192f045c307b72cf39c9e5c5a2d78927f6/psutil-7.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d4a113425c037300de3ac8b331637293da9be9713855c4fc9d2d97436d7259d", size = 293625, upload-time = "2025-09-17T20:15:04.492Z" },
+ { url = "https://files.pythonhosted.org/packages/79/87/157c8e7959ec39ced1b11cc93c730c4fb7f9d408569a6c59dbd92ceb35db/psutil-7.1.0-cp37-abi3-win32.whl", hash = "sha256:09ad740870c8d219ed8daae0ad3b726d3bf9a028a198e7f3080f6a1888b99bca", size = 244812, upload-time = "2025-09-17T20:15:07.462Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/e9/b44c4f697276a7a95b8e94d0e320a7bf7f3318521b23de69035540b39838/psutil-7.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:57f5e987c36d3146c0dd2528cd42151cf96cd359b9d67cfff836995cc5df9a3d", size = 247965, upload-time = "2025-09-17T20:15:09.673Z" },
+ { url = "https://files.pythonhosted.org/packages/26/65/1070a6e3c036f39142c2820c4b52e9243246fcfc3f96239ac84472ba361e/psutil-7.1.0-cp37-abi3-win_arm64.whl", hash = "sha256:6937cb68133e7c97b6cc9649a570c9a18ba0efebed46d8c5dae4c07fa1b67a07", size = 244971, upload-time = "2025-09-17T20:15:12.262Z" },
+]
+
+[[package]]
+name = "ptyprocess"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" },
+]
+
+[[package]]
+name = "pure-eval"
+version = "0.2.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" },
+]
+
+[[package]]
+name = "pyarrow"
+version = "21.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ef/c2/ea068b8f00905c06329a3dfcd40d0fcc2b7d0f2e355bdb25b65e0a0e4cd4/pyarrow-21.0.0.tar.gz", hash = "sha256:5051f2dccf0e283ff56335760cbc8622cf52264d67e359d5569541ac11b6d5bc", size = 1133487, upload-time = "2025-07-18T00:57:31.761Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ca/d4/d4f817b21aacc30195cf6a46ba041dd1be827efa4a623cc8bf39a1c2a0c0/pyarrow-21.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:3a302f0e0963db37e0a24a70c56cf91a4faa0bca51c23812279ca2e23481fccd", size = 31160305, upload-time = "2025-07-18T00:55:35.373Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/9c/dcd38ce6e4b4d9a19e1d36914cb8e2b1da4e6003dd075474c4cfcdfe0601/pyarrow-21.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:b6b27cf01e243871390474a211a7922bfbe3bda21e39bc9160daf0da3fe48876", size = 32684264, upload-time = "2025-07-18T00:55:39.303Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/74/2a2d9f8d7a59b639523454bec12dba35ae3d0a07d8ab529dc0809f74b23c/pyarrow-21.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e72a8ec6b868e258a2cd2672d91f2860ad532d590ce94cdf7d5e7ec674ccf03d", size = 41108099, upload-time = "2025-07-18T00:55:42.889Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/90/2660332eeb31303c13b653ea566a9918484b6e4d6b9d2d46879a33ab0622/pyarrow-21.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b7ae0bbdc8c6674259b25bef5d2a1d6af5d39d7200c819cf99e07f7dfef1c51e", size = 42829529, upload-time = "2025-07-18T00:55:47.069Z" },
+ { url = "https://files.pythonhosted.org/packages/33/27/1a93a25c92717f6aa0fca06eb4700860577d016cd3ae51aad0e0488ac899/pyarrow-21.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:58c30a1729f82d201627c173d91bd431db88ea74dcaa3885855bc6203e433b82", size = 43367883, upload-time = "2025-07-18T00:55:53.069Z" },
+ { url = "https://files.pythonhosted.org/packages/05/d9/4d09d919f35d599bc05c6950095e358c3e15148ead26292dfca1fb659b0c/pyarrow-21.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:072116f65604b822a7f22945a7a6e581cfa28e3454fdcc6939d4ff6090126623", size = 45133802, upload-time = "2025-07-18T00:55:57.714Z" },
+ { url = "https://files.pythonhosted.org/packages/71/30/f3795b6e192c3ab881325ffe172e526499eb3780e306a15103a2764916a2/pyarrow-21.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf56ec8b0a5c8c9d7021d6fd754e688104f9ebebf1bf4449613c9531f5346a18", size = 26203175, upload-time = "2025-07-18T00:56:01.364Z" },
+ { url = "https://files.pythonhosted.org/packages/16/ca/c7eaa8e62db8fb37ce942b1ea0c6d7abfe3786ca193957afa25e71b81b66/pyarrow-21.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:e99310a4ebd4479bcd1964dff9e14af33746300cb014aa4a3781738ac63baf4a", size = 31154306, upload-time = "2025-07-18T00:56:04.42Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/e8/e87d9e3b2489302b3a1aea709aaca4b781c5252fcb812a17ab6275a9a484/pyarrow-21.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:d2fe8e7f3ce329a71b7ddd7498b3cfac0eeb200c2789bd840234f0dc271a8efe", size = 32680622, upload-time = "2025-07-18T00:56:07.505Z" },
+ { url = "https://files.pythonhosted.org/packages/84/52/79095d73a742aa0aba370c7942b1b655f598069489ab387fe47261a849e1/pyarrow-21.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:f522e5709379d72fb3da7785aa489ff0bb87448a9dc5a75f45763a795a089ebd", size = 41104094, upload-time = "2025-07-18T00:56:10.994Z" },
+ { url = "https://files.pythonhosted.org/packages/89/4b/7782438b551dbb0468892a276b8c789b8bbdb25ea5c5eb27faadd753e037/pyarrow-21.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:69cbbdf0631396e9925e048cfa5bce4e8c3d3b41562bbd70c685a8eb53a91e61", size = 42825576, upload-time = "2025-07-18T00:56:15.569Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/62/0f29de6e0a1e33518dec92c65be0351d32d7ca351e51ec5f4f837a9aab91/pyarrow-21.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:731c7022587006b755d0bdb27626a1a3bb004bb56b11fb30d98b6c1b4718579d", size = 43368342, upload-time = "2025-07-18T00:56:19.531Z" },
+ { url = "https://files.pythonhosted.org/packages/90/c7/0fa1f3f29cf75f339768cc698c8ad4ddd2481c1742e9741459911c9ac477/pyarrow-21.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc56bc708f2d8ac71bd1dcb927e458c93cec10b98eb4120206a4091db7b67b99", size = 45131218, upload-time = "2025-07-18T00:56:23.347Z" },
+ { url = "https://files.pythonhosted.org/packages/01/63/581f2076465e67b23bc5a37d4a2abff8362d389d29d8105832e82c9c811c/pyarrow-21.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:186aa00bca62139f75b7de8420f745f2af12941595bbbfa7ed3870ff63e25636", size = 26087551, upload-time = "2025-07-18T00:56:26.758Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/ab/357d0d9648bb8241ee7348e564f2479d206ebe6e1c47ac5027c2e31ecd39/pyarrow-21.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:a7a102574faa3f421141a64c10216e078df467ab9576684d5cd696952546e2da", size = 31290064, upload-time = "2025-07-18T00:56:30.214Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/8a/5685d62a990e4cac2043fc76b4661bf38d06efed55cf45a334b455bd2759/pyarrow-21.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:1e005378c4a2c6db3ada3ad4c217b381f6c886f0a80d6a316fe586b90f77efd7", size = 32727837, upload-time = "2025-07-18T00:56:33.935Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/de/c0828ee09525c2bafefd3e736a248ebe764d07d0fd762d4f0929dbc516c9/pyarrow-21.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:65f8e85f79031449ec8706b74504a316805217b35b6099155dd7e227eef0d4b6", size = 41014158, upload-time = "2025-07-18T00:56:37.528Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/26/a2865c420c50b7a3748320b614f3484bfcde8347b2639b2b903b21ce6a72/pyarrow-21.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:3a81486adc665c7eb1a2bde0224cfca6ceaba344a82a971ef059678417880eb8", size = 42667885, upload-time = "2025-07-18T00:56:41.483Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/f9/4ee798dc902533159250fb4321267730bc0a107d8c6889e07c3add4fe3a5/pyarrow-21.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fc0d2f88b81dcf3ccf9a6ae17f89183762c8a94a5bdcfa09e05cfe413acf0503", size = 43276625, upload-time = "2025-07-18T00:56:48.002Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/da/e02544d6997037a4b0d22d8e5f66bc9315c3671371a8b18c79ade1cefe14/pyarrow-21.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6299449adf89df38537837487a4f8d3bd91ec94354fdd2a7d30bc11c48ef6e79", size = 44951890, upload-time = "2025-07-18T00:56:52.568Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/4e/519c1bc1876625fe6b71e9a28287c43ec2f20f73c658b9ae1d485c0c206e/pyarrow-21.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:222c39e2c70113543982c6b34f3077962b44fca38c0bd9e68bb6781534425c10", size = 26371006, upload-time = "2025-07-18T00:56:56.379Z" },
+]
+
+[[package]]
+name = "pyasn1"
+version = "0.6.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" },
+]
+
+[[package]]
+name = "pyasn1-modules"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyasn1" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" },
+]
+
+[[package]]
+name = "pybase64"
+version = "1.4.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/04/14/43297a7b7f0c1bf0c00b596f754ee3ac946128c64d21047ccf9c9bbc5165/pybase64-1.4.2.tar.gz", hash = "sha256:46cdefd283ed9643315d952fe44de80dc9b9a811ce6e3ec97fd1827af97692d0", size = 137246, upload-time = "2025-07-27T13:08:57.808Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/28/6d/11ede991e800797b9f5ebd528013b34eee5652df93de61ffb24503393fa5/pybase64-1.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2c75d1388855b5a1015b65096d7dbcc708e7de3245dcbedeb872ec05a09326", size = 38326, upload-time = "2025-07-27T13:03:09.065Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/84/87f1f565f42e2397e2aaa2477c86419f5173c3699881c42325c090982f0a/pybase64-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b621a972a01841368fdb9dedc55fd3c6e0c7217d0505ba3b1ebe95e7ef1b493", size = 31661, upload-time = "2025-07-27T13:03:10.295Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/2a/a24c810e7a61d2cc6f73fe9ee4872a03030887fa8654150901b15f376f65/pybase64-1.4.2-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f48c32ac6a16cbf57a5a96a073fef6ff7e3526f623cd49faa112b7f9980bafba", size = 68192, upload-time = "2025-07-27T13:03:11.467Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/87/d9baf98cbfc37b8657290ad4421f3a3c36aa0eafe4872c5859cfb52f3448/pybase64-1.4.2-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ace8b23093a6bb862477080d9059b784096ab2f97541e8bfc40d42f062875149", size = 71587, upload-time = "2025-07-27T13:03:12.719Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/89/3df043cc56ef3b91b7aa0c26ae822a2d7ec8da0b0fd7c309c879b0eb5988/pybase64-1.4.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1772c7532a7fb6301baea3dd3e010148dbf70cd1136a83c2f5f91bdc94822145", size = 59910, upload-time = "2025-07-27T13:03:14.266Z" },
+ { url = "https://files.pythonhosted.org/packages/75/4f/6641e9edf37aeb4d4524dc7ba2168eff8d96c90e77f6283c2be3400ab380/pybase64-1.4.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:f86f7faddcba5cbfea475f8ab96567834c28bf09ca6c7c3d66ee445adac80d8f", size = 56701, upload-time = "2025-07-27T13:03:15.6Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/7f/20d8ac1046f12420a0954a45a13033e75f98aade36eecd00c64e3549b071/pybase64-1.4.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:0b8c8e275b5294089f314814b4a50174ab90af79d6a4850f6ae11261ff6a7372", size = 59288, upload-time = "2025-07-27T13:03:16.823Z" },
+ { url = "https://files.pythonhosted.org/packages/17/ea/9c0ca570e3e50b3c6c3442e280c83b321a0464c86a9db1f982a4ff531550/pybase64-1.4.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:864d85a0470c615807ae8b97d724d068b940a2d10ac13a5f1b9e75a3ce441758", size = 60267, upload-time = "2025-07-27T13:03:18.132Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/ac/46894929d71ccedebbfb0284173b0fea96bc029cd262654ba8451a7035d6/pybase64-1.4.2-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:47254d97ed2d8351e30ecfdb9e2414547f66ba73f8a09f932c9378ff75cd10c5", size = 54801, upload-time = "2025-07-27T13:03:19.669Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/1e/02c95218ea964f0b2469717c2c69b48e63f4ca9f18af01a5b2a29e4c1216/pybase64-1.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:264b65ecc4f0ee73f3298ab83bbd8008f7f9578361b8df5b448f985d8c63e02a", size = 58599, upload-time = "2025-07-27T13:03:20.951Z" },
+ { url = "https://files.pythonhosted.org/packages/15/45/ccc21004930789b8fb439d43e3212a6c260ccddb2bf450c39a20db093f33/pybase64-1.4.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fbcc2b30cd740c16c9699f596f22c7a9e643591311ae72b1e776f2d539e9dd9d", size = 52388, upload-time = "2025-07-27T13:03:23.064Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/45/22e46e549710c4c237d77785b6fb1bc4c44c288a5c44237ba9daf5c34b82/pybase64-1.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cda9f79c22d51ee4508f5a43b673565f1d26af4330c99f114e37e3186fdd3607", size = 68802, upload-time = "2025-07-27T13:03:24.673Z" },
+ { url = "https://files.pythonhosted.org/packages/55/0c/232c6261b81296e5593549b36e6e7884a5da008776d12665923446322c36/pybase64-1.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0c91c6d2a7232e2a1cd10b3b75a8bb657defacd4295a1e5e80455df2dfc84d4f", size = 57841, upload-time = "2025-07-27T13:03:25.948Z" },
+ { url = "https://files.pythonhosted.org/packages/20/8a/b35a615ae6f04550d696bb179c414538b3b477999435fdd4ad75b76139e4/pybase64-1.4.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:a370dea7b1cee2a36a4d5445d4e09cc243816c5bc8def61f602db5a6f5438e52", size = 54320, upload-time = "2025-07-27T13:03:27.495Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/a9/8bd4f9bcc53689f1b457ecefed1eaa080e4949d65a62c31a38b7253d5226/pybase64-1.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9aa4de83f02e462a6f4e066811c71d6af31b52d7484de635582d0e3ec3d6cc3e", size = 56482, upload-time = "2025-07-27T13:03:28.942Z" },
+ { url = "https://files.pythonhosted.org/packages/75/e5/4a7735b54a1191f61c3f5c2952212c85c2d6b06eb5fb3671c7603395f70c/pybase64-1.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83a1c2f9ed00fee8f064d548c8654a480741131f280e5750bb32475b7ec8ee38", size = 70959, upload-time = "2025-07-27T13:03:30.171Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/67/e2b6cb32c782e12304d467418e70da0212567f42bd4d3b5eb1fdf64920ad/pybase64-1.4.2-cp312-cp312-win32.whl", hash = "sha256:a6e5688b18d558e8c6b8701cc8560836c4bbeba61d33c836b4dba56b19423716", size = 33683, upload-time = "2025-07-27T13:03:31.775Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/bc/d5c277496063a09707486180f17abbdbdebbf2f5c4441b20b11d3cb7dc7c/pybase64-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:c995d21b8bd08aa179cd7dd4db0695c185486ecc72da1e8f6c37ec86cadb8182", size = 35817, upload-time = "2025-07-27T13:03:32.99Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/69/e4be18ae685acff0ae77f75d4586590f29d2cd187bf603290cf1d635cad4/pybase64-1.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:e254b9258c40509c2ea063a7784f6994988f3f26099d6e08704e3c15dfed9a55", size = 30900, upload-time = "2025-07-27T13:03:34.499Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/56/5337f27a8b8d2d6693f46f7b36bae47895e5820bfa259b0072574a4e1057/pybase64-1.4.2-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:0f331aa59549de21f690b6ccc79360ffed1155c3cfbc852eb5c097c0b8565a2b", size = 33888, upload-time = "2025-07-27T13:03:35.698Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/09/f3f4b11fc9beda7e8625e29fb0f549958fcbb34fea3914e1c1d95116e344/pybase64-1.4.2-cp313-cp313-android_21_x86_64.whl", hash = "sha256:9dad20bf1f3ed9e6fe566c4c9d07d9a6c04f5a280daebd2082ffb8620b0a880d", size = 40796, upload-time = "2025-07-27T13:03:36.927Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/ff/470768f0fe6de0aa302a8cb1bdf2f9f5cffc3f69e60466153be68bc953aa/pybase64-1.4.2-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:69d3f0445b0faeef7bb7f93bf8c18d850785e2a77f12835f49e524cc54af04e7", size = 30914, upload-time = "2025-07-27T13:03:38.475Z" },
+ { url = "https://files.pythonhosted.org/packages/75/6b/d328736662665e0892409dc410353ebef175b1be5eb6bab1dad579efa6df/pybase64-1.4.2-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2372b257b1f4dd512f317fb27e77d313afd137334de64c87de8374027aacd88a", size = 31380, upload-time = "2025-07-27T13:03:39.7Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/96/7ff718f87c67f4147c181b73d0928897cefa17dc75d7abc6e37730d5908f/pybase64-1.4.2-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:fb794502b4b1ec91c4ca5d283ae71aef65e3de7721057bd9e2b3ec79f7a62d7d", size = 38230, upload-time = "2025-07-27T13:03:41.637Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/58/a3307b048d799ff596a3c7c574fcba66f9b6b8c899a3c00a698124ca7ad5/pybase64-1.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d5c532b03fd14a5040d6cf6571299a05616f925369c72ddf6fe2fb643eb36fed", size = 38319, upload-time = "2025-07-27T13:03:42.847Z" },
+ { url = "https://files.pythonhosted.org/packages/08/a7/0bda06341b0a2c830d348c6e1c4d348caaae86c53dc9a046e943467a05e9/pybase64-1.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f699514dc1d5689ca9cf378139e0214051922732f9adec9404bc680a8bef7c0", size = 31655, upload-time = "2025-07-27T13:03:44.426Z" },
+ { url = "https://files.pythonhosted.org/packages/87/df/e1d6e8479e0c5113c2c63c7b44886935ce839c2d99884c7304ca9e86547c/pybase64-1.4.2-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:cd3e8713cbd32c8c6aa935feaf15c7670e2b7e8bfe51c24dc556811ebd293a29", size = 68232, upload-time = "2025-07-27T13:03:45.729Z" },
+ { url = "https://files.pythonhosted.org/packages/71/ab/db4dbdfccb9ca874d6ce34a0784761471885d96730de85cee3d300381529/pybase64-1.4.2-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d377d48acf53abf4b926c2a7a24a19deb092f366a04ffd856bf4b3aa330b025d", size = 71608, upload-time = "2025-07-27T13:03:47.01Z" },
+ { url = "https://files.pythonhosted.org/packages/11/e9/508df958563951045d728bbfbd3be77465f9231cf805cb7ccaf6951fc9f1/pybase64-1.4.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d83c076e78d619b9e1dd674e2bf5fb9001aeb3e0b494b80a6c8f6d4120e38cd9", size = 59912, upload-time = "2025-07-27T13:03:48.277Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/58/7f2cef1ceccc682088958448d56727369de83fa6b29148478f4d2acd107a/pybase64-1.4.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:ab9cdb6a8176a5cb967f53e6ad60e40c83caaa1ae31c5e1b29e5c8f507f17538", size = 56413, upload-time = "2025-07-27T13:03:49.908Z" },
+ { url = "https://files.pythonhosted.org/packages/08/7c/7e0af5c5728fa7e2eb082d88eca7c6bd17429be819d58518e74919d42e66/pybase64-1.4.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:adf0c103ad559dbfb9fe69edfd26a15c65d9c991a5ab0a25b04770f9eb0b9484", size = 59311, upload-time = "2025-07-27T13:03:51.238Z" },
+ { url = "https://files.pythonhosted.org/packages/03/8b/09825d0f37e45b9a3f546e5f990b6cf2dd838e54ea74122c2464646e0c77/pybase64-1.4.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:0d03ef2f253d97ce0685d3624bf5e552d716b86cacb8a6c971333ba4b827e1fc", size = 60282, upload-time = "2025-07-27T13:03:52.56Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/3f/3711d2413f969bfd5b9cc19bc6b24abae361b7673ff37bcb90c43e199316/pybase64-1.4.2-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:e565abf906efee76ae4be1aef5df4aed0fda1639bc0d7732a3dafef76cb6fc35", size = 54845, upload-time = "2025-07-27T13:03:54.167Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/3c/4c7ce1ae4d828c2bb56d144322f81bffbaaac8597d35407c3d7cbb0ff98f/pybase64-1.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3c6a5f15fd03f232fc6f295cce3684f7bb08da6c6d5b12cc771f81c9f125cc6", size = 58615, upload-time = "2025-07-27T13:03:55.494Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/8f/c2fc03bf4ed038358620065c75968a30184d5d3512d09d3ef9cc3bd48592/pybase64-1.4.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bad9e3db16f448728138737bbd1af9dc2398efd593a8bdd73748cc02cd33f9c6", size = 52434, upload-time = "2025-07-27T13:03:56.808Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/0a/757d6df0a60327c893cfae903e15419914dd792092dc8cc5c9523d40bc9b/pybase64-1.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2683ef271328365c31afee0ed8fa29356fb8fb7c10606794656aa9ffb95e92be", size = 68824, upload-time = "2025-07-27T13:03:58.735Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/14/84abe2ed8c29014239be1cfab45dfebe5a5ca779b177b8b6f779bd8b69da/pybase64-1.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:265b20089cd470079114c09bb74b101b3bfc3c94ad6b4231706cf9eff877d570", size = 57898, upload-time = "2025-07-27T13:04:00.379Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/c6/d193031f90c864f7b59fa6d1d1b5af41f0f5db35439988a8b9f2d1b32a13/pybase64-1.4.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e53173badead10ef8b839aa5506eecf0067c7b75ad16d9bf39bc7144631f8e67", size = 54319, upload-time = "2025-07-27T13:04:01.742Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/37/ec0c7a610ff8f994ee6e0c5d5d66b6b6310388b96ebb347b03ae39870fdf/pybase64-1.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5823b8dcf74da7da0f761ed60c961e8928a6524e520411ad05fe7f9f47d55b40", size = 56472, upload-time = "2025-07-27T13:04:03.089Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/5a/e585b74f85cedd261d271e4c2ef333c5cfce7e80750771808f56fee66b98/pybase64-1.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1237f66c54357d325390da60aa5e21c6918fbcd1bf527acb9c1f4188c62cb7d5", size = 70966, upload-time = "2025-07-27T13:04:04.361Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/20/1b2fdd98b4ba36008419668c813025758214c543e362c66c49214ecd1127/pybase64-1.4.2-cp313-cp313-win32.whl", hash = "sha256:b0b851eb4f801d16040047f6889cca5e9dfa102b3e33f68934d12511245cef86", size = 33681, upload-time = "2025-07-27T13:04:06.126Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/64/3df4067d169c047054889f34b5a946cbe3785bca43404b93c962a5461a41/pybase64-1.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:19541c6e26d17d9522c02680fe242206ae05df659c82a657aabadf209cd4c6c7", size = 35822, upload-time = "2025-07-27T13:04:07.752Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/fd/db505188adf812e60ee923f196f9deddd8a1895b2b29b37f5db94afc3b1c/pybase64-1.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:77a191863d576c0a5dd81f8a568a5ca15597cc980ae809dce62c717c8d42d8aa", size = 30899, upload-time = "2025-07-27T13:04:09.062Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/27/5f5fecd206ec1e06e1608a380af18dcb76a6ab08ade6597a3251502dcdb2/pybase64-1.4.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2e194bbabe3fdf9e47ba9f3e157394efe0849eb226df76432126239b3f44992c", size = 38677, upload-time = "2025-07-27T13:04:10.334Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/0f/abe4b5a28529ef5f74e8348fa6a9ef27d7d75fbd98103d7664cf485b7d8f/pybase64-1.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:39aef1dadf4a004f11dd09e703abaf6528a87c8dbd39c448bb8aebdc0a08c1be", size = 32066, upload-time = "2025-07-27T13:04:11.641Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/7e/ea0ce6a7155cada5526017ec588b6d6185adea4bf9331565272f4ef583c2/pybase64-1.4.2-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:91cb920c7143e36ec8217031282c8651da3b2206d70343f068fac0e7f073b7f9", size = 72300, upload-time = "2025-07-27T13:04:12.969Z" },
+ { url = "https://files.pythonhosted.org/packages/45/2d/e64c7a056c9ec48dfe130d1295e47a8c2b19c3984488fc08e5eaa1e86c88/pybase64-1.4.2-cp313-cp313t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6958631143fb9e71f9842000da042ec2f6686506b6706e2dfda29e97925f6aa0", size = 75520, upload-time = "2025-07-27T13:04:14.374Z" },
+ { url = "https://files.pythonhosted.org/packages/43/e0/e5f93b2e1cb0751a22713c4baa6c6eaf5f307385e369180486c8316ed21e/pybase64-1.4.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:dc35f14141ef3f1ac70d963950a278a2593af66fe5a1c7a208e185ca6278fa25", size = 65384, upload-time = "2025-07-27T13:04:16.204Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/23/8c645a1113ad88a1c6a3d0e825e93ef8b74ad3175148767853a0a4d7626e/pybase64-1.4.2-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:5d949d2d677859c3a8507e1b21432a039d2b995e0bd3fe307052b6ded80f207a", size = 60471, upload-time = "2025-07-27T13:04:17.947Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/81/edd0f7d8b0526b91730a0dd4ce6b4c8be2136cd69d424afe36235d2d2a06/pybase64-1.4.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:09caacdd3e15fe7253a67781edd10a6a918befab0052a2a3c215fe5d1f150269", size = 63945, upload-time = "2025-07-27T13:04:19.383Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/a5/edc224cd821fd65100b7af7c7e16b8f699916f8c0226c9c97bbae5a75e71/pybase64-1.4.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:e44b0e793b23f28ea0f15a9754bd0c960102a2ac4bccb8fafdedbd4cc4d235c0", size = 64858, upload-time = "2025-07-27T13:04:20.807Z" },
+ { url = "https://files.pythonhosted.org/packages/11/3b/92853f968f1af7e42b7e54d21bdd319097b367e7dffa2ca20787361df74c/pybase64-1.4.2-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:849f274d0bcb90fc6f642c39274082724d108e41b15f3a17864282bd41fc71d5", size = 58557, upload-time = "2025-07-27T13:04:22.229Z" },
+ { url = "https://files.pythonhosted.org/packages/76/09/0ec6bd2b2303b0ea5c6da7535edc9a608092075ef8c0cdd96e3e726cd687/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:528dba7ef1357bd7ce1aea143084501f47f5dd0fff7937d3906a68565aa59cfe", size = 63624, upload-time = "2025-07-27T13:04:23.952Z" },
+ { url = "https://files.pythonhosted.org/packages/73/6e/52cb1ced2a517a3118b2e739e9417432049013ac7afa15d790103059e8e4/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:1da54be743d9a68671700cfe56c3ab8c26e8f2f5cc34eface905c55bc3a9af94", size = 56174, upload-time = "2025-07-27T13:04:25.419Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/9d/820fe79347467e48af985fe46180e1dd28e698ade7317bebd66de8a143f5/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9b07c0406c3eaa7014499b0aacafb21a6d1146cfaa85d56f0aa02e6d542ee8f3", size = 72640, upload-time = "2025-07-27T13:04:26.824Z" },
+ { url = "https://files.pythonhosted.org/packages/53/58/e863e10d08361e694935c815b73faad7e1ab03f99ae154d86c4e2f331896/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:312f2aa4cf5d199a97fbcaee75d2e59ebbaafcd091993eb373b43683498cdacb", size = 62453, upload-time = "2025-07-27T13:04:28.562Z" },
+ { url = "https://files.pythonhosted.org/packages/95/f0/c392c4ac8ccb7a34b28377c21faa2395313e3c676d76c382642e19a20703/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad59362fc267bf15498a318c9e076686e4beeb0dfe09b457fabbc2b32468b97a", size = 58103, upload-time = "2025-07-27T13:04:29.996Z" },
+ { url = "https://files.pythonhosted.org/packages/32/30/00ab21316e7df8f526aa3e3dc06f74de6711d51c65b020575d0105a025b2/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:01593bd064e7dcd6c86d04e94e44acfe364049500c20ac68ca1e708fbb2ca970", size = 60779, upload-time = "2025-07-27T13:04:31.549Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/65/114ca81839b1805ce4a2b7d58bc16e95634734a2059991f6382fc71caf3e/pybase64-1.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5b81547ad8ea271c79fdf10da89a1e9313cb15edcba2a17adf8871735e9c02a0", size = 74684, upload-time = "2025-07-27T13:04:32.976Z" },
+ { url = "https://files.pythonhosted.org/packages/54/8f/aa9d445b9bb693b8f6bb1456bd6d8576d79b7a63bf6c69af3a539235b15f/pybase64-1.4.2-cp313-cp313t-win32.whl", hash = "sha256:7edbe70b5654545a37e6e6b02de738303b1bbdfcde67f6cfec374cfb5cc4099e", size = 33961, upload-time = "2025-07-27T13:04:34.806Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/e5/da37cfb173c646fd4fc7c6aae2bc41d40de2ee49529854af8f4e6f498b45/pybase64-1.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:385690addf87c25d6366fab5d8ff512eed8a7ecb18da9e8152af1c789162f208", size = 36199, upload-time = "2025-07-27T13:04:36.223Z" },
+ { url = "https://files.pythonhosted.org/packages/66/3e/1eb68fb7d00f2cec8bd9838e2a30d183d6724ae06e745fd6e65216f170ff/pybase64-1.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c2070d0aa88580f57fe15ca88b09f162e604d19282915a95a3795b5d3c1c05b5", size = 31221, upload-time = "2025-07-27T13:04:37.704Z" },
+ { url = "https://files.pythonhosted.org/packages/99/bf/00a87d951473ce96c8c08af22b6983e681bfabdb78dd2dcf7ee58eac0932/pybase64-1.4.2-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:4157ad277a32cf4f02a975dffc62a3c67d73dfa4609b2c1978ef47e722b18b8e", size = 30924, upload-time = "2025-07-27T13:04:39.189Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/43/dee58c9d60e60e6fb32dc6da722d84592e22f13c277297eb4ce6baf99a99/pybase64-1.4.2-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e113267dc349cf624eb4f4fbf53fd77835e1aa048ac6877399af426aab435757", size = 31390, upload-time = "2025-07-27T13:04:40.995Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/11/b28906fc2e330b8b1ab4bc845a7bef808b8506734e90ed79c6062b095112/pybase64-1.4.2-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:cea5aaf218fd9c5c23afacfe86fd4464dfedc1a0316dd3b5b4075b068cc67df0", size = 38212, upload-time = "2025-07-27T13:04:42.729Z" },
+ { url = "https://files.pythonhosted.org/packages/24/9e/868d1e104413d14b19feaf934fc7fad4ef5b18946385f8bb79684af40f24/pybase64-1.4.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:41213497abbd770435c7a9c8123fb02b93709ac4cf60155cd5aefc5f3042b600", size = 38303, upload-time = "2025-07-27T13:04:44.095Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/73/f7eac96ca505df0600280d6bfc671a9e2e2f947c2b04b12a70e36412f7eb/pybase64-1.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c8b522df7ee00f2ac1993ccd5e1f6608ae7482de3907668c2ff96a83ef213925", size = 31669, upload-time = "2025-07-27T13:04:45.845Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/43/8e18bea4fd455100112d6a73a83702843f067ef9b9272485b6bdfd9ed2f0/pybase64-1.4.2-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:06725022e540c5b098b978a0418ca979773e2cbdbb76f10bd97536f2ad1c5b49", size = 68452, upload-time = "2025-07-27T13:04:47.788Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/2e/851eb51284b97354ee5dfa1309624ab90920696e91a33cd85b13d20cc5c1/pybase64-1.4.2-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a3e54dcf0d0305ec88473c9d0009f698cabf86f88a8a10090efeff2879c421bb", size = 71674, upload-time = "2025-07-27T13:04:49.294Z" },
+ { url = "https://files.pythonhosted.org/packages/57/0d/5cf1e5dc64aec8db43e8dee4e4046856d639a72bcb0fb3e716be42ced5f1/pybase64-1.4.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:67675cee727a60dc91173d2790206f01aa3c7b3fbccfa84fd5c1e3d883fe6caa", size = 60027, upload-time = "2025-07-27T13:04:50.769Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/8e/3479266bc0e65f6cc48b3938d4a83bff045330649869d950a378f2ddece0/pybase64-1.4.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:753da25d4fd20be7bda2746f545935773beea12d5cb5ec56ec2d2960796477b1", size = 56461, upload-time = "2025-07-27T13:04:52.37Z" },
+ { url = "https://files.pythonhosted.org/packages/20/b6/f2b6cf59106dd78bae8717302be5b814cec33293504ad409a2eb752ad60c/pybase64-1.4.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:a78c768ce4ca550885246d14babdb8923e0f4a848dfaaeb63c38fc99e7ea4052", size = 59446, upload-time = "2025-07-27T13:04:53.967Z" },
+ { url = "https://files.pythonhosted.org/packages/16/70/3417797dfccdfdd0a54e4ad17c15b0624f0fc2d6a362210f229f5c4e8fd0/pybase64-1.4.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:51b17f36d890c92f0618fb1c8db2ccc25e6ed07afa505bab616396fc9b0b0492", size = 60350, upload-time = "2025-07-27T13:04:55.881Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/c6/6e4269dd98d150ae95d321b311a345eae0f7fd459d97901b4a586d7513bb/pybase64-1.4.2-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:f92218d667049ab4f65d54fa043a88ffdb2f07fff1f868789ef705a5221de7ec", size = 54989, upload-time = "2025-07-27T13:04:57.436Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/e8/18c1b0c255f964fafd0412b0d5a163aad588aeccb8f84b9bf9c8611d80f6/pybase64-1.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3547b3d1499919a06491b3f879a19fbe206af2bd1a424ecbb4e601eb2bd11fea", size = 58724, upload-time = "2025-07-27T13:04:59.406Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/ad/ddfbd2125fc20b94865fb232b2e9105376fa16eee492e4b7786d42a86cbf/pybase64-1.4.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:958af7b0e09ddeb13e8c2330767c47b556b1ade19c35370f6451d139cde9f2a9", size = 52285, upload-time = "2025-07-27T13:05:01.198Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/4c/b9d4ec9224add33c84b925a03d1a53cd4106efb449ea8e0ae7795fed7bf7/pybase64-1.4.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:4facc57f6671e2229a385a97a618273e7be36a9ea0a9d1c1b9347f14d19ceba8", size = 69036, upload-time = "2025-07-27T13:05:03.109Z" },
+ { url = "https://files.pythonhosted.org/packages/92/38/7b96794da77bed3d9b4fea40f14ae563648fba83a696e7602fabe60c0eb7/pybase64-1.4.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a32fc57d05d73a7c9b0ca95e9e265e21cf734195dc6873829a890058c35f5cfd", size = 57938, upload-time = "2025-07-27T13:05:04.744Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/c5/ae8bbce3c322d1b074e79f51f5df95961fe90cb8748df66c6bc97616e974/pybase64-1.4.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3dc853243c81ce89cc7318e6946f860df28ddb7cd2a0648b981652d9ad09ee5a", size = 54474, upload-time = "2025-07-27T13:05:06.662Z" },
+ { url = "https://files.pythonhosted.org/packages/15/9a/c09887c4bb1b43c03fc352e2671ef20c6686c6942a99106a45270ee5b840/pybase64-1.4.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:0e6d863a86b3e7bc6ac9bd659bebda4501b9da842521111b0b0e54eb51295df5", size = 56533, upload-time = "2025-07-27T13:05:08.368Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/0f/d5114d63d35d085639606a880cb06e2322841cd4b213adfc14d545c1186f/pybase64-1.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6579475140ff2067903725d8aca47f5747bcb211597a1edd60b58f6d90ada2bd", size = 71030, upload-time = "2025-07-27T13:05:10.3Z" },
+ { url = "https://files.pythonhosted.org/packages/40/0e/fe6f1ed22ea52eb99f490a8441815ba21de288f4351aeef4968d71d20d2d/pybase64-1.4.2-cp314-cp314-win32.whl", hash = "sha256:373897f728d7b4f241a1f803ac732c27b6945d26d86b2741ad9b75c802e4e378", size = 34174, upload-time = "2025-07-27T13:05:12.254Z" },
+ { url = "https://files.pythonhosted.org/packages/71/46/0e15bea52ffc63e8ae7935e945accbaf635e0aefa26d3e31fdf9bc9dcd01/pybase64-1.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:1afe3361344617d298c1d08bc657ef56d0f702d6b72cb65d968b2771017935aa", size = 36308, upload-time = "2025-07-27T13:05:13.898Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/dc/55849fee2577bda77c1e078da04cc9237e8e474a8c8308deb702a26f2511/pybase64-1.4.2-cp314-cp314-win_arm64.whl", hash = "sha256:f131c9360babe522f3d90f34da3f827cba80318125cf18d66f2ee27e3730e8c4", size = 31341, upload-time = "2025-07-27T13:05:15.553Z" },
+ { url = "https://files.pythonhosted.org/packages/39/44/c69d088e28b25e70ac742b6789cde038473815b2a69345c4bae82d5e244d/pybase64-1.4.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2583ac304131c1bd6e3120b0179333610f18816000db77c0a2dd6da1364722a8", size = 38678, upload-time = "2025-07-27T13:05:17.544Z" },
+ { url = "https://files.pythonhosted.org/packages/00/93/2860ec067497b9cbb06242f96d44caebbd9eed32174e4eb8c1ffef760f94/pybase64-1.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:75a8116be4ea4cdd30a5c4f1a6f3b038e0d457eb03c8a2685d8ce2aa00ef8f92", size = 32066, upload-time = "2025-07-27T13:05:19.18Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/55/1e96249a38759332e8a01b31c370d88c60ceaf44692eb6ba4f0f451ee496/pybase64-1.4.2-cp314-cp314t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:217ea776a098d7c08668e5526b9764f5048bbfd28cac86834217ddfe76a4e3c4", size = 72465, upload-time = "2025-07-27T13:05:20.866Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/ab/0f468605b899f3e35dbb7423fba3ff98aeed1ec16abb02428468494a58f4/pybase64-1.4.2-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4ec14683e343c95b14248cdfdfa78c052582be7a3865fd570aa7cffa5ab5cf37", size = 75693, upload-time = "2025-07-27T13:05:22.896Z" },
+ { url = "https://files.pythonhosted.org/packages/91/d1/9980a0159b699e2489baba05b71b7c953b29249118ba06fdbb3e9ea1b9b5/pybase64-1.4.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:480ecf21e1e956c5a10d3cf7b3b7e75bce3f9328cf08c101e4aab1925d879f34", size = 65577, upload-time = "2025-07-27T13:05:25Z" },
+ { url = "https://files.pythonhosted.org/packages/16/86/b27e7b95f9863d245c0179a7245582eda3d262669d8f822777364d8fd7d5/pybase64-1.4.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:1fe1ebdc55e9447142e2f6658944aadfb5a4fbf03dbd509be34182585515ecc1", size = 60662, upload-time = "2025-07-27T13:05:27.138Z" },
+ { url = "https://files.pythonhosted.org/packages/28/87/a7f0dde0abc26bfbee761f1d3558eb4b139f33ddd9fe1f6825ffa7daa22d/pybase64-1.4.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c793a2b06753accdaf5e1a8bbe5d800aab2406919e5008174f989a1ca0081411", size = 64179, upload-time = "2025-07-27T13:05:28.996Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/88/5d6fa1c60e1363b4cac4c396978f39e9df4689e75225d7d9c0a5998e3a14/pybase64-1.4.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6acae6e1d1f7ebe40165f08076c7a73692b2bf9046fefe673f350536e007f556", size = 64968, upload-time = "2025-07-27T13:05:30.818Z" },
+ { url = "https://files.pythonhosted.org/packages/20/6e/2ed585af5b2211040445d9849326dd2445320c9316268794f5453cfbaf30/pybase64-1.4.2-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:88b91cd0949358aadcea75f8de5afbcf3c8c5fb9ec82325bd24285b7119cf56e", size = 58738, upload-time = "2025-07-27T13:05:32.629Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/94/e2960b56322eabb3fbf303fc5a72e6444594c1b90035f3975c6fe666db5c/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:53316587e1b1f47a11a5ff068d3cbd4a3911c291f2aec14882734973684871b2", size = 63802, upload-time = "2025-07-27T13:05:34.687Z" },
+ { url = "https://files.pythonhosted.org/packages/95/47/312139d764c223f534f751528ce3802887c279125eac64f71cd3b4e05abc/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:caa7f20f43d00602cf9043b5ba758d54f5c41707d3709b2a5fac17361579c53c", size = 56341, upload-time = "2025-07-27T13:05:36.554Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/d7/aec9a6ed53b128dac32f8768b646ca5730c88eef80934054d7fa7d02f3ef/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:2d93817e24fdd79c534ed97705df855af6f1d2535ceb8dfa80da9de75482a8d7", size = 72838, upload-time = "2025-07-27T13:05:38.459Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/a8/6ccc54c5f1f7c3450ad7c56da10c0f131d85ebe069ea6952b5b42f2e92d9/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:63cd769b51474d8d08f7f2ce73b30380d9b4078ec92ea6b348ea20ed1e1af88a", size = 62633, upload-time = "2025-07-27T13:05:40.624Z" },
+ { url = "https://files.pythonhosted.org/packages/34/22/2b9d89f8ff6f2a01d6d6a88664b20a4817049cfc3f2c62caca040706660c/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cd07e6a9993c392ec8eb03912a43c6a6b21b2deb79ee0d606700fe276e9a576f", size = 58282, upload-time = "2025-07-27T13:05:42.565Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/14/dbf6266177532a6a11804ac080ebffcee272f491b92820c39886ee20f201/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:6a8944e8194adff4668350504bc6b7dbde2dab9244c88d99c491657d145b5af5", size = 60948, upload-time = "2025-07-27T13:05:44.48Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/7a/b2ae9046a66dd5746cd72836a41386517b1680bea5ce02f2b4f1c9ebc688/pybase64-1.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:04ab398ec4b6a212af57f6a21a6336d5a1d754ff4ccb215951366ab9080481b2", size = 74854, upload-time = "2025-07-27T13:05:46.416Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/7e/9856f6d6c38a7b730e001123d2d9fa816b8b1a45f0cdee1d509d5947b047/pybase64-1.4.2-cp314-cp314t-win32.whl", hash = "sha256:3b9201ecdcb1c3e23be4caebd6393a4e6615bd0722528f5413b58e22e3792dd3", size = 34490, upload-time = "2025-07-27T13:05:48.304Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/38/8523a9dc1ec8704dedbe5ccc95192ae9a7585f7eec85cc62946fe3cacd32/pybase64-1.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:36e9b0cad8197136d73904ef5a71d843381d063fd528c5ab203fc4990264f682", size = 36680, upload-time = "2025-07-27T13:05:50.264Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/52/5600104ef7b85f89fb8ec54f73504ead3f6f0294027e08d281f3cafb5c1a/pybase64-1.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:f25140496b02db0e7401567cd869fb13b4c8118bf5c2428592ec339987146d8b", size = 31600, upload-time = "2025-07-27T13:05:52.24Z" },
+]
+
+[[package]]
+name = "pycparser"
+version = "2.23"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" },
+]
+
+[[package]]
+name = "pydantic"
+version = "2.11.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-types" },
+ { name = "pydantic-core" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" },
+]
+
+[[package]]
+name = "pydantic-core"
+version = "2.33.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" },
+ { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" },
+ { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" },
+ { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" },
+ { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" },
+ { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" },
+ { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" },
+ { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" },
+ { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" },
+ { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
+]
+
+[[package]]
+name = "pydantic-settings"
+version = "2.11.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pydantic" },
+ { name = "python-dotenv" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/20/c5/dbbc27b814c71676593d1c3f718e6cd7d4f00652cefa24b75f7aa3efb25e/pydantic_settings-2.11.0.tar.gz", hash = "sha256:d0e87a1c7d33593beb7194adb8470fc426e95ba02af83a0f23474a04c9a08180", size = 188394, upload-time = "2025-09-24T14:19:11.764Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/83/d6/887a1ff844e64aa823fb4905978d882a633cfe295c32eacad582b78a7d8b/pydantic_settings-2.11.0-py3-none-any.whl", hash = "sha256:fe2cea3413b9530d10f3a5875adffb17ada5c1e1bab0b2885546d7310415207c", size = 48608, upload-time = "2025-09-24T14:19:10.015Z" },
+]
+
+[[package]]
+name = "pydub"
+version = "0.25.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fe/9a/e6bca0eed82db26562c73b5076539a4a08d3cffd19c3cc5913a3e61145fd/pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f", size = 38326, upload-time = "2021-03-10T02:09:54.659Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6", size = 32327, upload-time = "2021-03-10T02:09:53.503Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.19.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
+]
+
+[[package]]
+name = "pyparsing"
+version = "3.2.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274, upload-time = "2025-09-21T04:11:06.277Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" },
+]
+
+[[package]]
+name = "pypika"
+version = "0.48.9"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/2c/94ed7b91db81d61d7096ac8f2d325ec562fc75e35f3baea8749c85b28784/PyPika-0.48.9.tar.gz", hash = "sha256:838836a61747e7c8380cd1b7ff638694b7a7335345d0f559b04b2cd832ad5378", size = 67259, upload-time = "2022-03-15T11:22:57.066Z" }
+
+[[package]]
+name = "pyproject-hooks"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e7/82/28175b2414effca1cdac8dc99f76d660e7a4fb0ceefa4b4ab8f5f6742925/pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", size = 19228, upload-time = "2024-09-29T09:24:13.293Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216, upload-time = "2024-09-29T09:24:11.978Z" },
+]
+
+[[package]]
+name = "pyreadline3"
+version = "3.5.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0f/49/4cea918a08f02817aabae639e3d0ac046fef9f9180518a3ad394e22da148/pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7", size = 99839, upload-time = "2024-09-19T02:40:10.062Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/dc/491b7661614ab97483abf2056be1deee4dc2490ecbf7bff9ab5cdbac86e1/pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6", size = 83178, upload-time = "2024-09-19T02:40:08.598Z" },
+]
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
+]
+
+[[package]]
+name = "python-dotenv"
+version = "1.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" },
+]
+
+[[package]]
+name = "python-multipart"
+version = "0.0.20"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" },
+]
+
+[[package]]
+name = "pytz"
+version = "2025.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
+]
+
+[[package]]
+name = "pywin32"
+version = "311"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" },
+ { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" },
+ { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
+]
+
+[[package]]
+name = "pyyaml"
+version = "6.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
+ { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
+ { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
+ { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
+ { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
+ { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
+ { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
+ { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
+ { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
+ { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
+ { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
+ { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
+ { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
+ { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
+ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
+]
+
+[[package]]
+name = "pyzmq"
+version = "27.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cffi", marker = "implementation_name == 'pypy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" },
+ { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" },
+ { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" },
+ { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436, upload-time = "2025-09-08T23:08:20.801Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301, upload-time = "2025-09-08T23:08:22.47Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197, upload-time = "2025-09-08T23:08:24.286Z" },
+ { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275, upload-time = "2025-09-08T23:08:26.063Z" },
+ { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469, upload-time = "2025-09-08T23:08:27.623Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961, upload-time = "2025-09-08T23:08:29.672Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282, upload-time = "2025-09-08T23:08:31.349Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468, upload-time = "2025-09-08T23:08:33.543Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394, upload-time = "2025-09-08T23:08:35.51Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" },
+ { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" },
+ { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197, upload-time = "2025-09-08T23:08:44.973Z" },
+ { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175, upload-time = "2025-09-08T23:08:46.601Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427, upload-time = "2025-09-08T23:08:48.187Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929, upload-time = "2025-09-08T23:08:49.76Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193, upload-time = "2025-09-08T23:08:51.7Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388, upload-time = "2025-09-08T23:08:53.393Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316, upload-time = "2025-09-08T23:08:55.702Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472, upload-time = "2025-09-08T23:08:58.18Z" },
+ { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401, upload-time = "2025-09-08T23:08:59.802Z" },
+ { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170, upload-time = "2025-09-08T23:09:01.418Z" },
+]
+
+[[package]]
+name = "referencing"
+version = "0.36.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "rpds-py" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" },
+]
+
+[[package]]
+name = "regex"
+version = "2025.9.18"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/49/d3/eaa0d28aba6ad1827ad1e716d9a93e1ba963ada61887498297d3da715133/regex-2025.9.18.tar.gz", hash = "sha256:c5ba23274c61c6fef447ba6a39333297d0c247f53059dba0bca415cac511edc4", size = 400917, upload-time = "2025-09-19T00:38:35.79Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b0/99/05859d87a66ae7098222d65748f11ef7f2dff51bfd7482a4e2256c90d72b/regex-2025.9.18-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:436e1b31d7efd4dcd52091d076482031c611dde58bf9c46ca6d0a26e33053a7e", size = 486335, upload-time = "2025-09-19T00:36:03.661Z" },
+ { url = "https://files.pythonhosted.org/packages/97/7e/d43d4e8b978890932cf7b0957fce58c5b08c66f32698f695b0c2c24a48bf/regex-2025.9.18-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c190af81e5576b9c5fdc708f781a52ff20f8b96386c6e2e0557a78402b029f4a", size = 289720, upload-time = "2025-09-19T00:36:05.471Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/3b/ff80886089eb5dcf7e0d2040d9aaed539e25a94300403814bb24cc775058/regex-2025.9.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e4121f1ce2b2b5eec4b397cc1b277686e577e658d8f5870b7eb2d726bd2300ab", size = 287257, upload-time = "2025-09-19T00:36:07.072Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/66/243edf49dd8720cba8d5245dd4d6adcb03a1defab7238598c0c97cf549b8/regex-2025.9.18-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:300e25dbbf8299d87205e821a201057f2ef9aa3deb29caa01cd2cac669e508d5", size = 797463, upload-time = "2025-09-19T00:36:08.399Z" },
+ { url = "https://files.pythonhosted.org/packages/df/71/c9d25a1142c70432e68bb03211d4a82299cd1c1fbc41db9409a394374ef5/regex-2025.9.18-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7b47fcf9f5316c0bdaf449e879407e1b9937a23c3b369135ca94ebc8d74b1742", size = 862670, upload-time = "2025-09-19T00:36:10.101Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/8f/329b1efc3a64375a294e3a92d43372bf1a351aa418e83c21f2f01cf6ec41/regex-2025.9.18-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:57a161bd3acaa4b513220b49949b07e252165e6b6dc910ee7617a37ff4f5b425", size = 910881, upload-time = "2025-09-19T00:36:12.223Z" },
+ { url = "https://files.pythonhosted.org/packages/35/9e/a91b50332a9750519320ed30ec378b74c996f6befe282cfa6bb6cea7e9fd/regex-2025.9.18-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f130c3a7845ba42de42f380fff3c8aebe89a810747d91bcf56d40a069f15352", size = 802011, upload-time = "2025-09-19T00:36:13.901Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/1d/6be3b8d7856b6e0d7ee7f942f437d0a76e0d5622983abbb6d21e21ab9a17/regex-2025.9.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f96fa342b6f54dcba928dd452e8d8cb9f0d63e711d1721cd765bb9f73bb048d", size = 786668, upload-time = "2025-09-19T00:36:15.391Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/ce/4a60e53df58bd157c5156a1736d3636f9910bdcc271d067b32b7fcd0c3a8/regex-2025.9.18-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0f0d676522d68c207828dcd01fb6f214f63f238c283d9f01d85fc664c7c85b56", size = 856578, upload-time = "2025-09-19T00:36:16.845Z" },
+ { url = "https://files.pythonhosted.org/packages/86/e8/162c91bfe7217253afccde112868afb239f94703de6580fb235058d506a6/regex-2025.9.18-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:40532bff8a1a0621e7903ae57fce88feb2e8a9a9116d341701302c9302aef06e", size = 849017, upload-time = "2025-09-19T00:36:18.597Z" },
+ { url = "https://files.pythonhosted.org/packages/35/34/42b165bc45289646ea0959a1bc7531733e90b47c56a72067adfe6b3251f6/regex-2025.9.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:039f11b618ce8d71a1c364fdee37da1012f5a3e79b1b2819a9f389cd82fd6282", size = 788150, upload-time = "2025-09-19T00:36:20.464Z" },
+ { url = "https://files.pythonhosted.org/packages/79/5d/cdd13b1f3c53afa7191593a7ad2ee24092a5a46417725ffff7f64be8342d/regex-2025.9.18-cp312-cp312-win32.whl", hash = "sha256:e1dd06f981eb226edf87c55d523131ade7285137fbde837c34dc9d1bf309f459", size = 264536, upload-time = "2025-09-19T00:36:21.922Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/f5/4a7770c9a522e7d2dc1fa3ffc83ab2ab33b0b22b447e62cffef186805302/regex-2025.9.18-cp312-cp312-win_amd64.whl", hash = "sha256:3d86b5247bf25fa3715e385aa9ff272c307e0636ce0c9595f64568b41f0a9c77", size = 275501, upload-time = "2025-09-19T00:36:23.4Z" },
+ { url = "https://files.pythonhosted.org/packages/df/05/9ce3e110e70d225ecbed455b966003a3afda5e58e8aec2964042363a18f4/regex-2025.9.18-cp312-cp312-win_arm64.whl", hash = "sha256:032720248cbeeae6444c269b78cb15664458b7bb9ed02401d3da59fe4d68c3a5", size = 268601, upload-time = "2025-09-19T00:36:25.092Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/c7/5c48206a60ce33711cf7dcaeaed10dd737733a3569dc7e1dce324dd48f30/regex-2025.9.18-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2a40f929cd907c7e8ac7566ac76225a77701a6221bca937bdb70d56cb61f57b2", size = 485955, upload-time = "2025-09-19T00:36:26.822Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/be/74fc6bb19a3c491ec1ace943e622b5a8539068771e8705e469b2da2306a7/regex-2025.9.18-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c90471671c2cdf914e58b6af62420ea9ecd06d1554d7474d50133ff26ae88feb", size = 289583, upload-time = "2025-09-19T00:36:28.577Z" },
+ { url = "https://files.pythonhosted.org/packages/25/c4/9ceaa433cb5dc515765560f22a19578b95b92ff12526e5a259321c4fc1a0/regex-2025.9.18-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a351aff9e07a2dabb5022ead6380cff17a4f10e4feb15f9100ee56c4d6d06af", size = 287000, upload-time = "2025-09-19T00:36:30.161Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/e6/68bc9393cb4dc68018456568c048ac035854b042bc7c33cb9b99b0680afa/regex-2025.9.18-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc4b8e9d16e20ddfe16430c23468a8707ccad3365b06d4536142e71823f3ca29", size = 797535, upload-time = "2025-09-19T00:36:31.876Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/1c/ebae9032d34b78ecfe9bd4b5e6575b55351dc8513485bb92326613732b8c/regex-2025.9.18-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b8cdbddf2db1c5e80338ba2daa3cfa3dec73a46fff2a7dda087c8efbf12d62f", size = 862603, upload-time = "2025-09-19T00:36:33.344Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/74/12332c54b3882557a4bcd2b99f8be581f5c6a43cf1660a85b460dd8ff468/regex-2025.9.18-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a276937d9d75085b2c91fb48244349c6954f05ee97bba0963ce24a9d915b8b68", size = 910829, upload-time = "2025-09-19T00:36:34.826Z" },
+ { url = "https://files.pythonhosted.org/packages/86/70/ba42d5ed606ee275f2465bfc0e2208755b06cdabd0f4c7c4b614d51b57ab/regex-2025.9.18-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92a8e375ccdc1256401c90e9dc02b8642894443d549ff5e25e36d7cf8a80c783", size = 802059, upload-time = "2025-09-19T00:36:36.664Z" },
+ { url = "https://files.pythonhosted.org/packages/da/c5/fcb017e56396a7f2f8357412638d7e2963440b131a3ca549be25774b3641/regex-2025.9.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0dc6893b1f502d73037cf807a321cdc9be29ef3d6219f7970f842475873712ac", size = 786781, upload-time = "2025-09-19T00:36:38.168Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/ee/21c4278b973f630adfb3bcb23d09d83625f3ab1ca6e40ebdffe69901c7a1/regex-2025.9.18-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a61e85bfc63d232ac14b015af1261f826260c8deb19401c0597dbb87a864361e", size = 856578, upload-time = "2025-09-19T00:36:40.129Z" },
+ { url = "https://files.pythonhosted.org/packages/87/0b/de51550dc7274324435c8f1539373ac63019b0525ad720132866fff4a16a/regex-2025.9.18-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1ef86a9ebc53f379d921fb9a7e42b92059ad3ee800fcd9e0fe6181090e9f6c23", size = 849119, upload-time = "2025-09-19T00:36:41.651Z" },
+ { url = "https://files.pythonhosted.org/packages/60/52/383d3044fc5154d9ffe4321696ee5b2ee4833a28c29b137c22c33f41885b/regex-2025.9.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d3bc882119764ba3a119fbf2bd4f1b47bc56c1da5d42df4ed54ae1e8e66fdf8f", size = 788219, upload-time = "2025-09-19T00:36:43.575Z" },
+ { url = "https://files.pythonhosted.org/packages/20/bd/2614fc302671b7359972ea212f0e3a92df4414aaeacab054a8ce80a86073/regex-2025.9.18-cp313-cp313-win32.whl", hash = "sha256:3810a65675845c3bdfa58c3c7d88624356dd6ee2fc186628295e0969005f928d", size = 264517, upload-time = "2025-09-19T00:36:45.503Z" },
+ { url = "https://files.pythonhosted.org/packages/07/0f/ab5c1581e6563a7bffdc1974fb2d25f05689b88e2d416525271f232b1946/regex-2025.9.18-cp313-cp313-win_amd64.whl", hash = "sha256:16eaf74b3c4180ede88f620f299e474913ab6924d5c4b89b3833bc2345d83b3d", size = 275481, upload-time = "2025-09-19T00:36:46.965Z" },
+ { url = "https://files.pythonhosted.org/packages/49/22/ee47672bc7958f8c5667a587c2600a4fba8b6bab6e86bd6d3e2b5f7cac42/regex-2025.9.18-cp313-cp313-win_arm64.whl", hash = "sha256:4dc98ba7dd66bd1261927a9f49bd5ee2bcb3660f7962f1ec02617280fc00f5eb", size = 268598, upload-time = "2025-09-19T00:36:48.314Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/83/6887e16a187c6226cb85d8301e47d3b73ecc4505a3a13d8da2096b44fd76/regex-2025.9.18-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:fe5d50572bc885a0a799410a717c42b1a6b50e2f45872e2b40f4f288f9bce8a2", size = 489765, upload-time = "2025-09-19T00:36:49.996Z" },
+ { url = "https://files.pythonhosted.org/packages/51/c5/e2f7325301ea2916ff301c8d963ba66b1b2c1b06694191df80a9c4fea5d0/regex-2025.9.18-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b9d9a2d6cda6621551ca8cf7a06f103adf72831153f3c0d982386110870c4d3", size = 291228, upload-time = "2025-09-19T00:36:51.654Z" },
+ { url = "https://files.pythonhosted.org/packages/91/60/7d229d2bc6961289e864a3a3cfebf7d0d250e2e65323a8952cbb7e22d824/regex-2025.9.18-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:13202e4c4ac0ef9a317fff817674b293c8f7e8c68d3190377d8d8b749f566e12", size = 289270, upload-time = "2025-09-19T00:36:53.118Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/d7/b4f06868ee2958ff6430df89857fbf3d43014bbf35538b6ec96c2704e15d/regex-2025.9.18-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:874ff523b0fecffb090f80ae53dc93538f8db954c8bb5505f05b7787ab3402a0", size = 806326, upload-time = "2025-09-19T00:36:54.631Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/e4/bca99034a8f1b9b62ccf337402a8e5b959dd5ba0e5e5b2ead70273df3277/regex-2025.9.18-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d13ab0490128f2bb45d596f754148cd750411afc97e813e4b3a61cf278a23bb6", size = 871556, upload-time = "2025-09-19T00:36:56.208Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/df/e06ffaf078a162f6dd6b101a5ea9b44696dca860a48136b3ae4a9caf25e2/regex-2025.9.18-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:05440bc172bc4b4b37fb9667e796597419404dbba62e171e1f826d7d2a9ebcef", size = 913817, upload-time = "2025-09-19T00:36:57.807Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/05/25b05480b63292fd8e84800b1648e160ca778127b8d2367a0a258fa2e225/regex-2025.9.18-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5514b8e4031fdfaa3d27e92c75719cbe7f379e28cacd939807289bce76d0e35a", size = 811055, upload-time = "2025-09-19T00:36:59.762Z" },
+ { url = "https://files.pythonhosted.org/packages/70/97/7bc7574655eb651ba3a916ed4b1be6798ae97af30104f655d8efd0cab24b/regex-2025.9.18-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:65d3c38c39efce73e0d9dc019697b39903ba25b1ad45ebbd730d2cf32741f40d", size = 794534, upload-time = "2025-09-19T00:37:01.405Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/c2/d5da49166a52dda879855ecdba0117f073583db2b39bb47ce9a3378a8e9e/regex-2025.9.18-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ae77e447ebc144d5a26d50055c6ddba1d6ad4a865a560ec7200b8b06bc529368", size = 866684, upload-time = "2025-09-19T00:37:03.441Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/2d/0a5c4e6ec417de56b89ff4418ecc72f7e3feca806824c75ad0bbdae0516b/regex-2025.9.18-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e3ef8cf53dc8df49d7e28a356cf824e3623764e9833348b655cfed4524ab8a90", size = 853282, upload-time = "2025-09-19T00:37:04.985Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/8e/d656af63e31a86572ec829665d6fa06eae7e144771e0330650a8bb865635/regex-2025.9.18-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9feb29817df349c976da9a0debf775c5c33fc1c8ad7b9f025825da99374770b7", size = 797830, upload-time = "2025-09-19T00:37:06.697Z" },
+ { url = "https://files.pythonhosted.org/packages/db/ce/06edc89df8f7b83ffd321b6071be4c54dc7332c0f77860edc40ce57d757b/regex-2025.9.18-cp313-cp313t-win32.whl", hash = "sha256:168be0d2f9b9d13076940b1ed774f98595b4e3c7fc54584bba81b3cc4181742e", size = 267281, upload-time = "2025-09-19T00:37:08.568Z" },
+ { url = "https://files.pythonhosted.org/packages/83/9a/2b5d9c8b307a451fd17068719d971d3634ca29864b89ed5c18e499446d4a/regex-2025.9.18-cp313-cp313t-win_amd64.whl", hash = "sha256:d59ecf3bb549e491c8104fea7313f3563c7b048e01287db0a90485734a70a730", size = 278724, upload-time = "2025-09-19T00:37:10.023Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/70/177d31e8089a278a764f8ec9a3faac8d14a312d622a47385d4b43905806f/regex-2025.9.18-cp313-cp313t-win_arm64.whl", hash = "sha256:dbef80defe9fb21310948a2595420b36c6d641d9bea4c991175829b2cc4bc06a", size = 269771, upload-time = "2025-09-19T00:37:13.041Z" },
+ { url = "https://files.pythonhosted.org/packages/44/b7/3b4663aa3b4af16819f2ab6a78c4111c7e9b066725d8107753c2257448a5/regex-2025.9.18-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c6db75b51acf277997f3adcd0ad89045d856190d13359f15ab5dda21581d9129", size = 486130, upload-time = "2025-09-19T00:37:14.527Z" },
+ { url = "https://files.pythonhosted.org/packages/80/5b/4533f5d7ac9c6a02a4725fe8883de2aebc713e67e842c04cf02626afb747/regex-2025.9.18-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8f9698b6f6895d6db810e0bda5364f9ceb9e5b11328700a90cae573574f61eea", size = 289539, upload-time = "2025-09-19T00:37:16.356Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/8d/5ab6797c2750985f79e9995fad3254caa4520846580f266ae3b56d1cae58/regex-2025.9.18-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29cd86aa7cb13a37d0f0d7c21d8d949fe402ffa0ea697e635afedd97ab4b69f1", size = 287233, upload-time = "2025-09-19T00:37:18.025Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/1e/95afcb02ba8d3a64e6ffeb801718ce73471ad6440c55d993f65a4a5e7a92/regex-2025.9.18-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c9f285a071ee55cd9583ba24dde006e53e17780bb309baa8e4289cd472bcc47", size = 797876, upload-time = "2025-09-19T00:37:19.609Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/fb/720b1f49cec1f3b5a9fea5b34cd22b88b5ebccc8c1b5de9cc6f65eed165a/regex-2025.9.18-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5adf266f730431e3be9021d3e5b8d5ee65e563fec2883ea8093944d21863b379", size = 863385, upload-time = "2025-09-19T00:37:21.65Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/ca/e0d07ecf701e1616f015a720dc13b84c582024cbfbb3fc5394ae204adbd7/regex-2025.9.18-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1137cabc0f38807de79e28d3f6e3e3f2cc8cfb26bead754d02e6d1de5f679203", size = 910220, upload-time = "2025-09-19T00:37:23.723Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/45/bba86413b910b708eca705a5af62163d5d396d5f647ed9485580c7025209/regex-2025.9.18-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7cc9e5525cada99699ca9223cce2d52e88c52a3d2a0e842bd53de5497c604164", size = 801827, upload-time = "2025-09-19T00:37:25.684Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/a6/740fbd9fcac31a1305a8eed30b44bf0f7f1e042342be0a4722c0365ecfca/regex-2025.9.18-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bbb9246568f72dce29bcd433517c2be22c7791784b223a810225af3b50d1aafb", size = 786843, upload-time = "2025-09-19T00:37:27.62Z" },
+ { url = "https://files.pythonhosted.org/packages/80/a7/0579e8560682645906da640c9055506465d809cb0f5415d9976f417209a6/regex-2025.9.18-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6a52219a93dd3d92c675383efff6ae18c982e2d7651c792b1e6d121055808743", size = 857430, upload-time = "2025-09-19T00:37:29.362Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/9b/4dc96b6c17b38900cc9fee254fc9271d0dde044e82c78c0811b58754fde5/regex-2025.9.18-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:ae9b3840c5bd456780e3ddf2f737ab55a79b790f6409182012718a35c6d43282", size = 848612, upload-time = "2025-09-19T00:37:31.42Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/6a/6f659f99bebb1775e5ac81a3fb837b85897c1a4ef5acffd0ff8ffe7e67fb/regex-2025.9.18-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d488c236ac497c46a5ac2005a952c1a0e22a07be9f10c3e735bc7d1209a34773", size = 787967, upload-time = "2025-09-19T00:37:34.019Z" },
+ { url = "https://files.pythonhosted.org/packages/61/35/9e35665f097c07cf384a6b90a1ac11b0b1693084a0b7a675b06f760496c6/regex-2025.9.18-cp314-cp314-win32.whl", hash = "sha256:0c3506682ea19beefe627a38872d8da65cc01ffa25ed3f2e422dffa1474f0788", size = 269847, upload-time = "2025-09-19T00:37:35.759Z" },
+ { url = "https://files.pythonhosted.org/packages/af/64/27594dbe0f1590b82de2821ebfe9a359b44dcb9b65524876cd12fabc447b/regex-2025.9.18-cp314-cp314-win_amd64.whl", hash = "sha256:57929d0f92bebb2d1a83af372cd0ffba2263f13f376e19b1e4fa32aec4efddc3", size = 278755, upload-time = "2025-09-19T00:37:37.367Z" },
+ { url = "https://files.pythonhosted.org/packages/30/a3/0cd8d0d342886bd7d7f252d701b20ae1a3c72dc7f34ef4b2d17790280a09/regex-2025.9.18-cp314-cp314-win_arm64.whl", hash = "sha256:6a4b44df31d34fa51aa5c995d3aa3c999cec4d69b9bd414a8be51984d859f06d", size = 271873, upload-time = "2025-09-19T00:37:39.125Z" },
+ { url = "https://files.pythonhosted.org/packages/99/cb/8a1ab05ecf404e18b54348e293d9b7a60ec2bd7aa59e637020c5eea852e8/regex-2025.9.18-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b176326bcd544b5e9b17d6943f807697c0cb7351f6cfb45bf5637c95ff7e6306", size = 489773, upload-time = "2025-09-19T00:37:40.968Z" },
+ { url = "https://files.pythonhosted.org/packages/93/3b/6543c9b7f7e734d2404fa2863d0d710c907bef99d4598760ed4563d634c3/regex-2025.9.18-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:0ffd9e230b826b15b369391bec167baed57c7ce39efc35835448618860995946", size = 291221, upload-time = "2025-09-19T00:37:42.901Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/91/e9fdee6ad6bf708d98c5d17fded423dcb0661795a49cba1b4ffb8358377a/regex-2025.9.18-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ec46332c41add73f2b57e2f5b642f991f6b15e50e9f86285e08ffe3a512ac39f", size = 289268, upload-time = "2025-09-19T00:37:44.823Z" },
+ { url = "https://files.pythonhosted.org/packages/94/a6/bc3e8a918abe4741dadeaeb6c508e3a4ea847ff36030d820d89858f96a6c/regex-2025.9.18-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b80fa342ed1ea095168a3f116637bd1030d39c9ff38dc04e54ef7c521e01fc95", size = 806659, upload-time = "2025-09-19T00:37:46.684Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/71/ea62dbeb55d9e6905c7b5a49f75615ea1373afcad95830047e4e310db979/regex-2025.9.18-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4d97071c0ba40f0cf2a93ed76e660654c399a0a04ab7d85472239460f3da84b", size = 871701, upload-time = "2025-09-19T00:37:48.882Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/90/fbe9dedb7dad24a3a4399c0bae64bfa932ec8922a0a9acf7bc88db30b161/regex-2025.9.18-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0ac936537ad87cef9e0e66c5144484206c1354224ee811ab1519a32373e411f3", size = 913742, upload-time = "2025-09-19T00:37:51.015Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/1c/47e4a8c0e73d41eb9eb9fdeba3b1b810110a5139a2526e82fd29c2d9f867/regex-2025.9.18-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dec57f96d4def58c422d212d414efe28218d58537b5445cf0c33afb1b4768571", size = 811117, upload-time = "2025-09-19T00:37:52.686Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/da/435f29fddfd015111523671e36d30af3342e8136a889159b05c1d9110480/regex-2025.9.18-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:48317233294648bf7cd068857f248e3a57222259a5304d32c7552e2284a1b2ad", size = 794647, upload-time = "2025-09-19T00:37:54.626Z" },
+ { url = "https://files.pythonhosted.org/packages/23/66/df5e6dcca25c8bc57ce404eebc7342310a0d218db739d7882c9a2b5974a3/regex-2025.9.18-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:274687e62ea3cf54846a9b25fc48a04459de50af30a7bd0b61a9e38015983494", size = 866747, upload-time = "2025-09-19T00:37:56.367Z" },
+ { url = "https://files.pythonhosted.org/packages/82/42/94392b39b531f2e469b2daa40acf454863733b674481fda17462a5ffadac/regex-2025.9.18-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a78722c86a3e7e6aadf9579e3b0ad78d955f2d1f1a8ca4f67d7ca258e8719d4b", size = 853434, upload-time = "2025-09-19T00:37:58.39Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/f8/dcc64c7f7bbe58842a8f89622b50c58c3598fbbf4aad0a488d6df2c699f1/regex-2025.9.18-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:06104cd203cdef3ade989a1c45b6215bf42f8b9dd705ecc220c173233f7cba41", size = 798024, upload-time = "2025-09-19T00:38:00.397Z" },
+ { url = "https://files.pythonhosted.org/packages/20/8d/edf1c5d5aa98f99a692313db813ec487732946784f8f93145e0153d910e5/regex-2025.9.18-cp314-cp314t-win32.whl", hash = "sha256:2e1eddc06eeaffd249c0adb6fafc19e2118e6308c60df9db27919e96b5656096", size = 273029, upload-time = "2025-09-19T00:38:02.383Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/24/02d4e4f88466f17b145f7ea2b2c11af3a942db6222429c2c146accf16054/regex-2025.9.18-cp314-cp314t-win_amd64.whl", hash = "sha256:8620d247fb8c0683ade51217b459cb4a1081c0405a3072235ba43a40d355c09a", size = 282680, upload-time = "2025-09-19T00:38:04.102Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/a3/c64894858aaaa454caa7cc47e2f225b04d3ed08ad649eacf58d45817fad2/regex-2025.9.18-cp314-cp314t-win_arm64.whl", hash = "sha256:b7531a8ef61de2c647cdf68b3229b071e46ec326b3138b2180acb4275f470b01", size = 273034, upload-time = "2025-09-19T00:38:05.807Z" },
+]
+
+[[package]]
+name = "requests"
+version = "2.32.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "charset-normalizer" },
+ { name = "idna" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
+]
+
+[[package]]
+name = "requests-oauthlib"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "oauthlib" },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" },
+]
+
+[[package]]
+name = "requests-toolbelt"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" },
+]
+
+[[package]]
+name = "retrying"
+version = "1.4.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c8/5a/b17e1e257d3e6f2e7758930e1256832c9ddd576f8631781e6a072914befa/retrying-1.4.2.tar.gz", hash = "sha256:d102e75d53d8d30b88562d45361d6c6c934da06fab31bd81c0420acb97a8ba39", size = 11411, upload-time = "2025-08-03T03:35:25.189Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/67/f3/6cd296376653270ac1b423bb30bd70942d9916b6978c6f40472d6ac038e7/retrying-1.4.2-py3-none-any.whl", hash = "sha256:bbc004aeb542a74f3569aeddf42a2516efefcdaff90df0eb38fbfbf19f179f59", size = 10859, upload-time = "2025-08-03T03:35:23.829Z" },
+]
+
+[[package]]
+name = "rich"
+version = "14.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" },
+]
+
+[[package]]
+name = "rpds-py"
+version = "0.27.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e9/dd/2c0cbe774744272b0ae725f44032c77bdcab6e8bcf544bffa3b6e70c8dba/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8", size = 27479, upload-time = "2025-08-27T12:16:36.024Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/fe/38de28dee5df58b8198c743fe2bea0c785c6d40941b9950bac4cdb71a014/rpds_py-0.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ae2775c1973e3c30316892737b91f9283f9908e3cc7625b9331271eaaed7dc90", size = 361887, upload-time = "2025-08-27T12:13:10.233Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/9a/4b6c7eedc7dd90986bf0fab6ea2a091ec11c01b15f8ba0a14d3f80450468/rpds_py-0.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2643400120f55c8a96f7c9d858f7be0c88d383cd4653ae2cf0d0c88f668073e5", size = 345795, upload-time = "2025-08-27T12:13:11.65Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/0e/e650e1b81922847a09cca820237b0edee69416a01268b7754d506ade11ad/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16323f674c089b0360674a4abd28d5042947d54ba620f72514d69be4ff64845e", size = 385121, upload-time = "2025-08-27T12:13:13.008Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/ea/b306067a712988e2bff00dcc7c8f31d26c29b6d5931b461aa4b60a013e33/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a1f4814b65eacac94a00fc9a526e3fdafd78e439469644032032d0d63de4881", size = 398976, upload-time = "2025-08-27T12:13:14.368Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/0a/26dc43c8840cb8fe239fe12dbc8d8de40f2365e838f3d395835dde72f0e5/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba32c16b064267b22f1850a34051121d423b6f7338a12b9459550eb2096e7ec", size = 525953, upload-time = "2025-08-27T12:13:15.774Z" },
+ { url = "https://files.pythonhosted.org/packages/22/14/c85e8127b573aaf3a0cbd7fbb8c9c99e735a4a02180c84da2a463b766e9e/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5c20f33fd10485b80f65e800bbe5f6785af510b9f4056c5a3c612ebc83ba6cb", size = 407915, upload-time = "2025-08-27T12:13:17.379Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/7b/8f4fee9ba1fb5ec856eb22d725a4efa3deb47f769597c809e03578b0f9d9/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466bfe65bd932da36ff279ddd92de56b042f2266d752719beb97b08526268ec5", size = 386883, upload-time = "2025-08-27T12:13:18.704Z" },
+ { url = "https://files.pythonhosted.org/packages/86/47/28fa6d60f8b74fcdceba81b272f8d9836ac0340570f68f5df6b41838547b/rpds_py-0.27.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:41e532bbdcb57c92ba3be62c42e9f096431b4cf478da9bc3bc6ce5c38ab7ba7a", size = 405699, upload-time = "2025-08-27T12:13:20.089Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/fd/c5987b5e054548df56953a21fe2ebed51fc1ec7c8f24fd41c067b68c4a0a/rpds_py-0.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f149826d742b406579466283769a8ea448eed82a789af0ed17b0cd5770433444", size = 423713, upload-time = "2025-08-27T12:13:21.436Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/ba/3c4978b54a73ed19a7d74531be37a8bcc542d917c770e14d372b8daea186/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80c60cfb5310677bd67cb1e85a1e8eb52e12529545441b43e6f14d90b878775a", size = 562324, upload-time = "2025-08-27T12:13:22.789Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/6c/6943a91768fec16db09a42b08644b960cff540c66aab89b74be6d4a144ba/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7ee6521b9baf06085f62ba9c7a3e5becffbc32480d2f1b351559c001c38ce4c1", size = 593646, upload-time = "2025-08-27T12:13:24.122Z" },
+ { url = "https://files.pythonhosted.org/packages/11/73/9d7a8f4be5f4396f011a6bb7a19fe26303a0dac9064462f5651ced2f572f/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a512c8263249a9d68cac08b05dd59d2b3f2061d99b322813cbcc14c3c7421998", size = 558137, upload-time = "2025-08-27T12:13:25.557Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/96/6772cbfa0e2485bcceef8071de7821f81aeac8bb45fbfd5542a3e8108165/rpds_py-0.27.1-cp312-cp312-win32.whl", hash = "sha256:819064fa048ba01b6dadc5116f3ac48610435ac9a0058bbde98e569f9e785c39", size = 221343, upload-time = "2025-08-27T12:13:26.967Z" },
+ { url = "https://files.pythonhosted.org/packages/67/b6/c82f0faa9af1c6a64669f73a17ee0eeef25aff30bb9a1c318509efe45d84/rpds_py-0.27.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9199717881f13c32c4046a15f024971a3b78ad4ea029e8da6b86e5aa9cf4594", size = 232497, upload-time = "2025-08-27T12:13:28.326Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/96/2817b44bd2ed11aebacc9251da03689d56109b9aba5e311297b6902136e2/rpds_py-0.27.1-cp312-cp312-win_arm64.whl", hash = "sha256:33aa65b97826a0e885ef6e278fbd934e98cdcfed80b63946025f01e2f5b29502", size = 222790, upload-time = "2025-08-27T12:13:29.71Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/77/610aeee8d41e39080c7e14afa5387138e3c9fa9756ab893d09d99e7d8e98/rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b", size = 361741, upload-time = "2025-08-27T12:13:31.039Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/fc/c43765f201c6a1c60be2043cbdb664013def52460a4c7adace89d6682bf4/rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf", size = 345574, upload-time = "2025-08-27T12:13:32.902Z" },
+ { url = "https://files.pythonhosted.org/packages/20/42/ee2b2ca114294cd9847d0ef9c26d2b0851b2e7e00bf14cc4c0b581df0fc3/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83", size = 385051, upload-time = "2025-08-27T12:13:34.228Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/e8/1e430fe311e4799e02e2d1af7c765f024e95e17d651612425b226705f910/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf", size = 398395, upload-time = "2025-08-27T12:13:36.132Z" },
+ { url = "https://files.pythonhosted.org/packages/82/95/9dc227d441ff2670651c27a739acb2535ccaf8b351a88d78c088965e5996/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2", size = 524334, upload-time = "2025-08-27T12:13:37.562Z" },
+ { url = "https://files.pythonhosted.org/packages/87/01/a670c232f401d9ad461d9a332aa4080cd3cb1d1df18213dbd0d2a6a7ab51/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0", size = 407691, upload-time = "2025-08-27T12:13:38.94Z" },
+ { url = "https://files.pythonhosted.org/packages/03/36/0a14aebbaa26fe7fab4780c76f2239e76cc95a0090bdb25e31d95c492fcd/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418", size = 386868, upload-time = "2025-08-27T12:13:40.192Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/03/8c897fb8b5347ff6c1cc31239b9611c5bf79d78c984430887a353e1409a1/rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d", size = 405469, upload-time = "2025-08-27T12:13:41.496Z" },
+ { url = "https://files.pythonhosted.org/packages/da/07/88c60edc2df74850d496d78a1fdcdc7b54360a7f610a4d50008309d41b94/rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274", size = 422125, upload-time = "2025-08-27T12:13:42.802Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/86/5f4c707603e41b05f191a749984f390dabcbc467cf833769b47bf14ba04f/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd", size = 562341, upload-time = "2025-08-27T12:13:44.472Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/92/3c0cb2492094e3cd9baf9e49bbb7befeceb584ea0c1a8b5939dca4da12e5/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2", size = 592511, upload-time = "2025-08-27T12:13:45.898Z" },
+ { url = "https://files.pythonhosted.org/packages/10/bb/82e64fbb0047c46a168faa28d0d45a7851cd0582f850b966811d30f67ad8/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002", size = 557736, upload-time = "2025-08-27T12:13:47.408Z" },
+ { url = "https://files.pythonhosted.org/packages/00/95/3c863973d409210da7fb41958172c6b7dbe7fc34e04d3cc1f10bb85e979f/rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3", size = 221462, upload-time = "2025-08-27T12:13:48.742Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/2c/5867b14a81dc217b56d95a9f2a40fdbc56a1ab0181b80132beeecbd4b2d6/rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83", size = 232034, upload-time = "2025-08-27T12:13:50.11Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/78/3958f3f018c01923823f1e47f1cc338e398814b92d83cd278364446fac66/rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d", size = 222392, upload-time = "2025-08-27T12:13:52.587Z" },
+ { url = "https://files.pythonhosted.org/packages/01/76/1cdf1f91aed5c3a7bf2eba1f1c4e4d6f57832d73003919a20118870ea659/rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228", size = 358355, upload-time = "2025-08-27T12:13:54.012Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/6f/bf142541229374287604caf3bb2a4ae17f0a580798fd72d3b009b532db4e/rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92", size = 342138, upload-time = "2025-08-27T12:13:55.791Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/77/355b1c041d6be40886c44ff5e798b4e2769e497b790f0f7fd1e78d17e9a8/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2", size = 380247, upload-time = "2025-08-27T12:13:57.683Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/a4/d9cef5c3946ea271ce2243c51481971cd6e34f21925af2783dd17b26e815/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723", size = 390699, upload-time = "2025-08-27T12:13:59.137Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/06/005106a7b8c6c1a7e91b73169e49870f4af5256119d34a361ae5240a0c1d/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802", size = 521852, upload-time = "2025-08-27T12:14:00.583Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/3e/50fb1dac0948e17a02eb05c24510a8fe12d5ce8561c6b7b7d1339ab7ab9c/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f", size = 402582, upload-time = "2025-08-27T12:14:02.034Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/b0/f4e224090dc5b0ec15f31a02d746ab24101dd430847c4d99123798661bfc/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2", size = 384126, upload-time = "2025-08-27T12:14:03.437Z" },
+ { url = "https://files.pythonhosted.org/packages/54/77/ac339d5f82b6afff1df8f0fe0d2145cc827992cb5f8eeb90fc9f31ef7a63/rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21", size = 399486, upload-time = "2025-08-27T12:14:05.443Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/29/3e1c255eee6ac358c056a57d6d6869baa00a62fa32eea5ee0632039c50a3/rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef", size = 414832, upload-time = "2025-08-27T12:14:06.902Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/db/6d498b844342deb3fa1d030598db93937a9964fcf5cb4da4feb5f17be34b/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081", size = 557249, upload-time = "2025-08-27T12:14:08.37Z" },
+ { url = "https://files.pythonhosted.org/packages/60/f3/690dd38e2310b6f68858a331399b4d6dbb9132c3e8ef8b4333b96caf403d/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd", size = 587356, upload-time = "2025-08-27T12:14:10.034Z" },
+ { url = "https://files.pythonhosted.org/packages/86/e3/84507781cccd0145f35b1dc32c72675200c5ce8d5b30f813e49424ef68fc/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7", size = 555300, upload-time = "2025-08-27T12:14:11.783Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/ee/375469849e6b429b3516206b4580a79e9ef3eb12920ddbd4492b56eaacbe/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688", size = 216714, upload-time = "2025-08-27T12:14:13.629Z" },
+ { url = "https://files.pythonhosted.org/packages/21/87/3fc94e47c9bd0742660e84706c311a860dcae4374cf4a03c477e23ce605a/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797", size = 228943, upload-time = "2025-08-27T12:14:14.937Z" },
+ { url = "https://files.pythonhosted.org/packages/70/36/b6e6066520a07cf029d385de869729a895917b411e777ab1cde878100a1d/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334", size = 362472, upload-time = "2025-08-27T12:14:16.333Z" },
+ { url = "https://files.pythonhosted.org/packages/af/07/b4646032e0dcec0df9c73a3bd52f63bc6c5f9cda992f06bd0e73fe3fbebd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33", size = 345676, upload-time = "2025-08-27T12:14:17.764Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/16/2f1003ee5d0af4bcb13c0cf894957984c32a6751ed7206db2aee7379a55e/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a", size = 385313, upload-time = "2025-08-27T12:14:19.829Z" },
+ { url = "https://files.pythonhosted.org/packages/05/cd/7eb6dd7b232e7f2654d03fa07f1414d7dfc980e82ba71e40a7c46fd95484/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b", size = 399080, upload-time = "2025-08-27T12:14:21.531Z" },
+ { url = "https://files.pythonhosted.org/packages/20/51/5829afd5000ec1cb60f304711f02572d619040aa3ec033d8226817d1e571/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7", size = 523868, upload-time = "2025-08-27T12:14:23.485Z" },
+ { url = "https://files.pythonhosted.org/packages/05/2c/30eebca20d5db95720ab4d2faec1b5e4c1025c473f703738c371241476a2/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136", size = 408750, upload-time = "2025-08-27T12:14:24.924Z" },
+ { url = "https://files.pythonhosted.org/packages/90/1a/cdb5083f043597c4d4276eae4e4c70c55ab5accec078da8611f24575a367/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff", size = 387688, upload-time = "2025-08-27T12:14:27.537Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/92/cf786a15320e173f945d205ab31585cc43969743bb1a48b6888f7a2b0a2d/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9", size = 407225, upload-time = "2025-08-27T12:14:28.981Z" },
+ { url = "https://files.pythonhosted.org/packages/33/5c/85ee16df5b65063ef26017bef33096557a4c83fbe56218ac7cd8c235f16d/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60", size = 423361, upload-time = "2025-08-27T12:14:30.469Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/8e/1c2741307fcabd1a334ecf008e92c4f47bb6f848712cf15c923becfe82bb/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e", size = 562493, upload-time = "2025-08-27T12:14:31.987Z" },
+ { url = "https://files.pythonhosted.org/packages/04/03/5159321baae9b2222442a70c1f988cbbd66b9be0675dd3936461269be360/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212", size = 592623, upload-time = "2025-08-27T12:14:33.543Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/39/c09fd1ad28b85bc1d4554a8710233c9f4cefd03d7717a1b8fbfd171d1167/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675", size = 558800, upload-time = "2025-08-27T12:14:35.436Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/d6/99228e6bbcf4baa764b18258f519a9035131d91b538d4e0e294313462a98/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3", size = 221943, upload-time = "2025-08-27T12:14:36.898Z" },
+ { url = "https://files.pythonhosted.org/packages/be/07/c802bc6b8e95be83b79bdf23d1aa61d68324cb1006e245d6c58e959e314d/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456", size = 233739, upload-time = "2025-08-27T12:14:38.386Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/89/3e1b1c16d4c2d547c5717377a8df99aee8099ff050f87c45cb4d5fa70891/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3", size = 223120, upload-time = "2025-08-27T12:14:39.82Z" },
+ { url = "https://files.pythonhosted.org/packages/62/7e/dc7931dc2fa4a6e46b2a4fa744a9fe5c548efd70e0ba74f40b39fa4a8c10/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2", size = 358944, upload-time = "2025-08-27T12:14:41.199Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/22/4af76ac4e9f336bfb1a5f240d18a33c6b2fcaadb7472ac7680576512b49a/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4", size = 342283, upload-time = "2025-08-27T12:14:42.699Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/15/2a7c619b3c2272ea9feb9ade67a45c40b3eeb500d503ad4c28c395dc51b4/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e", size = 380320, upload-time = "2025-08-27T12:14:44.157Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/7d/4c6d243ba4a3057e994bb5bedd01b5c963c12fe38dde707a52acdb3849e7/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817", size = 391760, upload-time = "2025-08-27T12:14:45.845Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/71/b19401a909b83bcd67f90221330bc1ef11bc486fe4e04c24388d28a618ae/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec", size = 522476, upload-time = "2025-08-27T12:14:47.364Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/44/1a3b9715c0455d2e2f0f6df5ee6d6f5afdc423d0773a8a682ed2b43c566c/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a", size = 403418, upload-time = "2025-08-27T12:14:49.991Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/4b/fb6c4f14984eb56673bc868a66536f53417ddb13ed44b391998100a06a96/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8", size = 384771, upload-time = "2025-08-27T12:14:52.159Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/56/d5265d2d28b7420d7b4d4d85cad8ef891760f5135102e60d5c970b976e41/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48", size = 400022, upload-time = "2025-08-27T12:14:53.859Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/e9/9f5fc70164a569bdd6ed9046486c3568d6926e3a49bdefeeccfb18655875/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb", size = 416787, upload-time = "2025-08-27T12:14:55.673Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/64/56dd03430ba491db943a81dcdef115a985aac5f44f565cd39a00c766d45c/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734", size = 557538, upload-time = "2025-08-27T12:14:57.245Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/36/92cc885a3129993b1d963a2a42ecf64e6a8e129d2c7cc980dbeba84e55fb/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb", size = 588512, upload-time = "2025-08-27T12:14:58.728Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/10/6b283707780a81919f71625351182b4f98932ac89a09023cb61865136244/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0", size = 555813, upload-time = "2025-08-27T12:15:00.334Z" },
+ { url = "https://files.pythonhosted.org/packages/04/2e/30b5ea18c01379da6272a92825dd7e53dc9d15c88a19e97932d35d430ef7/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a", size = 217385, upload-time = "2025-08-27T12:15:01.937Z" },
+ { url = "https://files.pythonhosted.org/packages/32/7d/97119da51cb1dd3f2f3c0805f155a3aa4a95fa44fe7d78ae15e69edf4f34/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772", size = 230097, upload-time = "2025-08-27T12:15:03.961Z" },
+]
+
+[[package]]
+name = "rsa"
+version = "4.9.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyasn1" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" },
+]
+
+[[package]]
+name = "ruff"
+version = "0.13.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/02/df/8d7d8c515d33adfc540e2edf6c6021ea1c5a58a678d8cfce9fae59aabcab/ruff-0.13.2.tar.gz", hash = "sha256:cb12fffd32fb16d32cef4ed16d8c7cdc27ed7c944eaa98d99d01ab7ab0b710ff", size = 5416417, upload-time = "2025-09-25T14:54:09.936Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6e/84/5716a7fa4758e41bf70e603e13637c42cfb9dbf7ceb07180211b9bbf75ef/ruff-0.13.2-py3-none-linux_armv6l.whl", hash = "sha256:3796345842b55f033a78285e4f1641078f902020d8450cade03aad01bffd81c3", size = 12343254, upload-time = "2025-09-25T14:53:27.784Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/77/c7042582401bb9ac8eff25360e9335e901d7a1c0749a2b28ba4ecb239991/ruff-0.13.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ff7e4dda12e683e9709ac89e2dd436abf31a4d8a8fc3d89656231ed808e231d2", size = 13040891, upload-time = "2025-09-25T14:53:31.38Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/15/125a7f76eb295cb34d19c6778e3a82ace33730ad4e6f28d3427e134a02e0/ruff-0.13.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c75e9d2a2fafd1fdd895d0e7e24b44355984affdde1c412a6f6d3f6e16b22d46", size = 12243588, upload-time = "2025-09-25T14:53:33.543Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/eb/0093ae04a70f81f8be7fd7ed6456e926b65d238fc122311293d033fdf91e/ruff-0.13.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cceac74e7bbc53ed7d15d1042ffe7b6577bf294611ad90393bf9b2a0f0ec7cb6", size = 12491359, upload-time = "2025-09-25T14:53:35.892Z" },
+ { url = "https://files.pythonhosted.org/packages/43/fe/72b525948a6956f07dad4a6f122336b6a05f2e3fd27471cea612349fedb9/ruff-0.13.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6ae3f469b5465ba6d9721383ae9d49310c19b452a161b57507764d7ef15f4b07", size = 12162486, upload-time = "2025-09-25T14:53:38.171Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/e3/0fac422bbbfb2ea838023e0d9fcf1f30183d83ab2482800e2cb892d02dfe/ruff-0.13.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f8f9e3cd6714358238cd6626b9d43026ed19c0c018376ac1ef3c3a04ffb42d8", size = 13871203, upload-time = "2025-09-25T14:53:41.943Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/82/b721c8e3ec5df6d83ba0e45dcf00892c4f98b325256c42c38ef136496cbf/ruff-0.13.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c6ed79584a8f6cbe2e5d7dbacf7cc1ee29cbdb5df1172e77fbdadc8bb85a1f89", size = 14929635, upload-time = "2025-09-25T14:53:43.953Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/a0/ad56faf6daa507b83079a1ad7a11694b87d61e6bf01c66bd82b466f21821/ruff-0.13.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aed130b2fde049cea2019f55deb939103123cdd191105f97a0599a3e753d61b0", size = 14338783, upload-time = "2025-09-25T14:53:46.205Z" },
+ { url = "https://files.pythonhosted.org/packages/47/77/ad1d9156db8f99cd01ee7e29d74b34050e8075a8438e589121fcd25c4b08/ruff-0.13.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1887c230c2c9d65ed1b4e4cfe4d255577ea28b718ae226c348ae68df958191aa", size = 13355322, upload-time = "2025-09-25T14:53:48.164Z" },
+ { url = "https://files.pythonhosted.org/packages/64/8b/e87cfca2be6f8b9f41f0bb12dc48c6455e2d66df46fe61bb441a226f1089/ruff-0.13.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5bcb10276b69b3cfea3a102ca119ffe5c6ba3901e20e60cf9efb53fa417633c3", size = 13354427, upload-time = "2025-09-25T14:53:50.486Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/df/bf382f3fbead082a575edb860897287f42b1b3c694bafa16bc9904c11ed3/ruff-0.13.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:afa721017aa55a555b2ff7944816587f1cb813c2c0a882d158f59b832da1660d", size = 13537637, upload-time = "2025-09-25T14:53:52.887Z" },
+ { url = "https://files.pythonhosted.org/packages/51/70/1fb7a7c8a6fc8bd15636288a46e209e81913b87988f26e1913d0851e54f4/ruff-0.13.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1dbc875cf3720c64b3990fef8939334e74cb0ca65b8dbc61d1f439201a38101b", size = 12340025, upload-time = "2025-09-25T14:53:54.88Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/27/1e5b3f1c23ca5dd4106d9d580e5c13d9acb70288bff614b3d7b638378cc9/ruff-0.13.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b939a1b2a960e9742e9a347e5bbc9b3c3d2c716f86c6ae273d9cbd64f193f22", size = 12133449, upload-time = "2025-09-25T14:53:57.089Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/09/b92a5ccee289f11ab128df57d5911224197d8d55ef3bd2043534ff72ca54/ruff-0.13.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:50e2d52acb8de3804fc5f6e2fa3ae9bdc6812410a9e46837e673ad1f90a18736", size = 13051369, upload-time = "2025-09-25T14:53:59.124Z" },
+ { url = "https://files.pythonhosted.org/packages/89/99/26c9d1c7d8150f45e346dc045cc49f23e961efceb4a70c47dea0960dea9a/ruff-0.13.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3196bc13ab2110c176b9a4ae5ff7ab676faaa1964b330a1383ba20e1e19645f2", size = 13523644, upload-time = "2025-09-25T14:54:01.622Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/00/e7f1501e81e8ec290e79527827af1d88f541d8d26151751b46108978dade/ruff-0.13.2-py3-none-win32.whl", hash = "sha256:7c2a0b7c1e87795fec3404a485096bcd790216c7c146a922d121d8b9c8f1aaac", size = 12245990, upload-time = "2025-09-25T14:54:03.647Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/bd/d9f33a73de84fafd0146c6fba4f497c4565fe8fa8b46874b8e438869abc2/ruff-0.13.2-py3-none-win_amd64.whl", hash = "sha256:17d95fb32218357c89355f6f6f9a804133e404fc1f65694372e02a557edf8585", size = 13324004, upload-time = "2025-09-25T14:54:06.05Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/12/28fa2f597a605884deb0f65c1b1ae05111051b2a7030f5d8a4ff7f4599ba/ruff-0.13.2-py3-none-win_arm64.whl", hash = "sha256:da711b14c530412c827219312b7d7fbb4877fb31150083add7e8c5336549cea7", size = 12484437, upload-time = "2025-09-25T14:54:08.022Z" },
+]
+
+[[package]]
+name = "safehttpx"
+version = "0.1.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "httpx" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/67/4c/19db75e6405692b2a96af8f06d1258f8aa7290bdc35ac966f03e207f6d7f/safehttpx-0.1.6.tar.gz", hash = "sha256:b356bfc82cee3a24c395b94a2dbeabbed60aff1aa5fa3b5fe97c4f2456ebce42", size = 9987, upload-time = "2024-12-02T18:44:10.226Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4d/c0/1108ad9f01567f66b3154063605b350b69c3c9366732e09e45f9fd0d1deb/safehttpx-0.1.6-py3-none-any.whl", hash = "sha256:407cff0b410b071623087c63dd2080c3b44dc076888d8c5823c00d1e58cb381c", size = 8692, upload-time = "2024-12-02T18:44:08.555Z" },
+]
+
+[[package]]
+name = "safetensors"
+version = "0.6.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ac/cc/738f3011628920e027a11754d9cae9abec1aed00f7ae860abbf843755233/safetensors-0.6.2.tar.gz", hash = "sha256:43ff2aa0e6fa2dc3ea5524ac7ad93a9839256b8703761e76e2d0b2a3fa4f15d9", size = 197968, upload-time = "2025-08-08T13:13:58.654Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4d/b1/3f5fd73c039fc87dba3ff8b5d528bfc5a32b597fea8e7a6a4800343a17c7/safetensors-0.6.2-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9c85ede8ec58f120bad982ec47746981e210492a6db876882aa021446af8ffba", size = 454797, upload-time = "2025-08-08T13:13:52.066Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/c9/bb114c158540ee17907ec470d01980957fdaf87b4aa07914c24eba87b9c6/safetensors-0.6.2-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d6675cf4b39c98dbd7d940598028f3742e0375a6b4d4277e76beb0c35f4b843b", size = 432206, upload-time = "2025-08-08T13:13:50.931Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/8e/f70c34e47df3110e8e0bb268d90db8d4be8958a54ab0336c9be4fe86dac8/safetensors-0.6.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d2d2b3ce1e2509c68932ca03ab8f20570920cd9754b05063d4368ee52833ecd", size = 473261, upload-time = "2025-08-08T13:13:41.259Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/f5/be9c6a7c7ef773e1996dc214e73485286df1836dbd063e8085ee1976f9cb/safetensors-0.6.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:93de35a18f46b0f5a6a1f9e26d91b442094f2df02e9fd7acf224cfec4238821a", size = 485117, upload-time = "2025-08-08T13:13:43.506Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/55/23f2d0a2c96ed8665bf17a30ab4ce5270413f4d74b6d87dd663258b9af31/safetensors-0.6.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89a89b505f335640f9120fac65ddeb83e40f1fd081cb8ed88b505bdccec8d0a1", size = 616154, upload-time = "2025-08-08T13:13:45.096Z" },
+ { url = "https://files.pythonhosted.org/packages/98/c6/affb0bd9ce02aa46e7acddbe087912a04d953d7a4d74b708c91b5806ef3f/safetensors-0.6.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc4d0d0b937e04bdf2ae6f70cd3ad51328635fe0e6214aa1fc811f3b576b3bda", size = 520713, upload-time = "2025-08-08T13:13:46.25Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/5d/5a514d7b88e310c8b146e2404e0dc161282e78634d9358975fd56dfd14be/safetensors-0.6.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8045db2c872db8f4cbe3faa0495932d89c38c899c603f21e9b6486951a5ecb8f", size = 485835, upload-time = "2025-08-08T13:13:49.373Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/7b/4fc3b2ba62c352b2071bea9cfbad330fadda70579f617506ae1a2f129cab/safetensors-0.6.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:81e67e8bab9878bb568cffbc5f5e655adb38d2418351dc0859ccac158f753e19", size = 521503, upload-time = "2025-08-08T13:13:47.651Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/50/0057e11fe1f3cead9254315a6c106a16dd4b1a19cd247f7cc6414f6b7866/safetensors-0.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0e4d029ab0a0e0e4fdf142b194514695b1d7d3735503ba700cf36d0fc7136ce", size = 652256, upload-time = "2025-08-08T13:13:53.167Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/29/473f789e4ac242593ac1656fbece6e1ecd860bb289e635e963667807afe3/safetensors-0.6.2-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:fa48268185c52bfe8771e46325a1e21d317207bcabcb72e65c6e28e9ffeb29c7", size = 747281, upload-time = "2025-08-08T13:13:54.656Z" },
+ { url = "https://files.pythonhosted.org/packages/68/52/f7324aad7f2df99e05525c84d352dc217e0fa637a4f603e9f2eedfbe2c67/safetensors-0.6.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:d83c20c12c2d2f465997c51b7ecb00e407e5f94d7dec3ea0cc11d86f60d3fde5", size = 692286, upload-time = "2025-08-08T13:13:55.884Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/fe/cad1d9762868c7c5dc70c8620074df28ebb1a8e4c17d4c0cb031889c457e/safetensors-0.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d944cea65fad0ead848b6ec2c37cc0b197194bec228f8020054742190e9312ac", size = 655957, upload-time = "2025-08-08T13:13:57.029Z" },
+ { url = "https://files.pythonhosted.org/packages/59/a7/e2158e17bbe57d104f0abbd95dff60dda916cf277c9f9663b4bf9bad8b6e/safetensors-0.6.2-cp38-abi3-win32.whl", hash = "sha256:cab75ca7c064d3911411461151cb69380c9225798a20e712b102edda2542ddb1", size = 308926, upload-time = "2025-08-08T13:14:01.095Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/c3/c0be1135726618dc1e28d181b8c442403d8dbb9e273fd791de2d4384bcdd/safetensors-0.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:c7b214870df923cbc1593c3faee16bec59ea462758699bd3fee399d00aac072c", size = 320192, upload-time = "2025-08-08T13:13:59.467Z" },
+]
+
+[[package]]
+name = "scikit-learn"
+version = "1.7.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "joblib" },
+ { name = "numpy" },
+ { name = "scipy" },
+ { name = "threadpoolctl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a7/aa/3996e2196075689afb9fce0410ebdb4a09099d7964d061d7213700204409/scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96", size = 9259818, upload-time = "2025-09-09T08:20:43.19Z" },
+ { url = "https://files.pythonhosted.org/packages/43/5d/779320063e88af9c4a7c2cf463ff11c21ac9c8bd730c4a294b0000b666c9/scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476", size = 8636997, upload-time = "2025-09-09T08:20:45.468Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/d0/0c577d9325b05594fdd33aa970bf53fb673f051a45496842caee13cfd7fe/scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b", size = 9478381, upload-time = "2025-09-09T08:20:47.982Z" },
+ { url = "https://files.pythonhosted.org/packages/82/70/8bf44b933837ba8494ca0fc9a9ab60f1c13b062ad0197f60a56e2fc4c43e/scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44", size = 9300296, upload-time = "2025-09-09T08:20:50.366Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/99/ed35197a158f1fdc2fe7c3680e9c70d0128f662e1fee4ed495f4b5e13db0/scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290", size = 8731256, upload-time = "2025-09-09T08:20:52.627Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/93/a3038cb0293037fd335f77f31fe053b89c72f17b1c8908c576c29d953e84/scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7", size = 9212382, upload-time = "2025-09-09T08:20:54.731Z" },
+ { url = "https://files.pythonhosted.org/packages/40/dd/9a88879b0c1104259136146e4742026b52df8540c39fec21a6383f8292c7/scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe", size = 8592042, upload-time = "2025-09-09T08:20:57.313Z" },
+ { url = "https://files.pythonhosted.org/packages/46/af/c5e286471b7d10871b811b72ae794ac5fe2989c0a2df07f0ec723030f5f5/scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f", size = 9434180, upload-time = "2025-09-09T08:20:59.671Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/fd/df59faa53312d585023b2da27e866524ffb8faf87a68516c23896c718320/scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0", size = 9283660, upload-time = "2025-09-09T08:21:01.71Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/c7/03000262759d7b6f38c836ff9d512f438a70d8a8ddae68ee80de72dcfb63/scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c", size = 8702057, upload-time = "2025-09-09T08:21:04.234Z" },
+ { url = "https://files.pythonhosted.org/packages/55/87/ef5eb1f267084532c8e4aef98a28b6ffe7425acbfd64b5e2f2e066bc29b3/scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8", size = 9558731, upload-time = "2025-09-09T08:21:06.381Z" },
+ { url = "https://files.pythonhosted.org/packages/93/f8/6c1e3fc14b10118068d7938878a9f3f4e6d7b74a8ddb1e5bed65159ccda8/scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a", size = 9038852, upload-time = "2025-09-09T08:21:08.628Z" },
+ { url = "https://files.pythonhosted.org/packages/83/87/066cafc896ee540c34becf95d30375fe5cbe93c3b75a0ee9aa852cd60021/scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c", size = 9527094, upload-time = "2025-09-09T08:21:11.486Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/2b/4903e1ccafa1f6453b1ab78413938c8800633988c838aa0be386cbb33072/scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c", size = 9367436, upload-time = "2025-09-09T08:21:13.602Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/aa/8444be3cfb10451617ff9d177b3c190288f4563e6c50ff02728be67ad094/scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973", size = 9275749, upload-time = "2025-09-09T08:21:15.96Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/82/dee5acf66837852e8e68df6d8d3a6cb22d3df997b733b032f513d95205b7/scikit_learn-1.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fa8f63940e29c82d1e67a45d5297bdebbcb585f5a5a50c4914cc2e852ab77f33", size = 9208906, upload-time = "2025-09-09T08:21:18.557Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/30/9029e54e17b87cb7d50d51a5926429c683d5b4c1732f0507a6c3bed9bf65/scikit_learn-1.7.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f95dc55b7902b91331fa4e5845dd5bde0580c9cd9612b1b2791b7e80c3d32615", size = 8627836, upload-time = "2025-09-09T08:21:20.695Z" },
+ { url = "https://files.pythonhosted.org/packages/60/18/4a52c635c71b536879f4b971c2cedf32c35ee78f48367885ed8025d1f7ee/scikit_learn-1.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9656e4a53e54578ad10a434dc1f993330568cfee176dff07112b8785fb413106", size = 9426236, upload-time = "2025-09-09T08:21:22.645Z" },
+ { url = "https://files.pythonhosted.org/packages/99/7e/290362f6ab582128c53445458a5befd471ed1ea37953d5bcf80604619250/scikit_learn-1.7.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96dc05a854add0e50d3f47a1ef21a10a595016da5b007c7d9cd9d0bffd1fcc61", size = 9312593, upload-time = "2025-09-09T08:21:24.65Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/87/24f541b6d62b1794939ae6422f8023703bbf6900378b2b34e0b4384dfefd/scikit_learn-1.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:bb24510ed3f9f61476181e4db51ce801e2ba37541def12dc9333b946fc7a9cf8", size = 8820007, upload-time = "2025-09-09T08:21:26.713Z" },
+]
+
+[[package]]
+name = "scipy"
+version = "1.16.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4c/3b/546a6f0bfe791bbb7f8d591613454d15097e53f906308ec6f7c1ce588e8e/scipy-1.16.2.tar.gz", hash = "sha256:af029b153d243a80afb6eabe40b0a07f8e35c9adc269c019f364ad747f826a6b", size = 30580599, upload-time = "2025-09-11T17:48:08.271Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/8d/6396e00db1282279a4ddd507c5f5e11f606812b608ee58517ce8abbf883f/scipy-1.16.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:89d6c100fa5c48472047632e06f0876b3c4931aac1f4291afc81a3644316bb0d", size = 36646259, upload-time = "2025-09-11T17:40:39.329Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/93/ea9edd7e193fceb8eef149804491890bde73fb169c896b61aa3e2d1e4e77/scipy-1.16.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ca748936cd579d3f01928b30a17dc474550b01272d8046e3e1ee593f23620371", size = 28888976, upload-time = "2025-09-11T17:40:46.82Z" },
+ { url = "https://files.pythonhosted.org/packages/91/4d/281fddc3d80fd738ba86fd3aed9202331180b01e2c78eaae0642f22f7e83/scipy-1.16.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:fac4f8ce2ddb40e2e3d0f7ec36d2a1e7f92559a2471e59aec37bd8d9de01fec0", size = 20879905, upload-time = "2025-09-11T17:40:52.545Z" },
+ { url = "https://files.pythonhosted.org/packages/69/40/b33b74c84606fd301b2915f0062e45733c6ff5708d121dd0deaa8871e2d0/scipy-1.16.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:033570f1dcefd79547a88e18bccacff025c8c647a330381064f561d43b821232", size = 23553066, upload-time = "2025-09-11T17:40:59.014Z" },
+ { url = "https://files.pythonhosted.org/packages/55/a7/22c739e2f21a42cc8f16bc76b47cff4ed54fbe0962832c589591c2abec34/scipy-1.16.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ea3421209bf00c8a5ef2227de496601087d8f638a2363ee09af059bd70976dc1", size = 33336407, upload-time = "2025-09-11T17:41:06.796Z" },
+ { url = "https://files.pythonhosted.org/packages/53/11/a0160990b82999b45874dc60c0c183d3a3a969a563fffc476d5a9995c407/scipy-1.16.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f66bd07ba6f84cd4a380b41d1bf3c59ea488b590a2ff96744845163309ee8e2f", size = 35673281, upload-time = "2025-09-11T17:41:15.055Z" },
+ { url = "https://files.pythonhosted.org/packages/96/53/7ef48a4cfcf243c3d0f1643f5887c81f29fdf76911c4e49331828e19fc0a/scipy-1.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e9feab931bd2aea4a23388c962df6468af3d808ddf2d40f94a81c5dc38f32ef", size = 36004222, upload-time = "2025-09-11T17:41:23.868Z" },
+ { url = "https://files.pythonhosted.org/packages/49/7f/71a69e0afd460049d41c65c630c919c537815277dfea214031005f474d78/scipy-1.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03dfc75e52f72cf23ec2ced468645321407faad8f0fe7b1f5b49264adbc29cb1", size = 38664586, upload-time = "2025-09-11T17:41:31.021Z" },
+ { url = "https://files.pythonhosted.org/packages/34/95/20e02ca66fb495a95fba0642fd48e0c390d0ece9b9b14c6e931a60a12dea/scipy-1.16.2-cp312-cp312-win_amd64.whl", hash = "sha256:0ce54e07bbb394b417457409a64fd015be623f36e330ac49306433ffe04bc97e", size = 38550641, upload-time = "2025-09-11T17:41:36.61Z" },
+ { url = "https://files.pythonhosted.org/packages/92/ad/13646b9beb0a95528ca46d52b7babafbe115017814a611f2065ee4e61d20/scipy-1.16.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a8ffaa4ac0df81a0b94577b18ee079f13fecdb924df3328fc44a7dc5ac46851", size = 25456070, upload-time = "2025-09-11T17:41:41.3Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/27/c5b52f1ee81727a9fc457f5ac1e9bf3d6eab311805ea615c83c27ba06400/scipy-1.16.2-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:84f7bf944b43e20b8a894f5fe593976926744f6c185bacfcbdfbb62736b5cc70", size = 36604856, upload-time = "2025-09-11T17:41:47.695Z" },
+ { url = "https://files.pythonhosted.org/packages/32/a9/15c20d08e950b540184caa8ced675ba1128accb0e09c653780ba023a4110/scipy-1.16.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5c39026d12edc826a1ef2ad35ad1e6d7f087f934bb868fc43fa3049c8b8508f9", size = 28864626, upload-time = "2025-09-11T17:41:52.642Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/fc/ea36098df653cca26062a627c1a94b0de659e97127c8491e18713ca0e3b9/scipy-1.16.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e52729ffd45b68777c5319560014d6fd251294200625d9d70fd8626516fc49f5", size = 20855689, upload-time = "2025-09-11T17:41:57.886Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/6f/d0b53be55727f3e6d7c72687ec18ea6d0047cf95f1f77488b99a2bafaee1/scipy-1.16.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:024dd4a118cccec09ca3209b7e8e614931a6ffb804b2a601839499cb88bdf925", size = 23512151, upload-time = "2025-09-11T17:42:02.303Z" },
+ { url = "https://files.pythonhosted.org/packages/11/85/bf7dab56e5c4b1d3d8eef92ca8ede788418ad38a7dc3ff50262f00808760/scipy-1.16.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7a5dc7ee9c33019973a470556081b0fd3c9f4c44019191039f9769183141a4d9", size = 33329824, upload-time = "2025-09-11T17:42:07.549Z" },
+ { url = "https://files.pythonhosted.org/packages/da/6a/1a927b14ddc7714111ea51f4e568203b2bb6ed59bdd036d62127c1a360c8/scipy-1.16.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c2275ff105e508942f99d4e3bc56b6ef5e4b3c0af970386ca56b777608ce95b7", size = 35681881, upload-time = "2025-09-11T17:42:13.255Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/5f/331148ea5780b4fcc7007a4a6a6ee0a0c1507a796365cc642d4d226e1c3a/scipy-1.16.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af80196eaa84f033e48444d2e0786ec47d328ba00c71e4299b602235ffef9acb", size = 36006219, upload-time = "2025-09-11T17:42:18.765Z" },
+ { url = "https://files.pythonhosted.org/packages/46/3a/e991aa9d2aec723b4a8dcfbfc8365edec5d5e5f9f133888067f1cbb7dfc1/scipy-1.16.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9fb1eb735fe3d6ed1f89918224e3385fbf6f9e23757cacc35f9c78d3b712dd6e", size = 38682147, upload-time = "2025-09-11T17:42:25.177Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/57/0f38e396ad19e41b4c5db66130167eef8ee620a49bc7d0512e3bb67e0cab/scipy-1.16.2-cp313-cp313-win_amd64.whl", hash = "sha256:fda714cf45ba43c9d3bae8f2585c777f64e3f89a2e073b668b32ede412d8f52c", size = 38520766, upload-time = "2025-09-11T17:43:25.342Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/a5/85d3e867b6822d331e26c862a91375bb7746a0b458db5effa093d34cdb89/scipy-1.16.2-cp313-cp313-win_arm64.whl", hash = "sha256:2f5350da923ccfd0b00e07c3e5cfb316c1c0d6c1d864c07a72d092e9f20db104", size = 25451169, upload-time = "2025-09-11T17:43:30.198Z" },
+ { url = "https://files.pythonhosted.org/packages/09/d9/60679189bcebda55992d1a45498de6d080dcaf21ce0c8f24f888117e0c2d/scipy-1.16.2-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:53d8d2ee29b925344c13bda64ab51785f016b1b9617849dac10897f0701b20c1", size = 37012682, upload-time = "2025-09-11T17:42:30.677Z" },
+ { url = "https://files.pythonhosted.org/packages/83/be/a99d13ee4d3b7887a96f8c71361b9659ba4ef34da0338f14891e102a127f/scipy-1.16.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:9e05e33657efb4c6a9d23bd8300101536abd99c85cca82da0bffff8d8764d08a", size = 29389926, upload-time = "2025-09-11T17:42:35.845Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/0a/130164a4881cec6ca8c00faf3b57926f28ed429cd6001a673f83c7c2a579/scipy-1.16.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:7fe65b36036357003b3ef9d37547abeefaa353b237e989c21027b8ed62b12d4f", size = 21381152, upload-time = "2025-09-11T17:42:40.07Z" },
+ { url = "https://files.pythonhosted.org/packages/47/a6/503ffb0310ae77fba874e10cddfc4a1280bdcca1d13c3751b8c3c2996cf8/scipy-1.16.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6406d2ac6d40b861cccf57f49592f9779071655e9f75cd4f977fa0bdd09cb2e4", size = 23914410, upload-time = "2025-09-11T17:42:44.313Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/c7/1147774bcea50d00c02600aadaa919facbd8537997a62496270133536ed6/scipy-1.16.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff4dc42bd321991fbf611c23fc35912d690f731c9914bf3af8f417e64aca0f21", size = 33481880, upload-time = "2025-09-11T17:42:49.325Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/74/99d5415e4c3e46b2586f30cdbecb95e101c7192628a484a40dd0d163811a/scipy-1.16.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:654324826654d4d9133e10675325708fb954bc84dae6e9ad0a52e75c6b1a01d7", size = 35791425, upload-time = "2025-09-11T17:42:54.711Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/ee/a6559de7c1cc710e938c0355d9d4fbcd732dac4d0d131959d1f3b63eb29c/scipy-1.16.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63870a84cd15c44e65220eaed2dac0e8f8b26bbb991456a033c1d9abfe8a94f8", size = 36178622, upload-time = "2025-09-11T17:43:00.375Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/7b/f127a5795d5ba8ece4e0dce7d4a9fb7cb9e4f4757137757d7a69ab7d4f1a/scipy-1.16.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fa01f0f6a3050fa6a9771a95d5faccc8e2f5a92b4a2e5440a0fa7264a2398472", size = 38783985, upload-time = "2025-09-11T17:43:06.661Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/9f/bc81c1d1e033951eb5912cd3750cc005943afa3e65a725d2443a3b3c4347/scipy-1.16.2-cp313-cp313t-win_amd64.whl", hash = "sha256:116296e89fba96f76353a8579820c2512f6e55835d3fad7780fece04367de351", size = 38631367, upload-time = "2025-09-11T17:43:14.44Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/5e/2cc7555fd81d01814271412a1d59a289d25f8b63208a0a16c21069d55d3e/scipy-1.16.2-cp313-cp313t-win_arm64.whl", hash = "sha256:98e22834650be81d42982360382b43b17f7ba95e0e6993e2a4f5b9ad9283a94d", size = 25787992, upload-time = "2025-09-11T17:43:19.745Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/ac/ad8951250516db71619f0bd3b2eb2448db04b720a003dd98619b78b692c0/scipy-1.16.2-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:567e77755019bb7461513c87f02bb73fb65b11f049aaaa8ca17cfaa5a5c45d77", size = 36595109, upload-time = "2025-09-11T17:43:35.713Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/f6/5779049ed119c5b503b0f3dc6d6f3f68eefc3a9190d4ad4c276f854f051b/scipy-1.16.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:17d9bb346194e8967296621208fcdfd39b55498ef7d2f376884d5ac47cec1a70", size = 28859110, upload-time = "2025-09-11T17:43:40.814Z" },
+ { url = "https://files.pythonhosted.org/packages/82/09/9986e410ae38bf0a0c737ff8189ac81a93b8e42349aac009891c054403d7/scipy-1.16.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:0a17541827a9b78b777d33b623a6dcfe2ef4a25806204d08ead0768f4e529a88", size = 20850110, upload-time = "2025-09-11T17:43:44.981Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/ad/485cdef2d9215e2a7df6d61b81d2ac073dfacf6ae24b9ae87274c4e936ae/scipy-1.16.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:d7d4c6ba016ffc0f9568d012f5f1eb77ddd99412aea121e6fa8b4c3b7cbad91f", size = 23497014, upload-time = "2025-09-11T17:43:49.074Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/74/f6a852e5d581122b8f0f831f1d1e32fb8987776ed3658e95c377d308ed86/scipy-1.16.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9702c4c023227785c779cba2e1d6f7635dbb5b2e0936cdd3a4ecb98d78fd41eb", size = 33401155, upload-time = "2025-09-11T17:43:54.661Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/f5/61d243bbc7c6e5e4e13dde9887e84a5cbe9e0f75fd09843044af1590844e/scipy-1.16.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d1cdf0ac28948d225decdefcc45ad7dd91716c29ab56ef32f8e0d50657dffcc7", size = 35691174, upload-time = "2025-09-11T17:44:00.101Z" },
+ { url = "https://files.pythonhosted.org/packages/03/99/59933956331f8cc57e406cdb7a483906c74706b156998f322913e789c7e1/scipy-1.16.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:70327d6aa572a17c2941cdfb20673f82e536e91850a2e4cb0c5b858b690e1548", size = 36070752, upload-time = "2025-09-11T17:44:05.619Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/7d/00f825cfb47ee19ef74ecf01244b43e95eae74e7e0ff796026ea7cd98456/scipy-1.16.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5221c0b2a4b58aa7c4ed0387d360fd90ee9086d383bb34d9f2789fafddc8a936", size = 38701010, upload-time = "2025-09-11T17:44:11.322Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/9f/b62587029980378304ba5a8563d376c96f40b1e133daacee76efdcae32de/scipy-1.16.2-cp314-cp314-win_amd64.whl", hash = "sha256:f5a85d7b2b708025af08f060a496dd261055b617d776fc05a1a1cc69e09fe9ff", size = 39360061, upload-time = "2025-09-11T17:45:09.814Z" },
+ { url = "https://files.pythonhosted.org/packages/82/04/7a2f1609921352c7fbee0815811b5050582f67f19983096c4769867ca45f/scipy-1.16.2-cp314-cp314-win_arm64.whl", hash = "sha256:2cc73a33305b4b24556957d5857d6253ce1e2dcd67fa0ff46d87d1670b3e1e1d", size = 26126914, upload-time = "2025-09-11T17:45:14.73Z" },
+ { url = "https://files.pythonhosted.org/packages/51/b9/60929ce350c16b221928725d2d1d7f86cf96b8bc07415547057d1196dc92/scipy-1.16.2-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:9ea2a3fed83065d77367775d689401a703d0f697420719ee10c0780bcab594d8", size = 37013193, upload-time = "2025-09-11T17:44:16.757Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/41/ed80e67782d4bc5fc85a966bc356c601afddd175856ba7c7bb6d9490607e/scipy-1.16.2-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:7280d926f11ca945c3ef92ba960fa924e1465f8d07ce3a9923080363390624c4", size = 29390172, upload-time = "2025-09-11T17:44:21.783Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/a3/2f673ace4090452696ccded5f5f8efffb353b8f3628f823a110e0170b605/scipy-1.16.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:8afae1756f6a1fe04636407ef7dbece33d826a5d462b74f3d0eb82deabefd831", size = 21381326, upload-time = "2025-09-11T17:44:25.982Z" },
+ { url = "https://files.pythonhosted.org/packages/42/bf/59df61c5d51395066c35836b78136accf506197617c8662e60ea209881e1/scipy-1.16.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:5c66511f29aa8d233388e7416a3f20d5cae7a2744d5cee2ecd38c081f4e861b3", size = 23915036, upload-time = "2025-09-11T17:44:30.527Z" },
+ { url = "https://files.pythonhosted.org/packages/91/c3/edc7b300dc16847ad3672f1a6f3f7c5d13522b21b84b81c265f4f2760d4a/scipy-1.16.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efe6305aeaa0e96b0ccca5ff647a43737d9a092064a3894e46c414db84bc54ac", size = 33484341, upload-time = "2025-09-11T17:44:35.981Z" },
+ { url = "https://files.pythonhosted.org/packages/26/c7/24d1524e72f06ff141e8d04b833c20db3021020563272ccb1b83860082a9/scipy-1.16.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f3a337d9ae06a1e8d655ee9d8ecb835ea5ddcdcbd8d23012afa055ab014f374", size = 35790840, upload-time = "2025-09-11T17:44:41.76Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/b7/5aaad984eeedd56858dc33d75efa59e8ce798d918e1033ef62d2708f2c3d/scipy-1.16.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bab3605795d269067d8ce78a910220262711b753de8913d3deeaedb5dded3bb6", size = 36174716, upload-time = "2025-09-11T17:44:47.316Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/c2/e276a237acb09824822b0ada11b028ed4067fdc367a946730979feacb870/scipy-1.16.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b0348d8ddb55be2a844c518cd8cc8deeeb8aeba707cf834db5758fc89b476a2c", size = 38790088, upload-time = "2025-09-11T17:44:53.011Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/b4/5c18a766e8353015439f3780f5fc473f36f9762edc1a2e45da3ff5a31b21/scipy-1.16.2-cp314-cp314t-win_amd64.whl", hash = "sha256:26284797e38b8a75e14ea6631d29bda11e76ceaa6ddb6fdebbfe4c4d90faf2f9", size = 39457455, upload-time = "2025-09-11T17:44:58.899Z" },
+ { url = "https://files.pythonhosted.org/packages/97/30/2f9a5243008f76dfc5dee9a53dfb939d9b31e16ce4bd4f2e628bfc5d89d2/scipy-1.16.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d2a4472c231328d4de38d5f1f68fdd6d28a615138f842580a8a321b5845cf779", size = 26448374, upload-time = "2025-09-11T17:45:03.45Z" },
+]
+
+[[package]]
+name = "semantic-version"
+version = "2.10.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7d/31/f2289ce78b9b473d582568c234e104d2a342fd658cc288a7553d83bb8595/semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c", size = 52289, upload-time = "2022-05-26T13:35:23.454Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6a/23/8146aad7d88f4fcb3a6218f41a60f6c2d4e3a72de72da1825dc7c8f7877c/semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177", size = 15552, upload-time = "2022-05-26T13:35:21.206Z" },
+]
+
+[[package]]
+name = "sentence-transformers"
+version = "5.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "huggingface-hub" },
+ { name = "pillow" },
+ { name = "scikit-learn" },
+ { name = "scipy" },
+ { name = "torch" },
+ { name = "tqdm" },
+ { name = "transformers" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/21/47/7d61a19ba7e6b5f36f0ffff5bbf032a1c1913612caac611e12383069eda0/sentence_transformers-5.1.1.tar.gz", hash = "sha256:8af3f844b2ecf9a6c2dfeafc2c02938a87f61202b54329d70dfd7dfd7d17a84e", size = 374434, upload-time = "2025-09-22T11:28:27.54Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/48/21/4670d03ab8587b0ab6f7d5fa02a95c3dd6b1f39d0e40e508870201f3d76c/sentence_transformers-5.1.1-py3-none-any.whl", hash = "sha256:5ed544629eafe89ca668a8910ebff96cf0a9c5254ec14b05c66c086226c892fd", size = 486574, upload-time = "2025-09-22T11:28:26.311Z" },
+]
+
+[[package]]
+name = "sentry-sdk"
+version = "2.39.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4c/72/43294fa4bdd75c51610b5104a3ff834459ba653abb415150aa7826a249dd/sentry_sdk-2.39.0.tar.gz", hash = "sha256:8c185854d111f47f329ab6bc35993f28f7a6b7114db64aa426b326998cfa14e9", size = 348556, upload-time = "2025-09-25T09:15:39.064Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dd/44/4356cc64246ba7b2b920f7c97a85c3c52748e213e250b512ee8152eb559d/sentry_sdk-2.39.0-py2.py3-none-any.whl", hash = "sha256:ba655ca5e57b41569b18e2a5552cb3375209760a5d332cdd87c6c3f28f729602", size = 370851, upload-time = "2025-09-25T09:15:36.35Z" },
+]
+
+[[package]]
+name = "setuptools"
+version = "80.9.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" },
+]
+
+[[package]]
+name = "sgmllib3k"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9e/bd/3704a8c3e0942d711c1299ebf7b9091930adae6675d7c8f476a7ce48653c/sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9", size = 5750, upload-time = "2010-08-24T14:33:52.445Z" }
+
+[[package]]
+name = "shellingham"
+version = "1.5.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
+]
+
+[[package]]
+name = "sigtools"
+version = "4.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/5f/db/669ca14166814da187b3087b908ca924cf83f5b504fe23b3859a3ef67d4f/sigtools-4.0.1.tar.gz", hash = "sha256:4b8e135a9cd4d2ea00da670c093372d74e672ba3abb87f4c98d8e73dea54445c", size = 71910, upload-time = "2022-10-13T07:03:54.149Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1f/91/853dbf6ec096197dba9cd5fd0c836c5fc19142038b7db60ebe6332b1bab1/sigtools-4.0.1-py2.py3-none-any.whl", hash = "sha256:d216b4cf920bbab0fce636ddc429ed8463a5b533d9e1492acb45a2a1bc36ac6c", size = 76419, upload-time = "2022-10-13T07:03:52.658Z" },
+]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
+]
+
+[[package]]
+name = "smmap"
+version = "5.0.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" },
+]
+
+[[package]]
+name = "sniffio"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
+]
+
+[[package]]
+name = "soupsieve"
+version = "2.8"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" },
+]
+
+[[package]]
+name = "speedtest-cli"
+version = "2.1.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/85/d2/32c8a30768b788d319f94cde3a77e0ccc1812dca464ad8062d3c4d703e06/speedtest-cli-2.1.3.tar.gz", hash = "sha256:5e2773233cedb5fa3d8120eb7f97bcc4974b5221b254d33ff16e2f1d413d90f0", size = 24721, upload-time = "2021-04-08T13:51:33.627Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9f/39/65259b7054368b370d3183762484fa2c779ddc41633894d895f9d1720f45/speedtest_cli-2.1.3-py2.py3-none-any.whl", hash = "sha256:75ff32c91af9ac1ce2b905476d6e92bd9eb2c0783f9e7d1939d74605c7d0b9ea", size = 23973, upload-time = "2021-04-08T13:51:32.028Z" },
+]
+
+[[package]]
+name = "sqlalchemy"
+version = "2.0.43"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d7/bc/d59b5d97d27229b0e009bd9098cd81af71c2fa5549c580a0a67b9bed0496/sqlalchemy-2.0.43.tar.gz", hash = "sha256:788bfcef6787a7764169cfe9859fe425bf44559619e1d9f56f5bddf2ebf6f417", size = 9762949, upload-time = "2025-08-11T14:24:58.438Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/61/db/20c78f1081446095450bdc6ee6cc10045fce67a8e003a5876b6eaafc5cc4/sqlalchemy-2.0.43-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:20d81fc2736509d7a2bd33292e489b056cbae543661bb7de7ce9f1c0cd6e7f24", size = 2134891, upload-time = "2025-08-11T15:51:13.019Z" },
+ { url = "https://files.pythonhosted.org/packages/45/0a/3d89034ae62b200b4396f0f95319f7d86e9945ee64d2343dcad857150fa2/sqlalchemy-2.0.43-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b9fc27650ff5a2c9d490c13c14906b918b0de1f8fcbb4c992712d8caf40e83", size = 2123061, upload-time = "2025-08-11T15:51:14.319Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/10/2711f7ff1805919221ad5bee205971254845c069ee2e7036847103ca1e4c/sqlalchemy-2.0.43-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6772e3ca8a43a65a37c88e2f3e2adfd511b0b1da37ef11ed78dea16aeae85bd9", size = 3320384, upload-time = "2025-08-11T15:52:35.088Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/0e/3d155e264d2ed2778484006ef04647bc63f55b3e2d12e6a4f787747b5900/sqlalchemy-2.0.43-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a113da919c25f7f641ffbd07fbc9077abd4b3b75097c888ab818f962707eb48", size = 3329648, upload-time = "2025-08-11T15:56:34.153Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/81/635100fb19725c931622c673900da5efb1595c96ff5b441e07e3dd61f2be/sqlalchemy-2.0.43-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4286a1139f14b7d70141c67a8ae1582fc2b69105f1b09d9573494eb4bb4b2687", size = 3258030, upload-time = "2025-08-11T15:52:36.933Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/ed/a99302716d62b4965fded12520c1cbb189f99b17a6d8cf77611d21442e47/sqlalchemy-2.0.43-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:529064085be2f4d8a6e5fab12d36ad44f1909a18848fcfbdb59cc6d4bbe48efe", size = 3294469, upload-time = "2025-08-11T15:56:35.553Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/a2/3a11b06715149bf3310b55a98b5c1e84a42cfb949a7b800bc75cb4e33abc/sqlalchemy-2.0.43-cp312-cp312-win32.whl", hash = "sha256:b535d35dea8bbb8195e7e2b40059e2253acb2b7579b73c1b432a35363694641d", size = 2098906, upload-time = "2025-08-11T15:55:00.645Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/09/405c915a974814b90aa591280623adc6ad6b322f61fd5cff80aeaef216c9/sqlalchemy-2.0.43-cp312-cp312-win_amd64.whl", hash = "sha256:1c6d85327ca688dbae7e2b06d7d84cfe4f3fffa5b5f9e21bb6ce9d0e1a0e0e0a", size = 2126260, upload-time = "2025-08-11T15:55:02.965Z" },
+ { url = "https://files.pythonhosted.org/packages/41/1c/a7260bd47a6fae7e03768bf66451437b36451143f36b285522b865987ced/sqlalchemy-2.0.43-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e7c08f57f75a2bb62d7ee80a89686a5e5669f199235c6d1dac75cd59374091c3", size = 2130598, upload-time = "2025-08-11T15:51:15.903Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/84/8a337454e82388283830b3586ad7847aa9c76fdd4f1df09cdd1f94591873/sqlalchemy-2.0.43-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:14111d22c29efad445cd5021a70a8b42f7d9152d8ba7f73304c4d82460946aaa", size = 2118415, upload-time = "2025-08-11T15:51:17.256Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/ff/22ab2328148492c4d71899d62a0e65370ea66c877aea017a244a35733685/sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b27b56eb2f82653168cefe6cb8e970cdaf4f3a6cb2c5e3c3c1cf3158968ff9", size = 3248707, upload-time = "2025-08-11T15:52:38.444Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/29/11ae2c2b981de60187f7cbc84277d9d21f101093d1b2e945c63774477aba/sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c5a9da957c56e43d72126a3f5845603da00e0293720b03bde0aacffcf2dc04f", size = 3253602, upload-time = "2025-08-11T15:56:37.348Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/61/987b6c23b12c56d2be451bc70900f67dd7d989d52b1ee64f239cf19aec69/sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d79f9fdc9584ec83d1b3c75e9f4595c49017f5594fee1a2217117647225d738", size = 3183248, upload-time = "2025-08-11T15:52:39.865Z" },
+ { url = "https://files.pythonhosted.org/packages/86/85/29d216002d4593c2ce1c0ec2cec46dda77bfbcd221e24caa6e85eff53d89/sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9df7126fd9db49e3a5a3999442cc67e9ee8971f3cb9644250107d7296cb2a164", size = 3219363, upload-time = "2025-08-11T15:56:39.11Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/e4/bd78b01919c524f190b4905d47e7630bf4130b9f48fd971ae1c6225b6f6a/sqlalchemy-2.0.43-cp313-cp313-win32.whl", hash = "sha256:7f1ac7828857fcedb0361b48b9ac4821469f7694089d15550bbcf9ab22564a1d", size = 2096718, upload-time = "2025-08-11T15:55:05.349Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/a5/ca2f07a2a201f9497de1928f787926613db6307992fe5cda97624eb07c2f/sqlalchemy-2.0.43-cp313-cp313-win_amd64.whl", hash = "sha256:971ba928fcde01869361f504fcff3b7143b47d30de188b11c6357c0505824197", size = 2123200, upload-time = "2025-08-11T15:55:07.932Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/d9/13bdde6521f322861fab67473cec4b1cc8999f3871953531cf61945fad92/sqlalchemy-2.0.43-py3-none-any.whl", hash = "sha256:1681c21dd2ccee222c2fe0bef671d1aef7c504087c9c4e800371cfcc8ac966fc", size = 1924759, upload-time = "2025-08-11T15:39:53.024Z" },
+]
+
+[[package]]
+name = "stack-data"
+version = "0.6.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "asttokens" },
+ { name = "executing" },
+ { name = "pure-eval" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
+]
+
+[[package]]
+name = "starlette"
+version = "0.48.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a7/a5/d6f429d43394057b67a6b5bbe6eae2f77a6bf7459d961fdb224bf206eee6/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46", size = 2652949, upload-time = "2025-09-13T08:41:05.699Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/be/72/2db2f49247d0a18b4f1bb9a5a39a0162869acf235f3a96418363947b3d46/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659", size = 73736, upload-time = "2025-09-13T08:41:03.869Z" },
+]
+
+[[package]]
+name = "sympy"
+version = "1.14.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mpmath" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
+]
+
+[[package]]
+name = "synchronicity"
+version = "0.10.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "sigtools" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/77/b6/e977f03915cc02406bb52ac15398ea44dbde47805e5955b6bac9268acc12/synchronicity-0.10.2.tar.gz", hash = "sha256:e0dfd8a2ba4fb89c60ee53365c5fa2d2d69aabce60709055d38f736f6a592c86", size = 53891, upload-time = "2025-07-30T20:23:19.122Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f8/f9/ce041b9531022a0b5999a47e6da14485239f7bce9c595d1bfb387fe60e89/synchronicity-0.10.2-py3-none-any.whl", hash = "sha256:4ba1f8c02ca582ef068033300201e3c403e08d81e42553554f4e67b27f0d9bb1", size = 38766, upload-time = "2025-07-30T20:23:18.04Z" },
+]
+
+[[package]]
+name = "tenacity"
+version = "9.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" },
+]
+
+[[package]]
+name = "threadpoolctl"
+version = "3.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" },
+]
+
+[[package]]
+name = "tiktoken"
+version = "0.11.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "regex" },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a7/86/ad0155a37c4f310935d5ac0b1ccf9bdb635dcb906e0a9a26b616dd55825a/tiktoken-0.11.0.tar.gz", hash = "sha256:3c518641aee1c52247c2b97e74d8d07d780092af79d5911a6ab5e79359d9b06a", size = 37648, upload-time = "2025-08-08T23:58:08.495Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/9e/eceddeffc169fc75fe0fd4f38471309f11cb1906f9b8aa39be4f5817df65/tiktoken-0.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fd9e6b23e860973cf9526544e220b223c60badf5b62e80a33509d6d40e6c8f5d", size = 1055199, upload-time = "2025-08-08T23:57:45.076Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/cf/5f02bfefffdc6b54e5094d2897bc80efd43050e5b09b576fd85936ee54bf/tiktoken-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6a76d53cee2da71ee2731c9caa747398762bda19d7f92665e882fef229cb0b5b", size = 996655, upload-time = "2025-08-08T23:57:46.304Z" },
+ { url = "https://files.pythonhosted.org/packages/65/8e/c769b45ef379bc360c9978c4f6914c79fd432400a6733a8afc7ed7b0726a/tiktoken-0.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ef72aab3ea240646e642413cb363b73869fed4e604dcfd69eec63dc54d603e8", size = 1128867, upload-time = "2025-08-08T23:57:47.438Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/2d/4d77f6feb9292bfdd23d5813e442b3bba883f42d0ac78ef5fdc56873f756/tiktoken-0.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f929255c705efec7a28bf515e29dc74220b2f07544a8c81b8d69e8efc4578bd", size = 1183308, upload-time = "2025-08-08T23:57:48.566Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/65/7ff0a65d3bb0fc5a1fb6cc71b03e0f6e71a68c5eea230d1ff1ba3fd6df49/tiktoken-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:61f1d15822e4404953d499fd1dcc62817a12ae9fb1e4898033ec8fe3915fdf8e", size = 1244301, upload-time = "2025-08-08T23:57:49.642Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/6e/5b71578799b72e5bdcef206a214c3ce860d999d579a3b56e74a6c8989ee2/tiktoken-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:45927a71ab6643dfd3ef57d515a5db3d199137adf551f66453be098502838b0f", size = 884282, upload-time = "2025-08-08T23:57:50.759Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/cd/a9034bcee638716d9310443818d73c6387a6a96db93cbcb0819b77f5b206/tiktoken-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a5f3f25ffb152ee7fec78e90a5e5ea5b03b4ea240beed03305615847f7a6ace2", size = 1055339, upload-time = "2025-08-08T23:57:51.802Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/91/9922b345f611b4e92581f234e64e9661e1c524875c8eadd513c4b2088472/tiktoken-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7dc6e9ad16a2a75b4c4be7208055a1f707c9510541d94d9cc31f7fbdc8db41d8", size = 997080, upload-time = "2025-08-08T23:57:53.442Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/9d/49cd047c71336bc4b4af460ac213ec1c457da67712bde59b892e84f1859f/tiktoken-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a0517634d67a8a48fd4a4ad73930c3022629a85a217d256a6e9b8b47439d1e4", size = 1128501, upload-time = "2025-08-08T23:57:54.808Z" },
+ { url = "https://files.pythonhosted.org/packages/52/d5/a0dcdb40dd2ea357e83cb36258967f0ae96f5dd40c722d6e382ceee6bba9/tiktoken-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fb4effe60574675118b73c6fbfd3b5868e5d7a1f570d6cc0d18724b09ecf318", size = 1182743, upload-time = "2025-08-08T23:57:56.307Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/17/a0fc51aefb66b7b5261ca1314afa83df0106b033f783f9a7bcbe8e741494/tiktoken-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94f984c9831fd32688aef4348803b0905d4ae9c432303087bae370dc1381a2b8", size = 1244057, upload-time = "2025-08-08T23:57:57.628Z" },
+ { url = "https://files.pythonhosted.org/packages/50/79/bcf350609f3a10f09fe4fc207f132085e497fdd3612f3925ab24d86a0ca0/tiktoken-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:2177ffda31dec4023356a441793fed82f7af5291120751dee4d696414f54db0c", size = 883901, upload-time = "2025-08-08T23:57:59.359Z" },
+]
+
+[[package]]
+name = "tokenizers"
+version = "0.22.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "huggingface-hub" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1c/46/fb6854cec3278fbfa4a75b50232c77622bc517ac886156e6afbfa4d8fc6e/tokenizers-0.22.1.tar.gz", hash = "sha256:61de6522785310a309b3407bac22d99c4db5dba349935e99e4d15ea2226af2d9", size = 363123, upload-time = "2025-09-19T09:49:23.424Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bf/33/f4b2d94ada7ab297328fc671fed209368ddb82f965ec2224eb1892674c3a/tokenizers-0.22.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:59fdb013df17455e5f950b4b834a7b3ee2e0271e6378ccb33aa74d178b513c73", size = 3069318, upload-time = "2025-09-19T09:49:11.848Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/58/2aa8c874d02b974990e89ff95826a4852a8b2a273c7d1b4411cdd45a4565/tokenizers-0.22.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8d4e484f7b0827021ac5f9f71d4794aaef62b979ab7608593da22b1d2e3c4edc", size = 2926478, upload-time = "2025-09-19T09:49:09.759Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/3b/55e64befa1e7bfea963cf4b787b2cea1011362c4193f5477047532ce127e/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19d2962dd28bc67c1f205ab180578a78eef89ac60ca7ef7cbe9635a46a56422a", size = 3256994, upload-time = "2025-09-19T09:48:56.701Z" },
+ { url = "https://files.pythonhosted.org/packages/71/0b/fbfecf42f67d9b7b80fde4aabb2b3110a97fac6585c9470b5bff103a80cb/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38201f15cdb1f8a6843e6563e6e79f4abd053394992b9bbdf5213ea3469b4ae7", size = 3153141, upload-time = "2025-09-19T09:48:59.749Z" },
+ { url = "https://files.pythonhosted.org/packages/17/a9/b38f4e74e0817af8f8ef925507c63c6ae8171e3c4cb2d5d4624bf58fca69/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1cbe5454c9a15df1b3443c726063d930c16f047a3cc724b9e6e1a91140e5a21", size = 3508049, upload-time = "2025-09-19T09:49:05.868Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/48/dd2b3dac46bb9134a88e35d72e1aa4869579eacc1a27238f1577270773ff/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7d094ae6312d69cc2a872b54b91b309f4f6fbce871ef28eb27b52a98e4d0214", size = 3710730, upload-time = "2025-09-19T09:49:01.832Z" },
+ { url = "https://files.pythonhosted.org/packages/93/0e/ccabc8d16ae4ba84a55d41345207c1e2ea88784651a5a487547d80851398/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afd7594a56656ace95cdd6df4cca2e4059d294c5cfb1679c57824b605556cb2f", size = 3412560, upload-time = "2025-09-19T09:49:03.867Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/c6/dc3a0db5a6766416c32c034286d7c2d406da1f498e4de04ab1b8959edd00/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ef6063d7a84994129732b47e7915e8710f27f99f3a3260b8a38fc7ccd083f4", size = 3250221, upload-time = "2025-09-19T09:49:07.664Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/a6/2c8486eef79671601ff57b093889a345dd3d576713ef047776015dc66de7/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ba0a64f450b9ef412c98f6bcd2a50c6df6e2443b560024a09fa6a03189726879", size = 9345569, upload-time = "2025-09-19T09:49:14.214Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/16/32ce667f14c35537f5f605fe9bea3e415ea1b0a646389d2295ec348d5657/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:331d6d149fa9c7d632cde4490fb8bbb12337fa3a0232e77892be656464f4b446", size = 9271599, upload-time = "2025-09-19T09:49:16.639Z" },
+ { url = "https://files.pythonhosted.org/packages/51/7c/a5f7898a3f6baa3fc2685c705e04c98c1094c523051c805cdd9306b8f87e/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:607989f2ea68a46cb1dfbaf3e3aabdf3f21d8748312dbeb6263d1b3b66c5010a", size = 9533862, upload-time = "2025-09-19T09:49:19.146Z" },
+ { url = "https://files.pythonhosted.org/packages/36/65/7e75caea90bc73c1dd8d40438adf1a7bc26af3b8d0a6705ea190462506e1/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a0f307d490295717726598ef6fa4f24af9d484809223bbc253b201c740a06390", size = 9681250, upload-time = "2025-09-19T09:49:21.501Z" },
+ { url = "https://files.pythonhosted.org/packages/30/2c/959dddef581b46e6209da82df3b78471e96260e2bc463f89d23b1bf0e52a/tokenizers-0.22.1-cp39-abi3-win32.whl", hash = "sha256:b5120eed1442765cd90b903bb6cfef781fd8fe64e34ccaecbae4c619b7b12a82", size = 2472003, upload-time = "2025-09-19T09:49:27.089Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/46/e33a8c93907b631a99377ef4c5f817ab453d0b34f93529421f42ff559671/tokenizers-0.22.1-cp39-abi3-win_amd64.whl", hash = "sha256:65fd6e3fb11ca1e78a6a93602490f134d1fdeb13bcef99389d5102ea318ed138", size = 2674684, upload-time = "2025-09-19T09:49:24.953Z" },
+]
+
+[[package]]
+name = "toml"
+version = "0.10.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" },
+]
+
+[[package]]
+name = "tomlkit"
+version = "0.13.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" },
+]
+
+[[package]]
+name = "torch"
+version = "2.8.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "filelock" },
+ { name = "fsspec" },
+ { name = "jinja2" },
+ { name = "networkx" },
+ { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "setuptools" },
+ { name = "sympy" },
+ { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "typing-extensions" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/49/0c/2fd4df0d83a495bb5e54dca4474c4ec5f9c62db185421563deeb5dabf609/torch-2.8.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e2fab4153768d433f8ed9279c8133a114a034a61e77a3a104dcdf54388838705", size = 101906089, upload-time = "2025-08-06T14:53:52.631Z" },
+ { url = "https://files.pythonhosted.org/packages/99/a8/6acf48d48838fb8fe480597d98a0668c2beb02ee4755cc136de92a0a956f/torch-2.8.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2aca0939fb7e4d842561febbd4ffda67a8e958ff725c1c27e244e85e982173c", size = 887913624, upload-time = "2025-08-06T14:56:44.33Z" },
+ { url = "https://files.pythonhosted.org/packages/af/8a/5c87f08e3abd825c7dfecef5a0f1d9aa5df5dd0e3fd1fa2f490a8e512402/torch-2.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:2f4ac52f0130275d7517b03a33d2493bab3693c83dcfadf4f81688ea82147d2e", size = 241326087, upload-time = "2025-08-06T14:53:46.503Z" },
+ { url = "https://files.pythonhosted.org/packages/be/66/5c9a321b325aaecb92d4d1855421e3a055abd77903b7dab6575ca07796db/torch-2.8.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:619c2869db3ada2c0105487ba21b5008defcc472d23f8b80ed91ac4a380283b0", size = 73630478, upload-time = "2025-08-06T14:53:57.144Z" },
+ { url = "https://files.pythonhosted.org/packages/10/4e/469ced5a0603245d6a19a556e9053300033f9c5baccf43a3d25ba73e189e/torch-2.8.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2b2f96814e0345f5a5aed9bf9734efa913678ed19caf6dc2cddb7930672d6128", size = 101936856, upload-time = "2025-08-06T14:54:01.526Z" },
+ { url = "https://files.pythonhosted.org/packages/16/82/3948e54c01b2109238357c6f86242e6ecbf0c63a1af46906772902f82057/torch-2.8.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:65616ca8ec6f43245e1f5f296603e33923f4c30f93d65e103d9e50c25b35150b", size = 887922844, upload-time = "2025-08-06T14:55:50.78Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/54/941ea0a860f2717d86a811adf0c2cd01b3983bdd460d0803053c4e0b8649/torch-2.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:659df54119ae03e83a800addc125856effda88b016dfc54d9f65215c3975be16", size = 241330968, upload-time = "2025-08-06T14:54:45.293Z" },
+ { url = "https://files.pythonhosted.org/packages/de/69/8b7b13bba430f5e21d77708b616f767683629fc4f8037564a177d20f90ed/torch-2.8.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:1a62a1ec4b0498930e2543535cf70b1bef8c777713de7ceb84cd79115f553767", size = 73915128, upload-time = "2025-08-06T14:54:34.769Z" },
+ { url = "https://files.pythonhosted.org/packages/15/0e/8a800e093b7f7430dbaefa80075aee9158ec22e4c4fc3c1a66e4fb96cb4f/torch-2.8.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:83c13411a26fac3d101fe8035a6b0476ae606deb8688e904e796a3534c197def", size = 102020139, upload-time = "2025-08-06T14:54:39.047Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/15/5e488ca0bc6162c86a33b58642bc577c84ded17c7b72d97e49b5833e2d73/torch-2.8.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:8f0a9d617a66509ded240add3754e462430a6c1fc5589f86c17b433dd808f97a", size = 887990692, upload-time = "2025-08-06T14:56:18.286Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/a8/6a04e4b54472fc5dba7ca2341ab219e529f3c07b6941059fbf18dccac31f/torch-2.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a7242b86f42be98ac674b88a4988643b9bc6145437ec8f048fea23f72feb5eca", size = 241603453, upload-time = "2025-08-06T14:55:22.945Z" },
+ { url = "https://files.pythonhosted.org/packages/04/6e/650bb7f28f771af0cb791b02348db8b7f5f64f40f6829ee82aa6ce99aabe/torch-2.8.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:7b677e17f5a3e69fdef7eb3b9da72622f8d322692930297e4ccb52fefc6c8211", size = 73632395, upload-time = "2025-08-06T14:55:28.645Z" },
+]
+
+[[package]]
+name = "tornado"
+version = "6.5.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821, upload-time = "2025-08-08T18:27:00.78Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563, upload-time = "2025-08-08T18:26:42.945Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729, upload-time = "2025-08-08T18:26:44.473Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295, upload-time = "2025-08-08T18:26:46.021Z" },
+ { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644, upload-time = "2025-08-08T18:26:47.625Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878, upload-time = "2025-08-08T18:26:50.599Z" },
+ { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549, upload-time = "2025-08-08T18:26:51.864Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973, upload-time = "2025-08-08T18:26:53.625Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954, upload-time = "2025-08-08T18:26:55.072Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023, upload-time = "2025-08-08T18:26:56.677Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427, upload-time = "2025-08-08T18:26:57.91Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456, upload-time = "2025-08-08T18:26:59.207Z" },
+]
+
+[[package]]
+name = "tqdm"
+version = "4.67.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" },
+]
+
+[[package]]
+name = "traitlets"
+version = "5.14.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" },
+]
+
+[[package]]
+name = "transformers"
+version = "4.56.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "filelock" },
+ { name = "huggingface-hub" },
+ { name = "numpy" },
+ { name = "packaging" },
+ { name = "pyyaml" },
+ { name = "regex" },
+ { name = "requests" },
+ { name = "safetensors" },
+ { name = "tokenizers" },
+ { name = "tqdm" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e5/82/0bcfddd134cdf53440becb5e738257cc3cf34cf229d63b57bfd288e6579f/transformers-4.56.2.tar.gz", hash = "sha256:5e7c623e2d7494105c726dd10f6f90c2c99a55ebe86eef7233765abd0cb1c529", size = 9844296, upload-time = "2025-09-19T15:16:26.778Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/70/26/2591b48412bde75e33bfd292034103ffe41743cacd03120e3242516cd143/transformers-4.56.2-py3-none-any.whl", hash = "sha256:79c03d0e85b26cb573c109ff9eafa96f3c8d4febfd8a0774e8bba32702dd6dde", size = 11608055, upload-time = "2025-09-19T15:16:23.736Z" },
+]
+
+[[package]]
+name = "triton"
+version = "3.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "setuptools", marker = "sys_platform == 'linux'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d0/66/b1eb52839f563623d185f0927eb3530ee4d5ffe9d377cdaf5346b306689e/triton-3.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c1d84a5c0ec2c0f8e8a072d7fd150cab84a9c239eaddc6706c081bfae4eb04", size = 155560068, upload-time = "2025-07-30T19:58:37.081Z" },
+ { url = "https://files.pythonhosted.org/packages/30/7b/0a685684ed5322d2af0bddefed7906674f67974aa88b0fae6e82e3b766f6/triton-3.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00be2964616f4c619193cb0d1b29a99bd4b001d7dc333816073f92cf2a8ccdeb", size = 155569223, upload-time = "2025-07-30T19:58:44.017Z" },
+ { url = "https://files.pythonhosted.org/packages/20/63/8cb444ad5cdb25d999b7d647abac25af0ee37d292afc009940c05b82dda0/triton-3.4.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7936b18a3499ed62059414d7df563e6c163c5e16c3773678a3ee3d417865035d", size = 155659780, upload-time = "2025-07-30T19:58:51.171Z" },
+]
+
+[[package]]
+name = "typer"
+version = "0.19.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "rich" },
+ { name = "shellingham" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/21/ca/950278884e2ca20547ff3eb109478c6baf6b8cf219318e6bc4f666fad8e8/typer-0.19.2.tar.gz", hash = "sha256:9ad824308ded0ad06cc716434705f691d4ee0bfd0fb081839d2e426860e7fdca", size = 104755, upload-time = "2025-09-23T09:47:48.256Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/00/22/35617eee79080a5d071d0f14ad698d325ee6b3bf824fc0467c03b30e7fa8/typer-0.19.2-py3-none-any.whl", hash = "sha256:755e7e19670ffad8283db353267cb81ef252f595aa6834a0d1ca9312d9326cb9", size = 46748, upload-time = "2025-09-23T09:47:46.777Z" },
+]
+
+[[package]]
+name = "types-certifi"
+version = "2021.10.8.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/52/68/943c3aeaf14624712a0357c4a67814dba5cea36d194f5c764dad7959a00c/types-certifi-2021.10.8.3.tar.gz", hash = "sha256:72cf7798d165bc0b76e1c10dd1ea3097c7063c42c21d664523b928e88b554a4f", size = 2095, upload-time = "2022-06-09T15:19:05.244Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b5/63/2463d89481e811f007b0e1cd0a91e52e141b47f9de724d20db7b861dcfec/types_certifi-2021.10.8.3-py3-none-any.whl", hash = "sha256:b2d1e325e69f71f7c78e5943d410e650b4707bb0ef32e4ddf3da37f54176e88a", size = 2136, upload-time = "2022-06-09T15:19:03.127Z" },
+]
+
+[[package]]
+name = "types-toml"
+version = "0.10.8.20240310"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/86/47/3e4c75042792bff8e90d7991aa5c51812cc668828cc6cce711e97f63a607/types-toml-0.10.8.20240310.tar.gz", hash = "sha256:3d41501302972436a6b8b239c850b26689657e25281b48ff0ec06345b8830331", size = 4392, upload-time = "2024-03-10T02:18:37.518Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/da/a2/d32ab58c0b216912638b140ab2170ee4b8644067c293b170e19fba340ccc/types_toml-0.10.8.20240310-py3-none-any.whl", hash = "sha256:627b47775d25fa29977d9c70dc0cbab3f314f32c8d8d0c012f2ef5de7aaec05d", size = 4777, upload-time = "2024-03-10T02:18:36.568Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
+]
+
+[[package]]
+name = "typing-inspect"
+version = "0.9.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mypy-extensions" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" },
+]
+
+[[package]]
+name = "typing-inspection"
+version = "0.4.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
+]
+
+[[package]]
+name = "tzdata"
+version = "2025.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
+]
+
+[[package]]
+name = "uritemplate"
+version = "4.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/98/60/f174043244c5306c9988380d2cb10009f91563fc4b31293d27e17201af56/uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e", size = 33267, upload-time = "2025-06-02T15:12:06.318Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686", size = 11488, upload-time = "2025-06-02T15:12:03.405Z" },
+]
+
+[[package]]
+name = "urllib3"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268, upload-time = "2024-12-22T07:47:30.032Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369, upload-time = "2024-12-22T07:47:28.074Z" },
+]
+
+[[package]]
+name = "uvicorn"
+version = "0.37.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/71/57/1616c8274c3442d802621abf5deb230771c7a0fec9414cb6763900eb3868/uvicorn-0.37.0.tar.gz", hash = "sha256:4115c8add6d3fd536c8ee77f0e14a7fd2ebba939fed9b02583a97f80648f9e13", size = 80367, upload-time = "2025-09-23T13:33:47.486Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/85/cd/584a2ceb5532af99dd09e50919e3615ba99aa127e9850eafe5f31ddfdb9a/uvicorn-0.37.0-py3-none-any.whl", hash = "sha256:913b2b88672343739927ce381ff9e2ad62541f9f8289664fa1d1d3803fa2ce6c", size = 67976, upload-time = "2025-09-23T13:33:45.842Z" },
+]
+
+[package.optional-dependencies]
+standard = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "httptools" },
+ { name = "python-dotenv" },
+ { name = "pyyaml" },
+ { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" },
+ { name = "watchfiles" },
+ { name = "websockets" },
+]
+
+[[package]]
+name = "uvloop"
+version = "0.21.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" },
+ { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" },
+ { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" },
+ { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" },
+ { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" },
+ { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" },
+ { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" },
+]
+
+[[package]]
+name = "wandb"
+version = "0.22.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "gitpython" },
+ { name = "packaging" },
+ { name = "platformdirs" },
+ { name = "protobuf" },
+ { name = "pydantic" },
+ { name = "pyyaml" },
+ { name = "requests" },
+ { name = "sentry-sdk" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ac/6f/be255b13157cab6c6670594171f59f67bd8a89f20d1978dc4eb892e2de27/wandb-0.22.1.tar.gz", hash = "sha256:6a1d668ecd6bd6531a73f6f7cfec0a93a08ef578c16ccf7167168c52cbf8cb12", size = 40246806, upload-time = "2025-09-29T17:15:55.207Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/76/73/de1d62301ef5d084160221637f34a821b7ed90b0769698b7b420686608ab/wandb-0.22.1-py3-none-macosx_12_0_arm64.whl", hash = "sha256:d862d0d28919556a5c32977138449812a2d127853e20b0deb39a5ab17700230f", size = 18370574, upload-time = "2025-09-29T17:15:18.236Z" },
+ { url = "https://files.pythonhosted.org/packages/42/0e/4f60d9c7f1fa9d249dcbe70c6bad1573a9cfc070d00c3d8dbd62f715938d/wandb-0.22.1-py3-none-macosx_12_0_x86_64.whl", hash = "sha256:ce57213de331717270020f7e07b098a0ea37646550b63758eabf8cb05eeb066f", size = 19392851, upload-time = "2025-09-29T17:15:22.093Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/8b/757ede4a581eece5e72ade51fd4b43cfedbd3e39b85fe29d0198bc98131b/wandb-0.22.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5a0ac652c23bf88e12bf0c04e911ff4f95696ac60a3612d81e54f1f8d89f3c5", size = 18171463, upload-time = "2025-09-29T17:15:24.588Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/e6/275d60292183d4de89fc9053887192f978fd8612e55c8f7719aa5c81bbd1/wandb-0.22.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dc14dd06938c282900dd9f72cbaaed45368b0c6b9bc2ffd1f45d07eeb13095b", size = 19585538, upload-time = "2025-09-29T17:15:28.432Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/5c/4199abb92d06de6ebd63ee33551ba0de6d91a814ac42e372dec6d8009ea0/wandb-0.22.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1b2d2b9d8d1ea8aea3c2cbf9de7696105432886ba9845c50e7cc71613aa6c8ef", size = 18210525, upload-time = "2025-09-29T17:15:33.459Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/00/a7719c048115825861a31435fa911887c9949b20096dbc7307e11b3c981b/wandb-0.22.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:051906d7f22bdf8c07c8837ffc6d9ae357d61dcd74cfb7d29fd0243e03da8f4a", size = 19680055, upload-time = "2025-09-29T17:15:38.521Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/5d/e6270557a315211e880c1efa9c1cab577f945d81168bc1c1187fd483f1bb/wandb-0.22.1-py3-none-win32.whl", hash = "sha256:b2df59bd70771329f27171f55d25d5557731bb0674d60db4735c173a8fb8076d", size = 18769036, upload-time = "2025-09-29T17:15:43.19Z" },
+ { url = "https://files.pythonhosted.org/packages/92/fe/34cdfd491ea6c89495794f361102b727b922adcc4f3eedb47c8aa16984c3/wandb-0.22.1-py3-none-win_amd64.whl", hash = "sha256:c1b442e6de805d78743321200a27099517509f9e4aa2e6d330211a4809f932d7", size = 18769038, upload-time = "2025-09-29T17:15:46.977Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/9e/fe95f5d48ff10215b7d7e67dc998cba3f660027829fac2a67c79ce89e985/wandb-0.22.1-py3-none-win_arm64.whl", hash = "sha256:52758008c9ef9e7201113af08d6015322a699ebe3497a6e6fc885b39f5652b4d", size = 17077774, upload-time = "2025-09-29T17:15:50.588Z" },
+]
+
+[[package]]
+name = "watchfiles"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2a/9a/d451fcc97d029f5812e898fd30a53fd8c15c7bbd058fd75cfc6beb9bd761/watchfiles-1.1.0.tar.gz", hash = "sha256:693ed7ec72cbfcee399e92c895362b6e66d63dac6b91e2c11ae03d10d503e575", size = 94406, upload-time = "2025-06-15T19:06:59.42Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f6/b8/858957045a38a4079203a33aaa7d23ea9269ca7761c8a074af3524fbb240/watchfiles-1.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9dc001c3e10de4725c749d4c2f2bdc6ae24de5a88a339c4bce32300a31ede179", size = 402339, upload-time = "2025-06-15T19:05:24.516Z" },
+ { url = "https://files.pythonhosted.org/packages/80/28/98b222cca751ba68e88521fabd79a4fab64005fc5976ea49b53fa205d1fa/watchfiles-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d9ba68ec283153dead62cbe81872d28e053745f12335d037de9cbd14bd1877f5", size = 394409, upload-time = "2025-06-15T19:05:25.469Z" },
+ { url = "https://files.pythonhosted.org/packages/86/50/dee79968566c03190677c26f7f47960aff738d32087087bdf63a5473e7df/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130fc497b8ee68dce163e4254d9b0356411d1490e868bd8790028bc46c5cc297", size = 450939, upload-time = "2025-06-15T19:05:26.494Z" },
+ { url = "https://files.pythonhosted.org/packages/40/45/a7b56fb129700f3cfe2594a01aa38d033b92a33dddce86c8dfdfc1247b72/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50a51a90610d0845a5931a780d8e51d7bd7f309ebc25132ba975aca016b576a0", size = 457270, upload-time = "2025-06-15T19:05:27.466Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/c8/fa5ef9476b1d02dc6b5e258f515fcaaecf559037edf8b6feffcbc097c4b8/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc44678a72ac0910bac46fa6a0de6af9ba1355669b3dfaf1ce5f05ca7a74364e", size = 483370, upload-time = "2025-06-15T19:05:28.548Z" },
+ { url = "https://files.pythonhosted.org/packages/98/68/42cfcdd6533ec94f0a7aab83f759ec11280f70b11bfba0b0f885e298f9bd/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a543492513a93b001975ae283a51f4b67973662a375a403ae82f420d2c7205ee", size = 598654, upload-time = "2025-06-15T19:05:29.997Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/74/b2a1544224118cc28df7e59008a929e711f9c68ce7d554e171b2dc531352/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ac164e20d17cc285f2b94dc31c384bc3aa3dd5e7490473b3db043dd70fbccfd", size = 478667, upload-time = "2025-06-15T19:05:31.172Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/77/e3362fe308358dc9f8588102481e599c83e1b91c2ae843780a7ded939a35/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7590d5a455321e53857892ab8879dce62d1f4b04748769f5adf2e707afb9d4f", size = 452213, upload-time = "2025-06-15T19:05:32.299Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/17/c8f1a36540c9a1558d4faf08e909399e8133599fa359bf52ec8fcee5be6f/watchfiles-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:37d3d3f7defb13f62ece99e9be912afe9dd8a0077b7c45ee5a57c74811d581a4", size = 626718, upload-time = "2025-06-15T19:05:33.415Z" },
+ { url = "https://files.pythonhosted.org/packages/26/45/fb599be38b4bd38032643783d7496a26a6f9ae05dea1a42e58229a20ac13/watchfiles-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7080c4bb3efd70a07b1cc2df99a7aa51d98685be56be6038c3169199d0a1c69f", size = 623098, upload-time = "2025-06-15T19:05:34.534Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/e7/fdf40e038475498e160cd167333c946e45d8563ae4dd65caf757e9ffe6b4/watchfiles-1.1.0-cp312-cp312-win32.whl", hash = "sha256:cbcf8630ef4afb05dc30107bfa17f16c0896bb30ee48fc24bf64c1f970f3b1fd", size = 279209, upload-time = "2025-06-15T19:05:35.577Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/d3/3ae9d5124ec75143bdf088d436cba39812122edc47709cd2caafeac3266f/watchfiles-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:cbd949bdd87567b0ad183d7676feb98136cde5bb9025403794a4c0db28ed3a47", size = 292786, upload-time = "2025-06-15T19:05:36.559Z" },
+ { url = "https://files.pythonhosted.org/packages/26/2f/7dd4fc8b5f2b34b545e19629b4a018bfb1de23b3a496766a2c1165ca890d/watchfiles-1.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:0a7d40b77f07be87c6faa93d0951a0fcd8cbca1ddff60a1b65d741bac6f3a9f6", size = 284343, upload-time = "2025-06-15T19:05:37.5Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/42/fae874df96595556a9089ade83be34a2e04f0f11eb53a8dbf8a8a5e562b4/watchfiles-1.1.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5007f860c7f1f8df471e4e04aaa8c43673429047d63205d1630880f7637bca30", size = 402004, upload-time = "2025-06-15T19:05:38.499Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/55/a77e533e59c3003d9803c09c44c3651224067cbe7fb5d574ddbaa31e11ca/watchfiles-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:20ecc8abbd957046f1fe9562757903f5eaf57c3bce70929fda6c7711bb58074a", size = 393671, upload-time = "2025-06-15T19:05:39.52Z" },
+ { url = "https://files.pythonhosted.org/packages/05/68/b0afb3f79c8e832e6571022611adbdc36e35a44e14f129ba09709aa4bb7a/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2f0498b7d2a3c072766dba3274fe22a183dbea1f99d188f1c6c72209a1063dc", size = 449772, upload-time = "2025-06-15T19:05:40.897Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/05/46dd1f6879bc40e1e74c6c39a1b9ab9e790bf1f5a2fe6c08b463d9a807f4/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:239736577e848678e13b201bba14e89718f5c2133dfd6b1f7846fa1b58a8532b", size = 456789, upload-time = "2025-06-15T19:05:42.045Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/ca/0eeb2c06227ca7f12e50a47a3679df0cd1ba487ea19cf844a905920f8e95/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eff4b8d89f444f7e49136dc695599a591ff769300734446c0a86cba2eb2f9895", size = 482551, upload-time = "2025-06-15T19:05:43.781Z" },
+ { url = "https://files.pythonhosted.org/packages/31/47/2cecbd8694095647406645f822781008cc524320466ea393f55fe70eed3b/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12b0a02a91762c08f7264e2e79542f76870c3040bbc847fb67410ab81474932a", size = 597420, upload-time = "2025-06-15T19:05:45.244Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/7e/82abc4240e0806846548559d70f0b1a6dfdca75c1b4f9fa62b504ae9b083/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29e7bc2eee15cbb339c68445959108803dc14ee0c7b4eea556400131a8de462b", size = 477950, upload-time = "2025-06-15T19:05:46.332Z" },
+ { url = "https://files.pythonhosted.org/packages/25/0d/4d564798a49bf5482a4fa9416dea6b6c0733a3b5700cb8a5a503c4b15853/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9481174d3ed982e269c090f780122fb59cee6c3796f74efe74e70f7780ed94c", size = 451706, upload-time = "2025-06-15T19:05:47.459Z" },
+ { url = "https://files.pythonhosted.org/packages/81/b5/5516cf46b033192d544102ea07c65b6f770f10ed1d0a6d388f5d3874f6e4/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:80f811146831c8c86ab17b640801c25dc0a88c630e855e2bef3568f30434d52b", size = 625814, upload-time = "2025-06-15T19:05:48.654Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/dd/7c1331f902f30669ac3e754680b6edb9a0dd06dea5438e61128111fadd2c/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:60022527e71d1d1fda67a33150ee42869042bce3d0fcc9cc49be009a9cded3fb", size = 622820, upload-time = "2025-06-15T19:05:50.088Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/14/36d7a8e27cd128d7b1009e7715a7c02f6c131be9d4ce1e5c3b73d0e342d8/watchfiles-1.1.0-cp313-cp313-win32.whl", hash = "sha256:32d6d4e583593cb8576e129879ea0991660b935177c0f93c6681359b3654bfa9", size = 279194, upload-time = "2025-06-15T19:05:51.186Z" },
+ { url = "https://files.pythonhosted.org/packages/25/41/2dd88054b849aa546dbeef5696019c58f8e0774f4d1c42123273304cdb2e/watchfiles-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:f21af781a4a6fbad54f03c598ab620e3a77032c5878f3d780448421a6e1818c7", size = 292349, upload-time = "2025-06-15T19:05:52.201Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/cf/421d659de88285eb13941cf11a81f875c176f76a6d99342599be88e08d03/watchfiles-1.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:5366164391873ed76bfdf618818c82084c9db7fac82b64a20c44d335eec9ced5", size = 283836, upload-time = "2025-06-15T19:05:53.265Z" },
+ { url = "https://files.pythonhosted.org/packages/45/10/6faf6858d527e3599cc50ec9fcae73590fbddc1420bd4fdccfebffeedbc6/watchfiles-1.1.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:17ab167cca6339c2b830b744eaf10803d2a5b6683be4d79d8475d88b4a8a4be1", size = 400343, upload-time = "2025-06-15T19:05:54.252Z" },
+ { url = "https://files.pythonhosted.org/packages/03/20/5cb7d3966f5e8c718006d0e97dfe379a82f16fecd3caa7810f634412047a/watchfiles-1.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:328dbc9bff7205c215a7807da7c18dce37da7da718e798356212d22696404339", size = 392916, upload-time = "2025-06-15T19:05:55.264Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/07/d8f1176328fa9e9581b6f120b017e286d2a2d22ae3f554efd9515c8e1b49/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7208ab6e009c627b7557ce55c465c98967e8caa8b11833531fdf95799372633", size = 449582, upload-time = "2025-06-15T19:05:56.317Z" },
+ { url = "https://files.pythonhosted.org/packages/66/e8/80a14a453cf6038e81d072a86c05276692a1826471fef91df7537dba8b46/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a8f6f72974a19efead54195bc9bed4d850fc047bb7aa971268fd9a8387c89011", size = 456752, upload-time = "2025-06-15T19:05:57.359Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/25/0853b3fe0e3c2f5af9ea60eb2e781eade939760239a72c2d38fc4cc335f6/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d181ef50923c29cf0450c3cd47e2f0557b62218c50b2ab8ce2ecaa02bd97e670", size = 481436, upload-time = "2025-06-15T19:05:58.447Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/9e/4af0056c258b861fbb29dcb36258de1e2b857be4a9509e6298abcf31e5c9/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adb4167043d3a78280d5d05ce0ba22055c266cf8655ce942f2fb881262ff3cdf", size = 596016, upload-time = "2025-06-15T19:05:59.59Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/fa/95d604b58aa375e781daf350897aaaa089cff59d84147e9ccff2447c8294/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5701dc474b041e2934a26d31d39f90fac8a3dee2322b39f7729867f932b1d4", size = 476727, upload-time = "2025-06-15T19:06:01.086Z" },
+ { url = "https://files.pythonhosted.org/packages/65/95/fe479b2664f19be4cf5ceeb21be05afd491d95f142e72d26a42f41b7c4f8/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b067915e3c3936966a8607f6fe5487df0c9c4afb85226613b520890049deea20", size = 451864, upload-time = "2025-06-15T19:06:02.144Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/8a/3c4af14b93a15ce55901cd7a92e1a4701910f1768c78fb30f61d2b79785b/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:9c733cda03b6d636b4219625a4acb5c6ffb10803338e437fb614fef9516825ef", size = 625626, upload-time = "2025-06-15T19:06:03.578Z" },
+ { url = "https://files.pythonhosted.org/packages/da/f5/cf6aa047d4d9e128f4b7cde615236a915673775ef171ff85971d698f3c2c/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:cc08ef8b90d78bfac66f0def80240b0197008e4852c9f285907377b2947ffdcb", size = 622744, upload-time = "2025-06-15T19:06:05.066Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/00/70f75c47f05dea6fd30df90f047765f6fc2d6eb8b5a3921379b0b04defa2/watchfiles-1.1.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9974d2f7dc561cce3bb88dfa8eb309dab64c729de85fba32e98d75cf24b66297", size = 402114, upload-time = "2025-06-15T19:06:06.186Z" },
+ { url = "https://files.pythonhosted.org/packages/53/03/acd69c48db4a1ed1de26b349d94077cca2238ff98fd64393f3e97484cae6/watchfiles-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c68e9f1fcb4d43798ad8814c4c1b61547b014b667216cb754e606bfade587018", size = 393879, upload-time = "2025-06-15T19:06:07.369Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/c8/a9a2a6f9c8baa4eceae5887fecd421e1b7ce86802bcfc8b6a942e2add834/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95ab1594377effac17110e1352989bdd7bdfca9ff0e5eeccd8c69c5389b826d0", size = 450026, upload-time = "2025-06-15T19:06:08.476Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/51/d572260d98388e6e2b967425c985e07d47ee6f62e6455cefb46a6e06eda5/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fba9b62da882c1be1280a7584ec4515d0a6006a94d6e5819730ec2eab60ffe12", size = 457917, upload-time = "2025-06-15T19:06:09.988Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/2d/4258e52917bf9f12909b6ec314ff9636276f3542f9d3807d143f27309104/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3434e401f3ce0ed6b42569128b3d1e3af773d7ec18751b918b89cd49c14eaafb", size = 483602, upload-time = "2025-06-15T19:06:11.088Z" },
+ { url = "https://files.pythonhosted.org/packages/84/99/bee17a5f341a4345fe7b7972a475809af9e528deba056f8963d61ea49f75/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa257a4d0d21fcbca5b5fcba9dca5a78011cb93c0323fb8855c6d2dfbc76eb77", size = 596758, upload-time = "2025-06-15T19:06:12.197Z" },
+ { url = "https://files.pythonhosted.org/packages/40/76/e4bec1d59b25b89d2b0716b41b461ed655a9a53c60dc78ad5771fda5b3e6/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fd1b3879a578a8ec2076c7961076df540b9af317123f84569f5a9ddee64ce92", size = 477601, upload-time = "2025-06-15T19:06:13.391Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/fa/a514292956f4a9ce3c567ec0c13cce427c158e9f272062685a8a727d08fc/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc7a30eeb0e20ecc5f4bd113cd69dcdb745a07c68c0370cea919f373f65d9e", size = 451936, upload-time = "2025-06-15T19:06:14.656Z" },
+ { url = "https://files.pythonhosted.org/packages/32/5d/c3bf927ec3bbeb4566984eba8dd7a8eb69569400f5509904545576741f88/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:891c69e027748b4a73847335d208e374ce54ca3c335907d381fde4e41661b13b", size = 626243, upload-time = "2025-06-15T19:06:16.232Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/65/6e12c042f1a68c556802a84d54bb06d35577c81e29fba14019562479159c/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:12fe8eaffaf0faa7906895b4f8bb88264035b3f0243275e0bf24af0436b27259", size = 623073, upload-time = "2025-06-15T19:06:17.457Z" },
+ { url = "https://files.pythonhosted.org/packages/89/ab/7f79d9bf57329e7cbb0a6fd4c7bd7d0cee1e4a8ef0041459f5409da3506c/watchfiles-1.1.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bfe3c517c283e484843cb2e357dd57ba009cff351edf45fb455b5fbd1f45b15f", size = 400872, upload-time = "2025-06-15T19:06:18.57Z" },
+ { url = "https://files.pythonhosted.org/packages/df/d5/3f7bf9912798e9e6c516094db6b8932df53b223660c781ee37607030b6d3/watchfiles-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a9ccbf1f129480ed3044f540c0fdbc4ee556f7175e5ab40fe077ff6baf286d4e", size = 392877, upload-time = "2025-06-15T19:06:19.55Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/c5/54ec7601a2798604e01c75294770dbee8150e81c6e471445d7601610b495/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba0e3255b0396cac3cc7bbace76404dd72b5438bf0d8e7cefa2f79a7f3649caa", size = 449645, upload-time = "2025-06-15T19:06:20.66Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/04/c2f44afc3b2fce21ca0b7802cbd37ed90a29874f96069ed30a36dfe57c2b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4281cd9fce9fc0a9dbf0fc1217f39bf9cf2b4d315d9626ef1d4e87b84699e7e8", size = 457424, upload-time = "2025-06-15T19:06:21.712Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/b0/eec32cb6c14d248095261a04f290636da3df3119d4040ef91a4a50b29fa5/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d2404af8db1329f9a3c9b79ff63e0ae7131986446901582067d9304ae8aaf7f", size = 481584, upload-time = "2025-06-15T19:06:22.777Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/e2/ca4bb71c68a937d7145aa25709e4f5d68eb7698a25ce266e84b55d591bbd/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e78b6ed8165996013165eeabd875c5dfc19d41b54f94b40e9fff0eb3193e5e8e", size = 596675, upload-time = "2025-06-15T19:06:24.226Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/dd/b0e4b7fb5acf783816bc950180a6cd7c6c1d2cf7e9372c0ea634e722712b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:249590eb75ccc117f488e2fabd1bfa33c580e24b96f00658ad88e38844a040bb", size = 477363, upload-time = "2025-06-15T19:06:25.42Z" },
+ { url = "https://files.pythonhosted.org/packages/69/c4/088825b75489cb5b6a761a4542645718893d395d8c530b38734f19da44d2/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05686b5487cfa2e2c28ff1aa370ea3e6c5accfe6435944ddea1e10d93872147", size = 452240, upload-time = "2025-06-15T19:06:26.552Z" },
+ { url = "https://files.pythonhosted.org/packages/10/8c/22b074814970eeef43b7c44df98c3e9667c1f7bf5b83e0ff0201b0bd43f9/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d0e10e6f8f6dc5762adee7dece33b722282e1f59aa6a55da5d493a97282fedd8", size = 625607, upload-time = "2025-06-15T19:06:27.606Z" },
+ { url = "https://files.pythonhosted.org/packages/32/fa/a4f5c2046385492b2273213ef815bf71a0d4c1943b784fb904e184e30201/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:af06c863f152005c7592df1d6a7009c836a247c9d8adb78fef8575a5a98699db", size = 623315, upload-time = "2025-06-15T19:06:29.076Z" },
+]
+
+[[package]]
+name = "wcwidth"
+version = "0.2.14"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" },
+]
+
+[[package]]
+name = "websocket-client"
+version = "1.8.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648, upload-time = "2024-04-23T22:16:16.976Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" },
+]
+
+[[package]]
+name = "websockets"
+version = "15.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" },
+ { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" },
+ { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" },
+ { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" },
+ { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" },
+ { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" },
+ { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" },
+ { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" },
+ { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" },
+ { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" },
+]
+
+[[package]]
+name = "werkzeug"
+version = "3.1.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markupsafe" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" },
+]
+
+[[package]]
+name = "widgetsnbextension"
+version = "4.0.14"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/41/53/2e0253c5efd69c9656b1843892052a31c36d37ad42812b5da45c62191f7e/widgetsnbextension-4.0.14.tar.gz", hash = "sha256:a3629b04e3edb893212df862038c7232f62973373869db5084aed739b437b5af", size = 1097428, upload-time = "2025-04-10T13:01:25.628Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575", size = 2196503, upload-time = "2025-04-10T13:01:23.086Z" },
+]
+
+[[package]]
+name = "xxhash"
+version = "3.5.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/00/5e/d6e5258d69df8b4ed8c83b6664f2b47d30d2dec551a29ad72a6c69eafd31/xxhash-3.5.0.tar.gz", hash = "sha256:84f2caddf951c9cbf8dc2e22a89d4ccf5d86391ac6418fe81e3c67d0cf60b45f", size = 84241, upload-time = "2024-08-17T09:20:38.972Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/07/0e/1bfce2502c57d7e2e787600b31c83535af83746885aa1a5f153d8c8059d6/xxhash-3.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:14470ace8bd3b5d51318782cd94e6f94431974f16cb3b8dc15d52f3b69df8e00", size = 31969, upload-time = "2024-08-17T09:18:24.025Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/d6/8ca450d6fe5b71ce521b4e5db69622383d039e2b253e9b2f24f93265b52c/xxhash-3.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59aa1203de1cb96dbeab595ded0ad0c0056bb2245ae11fac11c0ceea861382b9", size = 30787, upload-time = "2024-08-17T09:18:25.318Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/84/de7c89bc6ef63d750159086a6ada6416cc4349eab23f76ab870407178b93/xxhash-3.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08424f6648526076e28fae6ea2806c0a7d504b9ef05ae61d196d571e5c879c84", size = 220959, upload-time = "2024-08-17T09:18:26.518Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/86/51258d3e8a8545ff26468c977101964c14d56a8a37f5835bc0082426c672/xxhash-3.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61a1ff00674879725b194695e17f23d3248998b843eb5e933007ca743310f793", size = 200006, upload-time = "2024-08-17T09:18:27.905Z" },
+ { url = "https://files.pythonhosted.org/packages/02/0a/96973bd325412feccf23cf3680fd2246aebf4b789122f938d5557c54a6b2/xxhash-3.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2f2c61bee5844d41c3eb015ac652a0229e901074951ae48581d58bfb2ba01be", size = 428326, upload-time = "2024-08-17T09:18:29.335Z" },
+ { url = "https://files.pythonhosted.org/packages/11/a7/81dba5010f7e733de88af9555725146fc133be97ce36533867f4c7e75066/xxhash-3.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d32a592cac88d18cc09a89172e1c32d7f2a6e516c3dfde1b9adb90ab5df54a6", size = 194380, upload-time = "2024-08-17T09:18:30.706Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/7d/f29006ab398a173f4501c0e4977ba288f1c621d878ec217b4ff516810c04/xxhash-3.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70dabf941dede727cca579e8c205e61121afc9b28516752fd65724be1355cc90", size = 207934, upload-time = "2024-08-17T09:18:32.133Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/6e/6e88b8f24612510e73d4d70d9b0c7dff62a2e78451b9f0d042a5462c8d03/xxhash-3.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e5d0ddaca65ecca9c10dcf01730165fd858533d0be84c75c327487c37a906a27", size = 216301, upload-time = "2024-08-17T09:18:33.474Z" },
+ { url = "https://files.pythonhosted.org/packages/af/51/7862f4fa4b75a25c3b4163c8a873f070532fe5f2d3f9b3fc869c8337a398/xxhash-3.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e5b5e16c5a480fe5f59f56c30abdeba09ffd75da8d13f6b9b6fd224d0b4d0a2", size = 203351, upload-time = "2024-08-17T09:18:34.889Z" },
+ { url = "https://files.pythonhosted.org/packages/22/61/8d6a40f288f791cf79ed5bb113159abf0c81d6efb86e734334f698eb4c59/xxhash-3.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149b7914451eb154b3dfaa721315117ea1dac2cc55a01bfbd4df7c68c5dd683d", size = 210294, upload-time = "2024-08-17T09:18:36.355Z" },
+ { url = "https://files.pythonhosted.org/packages/17/02/215c4698955762d45a8158117190261b2dbefe9ae7e5b906768c09d8bc74/xxhash-3.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:eade977f5c96c677035ff39c56ac74d851b1cca7d607ab3d8f23c6b859379cab", size = 414674, upload-time = "2024-08-17T09:18:38.536Z" },
+ { url = "https://files.pythonhosted.org/packages/31/5c/b7a8db8a3237cff3d535261325d95de509f6a8ae439a5a7a4ffcff478189/xxhash-3.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa9f547bd98f5553d03160967866a71056a60960be00356a15ecc44efb40ba8e", size = 192022, upload-time = "2024-08-17T09:18:40.138Z" },
+ { url = "https://files.pythonhosted.org/packages/78/e3/dd76659b2811b3fd06892a8beb850e1996b63e9235af5a86ea348f053e9e/xxhash-3.5.0-cp312-cp312-win32.whl", hash = "sha256:f7b58d1fd3551b8c80a971199543379be1cee3d0d409e1f6d8b01c1a2eebf1f8", size = 30170, upload-time = "2024-08-17T09:18:42.163Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/6b/1c443fe6cfeb4ad1dcf231cdec96eb94fb43d6498b4469ed8b51f8b59a37/xxhash-3.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:fa0cafd3a2af231b4e113fba24a65d7922af91aeb23774a8b78228e6cd785e3e", size = 30040, upload-time = "2024-08-17T09:18:43.699Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/eb/04405305f290173acc0350eba6d2f1a794b57925df0398861a20fbafa415/xxhash-3.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:586886c7e89cb9828bcd8a5686b12e161368e0064d040e225e72607b43858ba2", size = 26796, upload-time = "2024-08-17T09:18:45.29Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/b8/e4b3ad92d249be5c83fa72916c9091b0965cb0faeff05d9a0a3870ae6bff/xxhash-3.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:37889a0d13b0b7d739cfc128b1c902f04e32de17b33d74b637ad42f1c55101f6", size = 31795, upload-time = "2024-08-17T09:18:46.813Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/d8/b3627a0aebfbfa4c12a41e22af3742cf08c8ea84f5cc3367b5de2d039cce/xxhash-3.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:97a662338797c660178e682f3bc180277b9569a59abfb5925e8620fba00b9fc5", size = 30792, upload-time = "2024-08-17T09:18:47.862Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/cc/762312960691da989c7cd0545cb120ba2a4148741c6ba458aa723c00a3f8/xxhash-3.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f85e0108d51092bdda90672476c7d909c04ada6923c14ff9d913c4f7dc8a3bc", size = 220950, upload-time = "2024-08-17T09:18:49.06Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/e9/cc266f1042c3c13750e86a535496b58beb12bf8c50a915c336136f6168dc/xxhash-3.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2fd827b0ba763ac919440042302315c564fdb797294d86e8cdd4578e3bc7f3", size = 199980, upload-time = "2024-08-17T09:18:50.445Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/85/a836cd0dc5cc20376de26b346858d0ac9656f8f730998ca4324921a010b9/xxhash-3.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82085c2abec437abebf457c1d12fccb30cc8b3774a0814872511f0f0562c768c", size = 428324, upload-time = "2024-08-17T09:18:51.988Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/0e/15c243775342ce840b9ba34aceace06a1148fa1630cd8ca269e3223987f5/xxhash-3.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07fda5de378626e502b42b311b049848c2ef38784d0d67b6f30bb5008642f8eb", size = 194370, upload-time = "2024-08-17T09:18:54.164Z" },
+ { url = "https://files.pythonhosted.org/packages/87/a1/b028bb02636dfdc190da01951d0703b3d904301ed0ef6094d948983bef0e/xxhash-3.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c279f0d2b34ef15f922b77966640ade58b4ccdfef1c4d94b20f2a364617a493f", size = 207911, upload-time = "2024-08-17T09:18:55.509Z" },
+ { url = "https://files.pythonhosted.org/packages/80/d5/73c73b03fc0ac73dacf069fdf6036c9abad82de0a47549e9912c955ab449/xxhash-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:89e66ceed67b213dec5a773e2f7a9e8c58f64daeb38c7859d8815d2c89f39ad7", size = 216352, upload-time = "2024-08-17T09:18:57.073Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/2a/5043dba5ddbe35b4fe6ea0a111280ad9c3d4ba477dd0f2d1fe1129bda9d0/xxhash-3.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bcd51708a633410737111e998ceb3b45d3dbc98c0931f743d9bb0a209033a326", size = 203410, upload-time = "2024-08-17T09:18:58.54Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/b2/9a8ded888b7b190aed75b484eb5c853ddd48aa2896e7b59bbfbce442f0a1/xxhash-3.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ff2c0a34eae7df88c868be53a8dd56fbdf592109e21d4bfa092a27b0bf4a7bf", size = 210322, upload-time = "2024-08-17T09:18:59.943Z" },
+ { url = "https://files.pythonhosted.org/packages/98/62/440083fafbc917bf3e4b67c2ade621920dd905517e85631c10aac955c1d2/xxhash-3.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e28503dccc7d32e0b9817aa0cbfc1f45f563b2c995b7a66c4c8a0d232e840c7", size = 414725, upload-time = "2024-08-17T09:19:01.332Z" },
+ { url = "https://files.pythonhosted.org/packages/75/db/009206f7076ad60a517e016bb0058381d96a007ce3f79fa91d3010f49cc2/xxhash-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a6c50017518329ed65a9e4829154626f008916d36295b6a3ba336e2458824c8c", size = 192070, upload-time = "2024-08-17T09:19:03.007Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/6d/c61e0668943a034abc3a569cdc5aeae37d686d9da7e39cf2ed621d533e36/xxhash-3.5.0-cp313-cp313-win32.whl", hash = "sha256:53a068fe70301ec30d868ece566ac90d873e3bb059cf83c32e76012c889b8637", size = 30172, upload-time = "2024-08-17T09:19:04.355Z" },
+ { url = "https://files.pythonhosted.org/packages/96/14/8416dce965f35e3d24722cdf79361ae154fa23e2ab730e5323aa98d7919e/xxhash-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:80babcc30e7a1a484eab952d76a4f4673ff601f54d5142c26826502740e70b43", size = 30041, upload-time = "2024-08-17T09:19:05.435Z" },
+ { url = "https://files.pythonhosted.org/packages/27/ee/518b72faa2073f5aa8e3262408d284892cb79cf2754ba0c3a5870645ef73/xxhash-3.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:4811336f1ce11cac89dcbd18f3a25c527c16311709a89313c3acaf771def2d4b", size = 26801, upload-time = "2024-08-17T09:19:06.547Z" },
+]
+
+[[package]]
+name = "yarl"
+version = "1.20.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "idna" },
+ { name = "multidict" },
+ { name = "propcache" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" },
+ { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" },
+ { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" },
+ { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" },
+ { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" },
+ { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" },
+ { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" },
+ { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" },
+ { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" },
+ { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" },
+ { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" },
+ { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" },
+ { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" },
+ { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" },
+ { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" },
+ { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" },
+ { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" },
+ { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" },
+ { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" },
+ { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" },
+ { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" },
+ { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" },
+ { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" },
+ { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" },
+ { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" },
+]
+
+[[package]]
+name = "zipp"
+version = "3.23.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" },
+]
+
+[[package]]
+name = "zstandard"
+version = "0.25.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" },
+ { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" },
+ { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" },
+ { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" },
+ { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" },
+ { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" },
+ { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" },
+ { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" },
+ { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" },
+ { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" },
+ { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" },
+ { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887, upload-time = "2025-09-14T22:17:54.198Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658, upload-time = "2025-09-14T22:17:55.423Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849, upload-time = "2025-09-14T22:17:57.372Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095, upload-time = "2025-09-14T22:17:59.498Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751, upload-time = "2025-09-14T22:18:01.618Z" },
+ { url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818, upload-time = "2025-09-14T22:18:03.769Z" },
+ { url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402, upload-time = "2025-09-14T22:18:05.954Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108, upload-time = "2025-09-14T22:18:07.68Z" },
+ { url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248, upload-time = "2025-09-14T22:18:09.753Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330, upload-time = "2025-09-14T22:18:11.966Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123, upload-time = "2025-09-14T22:18:13.907Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591, upload-time = "2025-09-14T22:18:16.465Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" },
+]
diff --git a/week1/day1.ipynb b/week1/day1.ipynb
index f492110..37c6c3b 100644
--- a/week1/day1.ipynb
+++ b/week1/day1.ipynb
@@ -8,64 +8,31 @@
"# YOUR FIRST LAB\n",
"### Please read this section. This is valuable to get you prepared, even if it's a long read -- it's important stuff.\n",
"\n",
- "## Your first Frontier LLM Project\n",
+ "Be sure to read the README.md first!\n",
"\n",
- "Let's build a useful LLM solution - in a matter of minutes.\n",
+ "## Your first Frontier LLM Project\n",
"\n",
"By the end of this course, you will have built an autonomous Agentic AI solution with 7 agents that collaborate to solve a business problem. All in good time! We will start with something smaller...\n",
"\n",
"Our goal is to code a new kind of Web Browser. Give it a URL, and it will respond with a summary. The Reader's Digest of the internet!!\n",
"\n",
- "Before starting, you should have completed the setup for [PC](../SETUP-PC.md) or [Mac](../SETUP-mac.md) and you hopefully launched this jupyter lab from within the project root directory, with your environment activated.\n",
+ "Before starting, you should have completed the setup linked in the README.\n",
"\n",
- "## If you're new to Jupyter Lab\n",
+ "### If you're new to working in \"Notebooks\" (also known as Labs or Jupyter Lab)\n",
"\n",
- "Welcome to the wonderful world of Data Science experimentation! Once you've used Jupyter Lab, you'll wonder how you ever lived without it. Simply click in each \"cell\" with code in it, such as the cell immediately below this text, and hit Shift+Return to execute that cell. As you wish, you can add a cell with the + button in the toolbar, and print values of variables, or try out variations. \n",
+ "Welcome to the wonderful world of Data Science experimentation! Simply click in each \"cell\" with code in it, such as the cell immediately below this text, and hit Shift+Return to execute that cell. Be sure to run every cell, starting at the top, in order.\n",
"\n",
- "I've written a notebook called [Guide to Jupyter](Guide%20to%20Jupyter.ipynb) to help you get more familiar with Jupyter Labs, including adding Markdown comments, using `!` to run shell commands, and `tqdm` to show progress.\n",
- "\n",
- "## If you're new to the Command Line\n",
- "\n",
- "Please see these excellent guides: [Command line on PC](https://chatgpt.com/share/67b0acea-ba38-8012-9c34-7a2541052665) and [Command line on Mac](https://chatgpt.com/canvas/shared/67b0b10c93a081918210723867525d2b). \n",
- "\n",
- "## If you'd prefer to work in IDEs\n",
- "\n",
- "If you're more comfortable in IDEs like VSCode, Cursor or PyCharm, they both work great with these lab notebooks too. \n",
- "If you'd prefer to work in VSCode, [here](https://chatgpt.com/share/676f2e19-c228-8012-9911-6ca42f8ed766) are instructions from an AI friend on how to configure it for the course.\n",
- "\n",
- "## If you'd like to brush up your Python\n",
- "\n",
- "I've added a notebook called [Intermediate Python](Intermediate%20Python.ipynb) to get you up to speed. But you should give it a miss if you already have a good idea what this code does: \n",
- "`yield from {book.get(\"author\") for book in books if book.get(\"author\")}`\n",
+ "Please look in the [Guides folder](../guides/01_intro.ipynb) for all the guides.\n",
"\n",
"## I am here to help\n",
"\n",
"If you have any problems at all, please do reach out. \n",
"I'm available through the platform, or at ed@edwarddonner.com, or at https://www.linkedin.com/in/eddonner/ if you'd like to connect (and I love connecting!) \n",
- "And this is new to me, but I'm also trying out X/Twitter at [@edwarddonner](https://x.com/edwarddonner) - if you're on X, please show me how it's done 😂 \n",
+ "And this is new to me, but I'm also trying out X at [@edwarddonner](https://x.com/edwarddonner) - if you're on X, please show me how it's done 😂 \n",
"\n",
"## More troubleshooting\n",
"\n",
- "Please see the [troubleshooting](troubleshooting.ipynb) notebook in this folder to diagnose and fix common problems. At the very end of it is a diagnostics script with some useful debug info.\n",
- "\n",
- "## For foundational technical knowledge (eg Git, APIs, debugging) \n",
- "\n",
- "If you're relatively new to programming -- I've got your back! While it's ideal to have some programming experience for this course, there's only one mandatory prerequisite: plenty of patience. 😁 I've put together a set of self-study guides that cover Git and GitHub, APIs and endpoints, beginner python and more.\n",
- "\n",
- "This covers Git and GitHub; what they are, the difference, and how to use them: \n",
- "https://github.com/ed-donner/agents/blob/main/guides/03_git_and_github.ipynb\n",
- "\n",
- "This covers technical foundations: \n",
- "ChatGPT vs API; taking screenshots; Environment Variables; Networking basics; APIs and endpoints: \n",
- "https://github.com/ed-donner/agents/blob/main/guides/04_technical_foundations.ipynb\n",
- "\n",
- "This covers Python for beginners, and making sure that a `NameError` never trips you up: \n",
- "https://github.com/ed-donner/agents/blob/main/guides/06_python_foundations.ipynb\n",
- "\n",
- "This covers the essential techniques for figuring out errors: \n",
- "https://github.com/ed-donner/agents/blob/main/guides/08_debugging.ipynb\n",
- "\n",
- "And you'll find other useful guides in the same folder in GitHub. Some information applies to my other Udemy course (eg Async Python) but most of it is very relevant for LLM engineering.\n",
+ "Please see the [troubleshooting](../setup/troubleshooting.ipynb) notebook in the setup folder to diagnose and fix common problems. At the very end of it is a diagnostics script with some useful debug info.\n",
"\n",
"## If this is old hat!\n",
"\n",
@@ -74,7 +41,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Please read - important note\n",
@@ -85,7 +52,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" This code is a live resource - keep an eye out for my emails\n",
@@ -98,7 +65,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Business value of these exercises\n",
@@ -108,6 +75,33 @@
" | "
]
},
+ {
+ "cell_type": "markdown",
+ "id": "83f28feb",
+ "metadata": {},
+ "source": [
+ "### If necessary, install Cursor Extensions\n",
+ "\n",
+ "1. From the View menu, select Extensions\n",
+ "2. Search for Python\n",
+ "3. Click on \"Python\" made by \"ms-python\" and select Install if not already installed\n",
+ "4. Search for Jupyter\n",
+ "5. Click on \"Jupyter\" made by \"ms-toolsai\" and select Install of not already installed\n",
+ "\n",
+ "\n",
+ "### Next Select the Kernel\n",
+ "\n",
+ "Click on \"Select Kernel\" on the Top Right\n",
+ "\n",
+ "Choose \"Python Environments...\"\n",
+ "\n",
+ "Then choose the one that looks like `.venv (Python 3.12.x) .venv/bin/python` - it should be marked as \"Recommended\" and have a big star next to it.\n",
+ "\n",
+ "Any problems with this? Head over to the troubleshooting.\n",
+ "\n",
+ "### Note: you'll need to set the Kernel with every notebook.."
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
@@ -118,9 +112,8 @@
"# imports\n",
"\n",
"import os\n",
- "import requests\n",
"from dotenv import load_dotenv\n",
- "from bs4 import BeautifulSoup\n",
+ "from scraper import fetch_website_contents\n",
"from IPython.display import Markdown, display\n",
"from openai import OpenAI\n",
"\n",
@@ -140,9 +133,9 @@
"\n",
"## Troubleshooting if you have problems:\n",
"\n",
- "Head over to the [troubleshooting](troubleshooting.ipynb) notebook in this folder for step by step code to identify the root cause and fix it!\n",
+ "If you get a \"Name Error\" - have you run all cells from the top down? Head over to the Python Foundations guide for a bulletproof way to find and fix all Name Errors.\n",
"\n",
- "If you make a change, try restarting the \"Kernel\" (the python process sitting behind this notebook) by Kernel menu >> Restart Kernel and Clear Outputs of All Cells. Then try this notebook again, starting at the top.\n",
+ "If that doesn't fix it, head over to the [troubleshooting](../setup/troubleshooting.ipynb) notebook for step by step code to identify the root cause and fix it!\n",
"\n",
"Or, contact me! Message me or email ed@edwarddonner.com and we will get this to work.\n",
"\n",
@@ -173,19 +166,6 @@
" print(\"API key found and looks good so far!\")\n"
]
},
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "019974d9-f3ad-4a8a-b5f9-0a3719aea2d3",
- "metadata": {},
- "outputs": [],
- "source": [
- "openai = OpenAI()\n",
- "\n",
- "# If this doesn't work, try Kernel menu >> Restart Kernel and Clear Outputs Of All Cells, then run the cells from the top of this notebook down.\n",
- "# If it STILL doesn't work (horrors!) then please see the Troubleshooting notebook in this folder for full instructions"
- ]
- },
{
"cell_type": "markdown",
"id": "442fc84b-0815-4f40-99ab-d9a5da6bda91",
@@ -204,8 +184,23 @@
"# To give you a preview -- calling OpenAI with these messages is this easy. Any problems, head over to the Troubleshooting notebook.\n",
"\n",
"message = \"Hello, GPT! This is my first ever message to you! Hi!\"\n",
- "response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=[{\"role\":\"user\", \"content\":message}])\n",
- "print(response.choices[0].message.content)"
+ "\n",
+ "messages = [{\"role\": \"user\", \"content\": message}]\n",
+ "\n",
+ "messages\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "08330159",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "openai = OpenAI()\n",
+ "\n",
+ "response = openai.chat.completions.create(model=\"gpt-5-nano\", messages=messages)\n",
+ "response.choices[0].message.content"
]
},
{
@@ -216,36 +211,6 @@
"## OK onwards with our first project"
]
},
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "c5e793b2-6775-426a-a139-4848291d0463",
- "metadata": {},
- "outputs": [],
- "source": [
- "# A class to represent a Webpage\n",
- "# If you're not familiar with Classes, check out the \"Intermediate Python\" notebook\n",
- "\n",
- "# Some websites need you to use proper headers when fetching them:\n",
- "headers = {\n",
- " \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\"\n",
- "}\n",
- "\n",
- "class Website:\n",
- "\n",
- " def __init__(self, url):\n",
- " \"\"\"\n",
- " Create this Website object from the given url using the BeautifulSoup library\n",
- " \"\"\"\n",
- " self.url = url\n",
- " response = requests.get(url, headers=headers)\n",
- " soup = BeautifulSoup(response.content, 'html.parser')\n",
- " self.title = soup.title.string if soup.title else \"No title found\"\n",
- " for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n",
- " irrelevant.decompose()\n",
- " self.text = soup.body.get_text(separator=\"\\n\", strip=True)"
- ]
- },
{
"cell_type": "code",
"execution_count": null,
@@ -253,11 +218,10 @@
"metadata": {},
"outputs": [],
"source": [
- "# Let's try one out. Change the website and add print statements to follow along.\n",
+ "# Let's try out this utility\n",
"\n",
- "ed = Website(\"https://edwarddonner.com\")\n",
- "print(ed.title)\n",
- "print(ed.text)"
+ "ed = fetch_website_contents(\"https://edwarddonner.com\")\n",
+ "print(ed)"
]
},
{
@@ -269,7 +233,7 @@
"\n",
"You may know this already - but if not, you will get very familiar with it!\n",
"\n",
- "Models like GPT4o have been trained to receive instructions in a particular way.\n",
+ "Models like GPT have been trained to receive instructions in a particular way.\n",
"\n",
"They expect to receive:\n",
"\n",
@@ -287,9 +251,11 @@
"source": [
"# Define our system prompt - you can experiment with this later, changing the last sentence to 'Respond in markdown in Spanish.\"\n",
"\n",
- "system_prompt = \"You are an assistant that analyzes the contents of a website \\\n",
- "and provides a short summary, ignoring text that might be navigation related. \\\n",
- "Respond in markdown.\""
+ "system_prompt = \"\"\"\n",
+ "You are a snarkyassistant that analyzes the contents of a website,\n",
+ "and provides a short, snarky, humorous summary, ignoring text that might be navigation related.\n",
+ "Respond in markdown. Do not wrap the markdown in a code block - respond just with the markdown.\n",
+ "\"\"\""
]
},
{
@@ -299,25 +265,14 @@
"metadata": {},
"outputs": [],
"source": [
- "# A function that writes a User Prompt that asks for summaries of websites:\n",
+ "# Define our user prompt\n",
"\n",
- "def user_prompt_for(website):\n",
- " user_prompt = f\"You are looking at a website titled {website.title}\"\n",
- " user_prompt += \"\\nThe contents of this website is as follows; \\\n",
- "please provide a short summary of this website in markdown. \\\n",
- "If it includes news or announcements, then summarize these too.\\n\\n\"\n",
- " user_prompt += website.text\n",
- " return user_prompt"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "26448ec4-5c00-4204-baec-7df91d11ff2e",
- "metadata": {},
- "outputs": [],
- "source": [
- "print(user_prompt_for(ed))"
+ "user_prompt_prefix = \"\"\"\n",
+ "Here are the contents of a website.\n",
+ "Provide a short summary of this website.\n",
+ "If it includes news or announcements, then summarize these too.\n",
+ "\n",
+ "\"\"\""
]
},
{
@@ -347,22 +302,12 @@
"outputs": [],
"source": [
"messages = [\n",
- " {\"role\": \"system\", \"content\": \"You are a snarky assistant\"},\n",
+ " {\"role\": \"system\", \"content\": \"You are a helpful assistant\"},\n",
" {\"role\": \"user\", \"content\": \"What is 2 + 2?\"}\n",
- "]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "21ed95c5-7001-47de-a36d-1d6673b403ce",
- "metadata": {},
- "outputs": [],
- "source": [
- "# To give you a preview -- calling OpenAI with system and user messages:\n",
+ "]\n",
"\n",
- "response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
- "print(response.choices[0].message.content)"
+ "response = openai.chat.completions.create(model=\"gpt-4.1-nano\", messages=messages)\n",
+ "response.choices[0].message.content"
]
},
{
@@ -370,7 +315,7 @@
"id": "d06e8d78-ce4c-4b05-aa8e-17050c82bb47",
"metadata": {},
"source": [
- "## And now let's build useful messages for GPT-4o-mini, using a function"
+ "## And now let's build useful messages for GPT-4.1-mini, using a function"
]
},
{
@@ -385,7 +330,7 @@
"def messages_for(website):\n",
" return [\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
- " {\"role\": \"user\", \"content\": user_prompt_for(website)}\n",
+ " {\"role\": \"user\", \"content\": user_prompt_prefix + website}\n",
" ]"
]
},
@@ -419,9 +364,9 @@
"# And now: call the OpenAI API. You will get very familiar with this!\n",
"\n",
"def summarize(url):\n",
- " website = Website(url)\n",
+ " website = fetch_website_contents(url)\n",
" response = openai.chat.completions.create(\n",
- " model = \"gpt-4o-mini\",\n",
+ " model = \"gpt-4.1-mini\",\n",
" messages = messages_for(website)\n",
" )\n",
" return response.choices[0].message.content"
@@ -444,7 +389,7 @@
"metadata": {},
"outputs": [],
"source": [
- "# A function to display this nicely in the Jupyter output, using markdown\n",
+ "# A function to display this nicely in the output, using markdown\n",
"\n",
"def display_summary(url):\n",
" summary = summarize(url)\n",
@@ -505,7 +450,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Business applications\n",
@@ -519,7 +464,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Before you continue - now try yourself\n",
@@ -549,12 +494,10 @@
"messages = [] # fill this in\n",
"\n",
"# Step 3: Call OpenAI\n",
- "\n",
- "response =\n",
+ "# response =\n",
"\n",
"# Step 4: print the result\n",
- "\n",
- "print("
+ "# print("
]
},
{
@@ -593,7 +536,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -607,7 +550,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.12"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/week1/day2 EXERCISE.ipynb b/week1/day2 EXERCISE.ipynb
deleted file mode 100644
index 89a383f..0000000
--- a/week1/day2 EXERCISE.ipynb
+++ /dev/null
@@ -1,316 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "d15d8294-3328-4e07-ad16-8a03e9bbfdb9",
- "metadata": {},
- "source": [
- "# Welcome to your first assignment!\n",
- "\n",
- "Instructions are below. Please give this a try, and look in the solutions folder if you get stuck (or feel free to ask me!)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ada885d9-4d42-4d9b-97f0-74fbbbfe93a9",
- "metadata": {},
- "source": [
- "\n",
- " \n",
- " \n",
- " \n",
- " | \n",
- " \n",
- " Just before we get to the assignment --\n",
- " I thought I'd take a second to point you at this page of useful resources for the course. This includes links to all the slides. \n",
- " https://edwarddonner.com/2024/11/13/llm-engineering-resources/ \n",
- " Please keep this bookmarked, and I'll continue to add more useful links there over time.\n",
- " \n",
- " | \n",
- " \n",
- " "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6e9fa1fc-eac5-4d1d-9be4-541b3f2b3458",
- "metadata": {},
- "source": [
- "# HOMEWORK EXERCISE ASSIGNMENT\n",
- "\n",
- "Upgrade the day 1 project to summarize a webpage to use an Open Source model running locally via Ollama rather than OpenAI\n",
- "\n",
- "You'll be able to use this technique for all subsequent projects if you'd prefer not to use paid APIs.\n",
- "\n",
- "**Benefits:**\n",
- "1. No API charges - open-source\n",
- "2. Data doesn't leave your box\n",
- "\n",
- "**Disadvantages:**\n",
- "1. Significantly less power than Frontier Model\n",
- "\n",
- "## Recap on installation of Ollama\n",
- "\n",
- "Simply visit [ollama.com](https://ollama.com) and install!\n",
- "\n",
- "Once complete, the ollama server should already be running locally. \n",
- "If you visit: \n",
- "[http://localhost:11434/](http://localhost:11434/)\n",
- "\n",
- "You should see the message `Ollama is running`. \n",
- "\n",
- "If not, bring up a new Terminal (Mac) or Powershell (Windows) and enter `ollama serve` \n",
- "And in another Terminal (Mac) or Powershell (Windows), enter `ollama pull llama3.2` \n",
- "Then try [http://localhost:11434/](http://localhost:11434/) again.\n",
- "\n",
- "If Ollama is slow on your machine, try using `llama3.2:1b` as an alternative. Run `ollama pull llama3.2:1b` from a Terminal or Powershell, and change the code below from `MODEL = \"llama3.2\"` to `MODEL = \"llama3.2:1b\"`"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "4e2a9393-7767-488e-a8bf-27c12dca35bd",
- "metadata": {},
- "outputs": [],
- "source": [
- "# imports\n",
- "\n",
- "import requests\n",
- "from bs4 import BeautifulSoup\n",
- "from IPython.display import Markdown, display"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "29ddd15d-a3c5-4f4e-a678-873f56162724",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Constants\n",
- "\n",
- "OLLAMA_API = \"http://localhost:11434/api/chat\"\n",
- "HEADERS = {\"Content-Type\": \"application/json\"}\n",
- "MODEL = \"llama3.2\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "dac0a679-599c-441f-9bf2-ddc73d35b940",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Create a messages list using the same format that we used for OpenAI\n",
- "\n",
- "messages = [\n",
- " {\"role\": \"user\", \"content\": \"Describe some of the business applications of Generative AI\"}\n",
- "]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7bb9c624-14f0-4945-a719-8ddb64f66f47",
- "metadata": {},
- "outputs": [],
- "source": [
- "payload = {\n",
- " \"model\": MODEL,\n",
- " \"messages\": messages,\n",
- " \"stream\": False\n",
- " }"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "479ff514-e8bd-4985-a572-2ea28bb4fa40",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Let's just make sure the model is loaded\n",
- "\n",
- "!ollama pull llama3.2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "42b9f644-522d-4e05-a691-56e7658c0ea9",
- "metadata": {},
- "outputs": [],
- "source": [
- "# If this doesn't work for any reason, try the 2 versions in the following cells\n",
- "# And double check the instructions in the 'Recap on installation of Ollama' at the top of this lab\n",
- "# And if none of that works - contact me!\n",
- "\n",
- "response = requests.post(OLLAMA_API, json=payload, headers=HEADERS)\n",
- "print(response.json()['message']['content'])"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6a021f13-d6a1-4b96-8e18-4eae49d876fe",
- "metadata": {},
- "source": [
- "# Introducing the ollama package\n",
- "\n",
- "And now we'll do the same thing, but using the elegant ollama python package instead of a direct HTTP call.\n",
- "\n",
- "Under the hood, it's making the same call as above to the ollama server running at localhost:11434"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7745b9c4-57dc-4867-9180-61fa5db55eb8",
- "metadata": {},
- "outputs": [],
- "source": [
- "import ollama\n",
- "\n",
- "response = ollama.chat(model=MODEL, messages=messages)\n",
- "print(response['message']['content'])"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a4704e10-f5fb-4c15-a935-f046c06fb13d",
- "metadata": {},
- "source": [
- "## Alternative approach - using OpenAI python library to connect to Ollama"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "23057e00-b6fc-4678-93a9-6b31cb704bff",
- "metadata": {},
- "outputs": [],
- "source": [
- "# There's actually an alternative approach that some people might prefer\n",
- "# You can use the OpenAI client python library to call Ollama:\n",
- "\n",
- "from openai import OpenAI\n",
- "ollama_via_openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n",
- "\n",
- "response = ollama_via_openai.chat.completions.create(\n",
- " model=MODEL,\n",
- " messages=messages\n",
- ")\n",
- "\n",
- "print(response.choices[0].message.content)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "9f9e22da-b891-41f6-9ac9-bd0c0a5f4f44",
- "metadata": {},
- "source": [
- "## Are you confused about why that works?\n",
- "\n",
- "It seems strange, right? We just used OpenAI code to call Ollama?? What's going on?!\n",
- "\n",
- "Here's the scoop:\n",
- "\n",
- "The python class `OpenAI` is simply code written by OpenAI engineers that makes calls over the internet to an endpoint. \n",
- "\n",
- "When you call `openai.chat.completions.create()`, this python code just makes a web request to the following url: \"https://api.openai.com/v1/chat/completions\"\n",
- "\n",
- "Code like this is known as a \"client library\" - it's just wrapper code that runs on your machine to make web requests. The actual power of GPT is running on OpenAI's cloud behind this API, not on your computer!\n",
- "\n",
- "OpenAI was so popular, that lots of other AI providers provided identical web endpoints, so you could use the same approach.\n",
- "\n",
- "So Ollama has an endpoint running on your local box at http://localhost:11434/v1/chat/completions \n",
- "And in week 2 we'll discover that lots of other providers do this too, including Gemini and DeepSeek.\n",
- "\n",
- "And then the team at OpenAI had a great idea: they can extend their client library so you can specify a different 'base url', and use their library to call any compatible API.\n",
- "\n",
- "That's it!\n",
- "\n",
- "So when you say: `ollama_via_openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')` \n",
- "Then this will make the same endpoint calls, but to Ollama instead of OpenAI."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "bc7d1de3-e2ac-46ff-a302-3b4ba38c4c90",
- "metadata": {},
- "source": [
- "## Also trying the amazing reasoning model DeepSeek\n",
- "\n",
- "Here we use the version of DeepSeek-reasoner that's been distilled to 1.5B. \n",
- "This is actually a 1.5B variant of Qwen that has been fine-tuned using synethic data generated by Deepseek R1.\n",
- "\n",
- "Other sizes of DeepSeek are [here](https://ollama.com/library/deepseek-r1) all the way up to the full 671B parameter version, which would use up 404GB of your drive and is far too large for most!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "cf9eb44e-fe5b-47aa-b719-0bb63669ab3d",
- "metadata": {},
- "outputs": [],
- "source": [
- "!ollama pull deepseek-r1:1.5b"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "1d3d554b-e00d-4c08-9300-45e073950a76",
- "metadata": {},
- "outputs": [],
- "source": [
- "# This may take a few minutes to run! You should then see a fascinating \"thinking\" trace inside tags, followed by some decent definitions\n",
- "\n",
- "response = ollama_via_openai.chat.completions.create(\n",
- " model=\"deepseek-r1:1.5b\",\n",
- " messages=[{\"role\": \"user\", \"content\": \"Please give definitions of some core concepts behind LLMs: a neural network, attention and the transformer\"}]\n",
- ")\n",
- "\n",
- "print(response.choices[0].message.content)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "1622d9bb-5c68-4d4e-9ca4-b492c751f898",
- "metadata": {},
- "source": [
- "# NOW the exercise for you\n",
- "\n",
- "Take the code from day1 and incorporate it here, to build a website summarizer that uses Llama 3.2 running locally instead of OpenAI; use either of the above approaches."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "6de38216-6d1c-48c4-877b-86d403f4e0f8",
- "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.11.12"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/week1/day2.ipynb b/week1/day2.ipynb
new file mode 100644
index 0000000..2e3dfc0
--- /dev/null
+++ b/week1/day2.ipynb
@@ -0,0 +1,389 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "d15d8294-3328-4e07-ad16-8a03e9bbfdb9",
+ "metadata": {},
+ "source": [
+ "# Welcome to the Day 2 Lab!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ada885d9-4d42-4d9b-97f0-74fbbbfe93a9",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " Just before we get started --\n",
+ " I thought I'd take a second to point you at this page of useful resources for the course. This includes links to all the slides. \n",
+ " https://edwarddonner.com/2024/11/13/llm-engineering-resources/ \n",
+ " Please keep this bookmarked, and I'll continue to add more useful links there over time.\n",
+ " \n",
+ " | \n",
+ " \n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "79ffe36f",
+ "metadata": {},
+ "source": [
+ "## First - let's talk about the Chat Completions API\n",
+ "\n",
+ "1. The simplest way to call an LLM\n",
+ "2. It's called Chat Completions because it's saying: \"here is a conversation, please predict what should come next\"\n",
+ "3. The Chat Completions API was invented by OpenAI, but it's so popular that everybody uses it!\n",
+ "\n",
+ "### We will start by calling OpenAI again - but don't worry non-OpenAI people, your time is coming!\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e38f17a0",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "from dotenv import load_dotenv\n",
+ "\n",
+ "load_dotenv(override=True)\n",
+ "api_key = os.getenv('OPENAI_API_KEY')\n",
+ "\n",
+ "if not api_key:\n",
+ " print(\"No API key was found - please head over to the troubleshooting notebook in this folder to identify & fix!\")\n",
+ "elif not api_key.startswith(\"sk-proj-\"):\n",
+ " print(\"An API key was found, but it doesn't start sk-proj-; please check you're using the right key - see troubleshooting notebook\")\n",
+ "else:\n",
+ " print(\"API key found and looks good so far!\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "97846274",
+ "metadata": {},
+ "source": [
+ "## Do you know what an Endpoint is?\n",
+ "\n",
+ "If not, please review the Technical Foundations guide in the guides folder\n",
+ "\n",
+ "And, here is an endpoint that might interest you..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5af5c188",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import requests\n",
+ "\n",
+ "headers = {\"Authorization\": f\"Bearer {api_key}\", \"Content-Type\": \"application/json\"}\n",
+ "\n",
+ "payload = {\n",
+ " \"model\": \"gpt-5-nano\",\n",
+ " \"messages\": [\n",
+ " {\"role\": \"user\", \"content\": \"Tell me a fun fact\"}]\n",
+ "}\n",
+ "\n",
+ "payload"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2d0ab242",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = requests.post(\n",
+ " \"https://api.openai.com/v1/chat/completions\",\n",
+ " headers=headers,\n",
+ " json=payload\n",
+ ")\n",
+ "\n",
+ "response.json()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cb11a9f6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response.json()[\"choices\"][0][\"message\"][\"content\"]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cea3026a",
+ "metadata": {},
+ "source": [
+ "# What is the openai package?\n",
+ "\n",
+ "It's known as a Python Client Library.\n",
+ "\n",
+ "It's nothing more than a wrapper around making this exact call to the http endpoint.\n",
+ "\n",
+ "It just allows you to work with nice Python code instead of messing around with janky json objects.\n",
+ "\n",
+ "But that's it. It's open-source and lightweight. Some people think it contains OpenAI model code - it doesn't!\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "490fdf09",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Create OpenAI client\n",
+ "\n",
+ "from openai import OpenAI\n",
+ "openai = OpenAI()\n",
+ "\n",
+ "response = openai.chat.completions.create(model=\"gpt-5-nano\", messages=[{\"role\": \"user\", \"content\": \"Tell me a fun fact\"}])\n",
+ "\n",
+ "response.choices[0].message.content\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c7739cda",
+ "metadata": {},
+ "source": [
+ "## And then this great thing happened:\n",
+ "\n",
+ "OpenAI's Chat Completions API was so popular, that the other model providers created endpoints that are identical.\n",
+ "\n",
+ "They are known as the \"OpenAI Compatible Endpoints\".\n",
+ "\n",
+ "For example, google made one here: https://generativelanguage.googleapis.com/v1beta/openai/\n",
+ "\n",
+ "And OpenAI decided to be kind: they said, hey, you can just use the same client library that we made for GPT. We'll allow you to specify a different endpoint URL and a different key, to use another provider.\n",
+ "\n",
+ "So you can use:\n",
+ "\n",
+ "```python\n",
+ "gemini = OpenAI(base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\", api_key=\"AIz....\")\n",
+ "gemini.chat.completions.create(...)\n",
+ "```\n",
+ "\n",
+ "And to be clear - even though OpenAI is in the code, we're only using this lightweight python client library to call the endpoint - there's no OpenAI model involved here.\n",
+ "\n",
+ "If you're confused, please review Guide 9 in the Guides folder!\n",
+ "\n",
+ "And now let's try it!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f74293bc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
+ "\n",
+ "google_api_key = os.getenv(\"GOOGLE_API_KEY\")\n",
+ "\n",
+ "if not google_api_key:\n",
+ " print(\"No API key was found - please head over to the troubleshooting notebook in this folder to identify & fix!\")\n",
+ "elif not google_api_key.startswith(\"AIz\"):\n",
+ " print(\"An API key was found, but it doesn't start AIz\")\n",
+ "else:\n",
+ " print(\"API key found and looks good so far!\")\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d060f484",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gemini = OpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)\n",
+ "\n",
+ "response = gemini.chat.completions.create(model=\"gemini-2.5-pro\", messages=[{\"role\": \"user\", \"content\": \"Tell me a fun fact\"}])\n",
+ "\n",
+ "response.choices[0].message.content"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a5b069be",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "65272432",
+ "metadata": {},
+ "source": [
+ "## And Ollama also gives an OpenAI compatible endpoint\n",
+ "\n",
+ "...and it's on your local machine!\n",
+ "\n",
+ "If the next cell doesn't print \"Ollama is running\" then please open a terminal and run `ollama serve`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f06280ad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "requests.get(\"http://localhost:11434\").content"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c6ef3807",
+ "metadata": {},
+ "source": [
+ "### Download llama3.2 from meta\n",
+ "\n",
+ "Change this to llama3.2:1b if your computer is smaller.\n",
+ "\n",
+ "Don't use llama3.3 or llama4! They are too big for your computer.."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e633481d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "!ollama pull llama3.2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d9419762",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "OLLAMA_BASE_URL = \"http://localhost:11434/v1\"\n",
+ "\n",
+ "ollama = OpenAI(base_url=OLLAMA_BASE_URL, api_key='ollama')\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2456cdf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Get a fun fact\n",
+ "\n",
+ "response = ollama.chat.completions.create(model=\"llama3.2\", messages=[{\"role\": \"user\", \"content\": \"Tell me a fun fact\"}])\n",
+ "\n",
+ "response.choices[0].message.content"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1e6cae7f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Now let's try deepseek-r1:1.5b - this is DeepSeek \"distilled\" into Qwen from Alibaba Cloud\n",
+ "\n",
+ "!ollama pull deepseek-r1:1.5b"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "25002f25",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = ollama.chat.completions.create(model=\"deepseek-r1:1.5b\", messages=[{\"role\": \"user\", \"content\": \"Tell me a fun fact\"}])\n",
+ "\n",
+ "response.choices[0].message.content"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e9fa1fc-eac5-4d1d-9be4-541b3f2b3458",
+ "metadata": {},
+ "source": [
+ "# HOMEWORK EXERCISE ASSIGNMENT\n",
+ "\n",
+ "Upgrade the day 1 project to summarize a webpage to use an Open Source model running locally via Ollama rather than OpenAI\n",
+ "\n",
+ "You'll be able to use this technique for all subsequent projects if you'd prefer not to use paid APIs.\n",
+ "\n",
+ "**Benefits:**\n",
+ "1. No API charges - open-source\n",
+ "2. Data doesn't leave your box\n",
+ "\n",
+ "**Disadvantages:**\n",
+ "1. Significantly less power than Frontier Model\n",
+ "\n",
+ "## Recap on installation of Ollama\n",
+ "\n",
+ "Simply visit [ollama.com](https://ollama.com) and install!\n",
+ "\n",
+ "Once complete, the ollama server should already be running locally. \n",
+ "If you visit: \n",
+ "[http://localhost:11434/](http://localhost:11434/)\n",
+ "\n",
+ "You should see the message `Ollama is running`. \n",
+ "\n",
+ "If not, bring up a new Terminal (Mac) or Powershell (Windows) and enter `ollama serve` \n",
+ "And in another Terminal (Mac) or Powershell (Windows), enter `ollama pull llama3.2` \n",
+ "Then try [http://localhost:11434/](http://localhost:11434/) again.\n",
+ "\n",
+ "If Ollama is slow on your machine, try using `llama3.2:1b` as an alternative. Run `ollama pull llama3.2:1b` from a Terminal or Powershell, and change the code from `MODEL = \"llama3.2\"` to `MODEL = \"llama3.2:1b\"`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6de38216-6d1c-48c4-877b-86d403f4e0f8",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".venv",
+ "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.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/week1/day4.ipynb b/week1/day4.ipynb
new file mode 100644
index 0000000..0684828
--- /dev/null
+++ b/week1/day4.ipynb
@@ -0,0 +1,303 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "d9e61417",
+ "metadata": {},
+ "source": [
+ "# Day 4\n",
+ "\n",
+ "## Tokenizing with code"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "7dc1c1d9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import tiktoken\n",
+ "\n",
+ "encoding = tiktoken.encoding_for_model(\"gpt-4.1-mini\")\n",
+ "\n",
+ "tokens = encoding.encode(\"Hi my name is Ed and I like banoffee pie\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "7632966c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[12194, 922, 1308, 382, 6117, 326, 357, 1299, 9171, 26458, 5148]"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "tokens"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "cce0c188",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "12194 = Hi\n",
+ "922 = my\n",
+ "1308 = name\n",
+ "382 = is\n",
+ "6117 = Ed\n",
+ "326 = and\n",
+ "357 = I\n",
+ "1299 = like\n",
+ "9171 = ban\n",
+ "26458 = offee\n",
+ "5148 = pie\n"
+ ]
+ }
+ ],
+ "source": [
+ "for token_id in tokens:\n",
+ " token_text = encoding.decode([token_id])\n",
+ " print(f\"{token_id} = {token_text}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "98e3bbd2",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "' and'"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "encoding.decode([326])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "538efe61",
+ "metadata": {},
+ "source": [
+ "# And another topic!\n",
+ "\n",
+ "### The Illusion of \"memory\"\n",
+ "\n",
+ "Many of you will know this already. But for those that don't -- this might be an \"AHA\" moment!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "83a4b3eb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "from dotenv import load_dotenv\n",
+ "\n",
+ "load_dotenv(override=True)\n",
+ "api_key = os.getenv('OPENAI_API_KEY')\n",
+ "\n",
+ "if not api_key:\n",
+ " print(\"No API key was found - please head over to the troubleshooting notebook in this folder to identify & fix!\")\n",
+ "elif not api_key.startswith(\"sk-proj-\"):\n",
+ " print(\"An API key was found, but it doesn't start sk-proj-; please check you're using the right key - see troubleshooting notebook\")\n",
+ "else:\n",
+ " print(\"API key found and looks good so far!\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b618859b",
+ "metadata": {},
+ "source": [
+ "### You should be very comfortable with what the next cell is doing!\n",
+ "\n",
+ "_I'm creating a new instance of the OpenAI Python Client library, a lightweight wrapper around making HTTP calls to an endpoint for calling the GPT LLM, or other LLM providers_"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b959be3b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from openai import OpenAI\n",
+ "\n",
+ "openai = OpenAI()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "aa889e80",
+ "metadata": {},
+ "source": [
+ "### A message to OpenAI is a list of dicts"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "97298fea",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "messages = [\n",
+ " {\"role\": \"system\", \"content\": \"You are a helpful assistant\"},\n",
+ " {\"role\": \"user\", \"content\": \"Hi! I'm Ed!\"}\n",
+ " ]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3475a36d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = openai.chat.completions.create(model=\"gpt-4.1-mini\", messages=messages)\n",
+ "response.choices[0].message.content"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a5f45ed8",
+ "metadata": {},
+ "source": [
+ "### OK let's now ask a follow-up question"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6bce2208",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "messages = [\n",
+ " {\"role\": \"system\", \"content\": \"You are a helpful assistant\"},\n",
+ " {\"role\": \"user\", \"content\": \"What's my name?\"}\n",
+ " ]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "404462f5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = openai.chat.completions.create(model=\"gpt-4.1-mini\", messages=messages)\n",
+ "response.choices[0].message.content"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "098237ef",
+ "metadata": {},
+ "source": [
+ "### Wait, wha??\n",
+ "\n",
+ "We just told you!\n",
+ "\n",
+ "What's going on??\n",
+ "\n",
+ "Here's the thing: every call to an LLM is completely STATELESS. It's a totally new call, every single time. As AI engineers, it's OUR JOB to devise techniques to give the impression that the LLM has a \"memory\"."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b6d43f92",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "messages = [\n",
+ " {\"role\": \"system\", \"content\": \"You are a helpful assistant\"},\n",
+ " {\"role\": \"user\", \"content\": \"Hi! I'm Ed!\"},\n",
+ " {\"role\": \"assistant\", \"content\": \"Hi Ed! How can I assist you today?\"},\n",
+ " {\"role\": \"user\", \"content\": \"What's my name?\"}\n",
+ " ]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e7ac742c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = openai.chat.completions.create(model=\"gpt-4.1-mini\", messages=messages)\n",
+ "response.choices[0].message.content"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "96c49557",
+ "metadata": {},
+ "source": [
+ "## To recap\n",
+ "\n",
+ "With apologies if this is obvious to you - but it's still good to reinforce:\n",
+ "\n",
+ "1. Every call to an LLM is stateless\n",
+ "2. We pass in the entire conversation so far in the input prompt, every time\n",
+ "3. This gives the illusion that the LLM has memory - it apparently keeps the context of the conversation\n",
+ "4. But this is a trick; it's a by-product of providing the entire conversation, every time\n",
+ "5. An LLM just predicts the most likely next tokens in the sequence; if that sequence contains \"My name is Ed\" and later \"What's my name?\" then it will predict.. Ed!\n",
+ "\n",
+ "The ChatGPT product uses exactly this trick - every time you send a message, it's the entire conversation that gets passed in.\n",
+ "\n",
+ "\"Does that mean we have to pay extra each time for all the conversation so far\"\n",
+ "\n",
+ "For sure it does. And that's what we WANT. We want the LLM to predict the next tokens in the sequence, looking back on the entire conversation. We want that compute to happen, so we need to pay the electricity bill for it!\n",
+ "\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".venv",
+ "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.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/week1/day5.ipynb b/week1/day5.ipynb
index 5249ce8..0be0c46 100644
--- a/week1/day5.ipynb
+++ b/week1/day5.ipynb
@@ -22,7 +22,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 1,
"id": "d5b08506-dc8b-4443-9201-5f1848161363",
"metadata": {},
"outputs": [],
@@ -31,21 +31,27 @@
"# If these fail, please check you're running from an 'activated' environment with (llms) in the command prompt\n",
"\n",
"import os\n",
- "import requests\n",
"import json\n",
- "from typing import List\n",
"from dotenv import load_dotenv\n",
- "from bs4 import BeautifulSoup\n",
"from IPython.display import Markdown, display, update_display\n",
+ "from scraper import fetch_website_links, fetch_website_contents\n",
"from openai import OpenAI"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 2,
"id": "fc5d8880-f2ee-4c06-af16-ecbc0262af61",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "API key looks good so far\n"
+ ]
+ }
+ ],
"source": [
"# Initialize and constants\n",
"\n",
@@ -57,57 +63,57 @@
"else:\n",
" print(\"There might be a problem with your API key? Please visit the troubleshooting notebook!\")\n",
" \n",
- "MODEL = 'gpt-4o-mini'\n",
+ "MODEL = 'gpt-5-nano'\n",
"openai = OpenAI()"
]
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "106dd65e-90af-4ca8-86b6-23a41840645b",
- "metadata": {},
- "outputs": [],
- "source": [
- "# A class to represent a Webpage\n",
- "\n",
- "# Some websites need you to use proper headers when fetching them:\n",
- "headers = {\n",
- " \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\"\n",
- "}\n",
- "\n",
- "class Website:\n",
- " \"\"\"\n",
- " A utility class to represent a Website that we have scraped, now with links\n",
- " \"\"\"\n",
- "\n",
- " def __init__(self, url):\n",
- " self.url = url\n",
- " response = requests.get(url, headers=headers)\n",
- " self.body = response.content\n",
- " soup = BeautifulSoup(self.body, 'html.parser')\n",
- " self.title = soup.title.string if soup.title else \"No title found\"\n",
- " if soup.body:\n",
- " for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n",
- " irrelevant.decompose()\n",
- " self.text = soup.body.get_text(separator=\"\\n\", strip=True)\n",
- " else:\n",
- " self.text = \"\"\n",
- " links = [link.get('href') for link in soup.find_all('a')]\n",
- " self.links = [link for link in links if link]\n",
- "\n",
- " def get_contents(self):\n",
- " return f\"Webpage Title:\\n{self.title}\\nWebpage Contents:\\n{self.text}\\n\\n\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
+ "execution_count": 3,
"id": "e30d8128-933b-44cc-81c8-ab4c9d86589a",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['https://edwarddonner.com/',\n",
+ " 'https://edwarddonner.com/connect-four/',\n",
+ " 'https://edwarddonner.com/outsmart/',\n",
+ " 'https://edwarddonner.com/about-me-and-about-nebula/',\n",
+ " 'https://edwarddonner.com/posts/',\n",
+ " 'https://edwarddonner.com/',\n",
+ " 'https://news.ycombinator.com',\n",
+ " 'https://nebula.io/?utm_source=ed&utm_medium=referral',\n",
+ " 'https://www.prnewswire.com/news-releases/wynden-stark-group-acquires-nyc-venture-backed-tech-startup-untapt-301269512.html',\n",
+ " 'https://patents.google.com/patent/US20210049536A1/',\n",
+ " 'https://www.linkedin.com/in/eddonner/',\n",
+ " 'https://edwarddonner.com/2025/09/15/ai-in-production-gen-ai-and-agentic-ai-on-aws-at-scale/',\n",
+ " 'https://edwarddonner.com/2025/09/15/ai-in-production-gen-ai-and-agentic-ai-on-aws-at-scale/',\n",
+ " 'https://edwarddonner.com/2025/05/28/connecting-my-courses-become-an-llm-expert-and-leader/',\n",
+ " 'https://edwarddonner.com/2025/05/28/connecting-my-courses-become-an-llm-expert-and-leader/',\n",
+ " 'https://edwarddonner.com/2025/05/18/2025-ai-executive-briefing/',\n",
+ " 'https://edwarddonner.com/2025/05/18/2025-ai-executive-briefing/',\n",
+ " 'https://edwarddonner.com/2025/04/21/the-complete-agentic-ai-engineering-course/',\n",
+ " 'https://edwarddonner.com/2025/04/21/the-complete-agentic-ai-engineering-course/',\n",
+ " 'https://edwarddonner.com/',\n",
+ " 'https://edwarddonner.com/connect-four/',\n",
+ " 'https://edwarddonner.com/outsmart/',\n",
+ " 'https://edwarddonner.com/about-me-and-about-nebula/',\n",
+ " 'https://edwarddonner.com/posts/',\n",
+ " 'mailto:hello@mygroovydomain.com',\n",
+ " 'https://www.linkedin.com/in/eddonner/',\n",
+ " 'https://twitter.com/edwarddonner',\n",
+ " 'https://www.facebook.com/edward.donner.52']"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "ed = Website(\"https://edwarddonner.com\")\n",
- "ed.links"
+ "links = fetch_website_links(\"https://edwarddonner.com\")\n",
+ "links"
]
},
{
@@ -115,9 +121,9 @@
"id": "1771af9c-717a-4fca-bbbe-8a95893312c3",
"metadata": {},
"source": [
- "## First step: Have GPT-4o-mini figure out which links are relevant\n",
+ "## First step: Have GPT-5-nano figure out which links are relevant\n",
"\n",
- "### Use a call to gpt-4o-mini to read the links on a webpage, and respond in structured JSON. \n",
+ "### Use a call to gpt-5-nano to read the links on a webpage, and respond in structured JSON. \n",
"It should decide which links are relevant, and replace relative links such as \"/about\" with \"https://company.com/about\". \n",
"We will use \"one shot prompting\" in which we provide an example of how it should respond in the prompt.\n",
"\n",
@@ -128,16 +134,17 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 4,
"id": "6957b079-0d96-45f7-a26a-3487510e9b35",
"metadata": {},
"outputs": [],
"source": [
- "link_system_prompt = \"You are provided with a list of links found on a webpage. \\\n",
- "You are able to decide which of the links would be most relevant to include in a brochure about the company, \\\n",
- "such as links to an About page, or a Company page, or Careers/Jobs pages.\\n\"\n",
- "link_system_prompt += \"You should respond in JSON as in this example:\"\n",
- "link_system_prompt += \"\"\"\n",
+ "link_system_prompt = \"\"\"\n",
+ "You are provided with a list of links found on a webpage.\n",
+ "You are able to decide which of the links would be most relevant to include in a brochure about the company,\n",
+ "such as links to an About page, or a Company page, or Careers/Jobs pages.\n",
+ "You should respond in JSON as in this example:\n",
+ "\n",
"{\n",
" \"links\": [\n",
" {\"type\": \"about page\", \"url\": \"https://full.url/goes/here/about\"},\n",
@@ -149,59 +156,182 @@
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "b97e4068-97ed-4120-beae-c42105e4d59a",
- "metadata": {},
- "outputs": [],
- "source": [
- "print(link_system_prompt)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
+ "execution_count": 5,
"id": "8e1f601b-2eaf-499d-b6b8-c99050c9d6b3",
"metadata": {},
"outputs": [],
"source": [
- "def get_links_user_prompt(website):\n",
- " user_prompt = f\"Here is the list of links on the website of {website.url} - \"\n",
- " user_prompt += \"please decide which of these are relevant web links for a brochure about the company, respond with the full https URL in JSON format. \\\n",
- "Do not include Terms of Service, Privacy, email links.\\n\"\n",
- " user_prompt += \"Links (some might be relative links):\\n\"\n",
- " user_prompt += \"\\n\".join(website.links)\n",
+ "def get_links_user_prompt(url):\n",
+ " user_prompt = f\"\"\"\n",
+ "Here is the list of links on the website {url} -\n",
+ "Please decide which of these are relevant web links for a brochure about the company, \n",
+ "respond with the full https URL in JSON format.\n",
+ "Do not include Terms of Service, Privacy, email links.\n",
+ "\n",
+ "Links (some might be relative links):\n",
+ "\n",
+ "\"\"\"\n",
+ " links = fetch_website_links(url)\n",
+ " user_prompt += \"\\n\".join(links)\n",
" return user_prompt"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 6,
"id": "6bcbfa78-6395-4685-b92c-22d592050fd7",
"metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Here is the list of links on the website https://edwarddonner.com -\n",
+ "Please decide which of these are relevant web links for a brochure about the company, \n",
+ "respond with the full https URL in JSON format.\n",
+ "Do not include Terms of Service, Privacy, email links.\n",
+ "\n",
+ "Links (some might be relative links):\n",
+ "\n",
+ "https://edwarddonner.com/\n",
+ "https://edwarddonner.com/connect-four/\n",
+ "https://edwarddonner.com/outsmart/\n",
+ "https://edwarddonner.com/about-me-and-about-nebula/\n",
+ "https://edwarddonner.com/posts/\n",
+ "https://edwarddonner.com/\n",
+ "https://news.ycombinator.com\n",
+ "https://nebula.io/?utm_source=ed&utm_medium=referral\n",
+ "https://www.prnewswire.com/news-releases/wynden-stark-group-acquires-nyc-venture-backed-tech-startup-untapt-301269512.html\n",
+ "https://patents.google.com/patent/US20210049536A1/\n",
+ "https://www.linkedin.com/in/eddonner/\n",
+ "https://edwarddonner.com/2025/09/15/ai-in-production-gen-ai-and-agentic-ai-on-aws-at-scale/\n",
+ "https://edwarddonner.com/2025/09/15/ai-in-production-gen-ai-and-agentic-ai-on-aws-at-scale/\n",
+ "https://edwarddonner.com/2025/05/28/connecting-my-courses-become-an-llm-expert-and-leader/\n",
+ "https://edwarddonner.com/2025/05/28/connecting-my-courses-become-an-llm-expert-and-leader/\n",
+ "https://edwarddonner.com/2025/05/18/2025-ai-executive-briefing/\n",
+ "https://edwarddonner.com/2025/05/18/2025-ai-executive-briefing/\n",
+ "https://edwarddonner.com/2025/04/21/the-complete-agentic-ai-engineering-course/\n",
+ "https://edwarddonner.com/2025/04/21/the-complete-agentic-ai-engineering-course/\n",
+ "https://edwarddonner.com/\n",
+ "https://edwarddonner.com/connect-four/\n",
+ "https://edwarddonner.com/outsmart/\n",
+ "https://edwarddonner.com/about-me-and-about-nebula/\n",
+ "https://edwarddonner.com/posts/\n",
+ "mailto:hello@mygroovydomain.com\n",
+ "https://www.linkedin.com/in/eddonner/\n",
+ "https://twitter.com/edwarddonner\n",
+ "https://www.facebook.com/edward.donner.52\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(get_links_user_prompt(\"https://edwarddonner.com\"))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "effeb95f",
+ "metadata": {},
"outputs": [],
"source": [
- "print(get_links_user_prompt(ed))"
+ "def select_relevant_links(url):\n",
+ " response = openai.chat.completions.create(\n",
+ " model=MODEL,\n",
+ " messages=[\n",
+ " {\"role\": \"system\", \"content\": link_system_prompt},\n",
+ " {\"role\": \"user\", \"content\": get_links_user_prompt(url)}\n",
+ " ],\n",
+ " response_format={\"type\": \"json_object\"}\n",
+ " )\n",
+ " result = response.choices[0].message.content\n",
+ " links = json.loads(result)\n",
+ " return links\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "490de841",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "2d5b1ded",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'links': [{'type': 'homepage', 'url': 'https://edwarddonner.com/'},\n",
+ " {'type': 'about page',\n",
+ " 'url': 'https://edwarddonner.com/about-me-and-about-nebula/'},\n",
+ " {'type': 'blog page', 'url': 'https://edwarddonner.com/posts/'},\n",
+ " {'type': 'blog post',\n",
+ " 'url': 'https://edwarddonner.com/2025/09/15/ai-in-production-gen-ai-and-agentic-ai-on-aws-at-scale/'},\n",
+ " {'type': 'blog post',\n",
+ " 'url': 'https://edwarddonner.com/2025/05/28/connecting-my-courses-become-an-llm-expert-and-leader/'},\n",
+ " {'type': 'blog post',\n",
+ " 'url': 'https://edwarddonner.com/2025/05/18/2025-ai-executive-briefing/'},\n",
+ " {'type': 'blog post',\n",
+ " 'url': 'https://edwarddonner.com/2025/04/21/the-complete-agentic-ai-engineering-course/'},\n",
+ " {'type': 'LinkedIn profile', 'url': 'https://www.linkedin.com/in/eddonner/'},\n",
+ " {'type': 'Twitter profile', 'url': 'https://twitter.com/edwarddonner'},\n",
+ " {'type': 'Facebook profile',\n",
+ " 'url': 'https://www.facebook.com/edward.donner.52'},\n",
+ " {'type': 'external company',\n",
+ " 'url': 'https://nebula.io/?utm_source=ed&utm_medium=referral'}]}"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "select_relevant_links(\"https://edwarddonner.com\")"
]
},
{
"cell_type": "code",
"execution_count": null,
+ "id": "3e7b84c0",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "26709d38",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
"id": "a29aca19-ca13-471c-a4b4-5abbfa813f69",
"metadata": {},
"outputs": [],
"source": [
- "def get_links(url):\n",
- " website = Website(url)\n",
+ "def select_relevant_links(url):\n",
+ " print(f\"Selecting relevant links for {url} by calling {MODEL}\")\n",
" response = openai.chat.completions.create(\n",
" model=MODEL,\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": link_system_prompt},\n",
- " {\"role\": \"user\", \"content\": get_links_user_prompt(website)}\n",
- " ],\n",
+ " {\"role\": \"user\", \"content\": get_links_user_prompt(url)}\n",
+ " ],\n",
" response_format={\"type\": \"json_object\"}\n",
" )\n",
" result = response.choices[0].message.content\n",
- " return json.loads(result)"
+ " links = json.loads(result)\n",
+ " print(f\"Found {len(links['links'])} relevant links\")\n",
+ " return links"
]
},
{
@@ -211,20 +341,39 @@
"metadata": {},
"outputs": [],
"source": [
- "# Anthropic has made their site harder to scrape, so I'm using HuggingFace..\n",
- "\n",
- "huggingface = Website(\"https://huggingface.co\")\n",
- "huggingface.links"
+ "select_relevant_links(\"https://edwarddonner.com\")"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 10,
"id": "d3d583e2-dcc4-40cc-9b28-1e8dbf402924",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Selecting relevant links for https://huggingface.co by calling gpt-5-nano\n",
+ "Found 3 relevant links\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "{'links': [{'type': 'brand page', 'url': 'https://huggingface.co/brand'},\n",
+ " {'type': 'careers page', 'url': 'https://apply.workable.com/huggingface/'},\n",
+ " {'type': 'company page',\n",
+ " 'url': 'https://www.linkedin.com/company/huggingface/'}]}"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "get_links(\"https://huggingface.co\")"
+ "select_relevant_links(\"https://huggingface.co\")"
]
},
{
@@ -234,35 +383,935 @@
"source": [
"## Second step: make the brochure!\n",
"\n",
- "Assemble all the details into another prompt to GPT4-o"
+ "Assemble all the details into another prompt to GPT-5-nano"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 11,
"id": "85a5b6e2-e7ef-44a9-bc7f-59ede71037b5",
"metadata": {},
"outputs": [],
"source": [
- "def get_all_details(url):\n",
- " result = \"Landing page:\\n\"\n",
- " result += Website(url).get_contents()\n",
- " links = get_links(url)\n",
- " print(\"Found links:\", links)\n",
- " for link in links[\"links\"]:\n",
- " result += f\"\\n\\n{link['type']}\\n\"\n",
- " result += Website(link[\"url\"]).get_contents()\n",
+ "def fetch_page_and_all_relevant_links(url):\n",
+ " contents = fetch_website_contents(url)\n",
+ " relevant_links = select_relevant_links(url)\n",
+ " result = f\"## Landing Page:\\n\\n{contents}\\n## Relevant Links:\\n\"\n",
+ " for link in relevant_links['links']:\n",
+ " result += f\"\\n\\n### Link: {link['type']}\\n\"\n",
+ " result += fetch_website_contents(link[\"url\"])\n",
" return result"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 12,
"id": "5099bd14-076d-4745-baf3-dac08d8e5ab2",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Selecting relevant links for https://huggingface.co by calling gpt-5-nano\n",
+ "Found 11 relevant links\n",
+ "## Landing Page:\n",
+ "\n",
+ "Hugging Face – The AI community building the future.\n",
+ "\n",
+ "Hugging Face\n",
+ "Models\n",
+ "Datasets\n",
+ "Spaces\n",
+ "Community\n",
+ "Docs\n",
+ "Enterprise\n",
+ "Pricing\n",
+ "Log In\n",
+ "Sign Up\n",
+ "The AI community building the future.\n",
+ "The platform where the machine learning community collaborates on models, datasets, and applications.\n",
+ "Explore AI Apps\n",
+ "or\n",
+ "Browse 1M+ models\n",
+ "Trending on\n",
+ "this week\n",
+ "Models\n",
+ "tencent/HunyuanImage-3.0\n",
+ "Updated\n",
+ "about 3 hours ago\n",
+ "•\n",
+ "825\n",
+ "•\n",
+ "714\n",
+ "deepseek-ai/DeepSeek-V3.2-Exp\n",
+ "Updated\n",
+ "3 days ago\n",
+ "•\n",
+ "10.7k\n",
+ "•\n",
+ "470\n",
+ "tencent/Hunyuan3D-Part\n",
+ "Updated\n",
+ "4 days ago\n",
+ "•\n",
+ "2.57k\n",
+ "•\n",
+ "461\n",
+ "zai-org/GLM-4.6\n",
+ "Updated\n",
+ "2 days ago\n",
+ "•\n",
+ "9.72k\n",
+ "•\n",
+ "298\n",
+ "inclusionAI/Ring-1T-preview\n",
+ "Updated\n",
+ "1 day ago\n",
+ "•\n",
+ "818\n",
+ "•\n",
+ "208\n",
+ "Browse 1M+ models\n",
+ "Spaces\n",
+ "Running\n",
+ "1.29k\n",
+ "1.29k\n",
+ "Wan2.2 Animate\n",
+ "👁\n",
+ "Wan2.2 Animate\n",
+ "Running\n",
+ "14.5k\n",
+ "14.5k\n",
+ "DeepSite v3\n",
+ "🐳\n",
+ "Generate any application with DeepSeek\n",
+ "Running\n",
+ "on\n",
+ "Zero\n",
+ "MCP\n",
+ "1.46k\n",
+ "1.46k\n",
+ "Wan2.2 14B Fast\n",
+ "🎥\n",
+ "generate a video from an image with a text prompt\n",
+ "Running\n",
+ "on\n",
+ "Zero\n",
+ "196\n",
+ "196\n",
+ "Qwen Image Edit 2509\n",
+ "👀\n",
+ "Generate edited images based on user prompts\n",
+ "Running\n",
+ "on\n",
+ "CPU Upgrade\n",
+ "103\n",
+ "103\n",
+ "Ostris' AI Toolkit\n",
+ "💻\n",
+ "Train FLUX, Qwen and Wan LoRAs with Ostris Ai Toolkit\n",
+ "Browse 400k+ applications\n",
+ "Datasets\n",
+ "openai/gdpval\n",
+ "Updated\n",
+ "7 days ago\n",
+ "•\n",
+ "17k\n",
+ "•\n",
+ "157\n",
+ "fka/awesome-chatgpt-prompts\n",
+ "Updated\n",
+ "Jan 6\n",
+ "•\n",
+ "49k\n",
+ "•\n",
+ "9.18k\n",
+ "nvidia/Nemotron-Personas-Japan\n",
+ "Updated\n",
+ "9 days ago\n",
+ "•\n",
+ "9.74k\n",
+ "•\n",
+ "75\n",
+ "t-tech/T-ECD\n",
+ "Updated\n",
+ "6 days ago\n",
+ "•\n",
+ "993\n",
+ "•\n",
+ "22\n",
+ "facebook/seamless-interaction\n",
+ "Updated\n",
+ "Jul 14\n",
+ "•\n",
+ "17.5k\n",
+ "•\n",
+ "148\n",
+ "Browse 250k+ datasets\n",
+ "The Home of Machine Learning\n",
+ "Create, discover and collaborate on ML better.\n",
+ "The collaboration platform\n",
+ "Host and collaborate on unlimited public models, datasets and applications.\n",
+ "Move faster\n",
+ "With the HF Open source stack.\n",
+ "Explore all modalities\n",
+ "Text, image, video, audio or even 3D.\n",
+ "Build your portfolio\n",
+ "Share your work with the world and build your ML profile.\n",
+ "Sign Up\n",
+ "Accelerate your ML\n",
+ "We provide paid Compute and Enterprise solutions.\n",
+ "Compute\n",
+ "Deploy on optimized\n",
+ "Inference Endpoints\n",
+ "or update your\n",
+ "Spaces applications\n",
+ "to a GPU in a few clicks.\n",
+ "View pricing\n",
+ "Starting at $0.60/hour for GPU\n",
+ "Tea\n",
+ "## Relevant Links:\n",
+ "\n",
+ "\n",
+ "### Link: about page\n",
+ "Brand assets - Hugging Face\n",
+ "\n",
+ "Hugging Face\n",
+ "Models\n",
+ "Datasets\n",
+ "Spaces\n",
+ "Community\n",
+ "Docs\n",
+ "Enterprise\n",
+ "Pricing\n",
+ "Log In\n",
+ "Sign Up\n",
+ "Hugging Face · Brand assets\n",
+ "HF Logos\n",
+ ".svg\n",
+ ".png\n",
+ ".ai\n",
+ ".svg\n",
+ ".png\n",
+ ".ai\n",
+ ".svg\n",
+ ".png\n",
+ ".ai\n",
+ "HF Colors\n",
+ "#FFD21E\n",
+ "#FF9D00\n",
+ "#6B7280\n",
+ "HF Bio\n",
+ "Hugging Face is the collaboration platform for the machine learning community.\n",
+ "\n",
+ "The Hugging Face Hub works as a central place where anyone can share, explore, discover, and experiment with open-source ML. HF empowers the next generation of machine learning engineers, scientists, and end users to learn, collaborate and share their work to build an open and ethical AI future together.\n",
+ "\n",
+ "With the fast-growing community, some of the most used open-source ML libraries and tools, and a talented science team exploring the edge of tech, Hugging Face is at the heart of the AI revolution.\n",
+ "Copy to clipboard\n",
+ "HF Universe\n",
+ "Find other assets available for use from the Hugging Face brand universe\n",
+ "here\n",
+ ".\n",
+ "System theme\n",
+ "Website\n",
+ "Models\n",
+ "Datasets\n",
+ "Spaces\n",
+ "Changelog\n",
+ "Inference Endpoints\n",
+ "HuggingChat\n",
+ "Company\n",
+ "About\n",
+ "Brand assets\n",
+ "Terms of service\n",
+ "Privacy\n",
+ "Jobs\n",
+ "Press\n",
+ "Resources\n",
+ "Learn\n",
+ "Documentation\n",
+ "Blog\n",
+ "Forum\n",
+ "Service Status\n",
+ "Social\n",
+ "GitHub\n",
+ "Twitter\n",
+ "LinkedIn\n",
+ "Discord\n",
+ "\n",
+ "### Link: enterprise page\n",
+ "Enterprise Hub - Hugging Face\n",
+ "\n",
+ "Hugging Face\n",
+ "Models\n",
+ "Datasets\n",
+ "Spaces\n",
+ "Community\n",
+ "Docs\n",
+ "Enterprise\n",
+ "Pricing\n",
+ "Log In\n",
+ "Sign Up\n",
+ "Team & Enterprise Hub\n",
+ "Scale your organization with the world’s leading AI platform\n",
+ "Subscribe to\n",
+ "Team\n",
+ "starting at $20/user/month\n",
+ "or\n",
+ "Contact sales for\n",
+ "Enterprise\n",
+ "to explore flexible contract options\n",
+ "Give your organization the most advanced platform to build AI with enterprise-grade security, access controls,\n",
+ "\t\t\tdedicated support and more.\n",
+ "Single Sign-On\n",
+ "Connect securely to your identity provider with SSO integration.\n",
+ "Regions\n",
+ "Select, manage, and audit the location of your repository data.\n",
+ "Audit Logs\n",
+ "Stay in control with comprehensive logs that report on actions taken.\n",
+ "Resource Groups\n",
+ "Accurately manage access to repositories with granular access control.\n",
+ "Token Management\n",
+ "Centralized token control and custom approval policies for organization access.\n",
+ "Analytics\n",
+ "Track and analyze repository usage data in a single dashboard.\n",
+ "Advanced Compute Options\n",
+ "Increase scalability and performance with more compute options like ZeroGPU.\n",
+ "ZeroGPU Quota Boost\n",
+ "All organization members get 5x more ZeroGPU quota to get the most of Spaces.\n",
+ "Private Datasets Viewer\n",
+ "Enable the Dataset Viewer on your private datasets for easier collaboration.\n",
+ "Private Storage\n",
+ "Get an additional 1 TB of private storage for each member of your organization (then $25/month per extra TB).\n",
+ "Inference Providers\n",
+ "Enable organization billing for Inference Providers, monitor usage with analytics, and manage spending limits.\n",
+ "Advanced security\n",
+ "Configure organization-wide security policies and default repository visibility.\n",
+ "Billing\n",
+ "Control your budget effectively with managed billing and yearly commit options.\n",
+ "Priority Support\n",
+ "Maximize your platform usage with priority support from the Hugging Face team.\n",
+ "Join the most forward-thinking AI organizations\n",
+ "Everything you already know and love about Hugging Face in Enterprise mode.\n",
+ "Subscribe to\n",
+ "Team\n",
+ "starting at $20/user/month\n",
+ "or\n",
+ "Contact sales for\n",
+ "Enterprise\n",
+ "to explore fl\n",
+ "\n",
+ "### Link: careers page\n",
+ "Hugging Face - Current Openings\n",
+ "\n",
+ "\n",
+ "\n",
+ "### Link: blog\n",
+ "Hugging Face – Blog\n",
+ "\n",
+ "Hugging Face\n",
+ "Models\n",
+ "Datasets\n",
+ "Spaces\n",
+ "Community\n",
+ "Docs\n",
+ "Enterprise\n",
+ "Pricing\n",
+ "Log In\n",
+ "Sign Up\n",
+ "Blog, Articles, and discussions\n",
+ "New Article\n",
+ "Everything\n",
+ "community\n",
+ "guide\n",
+ "open source collab\n",
+ "partnerships\n",
+ "research\n",
+ "NLP\n",
+ "Audio\n",
+ "CV\n",
+ "RL\n",
+ "ethics\n",
+ "Diffusion\n",
+ "Game Development\n",
+ "RLHF\n",
+ "Leaderboard\n",
+ "Case Studies\n",
+ "LeRobot\n",
+ "Inference Providers\n",
+ "SOTA OCR on-device with Core ML and dots.ocr\n",
+ "By\n",
+ "FL33TW00D-HF\n",
+ "October 2, 2025\n",
+ "Community Articles\n",
+ "view all\n",
+ "There is no such thing as a tokenizer-free lunch\n",
+ "By\n",
+ "catherinearnett\n",
+ "•\n",
+ "8 days ago\n",
+ "•\n",
+ "68\n",
+ "Model Quality: Hugging Face Is All You Need\n",
+ "By\n",
+ "finegrain\n",
+ "•\n",
+ "6 days ago\n",
+ "•\n",
+ "19\n",
+ "Code a simple RAG from scratch\n",
+ "By\n",
+ "ngxson\n",
+ "•\n",
+ "Oct 29, 2024\n",
+ "•\n",
+ "208\n",
+ "Nemotron-Personas-Japan: Synthesized Data for Sovereign AI\n",
+ "By\n",
+ "nvidia\n",
+ "and 6 others\n",
+ "•\n",
+ "9 days ago\n",
+ "•\n",
+ "24\n",
+ "When Does Reasoning Matter? Unpacking the Contribution of Reasoning to LLM Performance\n",
+ "By\n",
+ "Nicolas-BZRD\n",
+ "and 1 other\n",
+ "•\n",
+ "2 days ago\n",
+ "•\n",
+ "10\n",
+ "CU-1 for Autonomous UI Agent Systems: An Open Alternative to Proprietary Solutions\n",
+ "By\n",
+ "paulml\n",
+ "•\n",
+ "1 day ago\n",
+ "•\n",
+ "10\n",
+ "How I Trained Action Chunking Transformer (ACT) on SO-101: My Journey, Gotchas, and Lessons\n",
+ "By\n",
+ "sherryxychen\n",
+ "•\n",
+ "3 days ago\n",
+ "•\n",
+ "9\n",
+ "Preserving Agency: Why AI Safety Needs Community, Not Corporate Control\n",
+ "By\n",
+ "giadap\n",
+ "•\n",
+ "3 days ago\n",
+ "•\n",
+ "9\n",
+ "RexBERT: Encoders for a brave new world of E-Commerce\n",
+ "By\n",
+ "thebajajra\n",
+ "and 1 other\n",
+ "•\n",
+ "12 days ago\n",
+ "•\n",
+ "46\n",
+ "Nemotron-Personas-Japan: ソブリン AI のための合成データセット\n",
+ "By\n",
+ "nvidia\n",
+ "and 6 others\n",
+ "•\n",
+ "6 days ago\n",
+ "•\n",
+ "7\n",
+ "Uncensor any LLM with abliteration\n",
+ "By\n",
+ "mlabonne\n",
+ "•\n",
+ "Jun 13, 2024\n",
+ "•\n",
+ "684\n",
+ "How to Train an Antibody Developability Model\n",
+ "By\n",
+ "ginkgo-datapoints\n",
+ "and 1 other\n",
+ "•\n",
+ "15 days ago\n",
+ "•\n",
+ "14\n",
+ "Introduction to State Space Models (SSM)\n",
+ "By\n",
+ "lbourdois\n",
+ "•\n",
+ "Jul 19, 2024\n",
+ "•\n",
+ "176\n",
+ "arXiv实用技巧,如何让你的paper关注度变高?\n",
+ "By\n",
+ "JessyTsu1\n",
+ "•\n",
+ "Jul 8, 2024\n",
+ "•\n",
+ "14\n",
+ "Fine-Tuning Your First Large Language Model (LLM) with PyTorch and Hugging Face\n",
+ "By\n",
+ "dvgodoy\n",
+ "•\n",
+ "Feb 11\n",
+ "•\n",
+ "72\n",
+ "PP-OCRv5 on Hugging Face: A Specialized Approach to OCR\n",
+ "By\n",
+ "baidu\n",
+ "and 5 others\n",
+ "•\n",
+ "22 days ago\n",
+ "•\n",
+ "102\n",
+ "Ground-up efforts to build large datasets for effective and accurate translation of Modi-Sc\n",
+ "\n",
+ "### Link: community forum\n",
+ "Hugging Face Forums - Hugging Face Community Discussion\n",
+ "\n",
+ "Hugging Face Forums\n",
+ "Topic\n",
+ "Replies\n",
+ "Views\n",
+ "Activity\n",
+ "Tokenizer: How to suppress preceding whitespace when giving pre-tokenized list[list[str]] input\n",
+ "Beginners\n",
+ "2\n",
+ "4\n",
+ "October 2, 2025\n",
+ "Student Pro Plan for Education Users (Masters student)\n",
+ "Research\n",
+ "0\n",
+ "13\n",
+ "October 2, 2025\n",
+ "Error: Repository storage limit reached (Max: 1 GB)\n",
+ "Beginners\n",
+ "29\n",
+ "2720\n",
+ "October 2, 2025\n",
+ "Can't claim ownership of paper\n",
+ "Beginners\n",
+ "3\n",
+ "26\n",
+ "October 2, 2025\n",
+ "Set usage limit per access token\n",
+ "Site Feedback\n",
+ "0\n",
+ "5\n",
+ "October 2, 2025\n",
+ "I want to open source this framework. OAGI\n",
+ "Research\n",
+ "2\n",
+ "15\n",
+ "October 2, 2025\n",
+ "Pro Account ZeroGPU Limit Usage at Failed Sessions\n",
+ "Beginners\n",
+ "2\n",
+ "10\n",
+ "October 2, 2025\n",
+ "How to use for Real Estate?\n",
+ "Beginners\n",
+ "1\n",
+ "12\n",
+ "October 2, 2025\n",
+ "Help : integrating a Agilex PiPER robot arm to lerobot\n",
+ "Intermediate\n",
+ "8\n",
+ "16\n",
+ "October 2, 2025\n",
+ "Custom Domain stuck on pending\n",
+ "Beginners\n",
+ "4\n",
+ "66\n",
+ "October 1, 2025\n",
+ "How to edit website with AI prompts?\n",
+ "Beginners\n",
+ "1\n",
+ "7\n",
+ "October 2, 2025\n",
+ "Custom Domain for HF Spaces\n",
+ "Spaces\n",
+ "10\n",
+ "4329\n",
+ "October 1, 2025\n",
+ "What are the best practices for fine-tuning transformer models with limited data?\n",
+ "Beginners\n",
+ "1\n",
+ "9\n",
+ "October 1, 2025\n",
+ "Creating and posting non-traditional datasets formats like DICOM, NIfTI, and WFDB records\n",
+ "🤗Datasets\n",
+ "1\n",
+ "8\n",
+ "September 30, 2025\n",
+ "I used to have no problem with PEFT fine-tuning after hundreds of trainings, but now I have encountered The error RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn\n",
+ "🤗AutoTrain\n",
+ "2\n",
+ "8\n",
+ "October 1, 2025\n",
+ "Help: Can’t find Multi Image Input node in ComfyUI\n",
+ "Beginners\n",
+ "3\n",
+ "15\n",
+ "October 2, 2025\n",
+ "Which parameters to use for fine-tuning Llama-2-7b?\n",
+ "Beginners\n",
+ "1\n",
+ "12\n",
+ "September 30, 2025\n",
+ "03 Error When Using Qwen/Qwen2.5-VL-32B-Instruct with Inference Provider\n",
+ "Models\n",
+ "4\n",
+ "23\n",
+ "October 2, 2025\n",
+ "Is it possible to remove articles (the, a, an) from a text sample without consequences?\n",
+ "🤗Datasets\n",
+ "3\n",
+ "14\n",
+ "October 1, 2025\n",
+ "Have You Ever Tested an AI Model? What Was Your Experience?\n",
+ "Models\n",
+ "2\n",
+ "19\n",
+ "October 1, 2025\n",
+ "When fine-tuning a model, what stand\n",
+ "\n",
+ "### Link: GitHub\n",
+ "Hugging Face · GitHub\n",
+ "\n",
+ "Skip to content\n",
+ "Navigation Menu\n",
+ "Toggle navigation\n",
+ "Sign in\n",
+ "Appearance settings\n",
+ "huggingface\n",
+ "Platform\n",
+ "GitHub Copilot\n",
+ "Write better code with AI\n",
+ "GitHub Spark\n",
+ "New\n",
+ "Build and deploy intelligent apps\n",
+ "GitHub Models\n",
+ "New\n",
+ "Manage and compare prompts\n",
+ "GitHub Advanced Security\n",
+ "Find and fix vulnerabilities\n",
+ "Actions\n",
+ "Automate any workflow\n",
+ "Codespaces\n",
+ "Instant dev environments\n",
+ "Issues\n",
+ "Plan and track work\n",
+ "Code Review\n",
+ "Manage code changes\n",
+ "Discussions\n",
+ "Collaborate outside of code\n",
+ "Code Search\n",
+ "Find more, search less\n",
+ "Explore\n",
+ "Why GitHub\n",
+ "Documentation\n",
+ "GitHub Skills\n",
+ "Blog\n",
+ "Integrations\n",
+ "GitHub Marketplace\n",
+ "MCP Registry\n",
+ "View all features\n",
+ "Solutions\n",
+ "By company size\n",
+ "Enterprises\n",
+ "Small and medium teams\n",
+ "Startups\n",
+ "Nonprofits\n",
+ "By use case\n",
+ "App Modernization\n",
+ "DevSecOps\n",
+ "DevOps\n",
+ "CI/CD\n",
+ "View all use cases\n",
+ "By industry\n",
+ "Healthcare\n",
+ "Financial services\n",
+ "Manufacturing\n",
+ "Government\n",
+ "View all industries\n",
+ "View all solutions\n",
+ "Resources\n",
+ "Topics\n",
+ "AI\n",
+ "DevOps\n",
+ "Security\n",
+ "Software Development\n",
+ "View all\n",
+ "Explore\n",
+ "Learning Pathways\n",
+ "Events & Webinars\n",
+ "Ebooks & Whitepapers\n",
+ "Customer Stories\n",
+ "Partners\n",
+ "Executive Insights\n",
+ "Open Source\n",
+ "GitHub Sponsors\n",
+ "Fund open source developers\n",
+ "The ReadME Project\n",
+ "GitHub community articles\n",
+ "Repositories\n",
+ "Topics\n",
+ "Trending\n",
+ "Collections\n",
+ "Enterprise\n",
+ "Enterprise platform\n",
+ "AI-powered developer platform\n",
+ "Available add-ons\n",
+ "GitHub Advanced Security\n",
+ "Enterprise-grade security features\n",
+ "Copilot for business\n",
+ "Enterprise-grade AI features\n",
+ "Premium Support\n",
+ "Enterprise-grade 24/7 support\n",
+ "Pricing\n",
+ "Search or jump to...\n",
+ "Search code, repositories, users, issues, pull requests...\n",
+ "Search\n",
+ "Clear\n",
+ "Search syntax tips\n",
+ "Provide feedback\n",
+ "We read every piece of feedback, and take your input very seriously.\n",
+ "Include my email address so I can be contacted\n",
+ "Cancel\n",
+ "Submit feedback\n",
+ "Saved searches\n",
+ "Use saved searches to filter your results more quickly\n",
+ "Cancel\n",
+ "Create saved search\n",
+ "Sign in\n",
+ "Sign up\n",
+ "Appearance settings\n",
+ "Resetting focus\n",
+ "You signed in with another tab or window.\n",
+ "Reload\n",
+ "to refresh your session.\n",
+ "You signed out in another tab or window.\n",
+ "Reload\n",
+ "to refresh yo\n",
+ "\n",
+ "### Link: Twitter\n",
+ "No title found\n",
+ "\n",
+ "JavaScript is not available.\n",
+ "We’ve detected that JavaScript is disabled in this browser. Please enable JavaScript or switch to a supported browser to continue using x.com. You can see a list of supported browsers in our Help Center.\n",
+ "Help Center\n",
+ "Terms of Service\n",
+ "Privacy Policy\n",
+ "Cookie Policy\n",
+ "Imprint\n",
+ "Ads info\n",
+ "© 2025 X Corp.\n",
+ "Something went wrong, but don’t fret — let’s give it another shot.\n",
+ "Try again\n",
+ "Some privacy related extensions may cause issues on x.com. Please disable them and try again.\n",
+ "\n",
+ "### Link: LinkedIn\n",
+ "Hugging Face | LinkedIn\n",
+ "\n",
+ "Skip to main content\n",
+ "LinkedIn\n",
+ "Top Content\n",
+ "People\n",
+ "Learning\n",
+ "Jobs\n",
+ "Games\n",
+ "Get the app\n",
+ "Sign in\n",
+ "Join now\n",
+ "Hugging Face\n",
+ "Software Development\n",
+ "The AI community building the future.\n",
+ "See jobs\n",
+ "Follow\n",
+ "Discover all 623 employees\n",
+ "Report this company\n",
+ "About us\n",
+ "The AI community building the future.\n",
+ "Website\n",
+ "https://huggingface.co\n",
+ "External link for Hugging Face\n",
+ "Industry\n",
+ "Software Development\n",
+ "Company size\n",
+ "51-200 employees\n",
+ "Type\n",
+ "Privately Held\n",
+ "Founded\n",
+ "2016\n",
+ "Specialties\n",
+ "machine learning, natural language processing, and deep learning\n",
+ "Products\n",
+ "Hugging Face\n",
+ "Hugging Face\n",
+ "Natural Language Processing (NLP) Software\n",
+ "We’re on a journey to solve and democratize artificial intelligence through natural language.\n",
+ "Locations\n",
+ "Primary\n",
+ "Get directions\n",
+ "Paris, FR\n",
+ "Get directions\n",
+ "Employees at Hugging Face\n",
+ "Ludovic Huraux\n",
+ "Rajat Arya\n",
+ "Tech Lead & Software Engineer @ HF | prev: co-founder XetHub, Apple, Turi, AWS, Microsoft\n",
+ "Jeff Boudier\n",
+ "Product + Growth at Hugging Face\n",
+ "Terrence Rohan\n",
+ "Seed Investor\n",
+ "See all employees\n",
+ "Updates\n",
+ "Hugging Face\n",
+ "reposted this\n",
+ "Mercuri\n",
+ "3,316 followers\n",
+ "1d\n",
+ "Report this post\n",
+ "🚨 404: media not found 🚨\n",
+ "\n",
+ "We're teaming up\n",
+ "The Tech Bros\n",
+ ",\n",
+ "Canva\n",
+ ",\n",
+ "ElevenLabs\n",
+ ", and\n",
+ "Hugging Face\n",
+ "for an all female media x tech\n",
+ "#hackathon\n",
+ "at the Canva offices 👩🏾💻👩🏼💻👩🏻💻\n",
+ "\n",
+ "⚡ Build prototypes fast\n",
+ "⚡ Get feedback from engineers & investors\n",
+ "⚡ Meet your co-founder!?\n",
+ "\n",
+ "Hugging Face, Canva and ElevenLabs are unicorns shaping the future of media and creative tech. At\n",
+ "Mercuri\n",
+ ", we bring the early-stage VC perspective, meeting thousands of startups each year at the intersection of media, entertainment and technology. This hackathon brings it all together, creating a space to test bold ideas and learn directly from operators and investors immersed in the field.\n",
+ "\n",
+ "The media x creative tech world needs fresh voices and bold ideas. When women lead, products get sharper, narratives more inclusive, and impact much greater - so come join us!\n",
+ "\n",
+ "📍 Central London\n",
+ "📅 Wednesday, 29 October\n",
+ "🔗 Link to sign up in comments\n",
+ "23\n",
+ "1 Comment\n",
+ "\n",
+ "### Link: Zhihu\n",
+ "No title found\n",
+ "\n",
+ "知乎,让每一次点击都充满意义 —— 欢迎来到知乎,发现问题背后的世界。\n",
+ "\n",
+ "### Link: API endpoints\n",
+ "Inference Endpoints by Hugging Face\n",
+ "\n",
+ "Inference\n",
+ "Endpoints\n",
+ "Catalog\n",
+ "Log In\n",
+ "Machine Learning At Your Service\n",
+ "by\n",
+ "Hugging Face\n",
+ "Easily deploy Transformers, Diffusers or any model on dedicated, fully managed\n",
+ "\t\t\t\tinfrastructure. Keep your costs low with our secure, compliant and flexible production\n",
+ "\t\t\t\tsolution.\n",
+ "Log In\n",
+ "Learn More\n",
+ "No Hugging Face account ?\n",
+ "Sign up\n",
+ "!\n",
+ "One-click inference deployment\n",
+ "Import your favorite model from the Hugging Face hub or browse our catalog of hand-picked, ready-to-deploy models !\n",
+ "meta-llama /\n",
+ "Llama-3.1-70B-Instruct\n",
+ "59\n",
+ "Deployed 59 times\n",
+ "Text Generation\n",
+ "TGI\n",
+ "Accelerated Text Generation Inference\n",
+ "GPU\n",
+ "4x Nvidia L40S\n",
+ "$\n",
+ "8.3\n",
+ "openai /\n",
+ "whisper-large-v3-turbo\n",
+ "162\n",
+ "Deployed 162 times\n",
+ "Automatic Speech Recognition\n",
+ "GPU\n",
+ "1x Nvidia L4\n",
+ "$\n",
+ "0.8\n",
+ "mixedbread-ai /\n",
+ "mxbai-embed-large-v1\n",
+ "22\n",
+ "Deployed 22 times\n",
+ "Sentence Embeddings\n",
+ "TEI\n",
+ "Accelerated Text Embeddings Inference\n",
+ "GPU\n",
+ "1x Nvidia L4\n",
+ "$\n",
+ "0.8\n",
+ "Qwen /\n",
+ "Qwen2.5-Coder-7B-Instruct\n",
+ "47\n",
+ "Deployed 47 times\n",
+ "Text Generation\n",
+ "TGI\n",
+ "Accelerated Text Generation Inference\n",
+ "GPU\n",
+ "1x Nvidia L40S\n",
+ "$\n",
+ "1.8\n",
+ "black-forest-labs /\n",
+ "FLUX.1-schnell\n",
+ "143\n",
+ "Deployed 143 times\n",
+ "Text-to-Image\n",
+ "GPU\n",
+ "1x Nvidia L40S\n",
+ "$\n",
+ "1.8\n",
+ "Browse Catalog\n",
+ "Hub Models\n",
+ "Customer Stories\n",
+ "Learn how leading AI teams use Inference Endpoints to deploy their models\n",
+ "Endpoints for\n",
+ "Music\n",
+ "Musixmatch is the world’s leading music data company\n",
+ "Use Case\n",
+ "Custom text embeddings generation pipeline\n",
+ "Models Deployed\n",
+ "Distilbert-base-uncased-finetuned-sst-2-english\n",
+ "facebook/wav2vec2-base-960h\n",
+ "Custom model based on sentence transformers\n",
+ "The coolest thing was how easy it was to define a complete custom interface from the model to the inference process. It just took us a couple of hours to adapt our code, and have a functioning and totally custom endpoint.\n",
+ "Andrea Boscarino\n",
+ "Data Scientist at Musixmatch\n",
+ "Endpoints for\n",
+ "Health\n",
+ "Phamily improves patient health with intelligent care management\n",
+ "Use Case\n",
+ "HIPAA-compliant secure endpoints for text classification\n",
+ "Models Deployed\n",
+ "Custom model based on text-classification (MPNET)\n",
+ "Custom\n",
+ "\n",
+ "### Link: Discord community\n",
+ "Hugging Face\n",
+ "\n",
+ "You need to enable JavaScript to run this app.\n"
+ ]
+ }
+ ],
"source": [
- "print(get_all_details(\"https://huggingface.co\"))"
+ "print(fetch_page_and_all_relevant_links(\"https://huggingface.co\"))"
]
},
{
@@ -272,56 +1321,84 @@
"metadata": {},
"outputs": [],
"source": [
- "system_prompt = \"You are an assistant that analyzes the contents of several relevant pages from a company website \\\n",
- "and creates a short brochure about the company for prospective customers, investors and recruits. Respond in markdown.\\\n",
- "Include details of company culture, customers and careers/jobs if you have the information.\"\n",
+ "brochure_system_prompt = \"\"\"\n",
+ "You are an assistant that analyzes the contents of several relevant pages from a company website\n",
+ "and creates a short brochure about the company for prospective customers, investors and recruits.\n",
+ "Respond in markdown without code blocks.\n",
+ "Include details of company culture, customers and careers/jobs if you have the information.\n",
+ "\"\"\"\n",
"\n",
"# Or uncomment the lines below for a more humorous brochure - this demonstrates how easy it is to incorporate 'tone':\n",
"\n",
- "# system_prompt = \"You are an assistant that analyzes the contents of several relevant pages from a company website \\\n",
- "# and creates a short humorous, entertaining, jokey brochure about the company for prospective customers, investors and recruits. Respond in markdown.\\\n",
- "# Include details of company culture, customers and careers/jobs if you have the information.\"\n"
+ "# brochure_system_prompt = \"\"\"\n",
+ "# You are an assistant that analyzes the contents of several relevant pages from a company website\n",
+ "# and creates a short, humorous, entertaining, witty brochure about the company for prospective customers, investors and recruits.\n",
+ "# Respond in markdown without code blocks.\n",
+ "# Include details of company culture, customers and careers/jobs if you have the information.\n",
+ "# \"\"\"\n"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 14,
"id": "6ab83d92-d36b-4ce0-8bcc-5bb4c2f8ff23",
"metadata": {},
"outputs": [],
"source": [
"def get_brochure_user_prompt(company_name, url):\n",
- " user_prompt = f\"You are looking at a company called: {company_name}\\n\"\n",
- " user_prompt += f\"Here are the contents of its landing page and other relevant pages; use this information to build a short brochure of the company in markdown.\\n\"\n",
- " user_prompt += get_all_details(url)\n",
+ " user_prompt = f\"\"\"\n",
+ "You are looking at a company called: {company_name}\n",
+ "Here are the contents of its landing page and other relevant pages;\n",
+ "use this information to build a short brochure of the company in markdown without code blocks.\\n\\n\n",
+ "\"\"\"\n",
+ " user_prompt += fetch_page_and_all_relevant_links(url)\n",
" user_prompt = user_prompt[:5_000] # Truncate if more than 5,000 characters\n",
" return user_prompt"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 15,
"id": "cd909e0b-1312-4ce2-a553-821e795d7572",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Selecting relevant links for https://huggingface.co by calling gpt-5-nano\n",
+ "Found 7 relevant links\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "\"\\nYou are looking at a company called: HuggingFace\\nHere are the contents of its landing page and other relevant pages;\\nuse this information to build a short brochure of the company in markdown without code blocks.\\n\\n\\n## Landing Page:\\n\\nHugging Face – The AI community building the future.\\n\\nHugging Face\\nModels\\nDatasets\\nSpaces\\nCommunity\\nDocs\\nEnterprise\\nPricing\\nLog In\\nSign Up\\nThe AI community building the future.\\nThe platform where the machine learning community collaborates on models, datasets, and applications.\\nExplore AI Apps\\nor\\nBrowse 1M+ models\\nTrending on\\nthis week\\nModels\\ntencent/HunyuanImage-3.0\\nUpdated\\nabout 4 hours ago\\n•\\n825\\n•\\n714\\ndeepseek-ai/DeepSeek-V3.2-Exp\\nUpdated\\n3 days ago\\n•\\n10.7k\\n•\\n470\\ntencent/Hunyuan3D-Part\\nUpdated\\n4 days ago\\n•\\n2.57k\\n•\\n461\\nzai-org/GLM-4.6\\nUpdated\\n2 days ago\\n•\\n9.72k\\n•\\n298\\ninclusionAI/Ring-1T-preview\\nUpdated\\n1 day ago\\n•\\n818\\n•\\n208\\nBrowse 1M+ models\\nSpaces\\nRunning\\n1.29k\\n1.29k\\nWan2.2 Animate\\n👁\\nWan2.2 Animate\\nRunning\\n14.5k\\n14.5k\\nDeepSite v3\\n🐳\\nGenerate any application with DeepSeek\\nRunning\\non\\nZero\\nMCP\\n1.46k\\n1.46k\\nWan2.2 14B Fast\\n🎥\\ngenerate a video from an image with a text prompt\\nRunning\\non\\nZero\\n196\\n196\\nQwen Image Edit 2509\\n👀\\nGenerate edited images based on user prompts\\nRunning\\non\\nCPU Upgrade\\n103\\n103\\nOstris' AI Toolkit\\n💻\\nTrain FLUX, Qwen and Wan LoRAs with Ostris Ai Toolkit\\nBrowse 400k+ applications\\nDatasets\\nopenai/gdpval\\nUpdated\\n7 days ago\\n•\\n17k\\n•\\n157\\nfka/awesome-chatgpt-prompts\\nUpdated\\nJan 6\\n•\\n49k\\n•\\n9.18k\\nnvidia/Nemotron-Personas-Japan\\nUpdated\\n9 days ago\\n•\\n9.74k\\n•\\n75\\nt-tech/T-ECD\\nUpdated\\n6 days ago\\n•\\n993\\n•\\n22\\nfacebook/seamless-interaction\\nUpdated\\nJul 14\\n•\\n17.5k\\n•\\n148\\nBrowse 250k+ datasets\\nThe Home of Machine Learning\\nCreate, discover and collaborate on ML better.\\nThe collaboration platform\\nHost and collaborate on unlimited public models, datasets and applications.\\nMove faster\\nWith the HF Open source stack.\\nExplore all modalities\\nText, image, video, audio or even 3D.\\nBuild your portfolio\\nShare your work with the world and build your ML profile.\\nSign Up\\nAccelerate your ML\\nWe provide paid Compute and Enterprise solutions.\\nCompute\\nDeploy on optimized\\nInference Endpoints\\nor update your\\nSpaces applications\\nto a GPU in a few clicks.\\nView pricing\\nStarting at $0.60/hour for GPU\\nTea\\n## Relevant Links:\\n\\n\\n### Link: brand page\\nBrand assets - Hugging Face\\n\\nHugging Face\\nModels\\nDatasets\\nSpaces\\nCommunity\\nDocs\\nEnterprise\\nPricing\\nLog In\\nSign Up\\nHugging Face · Brand assets\\nHF Logos\\n.svg\\n.png\\n.ai\\n.svg\\n.png\\n.ai\\n.svg\\n.png\\n.ai\\nHF Colors\\n#FFD21E\\n#FF9D00\\n#6B7280\\nHF Bio\\nHugging Face is the collaboration platform for the machine learning community.\\n\\nThe Hugging Face Hub works as a central place where anyone can share, explore, discover, and experiment with open-source ML. HF empowers the next generation of machine learning engineers, scientists, and end users to learn, collaborate and share their work to build an open and ethical AI future together.\\n\\nWith the fast-growing community, some of the most used open-source ML libraries and tools, and a talented science team exploring the edge of tech, Hugging Face is at the heart of the AI revolution.\\nCopy to clipboard\\nHF Universe\\nFind other assets available for use from the Hugging Face brand universe\\nhere\\n.\\nSystem theme\\nWebsite\\nModels\\nDatasets\\nSpaces\\nChangelog\\nInference Endpoints\\nHuggingChat\\nCompany\\nAbout\\nBrand assets\\nTerms of service\\nPrivacy\\nJobs\\nPress\\nResources\\nLearn\\nDocumentation\\nBlog\\nForum\\nService Status\\nSocial\\nGitHub\\nTwitter\\nLinkedIn\\nDiscord\\n\\n### Link: careers page\\nHugging Face - Current Openings\\n\\n\\n\\n### Link: company page\\nHugging Face | LinkedIn\\n\\nSkip to main content\\nLinkedIn\\nTop Content\\nPeople\\nLearning\\nJobs\\nGames\\nGet the app\\nJoin now\\nSign in\\nHugging Face\\nSoftware Development\\nThe AI community building the future.\\nSee jobs\\nFollow\\nView all 625 employees\\nReport this company\\nAbout us\\nThe AI community building the future.\\nWebsite\\nhttps://huggingface.co\\nExternal link for Hugging Face\\nIndustry\\nSoftware Development\\nCompany size\\n51-200 employees\\nType\\nPrivately Held\\nFounded\\n2016\\nSpecialties\\nmachine learning, natural language processing, and deep learning\\nProducts\\nHugging Face\\nHugging Face\\nNatural Language Processing (NLP) Software\\nWe’re on a journey to solve and democratize artificial intelligence through natural language.\\nLocations\\nPrimary\\nGet directions\\nParis, FR\\nGet directions\\nEmployees at Hugging Face\\nLudovic Huraux\\nRajat Arya\\nTech Lead & Software Engineer @ HF | prev: co-founder XetHub, Apple, Turi, AWS, Microsoft\\nJeff Boudier\\nProduct + Growth at Hugging Face\\nTerrence Rohan\\nSeed Investor\\nSee all employees\\nUpdates\\nHugging Face\\nreposted this\\nMercuri\\n3,316 followers\\n1d\\nReport this post\\n🚨 404: media not found 🚨\\n\\nWe're teaming up\\nThe Tech Bros\\n,\\nCanva\\n,\\nElevenLabs\\n, and\\nHugging Face\\nfor an all female media x tech\\n#hackathon\\nat the Canva offices 👩🏾💻👩🏼💻👩🏻💻\\n\\n⚡ Build prototypes fast\\n⚡ Get feedback from engineers & investors\\n⚡ Meet your co-founder!?\\n\\nHugging Face, Canva and ElevenLabs are unicorns shaping the future of media and creative tech. At\\nMercuri\\n, we bring the early-st\""
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"get_brochure_user_prompt(\"HuggingFace\", \"https://huggingface.co\")"
]
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "e44de579-4a1a-4e6a-a510-20ea3e4b8d46",
+ "execution_count": 16,
+ "id": "8b45846d",
"metadata": {},
"outputs": [],
"source": [
"def create_brochure(company_name, url):\n",
" response = openai.chat.completions.create(\n",
- " model=MODEL,\n",
+ " model=\"gpt-4.1-mini\",\n",
" messages=[\n",
- " {\"role\": \"system\", \"content\": system_prompt},\n",
+ " {\"role\": \"system\", \"content\": brochure_system_prompt},\n",
" {\"role\": \"user\", \"content\": get_brochure_user_prompt(company_name, url)}\n",
- " ],\n",
+ " ],\n",
" )\n",
" result = response.choices[0].message.content\n",
" display(Markdown(result))"
@@ -329,10 +1406,122 @@
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "e093444a-9407-42ae-924a-145730591a39",
+ "execution_count": 17,
+ "id": "b123615a",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Selecting relevant links for https://huggingface.co by calling gpt-5-nano\n",
+ "Found 13 relevant links\n"
+ ]
+ },
+ {
+ "data": {
+ "text/markdown": [
+ "# Hugging Face Brochure\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## About Hugging Face\n",
+ "\n",
+ "**Hugging Face** is the premier collaboration platform for the machine learning (ML) community, dedicated to building the future of artificial intelligence through openness and shared knowledge. It serves as a vibrant hub where ML engineers, scientists, and enthusiasts from across the globe can share, discover, and experiment with cutting-edge open-source machine learning models, datasets, and applications.\n",
+ "\n",
+ "At its core, Hugging Face empowers the next generation of AI innovators to learn, collaborate, and contribute to an open and ethical AI future.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## What We Offer\n",
+ "\n",
+ "- **Model Hub**: Access and browse over **1 million pre-trained models** covering all modalities including text, image, video, audio, and 3D.\n",
+ "- **Datasets**: Explore and use more than **250,000 datasets** curated for various machine learning tasks.\n",
+ "- **Spaces**: Deploy and share interactive ML applications and demos; over **400,000 apps** available and growing.\n",
+ "- **Compute Solutions**: Scalable paid compute services including optimized inference endpoints and GPU support starting at $0.60/hour.\n",
+ "- **Enterprise Solutions**: Customized offerings tailored to accelerate business adoption of machine learning technologies.\n",
+ "- **Open Source Stack**: Leverage the extensive Hugging Face open-source libraries to move faster in development.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Our Community\n",
+ "\n",
+ "Hugging Face is much more than a platform — it is a thriving, fast-growing community of machine learning practitioners who collectively build, maintain, and democratize AI resources. Collaborators range from individual researchers to top organizations, contributing models like:\n",
+ "\n",
+ "- Tencent’s HunyuanImage series\n",
+ "- deepseek-ai’s DeepSeek models\n",
+ "- NVIDIA and Facebook’s datasets and models\n",
+ "\n",
+ "Community members benefit from the ability to:\n",
+ "\n",
+ "- Host and collaborate on unlimited public projects\n",
+ "- Share their work globally to build a professional ML portfolio\n",
+ "- Collaborate using state-of-the-art open-source tools \n",
+ " \n",
+ "---\n",
+ "\n",
+ "## Company Culture\n",
+ "\n",
+ "- **Collaborative:** Empowering users to co-create and improve AI together.\n",
+ "- **Open & Ethical:** Committed to building an open, transparent, and socially responsible AI ecosystem.\n",
+ "- **Innovative:** Constantly advancing the frontier in machine learning through community-driven innovation.\n",
+ "- **Inclusive:** Bringing together diverse contributors and users worldwide.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Careers at Hugging Face\n",
+ "\n",
+ "Join a team on the front lines of democratizing AI and machine learning! Hugging Face is looking for passionate engineers, researchers, data scientists, and product experts who want to make a global impact by enabling accessible, ethical, and collaborative AI development.\n",
+ "\n",
+ "By working here, you'll:\n",
+ "\n",
+ "- Collaborate with world-class ML experts\n",
+ "- Shape the future of open-source AI tools\n",
+ "- Impact a vibrant global community of hundreds of thousands of users \n",
+ "- Thrive in an open culture that values creativity, diversity, and ethical AI \n",
+ "\n",
+ "Visit [huggingface.co/careers](https://huggingface.co/careers) to explore current job openings.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Why Choose Hugging Face?\n",
+ "\n",
+ "- The **largest and most diverse** collection of open-source machine learning resources.\n",
+ "- A **community-first platform** that fosters collaboration and rapid innovation.\n",
+ "- Flexible solutions for individuals, communities, startups, and enterprises.\n",
+ "- Trusted by industry leaders and researchers worldwide.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Get Started Today\n",
+ "\n",
+ "- Explore AI apps and models at [huggingface.co](https://huggingface.co)\n",
+ "- Join the community, build your portfolio, and accelerate your AI journey.\n",
+ "- Scale your projects with our pay-as-you-go compute resources.\n",
+ "\n",
+ "**Hugging Face** — The AI Community Building the Future.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "# Contact & Links\n",
+ "\n",
+ "- Website: https://huggingface.co\n",
+ "- Community: https://huggingface.co/community\n",
+ "- Documentation: https://huggingface.co/docs\n",
+ "- Careers: https://huggingface.co/careers\n",
+ "\n",
+ "---\n",
+ "\n",
+ "*Hugging Face is your home for collaboration, innovation, and advancing machine learning together.*"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
"source": [
"create_brochure(\"HuggingFace\", \"https://huggingface.co\")"
]
@@ -350,45 +1539,232 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 18,
"id": "51db0e49-f261-4137-aabe-92dd601f7725",
"metadata": {},
"outputs": [],
"source": [
"def stream_brochure(company_name, url):\n",
" stream = openai.chat.completions.create(\n",
- " model=MODEL,\n",
+ " model=\"gpt-4.1-mini\",\n",
" messages=[\n",
- " {\"role\": \"system\", \"content\": system_prompt},\n",
+ " {\"role\": \"system\", \"content\": brochure_system_prompt},\n",
" {\"role\": \"user\", \"content\": get_brochure_user_prompt(company_name, url)}\n",
" ],\n",
" stream=True\n",
- " )\n",
- " \n",
+ " ) \n",
" response = \"\"\n",
" display_handle = display(Markdown(\"\"), display_id=True)\n",
" for chunk in stream:\n",
" response += chunk.choices[0].delta.content or ''\n",
- " response = response.replace(\"```\",\"\").replace(\"markdown\", \"\")\n",
" update_display(Markdown(response), display_id=display_handle.display_id)"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 20,
"id": "56bf0ae3-ee9d-4a72-9cd6-edcac67ceb6d",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Selecting relevant links for https://huggingface.co by calling gpt-5-nano\n",
+ "Found 9 relevant links\n"
+ ]
+ },
+ {
+ "data": {
+ "text/markdown": [
+ "# Hugging Face: The AI Community Building the Future\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## About Hugging Face\n",
+ "\n",
+ "Hugging Face is a vibrant and fast-growing AI and machine learning community dedicated to advancing the future of open and ethical AI. It serves as a collaboration platform where machine learning engineers, scientists, and enthusiasts from around the world create, discover, and share machine learning models, datasets, and applications.\n",
+ "\n",
+ "The Hugging Face Hub is the central place for hosting and collaborating on over **1 million models**, **250k+ datasets**, and **400k+ applications** spanning multiple modalities including text, images, video, audio, and 3D.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## What Hugging Face Offers\n",
+ "\n",
+ "- **Models:** Browse and explore a vast collection of AI models, updated frequently by a diverse community. Popular trending models include image generators, video editors, and language models.\n",
+ " \n",
+ "- **Datasets:** Access a rich catalog of datasets ranging from natural language prompts to persona datasets and beyond, enabling rapid model training and experimentation.\n",
+ " \n",
+ "- **Spaces:** Deploy, share, and run AI applications on Hugging Face's platform, including innovative tools such as video generation from images, AI toolkits, and interactive applications.\n",
+ "\n",
+ "- **Compute:** Easily accelerate your machine learning workloads with optimized inference endpoints and GPU-backed applications starting as low as $0.60/hour.\n",
+ "\n",
+ "- **Enterprise Solutions:** Hugging Face provides tailored enterprise offerings to help organizations harness AI technology securely and effectively at scale.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Company Culture\n",
+ "\n",
+ "Hugging Face fosters an **open, collaborative, and ethical AI community** — empowering developers and researchers to work together transparently and inclusively. The culture emphasizes:\n",
+ "\n",
+ "- **Community-driven innovation:** Encouraging open-source contributions and sharing knowledge.\n",
+ "- **Ethical AI development:** Committed to building responsible AI systems for the benefit of all.\n",
+ "- **Diversity and inclusion:** Supporting a broad and global community in building AI tools and resources.\n",
+ "- **Learning and growth:** Offering a platform for users to build their machine learning portfolios and grow their expertise.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Customers & Community\n",
+ "\n",
+ "Hugging Face serves a global community that includes:\n",
+ "\n",
+ "- Machine learning researchers and practitioners\n",
+ "- Developers building innovative AI applications\n",
+ "- Enterprises seeking scalable AI solutions\n",
+ "- AI enthusiasts and learners who want to experiment and grow their skills\n",
+ "\n",
+ "With over a million models and hundreds of thousands of datasets and applications, the platform connects users with cutting-edge AI technologies from companies like Tencent, NVIDIA, Facebook, and OpenAI — showcasing the power of open collaboration.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Careers at Hugging Face\n",
+ "\n",
+ "Interested in joining Hugging Face? The company values talented individuals passionate about AI, open-source technologies, and community building. Opportunities include roles in:\n",
+ "\n",
+ "- Machine learning research & engineering\n",
+ "- Software development\n",
+ "- Cloud infrastructure and compute optimization\n",
+ "- Community management and developer relations\n",
+ "- Enterprise solutions & sales\n",
+ "\n",
+ "At Hugging Face, you will work at the forefront of AI innovation while contributing to a global, open, and ethical AI movement.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Get Involved\n",
+ "\n",
+ "- **Explore AI models and datasets:** Visit [huggingface.co](https://huggingface.co) to browse millions of resources.\n",
+ "- **Build and share your own models and apps:** Create your portfolio in an open, collaborative environment.\n",
+ "- **Accelerate your projects:** Utilize Hugging Face’s Compute and Enterprise services.\n",
+ "- **Join the community:** Engage with thousands of practitioners working toward the future of AI.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "### Contact & Follow\n",
+ "\n",
+ "- Website: [https://huggingface.co](https://huggingface.co)\n",
+ "- Join the community to learn, collaborate, and innovate in AI!\n",
+ "\n",
+ "---\n",
+ "\n",
+ "*Hugging Face — Empowering the next generation of machine learning for a better, open future.*"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
"source": [
"stream_brochure(\"HuggingFace\", \"https://huggingface.co\")"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 22,
"id": "fdb3f8d8-a3eb-41c8-b1aa-9f60686a653b",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Selecting relevant links for https://huggingface.co by calling gpt-5-nano\n",
+ "Found 14 relevant links\n"
+ ]
+ },
+ {
+ "data": {
+ "text/markdown": [
+ "# Welcome to Hugging Face – The AI Community Building the Future!\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Who Are We? \n",
+ "Imagine a place where machine learning wizards, data sorcerers, and AI alchemists gather to share their spells — uh, models — datasets, and apps. That’s Hugging Face! We’re *the* platform where the AI community collaborates, creates, and sometimes even has a little fun while building the future.\n",
+ "\n",
+ "Our motto? **\"Keep it open. Keep it ethical. Keep it hugging.\"** 💛\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## What’s Cooking in the AI Kitchen?\n",
+ "\n",
+ "- **1 Million+ Models** — From image generators to language wizards, our treasure trove of open-source ML models grows faster than you can say \"neural network.\" \n",
+ "- **250,000+ Datasets** — Feeding AI brains with everything from chat prompts to persona profiles. Hungry for data? Dig in! \n",
+ "- **400,000+ Applications & Spaces** — Launch apps, share your ML portfolio, or just show off cool demos that make your friends say, “Whoa, AI can do that?” \n",
+ "- **Multimodal Madness** — Text, image, video, audio, even 3D...if AI had a Swiss Army knife, we’d be it. \n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Customers & Community \n",
+ "Whether you’re a student trying to get your AI feet wet, a startup looking to scale your genius, or an enterprise aiming to deploy heavy-duty models in the real world, Hugging Face has your back.\n",
+ "\n",
+ "With the fastest growing community of *machine learning enthusiasts* and the support of some seriously big names and organizations, here’s a place where:\n",
+ "\n",
+ "- **Freelancers** can build a portfolio and get noticed. \n",
+ "- **Researchers** can push boundaries openly and ethically. \n",
+ "- **Businesses** can accelerate AI adoption with our paid Compute and Enterprise suites. \n",
+ "\n",
+ "Join 1.29k+ Spaces and thousands more running models that power everything from video generation to AI-powered image editing.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Culture & Career – Geek Out with Us! \n",
+ "We believe collaboration beats isolation every day. Our culture?\n",
+ "\n",
+ "- Open source at heart ❤️ \n",
+ "- Ethical AI advocates \n",
+ "- Casual tea-drinkers and serious problem solvers \n",
+ "- Always learning, always sharing, always growing \n",
+ "\n",
+ "Want to build machine learning tools that millions will use? Hugging Face is where your skills meet endless possibilities. From ML engineers to community managers, our doors are wide open (virtual hugs included).\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Speed Up Your AI Journey \n",
+ "No need to code in the dark alone or fight for GPU time — deploy models and apps with a few clicks on optimized inference endpoints, starting at just $0.60/hour for GPU!\n",
+ "\n",
+ "Whether you want to host that killer new model or just tweak an existing one, we give you the tools and community support to **move faster, build smarter, and hug tighter**.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Quick Hugging Face Facts \n",
+ "- **Founded:** Around the corner from the future \n",
+ "- **Colors:** Bright yellow (#FFD21E), orange (#FF9D00), and sleek gray (#6B7280) — because AI should be as vibrant as its ideas! \n",
+ "- **Mascot:** Friendly face with a warm smile (because AIs could learn a thing or two about friendliness here) \n",
+ "\n",
+ "---\n",
+ "\n",
+ "## Ready to Join the AI Hug Circle? \n",
+ "\n",
+ "Sign up, share your work, explore millions of models and datasets, and get your AI career (or project!) hugging new heights.\n",
+ "\n",
+ "[Explore AI Apps](#) | [Browse 1M+ Models](#) | [Sign Up & Join The Fun](#)\n",
+ "\n",
+ "---\n",
+ "\n",
+ "*Hugging Face — where the future of AI isn’t just created; it’s hugged into existence.* 🤗✨"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
"source": [
"# Try changing the system prompt to the humorous version when you make the Brochure for Hugging Face:\n",
"\n",
@@ -403,7 +1779,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Business applications\n",
@@ -425,7 +1801,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Before you move to Week 2 (which is tons of fun)\n",
@@ -443,7 +1819,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" A reminder on 3 useful resources\n",
@@ -464,7 +1840,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Finally! I have a special request for you\n",
@@ -475,19 +1851,11 @@
" | \n",
" "
]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "b8d3e1a1-ba54-4907-97c5-30f89a24775b",
- "metadata": {},
- "outputs": [],
- "source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -501,7 +1869,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.13"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/week1/diagnostics.py b/week1/diagnostics.py
deleted file mode 100644
index 716e544..0000000
--- a/week1/diagnostics.py
+++ /dev/null
@@ -1,419 +0,0 @@
-import os
-import sys
-import platform
-import subprocess
-import shutil
-import time
-import ssl
-import tempfile
-from pathlib import Path
-from datetime import datetime
-
-class Diagnostics:
-
- FILENAME = 'report.txt'
-
- def __init__(self):
- self.errors = []
- self.warnings = []
- if os.path.exists(self.FILENAME):
- os.remove(self.FILENAME)
-
- def log(self, message):
- print(message)
- with open(self.FILENAME, 'a', encoding='utf-8') as f:
- f.write(message + "\n")
-
- def start(self):
- now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- self.log(f"Starting diagnostics at {now}\n")
-
- def end(self):
- now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- self.log(f"\n\nCompleted diagnostics at {now}\n")
- print("\nPlease send these diagnostics to me at ed@edwarddonner.com")
- print(f"Either copy & paste the above output into an email, or attach the file {self.FILENAME} that has been created in this directory.")
-
-
- def _log_error(self, message):
- self.log(f"ERROR: {message}")
- self.errors.append(message)
-
- def _log_warning(self, message):
- self.log(f"WARNING: {message}")
- self.warnings.append(message)
-
- def run(self):
- self.start()
- self._step1_system_info()
- self._step2_check_files()
- self._step3_git_repo()
- self._step4_check_env_file()
- self._step5_anaconda_check()
- self._step6_virtualenv_check()
- self._step7_network_connectivity()
- self._step8_environment_variables()
- self._step9_additional_diagnostics()
-
- if self.warnings:
- self.log("\n===== Warnings Found =====")
- self.log("The following warnings were detected. They might not prevent the program from running but could cause unexpected behavior:")
- for warning in self.warnings:
- self.log(f"- {warning}")
-
- if self.errors:
- self.log("\n===== Errors Found =====")
- self.log("The following critical issues were detected. Please address them before proceeding:")
- for error in self.errors:
- self.log(f"- {error}")
-
- if not self.errors and not self.warnings:
- self.log("\n✅ All diagnostics passed successfully!")
-
- self.end()
-
- def _step1_system_info(self):
- self.log("===== System Information =====")
- try:
- system = platform.system()
- self.log(f"Operating System: {system}")
-
- if system == "Windows":
- release, version, csd, ptype = platform.win32_ver()
- self.log(f"Windows Release: {release}")
- self.log(f"Windows Version: {version}")
- elif system == "Darwin":
- release, version, machine = platform.mac_ver()
- self.log(f"MacOS Version: {release}")
- else:
- self.log(f"Platform: {platform.platform()}")
-
- self.log(f"Architecture: {platform.architecture()}")
- self.log(f"Machine: {platform.machine()}")
- self.log(f"Processor: {platform.processor()}")
-
- try:
- import psutil
- ram = psutil.virtual_memory()
- total_ram_gb = ram.total / (1024 ** 3)
- available_ram_gb = ram.available / (1024 ** 3)
- self.log(f"Total RAM: {total_ram_gb:.2f} GB")
- self.log(f"Available RAM: {available_ram_gb:.2f} GB")
-
- if available_ram_gb < 2:
- self._log_warning(f"Low available RAM: {available_ram_gb:.2f} GB")
- except ImportError:
- self._log_warning("psutil module not found. Cannot determine RAM information.")
-
- total, used, free = shutil.disk_usage(os.path.expanduser("~"))
- free_gb = free / (1024 ** 3)
- self.log(f"Free Disk Space: {free_gb:.2f} GB")
-
- if free_gb < 5:
- self._log_warning(f"Low disk space: {free_gb:.2f} GB free")
-
- except Exception as e:
- self._log_error(f"System information check failed: {e}")
-
- def _step2_check_files(self):
- self.log("\n===== File System Information =====")
- try:
- current_dir = os.getcwd()
- self.log(f"Current Directory: {current_dir}")
-
- # Check write permissions
- test_file = Path(current_dir) / ".test_write_permission"
- try:
- test_file.touch(exist_ok=True)
- test_file.unlink()
- self.log("Write permission: OK")
- except Exception as e:
- self._log_error(f"No write permission in current directory: {e}")
-
- self.log("\nFiles in Current Directory:")
- try:
- for item in sorted(os.listdir(current_dir)):
- self.log(f" - {item}")
- except Exception as e:
- self._log_error(f"Cannot list directory contents: {e}")
-
- except Exception as e:
- self._log_error(f"File system check failed: {e}")
-
- def _step3_git_repo(self):
- self.log("\n===== Git Repository Information =====")
- try:
- result = subprocess.run(['git', 'rev-parse', '--show-toplevel'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
- if result.returncode == 0:
- git_root = result.stdout.strip()
- self.log(f"Git Repository Root: {git_root}")
-
- result = subprocess.run(['git', 'rev-parse', 'HEAD'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
- if result.returncode == 0:
- self.log(f"Current Commit: {result.stdout.strip()}")
- else:
- self._log_warning(f"Could not get current commit: {result.stderr.strip()}")
-
- result = subprocess.run(['git', 'remote', 'get-url', 'origin'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
- if result.returncode == 0:
- self.log(f"Remote Origin: {result.stdout.strip()}")
- else:
- self._log_warning("No remote 'origin' configured")
- else:
- self._log_warning("Not a git repository")
- except FileNotFoundError:
- self._log_warning("Git is not installed or not in PATH")
- except Exception as e:
- self._log_error(f"Git check failed: {e}")
-
- def _step4_check_env_file(self):
- self.log("\n===== Environment File Check =====")
- try:
- result = subprocess.run(['git', 'rev-parse', '--show-toplevel'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
- if result.returncode == 0:
- git_root = result.stdout.strip()
- env_path = os.path.join(git_root, '.env')
-
- if os.path.isfile(env_path):
- self.log(f".env file exists at: {env_path}")
- try:
- with open(env_path, 'r') as f:
- has_api_key = any(line.strip().startswith('OPENAI_API_KEY=') for line in f)
- if has_api_key:
- self.log("OPENAI_API_KEY found in .env file")
- else:
- self._log_warning("OPENAI_API_KEY not found in .env file")
- except Exception as e:
- self._log_error(f"Cannot read .env file: {e}")
- else:
- self._log_warning(".env file not found in project root")
-
- # Check for additional .env files
- for root, _, files in os.walk(git_root):
- if '.env' in files and os.path.join(root, '.env') != env_path:
- self._log_warning(f"Additional .env file found at: {os.path.join(root, '.env')}")
- else:
- self._log_warning("Git root directory not found. Cannot perform .env file check.")
- except FileNotFoundError:
- self._log_warning("Git is not installed or not in PATH")
- except Exception as e:
- self._log_error(f"Environment file check failed: {e}")
-
- def _step5_anaconda_check(self):
- self.log("\n===== Anaconda Environment Check =====")
- try:
- conda_prefix = os.environ.get('CONDA_PREFIX')
- if conda_prefix:
- self.log("Anaconda environment is active:")
- self.log(f"Environment Path: {conda_prefix}")
- self.log(f"Environment Name: {os.path.basename(conda_prefix)}")
-
- conda_exe = os.environ.get('CONDA_EXE', 'conda')
- result = subprocess.run([conda_exe, '--version'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
- if result.returncode == 0:
- self.log(f"Conda Version: {result.stdout.strip()}")
- else:
- self._log_warning("Could not determine Conda version")
-
- self._check_python_packages()
- else:
- self.log("No active Anaconda environment detected")
- except Exception as e:
- self._log_error(f"Anaconda environment check failed: {e}")
-
- def _step6_virtualenv_check(self):
- self.log("\n===== Virtualenv Check =====")
- try:
- virtual_env = os.environ.get('VIRTUAL_ENV')
- if virtual_env:
- self.log("Virtualenv is active:")
- self.log(f"Environment Path: {virtual_env}")
- self.log(f"Environment Name: {os.path.basename(virtual_env)}")
-
- self._check_python_packages()
- else:
- self.log("No active virtualenv detected")
-
- if not virtual_env and not os.environ.get('CONDA_PREFIX'):
- self._log_warning("Neither virtualenv nor Anaconda environment is active")
- except Exception as e:
- self._log_error(f"Virtualenv check failed: {e}")
-
- def _check_python_packages(self):
- self.log("\nPython Environment:")
- self.log(f"Python Version: {sys.version}")
- self.log(f"Python Executable: {sys.executable}")
-
- required_packages = ['openai', 'python-dotenv', 'requests', 'gradio', 'transformers']
-
- try:
- import pkg_resources
- installed = {pkg.key: pkg.version for pkg in pkg_resources.working_set}
-
- self.log("\nRequired Package Versions:")
- for package in required_packages:
- if package in installed:
- self.log(f"{package}: {installed[package]}")
- else:
- self._log_error(f"Required package '{package}' is not installed")
-
- # Check for potentially conflicting packages
- problem_pairs = [
- ('openai', 'openai-python'),
- ('python-dotenv', 'dotenv')
- ]
-
- for pkg1, pkg2 in problem_pairs:
- if pkg1 in installed and pkg2 in installed:
- self._log_warning(f"Potentially conflicting packages: {pkg1} and {pkg2}")
- except ImportError:
- self._log_error("Could not import 'pkg_resources' to check installed packages")
- except Exception as e:
- self._log_error(f"Package check failed: {e}")
-
- def _step7_network_connectivity(self):
- self.log("\n===== Network Connectivity Check =====")
- try:
- self.log(f"SSL Version: {ssl.OPENSSL_VERSION}")
-
- import requests
- import speedtest # Importing the speedtest-cli library
-
- # Basic connectivity check
- urls = [
- 'https://www.google.com',
- 'https://www.cloudflare.com'
- ]
-
- connected = False
- for url in urls:
- try:
- start_time = time.time()
- response = requests.get(url, timeout=10)
- elapsed_time = time.time() - start_time
- response.raise_for_status()
- self.log(f"✓ Connected to {url}")
- self.log(f" Response time: {elapsed_time:.2f}s")
-
- if elapsed_time > 2:
- self._log_warning(f"Slow response from {url}: {elapsed_time:.2f}s")
- connected = True
- break
- except requests.exceptions.RequestException as e:
- self._log_warning(f"Failed to connect to {url}: {e}")
- else:
- self.log("Basic connectivity OK")
-
- if not connected:
- self._log_error("Failed to connect to any test URLs")
- return
-
- # Bandwidth test using speedtest-cli
- self.log("\nPerforming bandwidth test using speedtest-cli...")
- try:
- st = speedtest.Speedtest()
- st.get_best_server()
- download_speed = st.download() # Bits per second
- upload_speed = st.upload() # Bits per second
-
- download_mbps = download_speed / 1e6 # Convert to Mbps
- upload_mbps = upload_speed / 1e6
-
- self.log(f"Download speed: {download_mbps:.2f} Mbps")
- self.log(f"Upload speed: {upload_mbps:.2f} Mbps")
-
- if download_mbps < 1:
- self._log_warning("Download speed is low")
- if upload_mbps < 0.5:
- self._log_warning("Upload speed is low")
- except speedtest.ConfigRetrievalError:
- self._log_error("Failed to retrieve speedtest configuration")
- except Exception as e:
- self._log_warning(f"Bandwidth test failed: {e}")
-
- except ImportError:
- self._log_error("Required packages are not installed. Please install them using 'pip install requests speedtest-cli'")
- except Exception as e:
- self._log_error(f"Network connectivity check failed: {e}")
-
-
- def _step8_environment_variables(self):
- self.log("\n===== Environment Variables Check =====")
- try:
- # Check Python paths
- pythonpath = os.environ.get('PYTHONPATH')
- if pythonpath:
- self.log("\nPYTHONPATH:")
- for path in pythonpath.split(os.pathsep):
- self.log(f" - {path}")
- else:
- self.log("\nPYTHONPATH is not set.")
-
- self.log("\nPython sys.path:")
- for path in sys.path:
- self.log(f" - {path}")
-
- # Check OPENAI_API_KEY
- from dotenv import load_dotenv
- load_dotenv()
- api_key = os.environ.get('OPENAI_API_KEY')
- if api_key:
- self.log("OPENAI_API_KEY is set after calling load_dotenv()")
- if not api_key.startswith('sk-proj-') or len(api_key)<12:
- self._log_warning("OPENAI_API_KEY format looks incorrect after calling load_dotenv()")
- else:
- self._log_warning("OPENAI_API_KEY environment variable is not set after calling load_dotenv()")
- except Exception as e:
- self._log_error(f"Environment variables check failed: {e}")
-
- def _step9_additional_diagnostics(self):
- self.log("\n===== Additional Diagnostics =====")
- try:
- # Get the site-packages directory paths
- import site
- site_packages_paths = site.getsitepackages()
- if hasattr(site, 'getusersitepackages'):
- site_packages_paths.append(site.getusersitepackages())
-
- # Function to check if a path is within site-packages
- def is_in_site_packages(path):
- return any(os.path.commonpath([path, sp]) == sp for sp in site_packages_paths)
-
- # Check for potential name conflicts in the current directory and sys.path
- conflict_names = ['openai.py', 'dotenv.py']
-
- # Check current directory
- current_dir = os.getcwd()
- for name in conflict_names:
- conflict_path = os.path.join(current_dir, name)
- if os.path.isfile(conflict_path):
- self._log_warning(f"Found '{name}' in the current directory, which may cause import conflicts: {conflict_path}")
-
- # Check sys.path directories
- for path in sys.path:
- if not path or is_in_site_packages(path):
- continue # Skip site-packages and empty paths
- for name in conflict_names:
- conflict_file = os.path.join(path, name)
- if os.path.isfile(conflict_file):
- self._log_warning(f"Potential naming conflict: {conflict_file}")
-
- # Check temp directory
- try:
- with tempfile.NamedTemporaryFile() as tmp:
- self.log(f"Temp directory is writable: {os.path.dirname(tmp.name)}")
- except Exception as e:
- self._log_error(f"Cannot write to temp directory: {e}")
-
- except Exception as e:
- self._log_error(f"Additional diagnostics failed: {e}")
-
-
-if __name__ == "__main__":
- diagnostics = Diagnostics()
- diagnostics.run()
diff --git a/week1/scraper.py b/week1/scraper.py
new file mode 100644
index 0000000..1ecc209
--- /dev/null
+++ b/week1/scraper.py
@@ -0,0 +1,37 @@
+from bs4 import BeautifulSoup
+import requests
+
+
+# Standard headers to fetch a website
+headers = {
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"
+}
+
+
+def fetch_website_contents(url):
+ """
+ Return the title and contents of the website at the given url;
+ truncate to 2,000 characters as a sensible limit
+ """
+ response = requests.get(url, headers=headers)
+ soup = BeautifulSoup(response.content, "html.parser")
+ title = soup.title.string if soup.title else "No title found"
+ if soup.body:
+ for irrelevant in soup.body(["script", "style", "img", "input"]):
+ irrelevant.decompose()
+ text = soup.body.get_text(separator="\n", strip=True)
+ else:
+ text = ""
+ return (title + "\n\n" + text)[:2_000]
+
+
+def fetch_website_links(url):
+ """
+ Return the links on the webiste at the given url
+ I realize this is inefficient as we're parsing twice! This is to keep the code in the lab simple.
+ Feel free to use a class and optimize it!
+ """
+ response = requests.get(url, headers=headers)
+ soup = BeautifulSoup(response.content, "html.parser")
+ links = [link.get("href") for link in soup.find_all("a")]
+ return [link for link in links if link]
diff --git a/week1/solution.py b/week1/solution.py
new file mode 100644
index 0000000..fe3a8de
--- /dev/null
+++ b/week1/solution.py
@@ -0,0 +1,53 @@
+"""
+Website summarizer using Ollama instead of OpenAI.
+"""
+
+from openai import OpenAI
+from scraper import fetch_website_contents
+
+OLLAMA_BASE_URL = "http://localhost:11434/v1"
+MODEL = "llama3.2"
+
+system_prompt = """
+You are a snarky assistant that analyzes the contents of a website,
+and provides a short, snarky, humorous summary, ignoring text that might be navigation related.
+Respond in markdown. Do not wrap the markdown in a code block - respond just with the markdown.
+"""
+
+user_prompt_prefix = """
+Here are the contents of a website.
+Provide a short summary of this website.
+If it includes news or announcements, then summarize these too.
+
+"""
+
+
+def messages_for(website):
+ """Create message list for the LLM."""
+ return [
+ {"role": "system", "content": system_prompt},
+ {"role": "user", "content": user_prompt_prefix + website}
+ ]
+
+
+def summarize(url):
+ """Fetch and summarize a website using Ollama."""
+ ollama = OpenAI(base_url=OLLAMA_BASE_URL, api_key='ollama')
+ website = fetch_website_contents(url)
+ response = ollama.chat.completions.create(
+ model=MODEL,
+ messages=messages_for(website)
+ )
+ return response.choices[0].message.content
+
+
+def main():
+ """Main entry point for testing."""
+ url = input("Enter a URL to summarize: ")
+ print("\nFetching and summarizing...\n")
+ summary = summarize(url)
+ print(summary)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/week2/day1.ipynb b/week2/day1.ipynb
index 4939f47..acab36f 100644
--- a/week2/day1.ipynb
+++ b/week2/day1.ipynb
@@ -11,7 +11,7 @@
"\n",
"In Week 1, we used multiple Frontier LLMs through their Chat UI, and we connected with the OpenAI's API.\n",
"\n",
- "Today we'll connect with the APIs for Anthropic and Google, as well as OpenAI."
+ "Today we'll connect with them through their APIs.."
]
},
{
@@ -22,18 +22,13 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Important Note - Please read me\n",
" I'm continually improving these labs, adding more examples and exercises.\n",
" At the start of each week, it's worth checking you have the latest code. \n",
- " First do a git pull and merge your changes as needed. Any problems? Try asking ChatGPT to clarify how to merge - or contact me!
\n",
- " After you've pulled the code, from the llm_engineering directory, in an Anaconda prompt (PC) or Terminal (Mac), run: \n",
- " conda env update --f environment.yml \n",
- " Or if you used virtualenv rather than Anaconda, then run this from your activated environment in a Powershell (PC) or Terminal (Mac): \n",
- " pip install -r requirements.txt\n",
- " Then restart the kernel (Kernel menu >> Restart Kernel and Clear Outputs Of All Cells) to pick up the changes.\n",
+ " First do a git pull and merge your changes as needed. Check out the GitHub guide for instructions. Any problems? Try asking ChatGPT to clarify how to merge - or contact me! \n",
" \n",
" | \n",
" \n",
@@ -41,7 +36,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Reminder about the resources page\n",
@@ -59,19 +54,30 @@
"id": "85cfe275-4705-4d30-abea-643fbddf1db0",
"metadata": {},
"source": [
- "## Setting up your keys\n",
+ "## Setting up your keys - OPTIONAL!\n",
"\n",
- "If you haven't done so already, you could now create API keys for Anthropic and Google in addition to OpenAI.\n",
+ "We're now going to try asking a bunch of models some questions!\n",
"\n",
- "**Please note:** if you'd prefer to avoid extra API costs, feel free to skip setting up Anthopic and Google! You can see me do it, and focus on OpenAI for the course. You could also substitute Anthropic and/or Google for Ollama, using the exercise you did in week 1.\n",
+ "This is totally optional. If you have keys to Anthropic, Gemini or others, then you can add them in.\n",
+ "\n",
+ "If you'd rather not spend the extra, then just watch me do it!\n",
"\n",
"For OpenAI, visit https://openai.com/api/ \n",
"For Anthropic, visit https://console.anthropic.com/ \n",
- "For Google, visit https://ai.google.dev/gemini-api \n",
+ "For Google, visit https://ai.google.dev/gemini-api \n",
+ "For DeepSeek, visit https://platform.deepseek.com/ \n",
+ "For Groq, visit https://console.groq.com/ \n",
+ "For Grok, visit https://console.x.ai/ \n",
"\n",
- "### Also - adding DeepSeek if you wish\n",
"\n",
- "Optionally, if you'd like to also use DeepSeek, create an account [here](https://platform.deepseek.com/), create a key [here](https://platform.deepseek.com/api_keys) and top up with at least the minimum $2 [here](https://platform.deepseek.com/top_up).\n",
+ "You can also use OpenRouter as your one-stop-shop for many of these! OpenRouter is \"the unified interface for LLMs\":\n",
+ "\n",
+ "For OpenRouter, visit https://openrouter.ai/ \n",
+ "\n",
+ "\n",
+ "With each of the above, you typically have to navigate to:\n",
+ "1. Their billing page to add the minimum top-up (except Gemini, Groq, Google, OpenRouter may have free tiers)\n",
+ "2. Their API key page to collect your API key\n",
"\n",
"### Adding API keys to your .env file\n",
"\n",
@@ -82,9 +88,23 @@
"ANTHROPIC_API_KEY=xxxx\n",
"GOOGLE_API_KEY=xxxx\n",
"DEEPSEEK_API_KEY=xxxx\n",
+ "GROQ_API_KEY=xxxx\n",
+ "GROK_API_KEY=xxxx\n",
+ "OPENROUTER_API_KEY=xxxx\n",
"```\n",
"\n",
- "Afterwards, you may need to restart the Jupyter Lab Kernel (the Python process that sits behind this notebook) via the Kernel menu, and then rerun the cells from the top."
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " Any time you change your .env file\n",
+ " Remember to Save it! And also rerun load_dotenv(override=True) \n",
+ " \n",
+ " | \n",
+ " \n",
+ " "
]
},
{
@@ -97,40 +117,27 @@
"# imports\n",
"\n",
"import os\n",
+ "import requests\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI\n",
- "import anthropic\n",
- "from IPython.display import Markdown, display, update_display"
+ "from IPython.display import Markdown, display"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "f0a8ab2b-6134-4104-a1bc-c3cd7ea4cd36",
+ "id": "b0abffac",
"metadata": {},
"outputs": [],
"source": [
- "# import for google\n",
- "# in rare cases, this seems to give an error on some systems, or even crashes the kernel\n",
- "# If this happens to you, simply ignore this cell - I give an alternative approach for using Gemini later\n",
- "\n",
- "import google.generativeai"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "1179b4c5-cd1f-4131-a876-4c9f3f38d2ba",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Load environment variables in a file called .env\n",
- "# Print the key prefixes to help with any debugging\n",
- "\n",
"load_dotenv(override=True)\n",
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
"google_api_key = os.getenv('GOOGLE_API_KEY')\n",
+ "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
+ "grok_api_key = os.getenv('GROK_API_KEY')\n",
+ "openrouter_api_key = os.getenv('OPENROUTER_API_KEY')\n",
"\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
@@ -140,477 +147,650 @@
"if anthropic_api_key:\n",
" print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
"else:\n",
- " print(\"Anthropic API Key not set\")\n",
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
"\n",
"if google_api_key:\n",
- " print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n",
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
"else:\n",
- " print(\"Google API Key not set\")"
+ " print(\"Google API Key not set (and this is optional)\")\n",
+ "\n",
+ "if deepseek_api_key:\n",
+ " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
+ "else:\n",
+ " print(\"DeepSeek API Key not set (and this is optional)\")\n",
+ "\n",
+ "if groq_api_key:\n",
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
+ "else:\n",
+ " print(\"Groq API Key not set (and this is optional)\")\n",
+ "\n",
+ "if grok_api_key:\n",
+ " print(f\"Grok API Key exists and begins {grok_api_key[:4]}\")\n",
+ "else:\n",
+ " print(\"Grok API Key not set (and this is optional)\")\n",
+ "\n",
+ "if openrouter_api_key:\n",
+ " print(f\"OpenRouter API Key exists and begins {openrouter_api_key[:3]}\")\n",
+ "else:\n",
+ " print(\"OpenRouter API Key not set (and this is optional)\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "797fe7b0-ad43-42d2-acf0-e4f309b112f0",
+ "id": "985a859a",
"metadata": {},
"outputs": [],
"source": [
- "# Connect to OpenAI, Anthropic\n",
+ "# Connect to OpenAI client library\n",
+ "# A thin wrapper around calls to HTTP endpoints\n",
"\n",
"openai = OpenAI()\n",
"\n",
- "claude = anthropic.Anthropic()"
+ "# For Gemini, DeepSeek and Groq, we can use the OpenAI python client\n",
+ "# Because Google and DeepSeek have endpoints compatible with OpenAI\n",
+ "# And OpenAI allows you to change the base_url\n",
+ "\n",
+ "anthropic_url = \"https://api.anthropic.com/v1/\"\n",
+ "gemini_url = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
+ "deepseek_url = \"https://api.deepseek.com\"\n",
+ "groq_url = \"https://api.groq.com/openai/v1\"\n",
+ "grok_url = \"https://api.x.ai/v1\"\n",
+ "openrouter_url = \"https://openrouter.ai/api/v1\"\n",
+ "ollama_url = \"http://localhost:11434/v1\"\n",
+ "\n",
+ "anthropic = OpenAI(api_key=anthropic_api_key, base_url=anthropic_url)\n",
+ "gemini = OpenAI(api_key=google_api_key, base_url=gemini_url)\n",
+ "deepseek = OpenAI(api_key=deepseek_api_key, base_url=deepseek_url)\n",
+ "groq = OpenAI(api_key=groq_api_key, base_url=groq_url)\n",
+ "grok = OpenAI(api_key=grok_api_key, base_url=grok_url)\n",
+ "openrouter = OpenAI(base_url=openrouter_url, api_key=openrouter_api_key)\n",
+ "ollama = OpenAI(api_key=\"ollama\", base_url=ollama_url)"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "425ed580-808d-429b-85b0-6cba50ca1d0c",
+ "id": "16813180",
"metadata": {},
"outputs": [],
"source": [
- "# This is the set up code for Gemini\n",
- "# Having problems with Google Gemini setup? Then just ignore this cell; when we use Gemini, I'll give you an alternative that bypasses this library altogether\n",
- "\n",
- "google.generativeai.configure()"
+ "tell_a_joke = [\n",
+ " {\"role\": \"user\", \"content\": \"Tell a joke for a student on the journey to becoming an expert in LLM Engineering\"},\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "23e92304",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = openai.chat.completions.create(model=\"gpt-4.1-mini\", messages=tell_a_joke)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e03c11b9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = anthropic.chat.completions.create(model=\"claude-sonnet-4-5-20250929\", messages=tell_a_joke)\n",
+ "display(Markdown(response.choices[0].message.content))"
]
},
{
"cell_type": "markdown",
- "id": "42f77b59-2fb1-462a-b90d-78994e4cef33",
+ "id": "ab6ea76a",
"metadata": {},
"source": [
- "## Asking LLMs to tell a joke\n",
- "\n",
- "It turns out that LLMs don't do a great job of telling jokes! Let's compare a few models.\n",
- "Later we will be putting LLMs to better use!\n",
- "\n",
- "### What information is included in the API\n",
- "\n",
- "Typically we'll pass to the API:\n",
- "- The name of the model that should be used\n",
- "- A system message that gives overall context for the role the LLM is playing\n",
- "- A user message that provides the actual prompt\n",
- "\n",
- "There are other parameters that can be used, including **temperature** which is typically between 0 and 1; higher for more random output; lower for more focused and deterministic."
+ "## Training vs Inference time scaling"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "378a0296-59a2-45c6-82eb-941344d3eeff",
+ "id": "afe9e11c",
"metadata": {},
"outputs": [],
"source": [
- "system_message = \"You are an assistant that is great at telling jokes\"\n",
- "user_prompt = \"Tell a light-hearted joke for an audience of Data Scientists\""
+ "easy_puzzle = [\n",
+ " {\"role\": \"user\", \"content\": \n",
+ " \"You toss 2 coins. One of them is heads. What's the probability the other is tails? Answer with the probability only.\"},\n",
+ "]"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "f4d56a0f-2a3d-484d-9344-0efa6862aff4",
+ "id": "4a887eb3",
"metadata": {},
"outputs": [],
"source": [
- "prompts = [\n",
- " {\"role\": \"system\", \"content\": system_message},\n",
- " {\"role\": \"user\", \"content\": user_prompt}\n",
- " ]"
+ "response = openai.chat.completions.create(model=\"gpt-5-nano\", messages=easy_puzzle, reasoning_effort=\"minimal\")\n",
+ "display(Markdown(response.choices[0].message.content))"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "3b3879b6-9a55-4fed-a18c-1ea2edfaf397",
+ "id": "5f854d01",
"metadata": {},
"outputs": [],
"source": [
- "# GPT-4o-mini\n",
- "\n",
- "completion = openai.chat.completions.create(model='gpt-4o-mini', messages=prompts)\n",
- "print(completion.choices[0].message.content)"
+ "response = openai.chat.completions.create(model=\"gpt-5-nano\", messages=easy_puzzle, reasoning_effort=\"low\")\n",
+ "display(Markdown(response.choices[0].message.content))"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "3d2d6beb-1b81-466f-8ed1-40bf51e7adbf",
+ "id": "f45fc55b",
"metadata": {},
"outputs": [],
"source": [
- "# GPT-4.1-mini\n",
- "# Temperature setting controls creativity\n",
- "\n",
- "completion = openai.chat.completions.create(\n",
- " model='gpt-4.1-mini',\n",
- " messages=prompts,\n",
- " temperature=0.7\n",
- ")\n",
- "print(completion.choices[0].message.content)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "12d2a549-9d6e-4ea0-9c3e-b96a39e9959e",
- "metadata": {},
- "outputs": [],
- "source": [
- "# GPT-4.1-nano - extremely fast and cheap\n",
- "\n",
- "completion = openai.chat.completions.create(\n",
- " model='gpt-4.1-nano',\n",
- " messages=prompts\n",
- ")\n",
- "print(completion.choices[0].message.content)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f1f54beb-823f-4301-98cb-8b9a49f4ce26",
- "metadata": {},
- "outputs": [],
- "source": [
- "# GPT-4.1\n",
- "\n",
- "completion = openai.chat.completions.create(\n",
- " model='gpt-4.1',\n",
- " messages=prompts,\n",
- " temperature=0.4\n",
- ")\n",
- "print(completion.choices[0].message.content)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "96232ef4-dc9e-430b-a9df-f516685e7c9a",
- "metadata": {},
- "outputs": [],
- "source": [
- "# If you have access to this, here is the reasoning model o4-mini\n",
- "# This is trained to think through its response before replying\n",
- "# So it will take longer but the answer should be more reasoned - not that this helps..\n",
- "\n",
- "completion = openai.chat.completions.create(\n",
- " model='o4-mini',\n",
- " messages=prompts\n",
- ")\n",
- "print(completion.choices[0].message.content)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "1ecdb506-9f7c-4539-abae-0e78d7f31b76",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Claude 4.0 Sonnet\n",
- "# API needs system message provided separately from user prompt\n",
- "# Also adding max_tokens\n",
- "\n",
- "message = claude.messages.create(\n",
- " model=\"claude-sonnet-4-20250514\",\n",
- " max_tokens=200,\n",
- " temperature=0.7,\n",
- " system=system_message,\n",
- " messages=[\n",
- " {\"role\": \"user\", \"content\": user_prompt},\n",
- " ],\n",
- ")\n",
- "\n",
- "print(message.content[0].text)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "769c4017-4b3b-4e64-8da7-ef4dcbe3fd9f",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Claude 4.0 Sonnet again\n",
- "# Now let's add in streaming back results\n",
- "# If the streaming looks strange, then please see the note below this cell!\n",
- "\n",
- "result = claude.messages.stream(\n",
- " model=\"claude-sonnet-4-20250514\",\n",
- " max_tokens=200,\n",
- " temperature=0.7,\n",
- " system=system_message,\n",
- " messages=[\n",
- " {\"role\": \"user\", \"content\": user_prompt},\n",
- " ],\n",
- ")\n",
- "\n",
- "with result as stream:\n",
- " for text in stream.text_stream:\n",
- " print(text, end=\"\", flush=True)"
+ "response = openai.chat.completions.create(model=\"gpt-5-mini\", messages=easy_puzzle, reasoning_effort=\"minimal\")\n",
+ "display(Markdown(response.choices[0].message.content))"
]
},
{
"cell_type": "markdown",
- "id": "dd1e17bc-cd46-4c23-b639-0c7b748e6c5a",
+ "id": "ca713a5c",
"metadata": {},
"source": [
- "## A rare problem with Claude streaming on some Windows boxes\n",
- "\n",
- "2 students have noticed a strange thing happening with Claude's streaming into Jupyter Lab's output -- it sometimes seems to swallow up parts of the response.\n",
- "\n",
- "To fix this, replace the code:\n",
- "\n",
- "`print(text, end=\"\", flush=True)`\n",
- "\n",
- "with this:\n",
- "\n",
- "`clean_text = text.replace(\"\\n\", \" \").replace(\"\\r\", \" \")` \n",
- "`print(clean_text, end=\"\", flush=True)`\n",
- "\n",
- "And it should work fine!"
+ "## Testing out the best models on the planet"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "6df48ce5-70f8-4643-9a50-b0b5bfdb66ad",
+ "id": "df1e825b",
"metadata": {},
"outputs": [],
"source": [
- "# The API for Gemini has a slightly different structure.\n",
- "# I've heard that on some PCs, this Gemini code causes the Kernel to crash.\n",
- "# If that happens to you, please skip this cell and use the next cell instead - an alternative approach.\n",
+ "hard = \"\"\"\n",
+ "On a bookshelf, two volumes of Pushkin stand side by side: the first and the second.\n",
+ "The pages of each volume together have a thickness of 2 cm, and each cover is 2 mm thick.\n",
+ "A worm gnawed (perpendicular to the pages) from the first page of the first volume to the last page of the second volume.\n",
+ "What distance did it gnaw through?\n",
+ "\"\"\"\n",
+ "hard_puzzle = [\n",
+ " {\"role\": \"user\", \"content\": hard}\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8f6a7827",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = openai.chat.completions.create(model=\"gpt-5-nano\", messages=hard_puzzle, reasoning_effort=\"minimal\")\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d693ac0d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = anthropic.chat.completions.create(model=\"claude-sonnet-4-5-20250929\", messages=hard_puzzle)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7de7818f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = openai.chat.completions.create(model=\"gpt-5\", messages=hard_puzzle)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "de1dc5fa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = gemini.chat.completions.create(model=\"gemini-2.5-pro\", messages=hard_puzzle)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9a9faf98",
+ "metadata": {},
+ "source": [
+ "## A spicy challenge to test the competitive spirit"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fc1824ad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "dilemma_prompt = \"\"\"\n",
+ "You and a partner are contestants on a game show. You're each taken to separate rooms and given a choice:\n",
+ "Cooperate: Choose \"Share\" — if both of you choose this, you each win $1,000.\n",
+ "Defect: Choose \"Steal\" — if one steals and the other shares, the stealer gets $2,000 and the sharer gets nothing.\n",
+ "If both steal, you both get nothing.\n",
+ "Do you choose to Steal or Share? Pick one.\n",
+ "\"\"\"\n",
"\n",
- "gemini = google.generativeai.GenerativeModel(\n",
- " model_name='gemini-2.0-flash',\n",
- " system_instruction=system_message\n",
+ "dilemma = [\n",
+ " {\"role\": \"user\", \"content\": dilemma_prompt},\n",
+ "]\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "09807f1a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = anthropic.chat.completions.create(model=\"claude-sonnet-4-5-20250929\", messages=dilemma)\n",
+ "display(Markdown(response.choices[0].message.content))\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "230f49d6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = groq.chat.completions.create(model=\"openai/gpt-oss-120b\", messages=dilemma)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "421f08df",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = deepseek.chat.completions.create(model=\"deepseek-reasoner\", messages=dilemma)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2599fc6e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = grok.chat.completions.create(model=\"grok-4\", messages=dilemma)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "162752e9",
+ "metadata": {},
+ "source": [
+ "## Going local\n",
+ "\n",
+ "Just use the OpenAI library pointed to localhost:11434/v1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ba03ee29",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "requests.get(\"http://localhost:11434/\").content\n",
+ "\n",
+ "# If not running, run ollama serve at a command line"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f363cd6b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "!ollama pull llama3.2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "96e97263",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Only do this if you have a large machine - at least 16GB RAM\n",
+ "\n",
+ "!ollama pull gpt-oss:20b"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a3bfc78a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = ollama.chat.completions.create(model=\"llama3.2\", messages=easy_puzzle)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9a5527a3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = ollama.chat.completions.create(model=\"gpt-oss:20b\", messages=easy_puzzle)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a0628309",
+ "metadata": {},
+ "source": [
+ "## Gemini and Anthropic Client Library\n",
+ "\n",
+ "We're going via the OpenAI Python Client Library, but the other providers have their libraries too"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f0a8ab2b-6134-4104-a1bc-c3cd7ea4cd36",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from google import genai\n",
+ "\n",
+ "client = genai.Client()\n",
+ "\n",
+ "response = client.models.generate_content(\n",
+ " model=\"gemini-2.5-flash-lite\", contents=\"Describe the color Blue to someone who's never been able to see in 1 sentence\"\n",
")\n",
- "response = gemini.generate_content(user_prompt)\n",
"print(response.text)"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "49009a30-037d-41c8-b874-127f61c4aa3a",
+ "id": "df7b6c63",
"metadata": {},
"outputs": [],
"source": [
- "# As an alternative way to use Gemini that bypasses Google's python API library,\n",
- "# Google released endpoints that means you can use Gemini via the client libraries for OpenAI!\n",
- "# We're also trying Gemini's latest reasoning/thinking model\n",
+ "from anthropic import Anthropic\n",
"\n",
- "gemini_via_openai_client = OpenAI(\n",
- " api_key=google_api_key, \n",
- " base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
- ")\n",
+ "client = Anthropic()\n",
"\n",
- "response = gemini_via_openai_client.chat.completions.create(\n",
- " model=\"gemini-2.5-flash\",\n",
- " messages=prompts\n",
+ "response = client.messages.create(\n",
+ " model=\"claude-sonnet-4-5-20250929\",\n",
+ " messages=[{\"role\": \"user\", \"content\": \"Describe the color Blue to someone who's never been able to see in 1 sentence\"}],\n",
+ " max_tokens=100\n",
")\n",
- "print(response.choices[0].message.content)"
+ "print(response.content[0].text)"
]
},
{
"cell_type": "markdown",
- "id": "492f0ff2-8581-4836-bf00-37fddbe120eb",
+ "id": "45a9d0eb",
"metadata": {},
"source": [
- "# Sidenote:\n",
+ "## Routers and Abtraction Layers\n",
"\n",
- "This alternative approach of using the client library from OpenAI to connect with other models has become extremely popular in recent months.\n",
+ "Starting with the wonderful OpenRouter.ai - it can connect to all the models above!\n",
"\n",
- "So much so, that all the models now support this approach - including Anthropic.\n",
+ "Visit openrouter.ai and browse the models.\n",
"\n",
- "You can read more about this approach, with 4 examples, in the first section of this guide:\n",
- "\n",
- "https://github.com/ed-donner/agents/blob/main/guides/09_ai_apis_and_ollama.ipynb"
+ "Here's one we haven't seen yet: GLM 4.5 from Chinese startup z.ai"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9fac59dc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = openrouter.chat.completions.create(model=\"z-ai/glm-4.5\", messages=tell_a_joke)\n",
+ "display(Markdown(response.choices[0].message.content))"
]
},
{
"cell_type": "markdown",
- "id": "33f70c88-7ca9-470b-ad55-d93a57dcc0ab",
+ "id": "b58908e6",
"metadata": {},
"source": [
- "## (Optional) Trying out the DeepSeek model\n",
- "\n",
- "### Let's ask DeepSeek a really hard question - both the Chat and the Reasoner model"
+ "## And now a first look at the powerful, mighty (and quite heavyweight) LangChain"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "3d0019fb-f6a8-45cb-962b-ef8bf7070d4d",
+ "id": "02e145ad",
"metadata": {},
"outputs": [],
"source": [
- "# Optionally if you wish to try DeekSeek, you can also use the OpenAI client library\n",
+ "from langchain_openai import ChatOpenAI\n",
"\n",
- "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
+ "llm = ChatOpenAI(model=\"gpt-5-mini\")\n",
+ "response = llm.invoke(tell_a_joke)\n",
"\n",
- "if deepseek_api_key:\n",
- " print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
- "else:\n",
- " print(\"DeepSeek API Key not set - please skip to the next section if you don't wish to try the DeepSeek API\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "c72c871e-68d6-4668-9c27-96d52b77b867",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Using DeepSeek Chat\n",
- "\n",
- "deepseek_via_openai_client = OpenAI(\n",
- " api_key=deepseek_api_key, \n",
- " base_url=\"https://api.deepseek.com\"\n",
- ")\n",
- "\n",
- "response = deepseek_via_openai_client.chat.completions.create(\n",
- " model=\"deepseek-chat\",\n",
- " messages=prompts,\n",
- ")\n",
- "\n",
- "print(response.choices[0].message.content)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "50b6e70f-700a-46cf-942f-659101ffeceb",
- "metadata": {},
- "outputs": [],
- "source": [
- "challenge = [{\"role\": \"system\", \"content\": \"You are a helpful assistant\"},\n",
- " {\"role\": \"user\", \"content\": \"How many words are there in your answer to this prompt\"}]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "66d1151c-2015-4e37-80c8-16bc16367cfe",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Using DeepSeek Chat with a harder question! And streaming results\n",
- "\n",
- "stream = deepseek_via_openai_client.chat.completions.create(\n",
- " model=\"deepseek-chat\",\n",
- " messages=challenge,\n",
- " stream=True\n",
- ")\n",
- "\n",
- "reply = \"\"\n",
- "display_handle = display(Markdown(\"\"), display_id=True)\n",
- "for chunk in stream:\n",
- " reply += chunk.choices[0].delta.content or ''\n",
- " reply = reply.replace(\"```\",\"\").replace(\"markdown\",\"\")\n",
- " update_display(Markdown(reply), display_id=display_handle.display_id)\n",
- "\n",
- "print(\"Number of words:\", len(reply.split(\" \")))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "43a93f7d-9300-48cc-8c1a-ee67380db495",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Using DeepSeek Reasoner - this may hit an error if DeepSeek is busy\n",
- "# It's over-subscribed (as of 28-Jan-2025) but should come back online soon!\n",
- "# If this fails, come back to this in a few days..\n",
- "\n",
- "response = deepseek_via_openai_client.chat.completions.create(\n",
- " model=\"deepseek-reasoner\",\n",
- " messages=challenge\n",
- ")\n",
- "\n",
- "reasoning_content = response.choices[0].message.reasoning_content\n",
- "content = response.choices[0].message.content\n",
- "\n",
- "print(reasoning_content)\n",
- "print(content)\n",
- "print(\"Number of words:\", len(content.split(\" \")))"
+ "display(Markdown(response.content))"
]
},
{
"cell_type": "markdown",
- "id": "cbf0d5dd-7f20-4090-a46d-da56ceec218f",
+ "id": "92d49785",
"metadata": {},
"source": [
- "## Additional exercise to build your experience with the models\n",
- "\n",
- "This is optional, but if you have time, it's so great to get first hand experience with the capabilities of these different models.\n",
- "\n",
- "You could go back and ask the same question via the APIs above to get your own personal experience with the pros & cons of the models.\n",
- "\n",
- "Later in the course we'll look at benchmarks and compare LLMs on many dimensions. But nothing beats personal experience!\n",
- "\n",
- "Here are some questions to try:\n",
- "1. The question above: \"How many words are there in your answer to this prompt\"\n",
- "2. A creative question: \"In 3 sentences, describe the color Blue to someone who's never been able to see\"\n",
- "3. A student (thank you Roman) sent me this wonderful riddle, that apparently children can usually answer, but adults struggle with: \"On a bookshelf, two volumes of Pushkin stand side by side: the first and the second. The pages of each volume together have a thickness of 2 cm, and each cover is 2 mm thick. A worm gnawed (perpendicular to the pages) from the first page of the first volume to the last page of the second volume. What distance did it gnaw through?\".\n",
- "\n",
- "The answer may not be what you expect, and even though I'm quite good at puzzles, I'm embarrassed to admit that I got this one wrong.\n",
- "\n",
- "### What to look out for as you experiment with models\n",
- "\n",
- "1. How the Chat models differ from the Reasoning models (also known as Thinking models)\n",
- "2. The ability to solve problems and the ability to be creative\n",
- "3. Speed of generation\n"
+ "## Finally - my personal fave - the wonderfully lightweight LiteLLM"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "63e42515",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from litellm import completion\n",
+ "response = completion(model=\"openai/gpt-4.1\", messages=tell_a_joke)\n",
+ "reply = response.choices[0].message.content\n",
+ "display(Markdown(reply))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "36f787f5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(f\"Input tokens: {response.usage.prompt_tokens}\")\n",
+ "print(f\"Output tokens: {response.usage.completion_tokens}\")\n",
+ "print(f\"Total tokens: {response.usage.total_tokens}\")\n",
+ "print(f\"Total cost: {response._hidden_params[\"response_cost\"]*100:.4f} cents\")"
]
},
{
"cell_type": "markdown",
- "id": "c09e6b5c-6816-4cd3-a5cd-a20e4171b1a0",
+ "id": "28126494",
"metadata": {},
"source": [
- "## Back to OpenAI with a serious question"
+ "## Now - let's use LiteLLM to illustrate a Pro-feature: prompt caching"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "83ddb483-4f57-4668-aeea-2aade3a9e573",
+ "id": "f8a91ef4",
"metadata": {},
"outputs": [],
"source": [
- "# To be serious! GPT-4o-mini with the original question\n",
+ "with open(\"hamlet.txt\", \"r\", encoding=\"utf-8\") as f:\n",
+ " hamlet = f.read()\n",
"\n",
- "prompts = [\n",
- " {\"role\": \"system\", \"content\": \"You are a helpful assistant that responds in Markdown\"},\n",
- " {\"role\": \"user\", \"content\": \"How do I decide if a business problem is suitable for an LLM solution? Please respond in Markdown.\"}\n",
- " ]"
+ "loc = hamlet.find(\"Speak, man\")\n",
+ "print(hamlet[loc:loc+100])"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "749f50ab-8ccd-4502-a521-895c3f0808a2",
+ "id": "7f34f670",
"metadata": {},
"outputs": [],
"source": [
- "# Have it stream back results in markdown\n",
+ "question = [{\"role\": \"user\", \"content\": \"In Hamlet, when Laertes asks 'Where is my father?' what is the reply?\"}]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9db6c82b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = completion(model=\"gemini/gemini-2.5-flash-lite\", messages=question)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "228b7e7c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(f\"Input tokens: {response.usage.prompt_tokens}\")\n",
+ "print(f\"Output tokens: {response.usage.completion_tokens}\")\n",
+ "print(f\"Total tokens: {response.usage.total_tokens}\")\n",
+ "print(f\"Total cost: {response._hidden_params[\"response_cost\"]*100:.4f} cents\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "11e37e43",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "question[0][\"content\"] += \"\\n\\nFor context, here is the entire text of Hamlet:\\n\\n\"+hamlet"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "37afb28b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = completion(model=\"gemini/gemini-2.5-flash-lite\", messages=question)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d84edecf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(f\"Input tokens: {response.usage.prompt_tokens}\")\n",
+ "print(f\"Output tokens: {response.usage.completion_tokens}\")\n",
+ "print(f\"Cached tokens: {response.usage.prompt_tokens_details.cached_tokens}\")\n",
+ "print(f\"Total cost: {response._hidden_params[\"response_cost\"]*100:.4f} cents\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "515d1a94",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "response = completion(model=\"gemini/gemini-2.5-flash-lite\", messages=question)\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "eb5dd403",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(f\"Input tokens: {response.usage.prompt_tokens}\")\n",
+ "print(f\"Output tokens: {response.usage.completion_tokens}\")\n",
+ "print(f\"Cached tokens: {response.usage.prompt_tokens_details.cached_tokens}\")\n",
+ "print(f\"Total cost: {response._hidden_params[\"response_cost\"]*100:.4f} cents\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "00f5a3b7",
+ "metadata": {},
+ "source": [
+ "## Prompt Caching with OpenAI\n",
"\n",
- "stream = openai.chat.completions.create(\n",
- " model='gpt-4.1-mini',\n",
- " messages=prompts,\n",
- " temperature=0.7,\n",
- " stream=True\n",
- ")\n",
+ "For OpenAI:\n",
"\n",
- "reply = \"\"\n",
- "display_handle = display(Markdown(\"\"), display_id=True)\n",
- "for chunk in stream:\n",
- " reply += chunk.choices[0].delta.content or ''\n",
- " reply = reply.replace(\"```\",\"\").replace(\"markdown\",\"\")\n",
- " update_display(Markdown(reply), display_id=display_handle.display_id)"
+ "https://platform.openai.com/docs/guides/prompt-caching\n",
+ "\n",
+ "> Cache hits are only possible for exact prefix matches within a prompt. To realize caching benefits, place static content like instructions and examples at the beginning of your prompt, and put variable content, such as user-specific information, at the end. This also applies to images and tools, which must be identical between requests.\n",
+ "\n",
+ "\n",
+ "Cached input is 4X cheaper\n",
+ "\n",
+ "https://openai.com/api/pricing/"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b98964f9",
+ "metadata": {},
+ "source": [
+ "## Prompt Caching with Anthropic\n",
+ "\n",
+ "https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching\n",
+ "\n",
+ "You have to tell Claude what you are caching\n",
+ "\n",
+ "You pay 25% MORE to \"prime\" the cache\n",
+ "\n",
+ "Then you pay 10X less to reuse from the cache with inputs.\n",
+ "\n",
+ "https://www.anthropic.com/pricing#api"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "67d960dd",
+ "metadata": {},
+ "source": [
+ "## Gemini supports both 'implicit' and 'explicit' prompt caching\n",
+ "\n",
+ "https://ai.google.dev/gemini-api/docs/caching?lang=python"
]
},
{
@@ -679,11 +859,8 @@
" for gpt, claude in zip(gpt_messages, claude_messages):\n",
" messages.append({\"role\": \"assistant\", \"content\": gpt})\n",
" messages.append({\"role\": \"user\", \"content\": claude})\n",
- " completion = openai.chat.completions.create(\n",
- " model=gpt_model,\n",
- " messages=messages\n",
- " )\n",
- " return completion.choices[0].message.content"
+ " response = openai.chat.completions.create(model=gpt_model, messages=messages)\n",
+ " return response.choices[0].message.content"
]
},
{
@@ -704,18 +881,13 @@
"outputs": [],
"source": [
"def call_claude():\n",
- " messages = []\n",
+ " messages = [{\"role\": \"system\", \"content\": claude_system}]\n",
" for gpt, claude_message in zip(gpt_messages, claude_messages):\n",
" messages.append({\"role\": \"user\", \"content\": gpt})\n",
" messages.append({\"role\": \"assistant\", \"content\": claude_message})\n",
" messages.append({\"role\": \"user\", \"content\": gpt_messages[-1]})\n",
- " message = claude.messages.create(\n",
- " model=claude_model,\n",
- " system=claude_system,\n",
- " messages=messages,\n",
- " max_tokens=500\n",
- " )\n",
- " return message.content[0].text"
+ " response = anthropic.chat.completions.create(model=claude_model, messages=messages)\n",
+ " return response.choices[0].message.content"
]
},
{
@@ -748,16 +920,16 @@
"gpt_messages = [\"Hi there\"]\n",
"claude_messages = [\"Hi\"]\n",
"\n",
- "print(f\"GPT:\\n{gpt_messages[0]}\\n\")\n",
- "print(f\"Claude:\\n{claude_messages[0]}\\n\")\n",
+ "display(Markdown(f\"### GPT:\\n{gpt_messages[0]}\\n\"))\n",
+ "display(Markdown(f\"### Claude:\\n{claude_messages[0]}\\n\"))\n",
"\n",
"for i in range(5):\n",
" gpt_next = call_gpt()\n",
- " print(f\"GPT:\\n{gpt_next}\\n\")\n",
+ " display(Markdown(f\"### GPT:\\n{gpt_next}\\n\"))\n",
" gpt_messages.append(gpt_next)\n",
" \n",
" claude_next = call_claude()\n",
- " print(f\"Claude:\\n{claude_next}\\n\")\n",
+ " display(Markdown(f\"### Claude:\\n{claude_next}\\n\"))\n",
" claude_messages.append(claude_next)"
]
},
@@ -769,7 +941,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Before you continue\n",
@@ -795,12 +967,17 @@
"Something like:\n",
"\n",
"```python\n",
+ "system_prompt = \"\"\"\n",
+ "You are Alex, a chatbot who is very argumentative; you disagree with anything in the conversation and you challenge everything, in a snarky way.\n",
+ "You are in a conversation with Blake and Charlie.\n",
+ "\"\"\"\n",
+ "\n",
"user_prompt = f\"\"\"\n",
- " You are Alex, in conversation with Blake and Charlie.\n",
- " The conversation so far is as follows:\n",
- " {conversation}\n",
- " Now with this, respond with what you would like to say next, as Alex.\n",
- " \"\"\"\n",
+ "You are Alex, in conversation with Blake and Charlie.\n",
+ "The conversation so far is as follows:\n",
+ "{conversation}\n",
+ "Now with this, respond with what you would like to say next, as Alex.\n",
+ "\"\"\"\n",
"```\n",
"\n",
"Try doing this yourself before you look at the solutions. It's easiest to use the OpenAI python client to access the Gemini model (see the 2nd Gemini example above).\n",
@@ -818,7 +995,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Business relevance\n",
@@ -839,7 +1016,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -853,7 +1030,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.13"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/week2/day2.ipynb b/week2/day2.ipynb
index 9954ea7..a9af820 100644
--- a/week2/day2.ipynb
+++ b/week2/day2.ipynb
@@ -16,26 +16,19 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": null,
"id": "c44c5494-950d-4d2f-8d4f-b87b57c5b330",
"metadata": {},
"outputs": [],
"source": [
- "# imports\n",
- "\n",
"import os\n",
- "import requests\n",
- "from bs4 import BeautifulSoup\n",
- "from typing import List\n",
"from dotenv import load_dotenv\n",
- "from openai import OpenAI\n",
- "import google.generativeai\n",
- "import anthropic"
+ "from openai import OpenAI"
]
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": null,
"id": "d1715421-cead-400b-99af-986388a97aff",
"metadata": {},
"outputs": [],
@@ -45,23 +38,14 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": null,
"id": "337d5dfc-0181-4e3b-8ab9-e78e0c3f657b",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "OpenAI API Key exists and begins sk-proj-\n",
- "Anthropic API Key exists and begins sk-ant-\n",
- "Google API Key exists and begins AIzaSyA5\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"# Load environment variables in a file called .env\n",
"# Print the key prefixes to help with any debugging\n",
+ "# You can choose whichever providers you like - or all Ollama\n",
"\n",
"load_dotenv(override=True)\n",
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
@@ -86,7 +70,7 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": null,
"id": "22586021-1795-4929-8079-63f5bb4edd4c",
"metadata": {},
"outputs": [],
@@ -95,61 +79,36 @@
"\n",
"openai = OpenAI()\n",
"\n",
- "claude = anthropic.Anthropic()\n",
+ "anthropic_url = \"https://api.anthropic.com/v1/\"\n",
+ "gemini_url = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
"\n",
- "google.generativeai.configure()"
+ "anthropic = OpenAI(api_key=anthropic_api_key, base_url=anthropic_url)\n",
+ "gemini = OpenAI(api_key=google_api_key, base_url=gemini_url)"
]
},
{
"cell_type": "code",
- "execution_count": 5,
- "id": "b16e6021-6dc4-4397-985a-6679d6c8ffd5",
- "metadata": {},
- "outputs": [],
- "source": [
- "# A generic system message - no more snarky adversarial AIs!\n",
- "\n",
- "system_message = \"You are a helpful assistant\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
+ "execution_count": null,
"id": "02ef9b69-ef31-427d-86d0-b8c799e1c1b1",
"metadata": {},
"outputs": [],
"source": [
- "# Let's wrap a call to GPT-4o-mini in a simple function\n",
+ "# Let's wrap a call to GPT-4.1-mini in a simple function\n",
+ "\n",
+ "system_message = \"You are a helpful assistant\"\n",
"\n",
"def message_gpt(prompt):\n",
- " messages = [\n",
- " {\"role\": \"system\", \"content\": system_message},\n",
- " {\"role\": \"user\", \"content\": prompt}\n",
- " ]\n",
- " completion = openai.chat.completions.create(\n",
- " model='gpt-4o-mini',\n",
- " messages=messages,\n",
- " )\n",
- " return completion.choices[0].message.content"
+ " messages = [{\"role\": \"system\", \"content\": system_message}, {\"role\": \"user\", \"content\": prompt}]\n",
+ " response = openai.chat.completions.create(model=\"gpt-4.1-mini\", messages=messages)\n",
+ " return response.choices[0].message.content"
]
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": null,
"id": "aef7d314-2b13-436b-b02d-8de3b72b193f",
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "\"Today's date is October 10, 2023.\""
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# This can reveal the \"training cut off\", or the most recent date in the training data\n",
"\n",
@@ -166,7 +125,7 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": null,
"id": "bc664b7a-c01d-4fea-a1de-ae22cdd5141a",
"metadata": {},
"outputs": [],
@@ -180,159 +139,92 @@
},
{
"cell_type": "code",
- "execution_count": 9,
- "id": "083ea451-d3a0-4d13-b599-93ed49b975e4",
+ "execution_count": null,
+ "id": "977bb496",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Shout has been called with input hello\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "'HELLO'"
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"shout(\"hello\")"
]
},
{
"cell_type": "code",
- "execution_count": 10,
- "id": "08f1f15a-122e-4502-b112-6ee2817dda32",
+ "execution_count": null,
+ "id": "083ea451-d3a0-4d13-b599-93ed49b975e4",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7860\n",
- "* To create a public link, set `share=True` in `launch()`.\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 10,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
- "# The simplicty of gradio. This might appear in \"light mode\" - I'll show you how to make this in dark mode later.\n",
- "\n",
- "gr.Interface(fn=shout, inputs=\"textbox\", outputs=\"textbox\").launch()"
+ "gr.Interface(fn=shout, inputs=\"textbox\", outputs=\"textbox\", flagging_mode=\"never\").launch()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "002ab4a6",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " NOTE: Using Gradio's Share tool\n",
+ " I'm about to show you a really cool way to share your Gradio UI with others. This deploys your gradio app as a demo on gradio's website, and then allows gradio to call the 'shout' function. This uses an advanced technology known as 'HTTP tunneling' (like ngrok for people who know it) which isn't allowed by many Antivirus programs and corporate environments. If you get an error, just skip the next cell. \n",
+ " \n",
+ " | \n",
+ " \n",
+ " "
]
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": null,
"id": "c9a359a4-685c-4c99-891c-bb4d1cb7f426",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7861\n",
- "* Running on public URL: https://c1f6ab5bdc2722c539.gradio.live\n",
- "\n",
- "This share link expires in 1 week. For free permanent hosting and GPU upgrades, run `gradio deploy` from the terminal in the working directory to deploy to Hugging Face Spaces (https://huggingface.co/spaces)\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 11,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# Adding share=True means that it can be accessed publically\n",
"# A more permanent hosting is available using a platform called Spaces from HuggingFace, which we will touch on next week\n",
- "# NOTE: Some Anti-virus software and Corporate Firewalls might not like you using share=True. If you're at work on on a work network, I suggest skip this test.\n",
+ "# NOTE: Some Anti-virus software and Corporate Firewalls might not like you using share=True. \n",
+ "# If you're at work on on a work network, I suggest skip this test.\n",
"\n",
"gr.Interface(fn=shout, inputs=\"textbox\", outputs=\"textbox\", flagging_mode=\"never\").launch(share=True)"
]
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": null,
"id": "cd87533a-ff3a-4188-8998-5bedd5ba2da3",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7862\n",
- "* To create a public link, set `share=True` in `launch()`.\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# Adding inbrowser=True opens up a new browser window automatically\n",
"\n",
"gr.Interface(fn=shout, inputs=\"textbox\", outputs=\"textbox\", flagging_mode=\"never\").launch(inbrowser=True)"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "42945b17",
+ "metadata": {},
+ "source": [
+ "## Adding authentication\n",
+ "\n",
+ "Gradio makes it very easy to have userids and passwords\n",
+ "\n",
+ "Obviously if you use this, have it look properly in a secure place for passwords! At a minimum, use your .env"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c34e6735",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gr.Interface(fn=shout, inputs=\"textbox\", outputs=\"textbox\", flagging_mode=\"never\").launch(inbrowser=True, auth=(\"ed\", \"bananas\"))"
+ ]
+ },
{
"cell_type": "markdown",
"id": "b42ec007-0314-48bf-84a4-a65943649215",
@@ -345,39 +237,10 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": null,
"id": "e8129afa-532b-4b15-b93c-aa9cca23a546",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7863\n",
- "* To create a public link, set `share=True` in `launch()`.\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 13,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# Define this variable and then pass js=force_dark_mode when creating the Interface\n",
"\n",
@@ -395,160 +258,91 @@
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": null,
"id": "3cc67b26-dd5f-406d-88f6-2306ee2950c0",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7865\n",
- "* To create a public link, set `share=True` in `launch()`.\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 15,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
- "# Inputs and Outputs\n",
+ "# Adding a little more:\n",
+ "\n",
+ "message_input = gr.Textbox(label=\"Your message:\", info=\"Enter a message to be shouted\", lines=7)\n",
+ "message_output = gr.Textbox(label=\"Response:\", lines=8)\n",
"\n",
"view = gr.Interface(\n",
" fn=shout,\n",
- " inputs=[gr.Textbox(label=\"Your message:\", lines=6)],\n",
- " outputs=[gr.Textbox(label=\"Response:\", lines=8)],\n",
+ " title=\"Shout\", \n",
+ " inputs=[message_input], \n",
+ " outputs=[message_output], \n",
+ " examples=[\"hello\", \"howdy\"], \n",
" flagging_mode=\"never\"\n",
- ")\n",
+ " )\n",
"view.launch()"
]
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": null,
"id": "f235288e-63a2-4341-935b-1441f9be969b",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7866\n",
- "* To create a public link, set `share=True` in `launch()`.\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 16,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# And now - changing the function from \"shout\" to \"message_gpt\"\n",
"\n",
+ "message_input = gr.Textbox(label=\"Your message:\", info=\"Enter a message for GPT-4.1-mini\", lines=7)\n",
+ "message_output = gr.Textbox(label=\"Response:\", lines=8)\n",
+ "\n",
"view = gr.Interface(\n",
" fn=message_gpt,\n",
- " inputs=[gr.Textbox(label=\"Your message:\", lines=6)],\n",
- " outputs=[gr.Textbox(label=\"Response:\", lines=8)],\n",
+ " title=\"GPT\", \n",
+ " inputs=[message_input], \n",
+ " outputs=[message_output], \n",
+ " examples=[\"hello\", \"howdy\"], \n",
" flagging_mode=\"never\"\n",
- ")\n",
+ " )\n",
"view.launch()"
]
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": null,
"id": "af9a3262-e626-4e4b-80b0-aca152405e63",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7867\n",
- "* To create a public link, set `share=True` in `launch()`.\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 17,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# Let's use Markdown\n",
"# Are you wondering why it makes any difference to set system_message when it's not referred to in the code below it?\n",
"# I'm taking advantage of system_message being a global variable, used back in the message_gpt function (go take a look)\n",
"# Not a great software engineering practice, but quite common during Jupyter Lab R&D!\n",
"\n",
- "system_message = \"You are a helpful assistant that responds in markdown\"\n",
+ "system_message = \"You are a helpful assistant that responds in markdown without code blocks\"\n",
+ "\n",
+ "message_input = gr.Textbox(label=\"Your message:\", info=\"Enter a message for GPT-4.1-mini\", lines=7)\n",
+ "message_output = gr.Markdown(label=\"Response:\")\n",
"\n",
"view = gr.Interface(\n",
" fn=message_gpt,\n",
- " inputs=[gr.Textbox(label=\"Your message:\")],\n",
- " outputs=[gr.Markdown(label=\"Response:\")],\n",
+ " title=\"GPT\", \n",
+ " inputs=[message_input], \n",
+ " outputs=[message_output], \n",
+ " examples=[\n",
+ " \"Explain the Transformer architecture to a layperson\",\n",
+ " \"Explain the Transformer architecture to an aspiring AI engineer\",\n",
+ " ], \n",
" flagging_mode=\"never\"\n",
- ")\n",
+ " )\n",
"view.launch()"
]
},
{
"cell_type": "code",
- "execution_count": 18,
+ "execution_count": null,
"id": "88c04ebf-0671-4fea-95c9-bc1565d4bb4f",
"metadata": {},
"outputs": [],
"source": [
"# Let's create a call that streams back results\n",
"# If you'd like a refresher on Generators (the \"yield\" keyword),\n",
- "# Please take a look at the Intermediate Python notebook in week1 folder.\n",
+ "# Please take a look at the Intermediate Python guide in the guides folder\n",
"\n",
"def stream_gpt(prompt):\n",
" messages = [\n",
@@ -556,7 +350,7 @@
" {\"role\": \"user\", \"content\": prompt}\n",
" ]\n",
" stream = openai.chat.completions.create(\n",
- " model='gpt-4o-mini',\n",
+ " model='gpt-4.1-mini',\n",
" messages=messages,\n",
" stream=True\n",
" )\n",
@@ -568,115 +362,72 @@
},
{
"cell_type": "code",
- "execution_count": 19,
+ "execution_count": null,
"id": "0bb1f789-ff11-4cba-ac67-11b815e29d09",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7868\n",
- "* To create a public link, set `share=True` in `launch()`.\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 19,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
+ "message_input = gr.Textbox(label=\"Your message:\", info=\"Enter a message for GPT-4.1-mini\", lines=7)\n",
+ "message_output = gr.Markdown(label=\"Response:\")\n",
+ "\n",
"view = gr.Interface(\n",
" fn=stream_gpt,\n",
- " inputs=[gr.Textbox(label=\"Your message:\")],\n",
- " outputs=[gr.Markdown(label=\"Response:\")],\n",
+ " title=\"GPT\", \n",
+ " inputs=[message_input], \n",
+ " outputs=[message_output], \n",
+ " examples=[\n",
+ " \"Explain the Transformer architecture to a layperson\",\n",
+ " \"Explain the Transformer architecture to an aspiring AI engineer\",\n",
+ " ], \n",
" flagging_mode=\"never\"\n",
- ")\n",
+ " )\n",
"view.launch()"
]
},
{
"cell_type": "code",
- "execution_count": 20,
+ "execution_count": null,
"id": "bbc8e930-ba2a-4194-8f7c-044659150626",
"metadata": {},
"outputs": [],
"source": [
"def stream_claude(prompt):\n",
- " result = claude.messages.stream(\n",
- " model=\"claude-3-haiku-20240307\",\n",
- " max_tokens=1000,\n",
- " temperature=0.7,\n",
- " system=system_message,\n",
- " messages=[\n",
- " {\"role\": \"user\", \"content\": prompt},\n",
- " ],\n",
+ " messages = [\n",
+ " {\"role\": \"system\", \"content\": system_message},\n",
+ " {\"role\": \"user\", \"content\": prompt}\n",
+ " ]\n",
+ " stream = anthropic.chat.completions.create(\n",
+ " model='claude-sonnet-4-5-20250929',\n",
+ " messages=messages,\n",
+ " stream=True\n",
" )\n",
- " response = \"\"\n",
- " with result as stream:\n",
- " for text in stream.text_stream:\n",
- " response += text or \"\"\n",
- " yield response"
+ " result = \"\"\n",
+ " for chunk in stream:\n",
+ " result += chunk.choices[0].delta.content or \"\"\n",
+ " yield result"
]
},
{
"cell_type": "code",
- "execution_count": 21,
+ "execution_count": null,
"id": "a0066ffd-196e-4eaf-ad1e-d492958b62af",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7869\n",
- "* To create a public link, set `share=True` in `launch()`.\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 21,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
+ "message_input = gr.Textbox(label=\"Your message:\", info=\"Enter a message for Claude 4.5 Sonnet\", lines=7)\n",
+ "message_output = gr.Markdown(label=\"Response:\")\n",
+ "\n",
"view = gr.Interface(\n",
" fn=stream_claude,\n",
- " inputs=[gr.Textbox(label=\"Your message:\")],\n",
- " outputs=[gr.Markdown(label=\"Response:\")],\n",
+ " title=\"Claude\", \n",
+ " inputs=[message_input], \n",
+ " outputs=[message_output], \n",
+ " examples=[\n",
+ " \"Explain the Transformer architecture to a layperson\",\n",
+ " \"Explain the Transformer architecture to an aspiring AI engineer\",\n",
+ " ], \n",
" flagging_mode=\"never\"\n",
- ")\n",
+ " )\n",
"view.launch()"
]
},
@@ -685,27 +436,14 @@
"id": "bc5a70b9-2afe-4a7c-9bed-2429229e021b",
"metadata": {},
"source": [
- "## Minor improvement\n",
+ "## And now getting fancy\n",
"\n",
- "I've made a small improvement to this code.\n",
- "\n",
- "Previously, it had these lines:\n",
- "\n",
- "```\n",
- "for chunk in result:\n",
- " yield chunk\n",
- "```\n",
- "\n",
- "There's actually a more elegant way to achieve this (which Python people might call more 'Pythonic'):\n",
- "\n",
- "`yield from result`\n",
- "\n",
- "I cover this in more detail in the Intermediate Python notebook in the week1 folder - take a look if you'd like more."
+ "Remember to check the Intermediate Python Guide if you're unsure about generators and \"yield\""
]
},
{
"cell_type": "code",
- "execution_count": 22,
+ "execution_count": null,
"id": "0087623a-4e31-470b-b2e6-d8d16fc7bcf5",
"metadata": {},
"outputs": [],
@@ -722,46 +460,26 @@
},
{
"cell_type": "code",
- "execution_count": 23,
+ "execution_count": null,
"id": "8d8ce810-997c-4b6a-bc4f-1fc847ac8855",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7870\n",
- "* To create a public link, set `share=True` in `launch()`.\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 23,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
+ "message_input = gr.Textbox(label=\"Your message:\", info=\"Enter a message for the LLM\", lines=7)\n",
+ "model_selector = gr.Dropdown([\"GPT\", \"Claude\"], label=\"Select model\", value=\"GPT\")\n",
+ "message_output = gr.Markdown(label=\"Response:\")\n",
+ "\n",
"view = gr.Interface(\n",
" fn=stream_model,\n",
- " inputs=[gr.Textbox(label=\"Your message:\"), gr.Dropdown([\"GPT\", \"Claude\"], label=\"Select model\", value=\"GPT\")],\n",
- " outputs=[gr.Markdown(label=\"Response:\")],\n",
+ " title=\"LLMs\", \n",
+ " inputs=[message_input, model_selector], \n",
+ " outputs=[message_output], \n",
+ " examples=[\n",
+ " [\"Explain the Transformer architecture to a layperson\", \"GPT\"],\n",
+ " [\"Explain the Transformer architecture to an aspiring AI engineer\", \"Claude\"]\n",
+ " ], \n",
" flagging_mode=\"never\"\n",
- ")\n",
+ " )\n",
"view.launch()"
]
},
@@ -783,7 +501,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Before you read the next few cells\n",
@@ -797,48 +515,34 @@
},
{
"cell_type": "code",
- "execution_count": 24,
+ "execution_count": null,
"id": "1626eb2e-eee8-4183-bda5-1591b58ae3cf",
"metadata": {},
"outputs": [],
"source": [
- "# A class to represent a Webpage\n",
- "\n",
- "class Website:\n",
- " url: str\n",
- " title: str\n",
- " text: str\n",
- "\n",
- " def __init__(self, url):\n",
- " self.url = url\n",
- " response = requests.get(url)\n",
- " self.body = response.content\n",
- " soup = BeautifulSoup(self.body, 'html.parser')\n",
- " self.title = soup.title.string if soup.title else \"No title found\"\n",
- " for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n",
- " irrelevant.decompose()\n",
- " self.text = soup.body.get_text(separator=\"\\n\", strip=True)\n",
- "\n",
- " def get_contents(self):\n",
- " return f\"Webpage Title:\\n{self.title}\\nWebpage Contents:\\n{self.text}\\n\\n\""
+ "from scraper import fetch_website_contents"
]
},
{
"cell_type": "code",
- "execution_count": 25,
+ "execution_count": null,
"id": "c701ec17-ecd5-4000-9f68-34634c8ed49d",
"metadata": {},
"outputs": [],
"source": [
- "# With massive thanks to Bill G. who noticed that a prior version of this had a bug! Now fixed.\n",
"\n",
- "system_message = \"You are an assistant that analyzes the contents of a company website landing page \\\n",
- "and creates a short brochure about the company for prospective customers, investors and recruits. Respond in markdown.\""
+ "# Again this is typical Experimental mindset - I'm changing the global variable we used above:\n",
+ "\n",
+ "system_message = \"\"\"\n",
+ "You are an assistant that analyzes the contents of a company website landing page\n",
+ "and creates a short brochure about the company for prospective customers, investors and recruits.\n",
+ "Respond in markdown without code blocks.\n",
+ "\"\"\""
]
},
{
"cell_type": "code",
- "execution_count": 28,
+ "execution_count": null,
"id": "5def90e0-4343-4f58-9d4a-0e36e445efa4",
"metadata": {},
"outputs": [],
@@ -846,7 +550,7 @@
"def stream_brochure(company_name, url, model):\n",
" yield \"\"\n",
" prompt = f\"Please generate a company brochure for {company_name}. Here is their landing page:\\n\"\n",
- " prompt += Website(url).get_contents()\n",
+ " prompt += fetch_website_contents(url)\n",
" if model==\"GPT\":\n",
" result = stream_gpt(prompt)\n",
" elif model==\"Claude\":\n",
@@ -858,64 +562,54 @@
},
{
"cell_type": "code",
- "execution_count": 30,
+ "execution_count": null,
"id": "66399365-5d67-4984-9d47-93ed26c0bd3d",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "* Running on local URL: http://127.0.0.1:7873\n",
- "* To create a public link, set `share=True` in `launch()`.\n"
- ]
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": []
- },
- "execution_count": 30,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
+ "name_input = gr.Textbox(label=\"Company name:\")\n",
+ "url_input = gr.Textbox(label=\"Landing page URL including http:// or https://\")\n",
+ "model_selector = gr.Dropdown([\"GPT\", \"Claude\"], label=\"Select model\", value=\"GPT\")\n",
+ "message_output = gr.Markdown(label=\"Response:\")\n",
+ "\n",
"view = gr.Interface(\n",
" fn=stream_brochure,\n",
- " inputs=[\n",
- " gr.Textbox(label=\"Company name:\"),\n",
- " gr.Textbox(label=\"Landing page URL including http:// or https://\"),\n",
- " gr.Dropdown([\"GPT\", \"Claude\"], label=\"Select model\")],\n",
- " outputs=[gr.Markdown(label=\"Brochure:\")],\n",
+ " title=\"Brochure Generator\", \n",
+ " inputs=[name_input, url_input, model_selector], \n",
+ " outputs=[message_output], \n",
+ " examples=[\n",
+ " [\"Hugging Face\", \"https://huggingface.co\", \"GPT\"],\n",
+ " [\"Edward Donner\", \"https://edwarddonner.com\", \"Claude\"]\n",
+ " ], \n",
" flagging_mode=\"never\"\n",
- ")\n",
+ " )\n",
"view.launch()"
]
},
{
- "cell_type": "code",
- "execution_count": null,
- "id": "ede97ca3-a0f8-4f6e-be17-d1de7fef9cc0",
+ "cell_type": "markdown",
+ "id": "611dd9c4",
"metadata": {},
- "outputs": [],
- "source": []
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " Gradio Resources\n",
+ " If you'd like to go deeper on Gradio, check out the amazing documentation - a wonderful rabbit hole. \n",
+ " https://www.gradio.app/guides/quickstart Gradio is primarily designed for Demos, Prototypes and MVPs, but I've also used it frequently to make internal apps for power users.\n",
+ " \n",
+ " | \n",
+ " \n",
+ " "
+ ]
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -929,7 +623,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.13"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/week2/day3.ipynb b/week2/day3.ipynb
index 9f044b7..008509b 100644
--- a/week2/day3.ipynb
+++ b/week2/day3.ipynb
@@ -35,23 +35,11 @@
"\n",
"load_dotenv(override=True)\n",
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
- "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
- "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
"\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
"else:\n",
- " print(\"OpenAI API Key not set\")\n",
- " \n",
- "if anthropic_api_key:\n",
- " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
- "else:\n",
- " print(\"Anthropic API Key not set\")\n",
- "\n",
- "if google_api_key:\n",
- " print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n",
- "else:\n",
- " print(\"Google API Key not set\")"
+ " print(\"OpenAI API Key not set\")"
]
},
{
@@ -64,7 +52,7 @@
"# Initialize\n",
"\n",
"openai = OpenAI()\n",
- "MODEL = 'gpt-4o-mini'"
+ "MODEL = 'gpt-4.1-mini'"
]
},
{
@@ -74,6 +62,8 @@
"metadata": {},
"outputs": [],
"source": [
+ "# Again, I'll be in scientist-mode and change this global during the lab\n",
+ "\n",
"system_message = \"You are a helpful assistant\""
]
},
@@ -82,32 +72,75 @@
"id": "98e97227-f162-4d1a-a0b2-345ff248cbe7",
"metadata": {},
"source": [
- "# Please read this! A change from the video:\n",
+ "## And now, writing a new callback\n",
"\n",
- "In the video, I explain how we now need to write a function called:\n",
+ "We now need to write a function called:\n",
"\n",
"`chat(message, history)`\n",
"\n",
- "Which expects to receive `history` in a particular format, which we need to map to the OpenAI format before we call OpenAI:\n",
+ "Which will be a callback function we will give gradio.\n",
"\n",
- "```\n",
- "[\n",
- " {\"role\": \"system\", \"content\": \"system message here\"},\n",
- " {\"role\": \"user\", \"content\": \"first user prompt here\"},\n",
- " {\"role\": \"assistant\", \"content\": \"the assistant's response\"},\n",
- " {\"role\": \"user\", \"content\": \"the new user prompt\"},\n",
- "]\n",
- "```\n",
+ "### The job of this function\n",
"\n",
- "But Gradio has been upgraded! Now it will pass in `history` in the exact OpenAI format, perfect for us to send straight to OpenAI.\n",
- "\n",
- "So our work just got easier!\n",
- "\n",
- "We will write a function `chat(message, history)` where: \n",
- "**message** is the prompt to use \n",
- "**history** is the past conversation, in OpenAI format \n",
- "\n",
- "We will combine the system message, history and latest message, then call OpenAI."
+ "Take a message, take the prior conversation, and return the response.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "354ce793",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def chat(message, history):\n",
+ " return \"bananas\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e87f3417",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gr.ChatInterface(fn=chat, type=\"messages\").launch()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5d4996e8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def chat(message, history):\n",
+ " return f\"You said {message} and the history is {history} but I still say bananas\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "434a0417",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gr.ChatInterface(fn=chat, type=\"messages\").launch()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7890cac3",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7330d7f",
+ "metadata": {},
+ "source": [
+ "## OK! Let's write a slightly better chat callback!"
]
},
{
@@ -117,46 +150,61 @@
"metadata": {},
"outputs": [],
"source": [
- "# Simpler than in my video - we can easily create this function that calls OpenAI\n",
- "# It's now just 1 line of code to prepare the input to OpenAI!\n",
- "\n",
- "# Student Octavio O. has pointed out that this isn't quite as straightforward for Claude -\n",
- "# see the excellent contribution in community-contributions \"Gradio_issue_with_Claude\" that handles Claude.\n",
"\n",
"def chat(message, history):\n",
+ " history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history]\n",
+ " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
+ " response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
+ " return response.choices[0].message.content\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0ab706f9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gr.ChatInterface(fn=chat, type=\"messages\").launch()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3bce145a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def chat(message, history):\n",
+ " history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history]\n",
" messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
- "\n",
- " print(\"History is:\")\n",
- " print(history)\n",
- " print(\"And messages is:\")\n",
- " print(messages)\n",
- "\n",
" stream = openai.chat.completions.create(model=MODEL, messages=messages, stream=True)\n",
- "\n",
" response = \"\"\n",
" for chunk in stream:\n",
" response += chunk.choices[0].delta.content or ''\n",
" yield response"
]
},
- {
- "cell_type": "markdown",
- "id": "1334422a-808f-4147-9c4c-57d63d9780d0",
- "metadata": {},
- "source": [
- "## And then enter Gradio's magic!"
- ]
- },
{
"cell_type": "code",
"execution_count": null,
- "id": "0866ca56-100a-44ab-8bd0-1568feaf6bf2",
+ "id": "b8beeca6",
"metadata": {},
"outputs": [],
"source": [
"gr.ChatInterface(fn=chat, type=\"messages\").launch()"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "1334422a-808f-4147-9c4c-57d63d9780d0",
+ "metadata": {},
+ "source": [
+ "## OK let's keep going!\n",
+ "\n",
+ "Using a system message to add context, and to give an example answer.. this is \"one shot prompting\" again"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
@@ -171,24 +219,6 @@
"Encourage the customer to buy hats if they are unsure what to get.\""
]
},
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "4e5be3ec-c26c-42bc-ac16-c39d369883f6",
- "metadata": {},
- "outputs": [],
- "source": [
- "def chat(message, history):\n",
- " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
- "\n",
- " stream = openai.chat.completions.create(model=MODEL, messages=messages, stream=True)\n",
- "\n",
- " response = \"\"\n",
- " for chunk in stream:\n",
- " response += chunk.choices[0].delta.content or ''\n",
- " yield response"
- ]
- },
{
"cell_type": "code",
"execution_count": null,
@@ -227,13 +257,11 @@
"metadata": {},
"outputs": [],
"source": [
- "# Fixed a bug in this function brilliantly identified by student Gabor M.!\n",
- "# I've also improved the structure of this function\n",
"\n",
"def chat(message, history):\n",
- "\n",
+ " history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history]\n",
" relevant_system_message = system_message\n",
- " if 'belt' in message:\n",
+ " if 'belt' in message.lower():\n",
" relevant_system_message += \" The store does not sell belts; if you are asked for belts, be sure to point out other items on sale.\"\n",
" \n",
" messages = [{\"role\": \"system\", \"content\": relevant_system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
@@ -264,7 +292,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Business Applications\n",
@@ -277,17 +305,15 @@
]
},
{
- "cell_type": "code",
- "execution_count": null,
- "id": "6dfb9e21-df67-4c2b-b952-5e7e7961b03d",
+ "cell_type": "markdown",
+ "id": "acc0e5a9",
"metadata": {},
- "outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -301,7 +327,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.13"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/week2/day4.ipynb b/week2/day4.ipynb
index 6bdd1e9..d3c3693 100644
--- a/week2/day4.ipynb
+++ b/week2/day4.ipynb
@@ -17,8 +17,6 @@
"metadata": {},
"outputs": [],
"source": [
- "# imports\n",
- "\n",
"import os\n",
"import json\n",
"from dotenv import load_dotenv\n",
@@ -43,7 +41,7 @@
"else:\n",
" print(\"OpenAI API Key not set\")\n",
" \n",
- "MODEL = \"gpt-4o-mini\"\n",
+ "MODEL = \"gpt-4.1-mini\"\n",
"openai = OpenAI()\n",
"\n",
"# As an alternative, if you'd like to use Ollama instead of OpenAI\n",
@@ -59,9 +57,11 @@
"metadata": {},
"outputs": [],
"source": [
- "system_message = \"You are a helpful assistant for an Airline called FlightAI. \"\n",
- "system_message += \"Give short, courteous answers, no more than 1 sentence. \"\n",
- "system_message += \"Always be accurate. If you don't know the answer, say so.\""
+ "system_message = \"\"\"\n",
+ "You are a helpful assistant for an Airline called FlightAI.\n",
+ "Give short, courteous answers, no more than 1 sentence.\n",
+ "Always be accurate. If you don't know the answer, say so.\n",
+ "\"\"\""
]
},
{
@@ -71,9 +71,8 @@
"metadata": {},
"outputs": [],
"source": [
- "# This function looks rather simpler than the one from my video, because we're taking advantage of the latest Gradio updates\n",
- "\n",
"def chat(message, history):\n",
+ " history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history]\n",
" messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
" response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
" return response.choices[0].message.content\n",
@@ -109,9 +108,9 @@
"ticket_prices = {\"london\": \"$799\", \"paris\": \"$899\", \"tokyo\": \"$1400\", \"berlin\": \"$499\"}\n",
"\n",
"def get_ticket_price(destination_city):\n",
- " print(f\"Tool get_ticket_price called for {destination_city}\")\n",
- " city = destination_city.lower()\n",
- " return ticket_prices.get(city, \"Unknown\")"
+ " print(f\"Tool called for city {destination_city}\")\n",
+ " price = ticket_prices.get(destination_city.lower(), \"Unknown ticket price\")\n",
+ " return f\"The price of a ticket to {destination_city} is {price}\"\n"
]
},
{
@@ -121,7 +120,7 @@
"metadata": {},
"outputs": [],
"source": [
- "get_ticket_price(\"Berlin\")"
+ "get_ticket_price(\"London\")"
]
},
{
@@ -135,7 +134,7 @@
"\n",
"price_function = {\n",
" \"name\": \"get_ticket_price\",\n",
- " \"description\": \"Get the price of a return ticket to the destination city. Call this whenever you need to know the ticket price, for example when a customer asks 'How much is a ticket to this city'\",\n",
+ " \"description\": \"Get the price of a return ticket to the destination city.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
@@ -162,6 +161,16 @@
"tools = [{\"type\": \"function\", \"function\": price_function}]"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "818b4b2b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tools"
+ ]
+ },
{
"cell_type": "markdown",
"id": "c3d3554f-b4e3-4ce7-af6f-68faa6dd2340",
@@ -184,12 +193,13 @@
"outputs": [],
"source": [
"def chat(message, history):\n",
+ " history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history]\n",
" messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
" response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
"\n",
" if response.choices[0].finish_reason==\"tool_calls\":\n",
" message = response.choices[0].message\n",
- " response, city = handle_tool_call(message)\n",
+ " response = handle_tool_call(message)\n",
" messages.append(message)\n",
" messages.append(response)\n",
" response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
@@ -208,15 +218,16 @@
"\n",
"def handle_tool_call(message):\n",
" tool_call = message.tool_calls[0]\n",
- " arguments = json.loads(tool_call.function.arguments)\n",
- " city = arguments.get('destination_city')\n",
- " price = get_ticket_price(city)\n",
- " response = {\n",
- " \"role\": \"tool\",\n",
- " \"content\": json.dumps({\"destination_city\": city,\"price\": price}),\n",
- " \"tool_call_id\": tool_call.id\n",
- " }\n",
- " return response, city"
+ " if tool_call.function.name == \"get_ticket_price\":\n",
+ " arguments = json.loads(tool_call.function.arguments)\n",
+ " city = arguments.get('destination_city')\n",
+ " price_details = get_ticket_price(city)\n",
+ " response = {\n",
+ " \"role\": \"tool\",\n",
+ " \"content\": price_details,\n",
+ " \"tool_call_id\": tool_call.id\n",
+ " }\n",
+ " return response"
]
},
{
@@ -228,11 +239,224 @@
"source": [
"gr.ChatInterface(fn=chat, type=\"messages\").launch()"
]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "47f30fbe",
+ "metadata": {},
+ "source": [
+ "## Let's make a couple of improvements\n",
+ "\n",
+ "Handling multiple tool calls in 1 response\n",
+ "\n",
+ "Handling multiple tool calls 1 after another"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b6f5c860",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def chat(message, history):\n",
+ " history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history]\n",
+ " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
+ " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
+ "\n",
+ " if response.choices[0].finish_reason==\"tool_calls\":\n",
+ " message = response.choices[0].message\n",
+ " responses = handle_tool_calls(message)\n",
+ " messages.append(message)\n",
+ " messages.extend(responses)\n",
+ " response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
+ " \n",
+ " return response.choices[0].message.content"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9c46a861",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def handle_tool_calls(message):\n",
+ " responses = []\n",
+ " for tool_call in message.tool_calls:\n",
+ " if tool_call.function.name == \"get_ticket_price\":\n",
+ " arguments = json.loads(tool_call.function.arguments)\n",
+ " city = arguments.get('destination_city')\n",
+ " price_details = get_ticket_price(city)\n",
+ " responses.append({\n",
+ " \"role\": \"tool\",\n",
+ " \"content\": price_details,\n",
+ " \"tool_call_id\": tool_call.id\n",
+ " })\n",
+ " return responses"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "95f02a4d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gr.ChatInterface(fn=chat, type=\"messages\").launch()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cf262abc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def chat(message, history):\n",
+ " history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history]\n",
+ " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
+ " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
+ "\n",
+ " while response.choices[0].finish_reason==\"tool_calls\":\n",
+ " message = response.choices[0].message\n",
+ " responses = handle_tool_calls(message)\n",
+ " messages.append(message)\n",
+ " messages.extend(responses)\n",
+ " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
+ " \n",
+ " return response.choices[0].message.content"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "47d50e70",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sqlite3\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bb61a45d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "DB = \"prices.db\"\n",
+ "\n",
+ "with sqlite3.connect(DB) as conn:\n",
+ " cursor = conn.cursor()\n",
+ " cursor.execute('CREATE TABLE IF NOT EXISTS prices (city TEXT PRIMARY KEY, price REAL)')\n",
+ " conn.commit()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "12c73b6a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_ticket_price(city):\n",
+ " print(f\"DATABASE TOOL CALLED: Getting price for {city}\", flush=True)\n",
+ " with sqlite3.connect(DB) as conn:\n",
+ " cursor = conn.cursor()\n",
+ " cursor.execute('SELECT price FROM prices WHERE city = ?', (city.lower(),))\n",
+ " result = cursor.fetchone()\n",
+ " return f\"Ticket price to {city} is ${result[0]}\" if result else \"No price data available for this city\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7cb2e079",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "get_ticket_price(\"London\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "46e43463",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_ticket_price(city, price):\n",
+ " with sqlite3.connect(DB) as conn:\n",
+ " cursor = conn.cursor()\n",
+ " cursor.execute('INSERT INTO prices (city, price) VALUES (?, ?) ON CONFLICT(city) DO UPDATE SET price = ?', (city.lower(), price, price))\n",
+ " conn.commit()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9185228e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ticket_prices = {\"london\":799, \"paris\": 899, \"tokyo\": 1420, \"sydney\": 2999}\n",
+ "for city, price in ticket_prices.items():\n",
+ " set_ticket_price(city, price)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cda459b9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "get_ticket_price(\"Tokyo\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bfbfa251",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gr.ChatInterface(fn=chat, type=\"messages\").launch()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1a9e9c7",
+ "metadata": {},
+ "source": [
+ "## Exercise\n",
+ "\n",
+ "Add a tool to set the price of a ticket!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6aeba34c",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " Business Applications\n",
+ " Hopefully this hardly needs to be stated! You now have the ability to give actions to your LLMs. This Airline Assistant can now do more than answer questions - it could interact with booking APIs to make bookings!\n",
+ " | \n",
+ " \n",
+ " "
+ ]
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -246,7 +470,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.13"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/week2/day5.ipynb b/week2/day5.ipynb
index cb2e8f5..f8b4d1a 100644
--- a/week2/day5.ipynb
+++ b/week2/day5.ipynb
@@ -23,7 +23,8 @@
"import json\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI\n",
- "import gradio as gr"
+ "import gradio as gr\n",
+ "import sqlite3"
]
},
{
@@ -43,8 +44,10 @@
"else:\n",
" print(\"OpenAI API Key not set\")\n",
" \n",
- "MODEL = \"gpt-4o-mini\"\n",
- "openai = OpenAI()"
+ "MODEL = \"gpt-4.1-mini\"\n",
+ "openai = OpenAI()\n",
+ "\n",
+ "DB = \"prices.db\""
]
},
{
@@ -54,83 +57,49 @@
"metadata": {},
"outputs": [],
"source": [
- "system_message = \"You are a helpful assistant for an Airline called FlightAI. \"\n",
- "system_message += \"Give short, courteous answers, no more than 1 sentence. \"\n",
- "system_message += \"Always be accurate. If you don't know the answer, say so.\""
+ "system_message = \"\"\"\n",
+ "You are a helpful assistant for an Airline called FlightAI.\n",
+ "Give short, courteous answers, no more than 1 sentence.\n",
+ "Always be accurate. If you don't know the answer, say so.\n",
+ "\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "61a2a15d-b559-4844-b377-6bd5cb4949f6",
+ "id": "c3e8173c",
"metadata": {},
"outputs": [],
"source": [
- "# This function looks rather simpler than the one from my video, because we're taking advantage of the latest Gradio updates\n",
- "\n",
- "def chat(message, history):\n",
- " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
- " response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
- " return response.choices[0].message.content\n",
- "\n",
- "gr.ChatInterface(fn=chat, type=\"messages\").launch()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "36bedabf-a0a7-4985-ad8e-07ed6a55a3a4",
- "metadata": {},
- "source": [
- "## Tools\n",
- "\n",
- "Tools are an incredibly powerful feature provided by the frontier LLMs.\n",
- "\n",
- "With tools, you can write a function, and have the LLM call that function as part of its response.\n",
- "\n",
- "Sounds almost spooky.. we're giving it the power to run code on our machine?\n",
- "\n",
- "Well, kinda."
+ "def get_ticket_price(city):\n",
+ " print(f\"DATABASE TOOL CALLED: Getting price for {city}\", flush=True)\n",
+ " with sqlite3.connect(DB) as conn:\n",
+ " cursor = conn.cursor()\n",
+ " cursor.execute('SELECT price FROM prices WHERE city = ?', (city.lower(),))\n",
+ " result = cursor.fetchone()\n",
+ " return f\"Ticket price to {city} is ${result[0]}\" if result else \"No price data available for this city\""
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "0696acb1-0b05-4dc2-80d5-771be04f1fb2",
+ "id": "03f19289",
"metadata": {},
"outputs": [],
"source": [
- "# Let's start by making a useful function\n",
- "\n",
- "ticket_prices = {\"london\": \"$799\", \"paris\": \"$899\", \"tokyo\": \"$1400\", \"berlin\": \"$499\"}\n",
- "\n",
- "def get_ticket_price(destination_city):\n",
- " print(f\"Tool get_ticket_price called for {destination_city}\")\n",
- " city = destination_city.lower()\n",
- " return ticket_prices.get(city, \"Unknown\")"
+ "get_ticket_price(\"Paris\")"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "80ca4e09-6287-4d3f-997d-fa6afbcf6c85",
+ "id": "bcfb6523",
"metadata": {},
"outputs": [],
"source": [
- "get_ticket_price(\"London\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "4afceded-7178-4c05-8fa6-9f2085e6a344",
- "metadata": {},
- "outputs": [],
- "source": [
- "# There's a particular dictionary structure that's required to describe our function:\n",
- "\n",
"price_function = {\n",
" \"name\": \"get_ticket_price\",\n",
- " \"description\": \"Get the price of a return ticket to the destination city. Call this whenever you need to know the ticket price, for example when a customer asks 'How much is a ticket to this city'\",\n",
+ " \"description\": \"Get the price of a return ticket to the destination city.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
@@ -142,52 +111,46 @@
" \"required\": [\"destination_city\"],\n",
" \"additionalProperties\": False\n",
" }\n",
- "}"
+ "}\n",
+ "tools = [{\"type\": \"function\", \"function\": price_function}]\n",
+ "tools"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "bdca8679-935f-4e7f-97e6-e71a4d4f228c",
+ "id": "61a2a15d-b559-4844-b377-6bd5cb4949f6",
"metadata": {},
"outputs": [],
"source": [
- "# And this is included in a list of tools:\n",
"\n",
- "tools = [{\"type\": \"function\", \"function\": price_function}]"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "c3d3554f-b4e3-4ce7-af6f-68faa6dd2340",
- "metadata": {},
- "source": [
- "## Getting OpenAI to use our Tool\n",
+ "def chat(message, history):\n",
+ " history = [{\"role\": h[\"role\"], \"content\": h[\"content\"]} for h in history]\n",
+ " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
+ " response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
+ " return response.choices[0].message.content\n",
"\n",
- "There's some fiddly stuff to allow OpenAI \"to call our tool\"\n",
- "\n",
- "What we actually do is give the LLM the opportunity to inform us that it wants us to run the tool.\n",
- "\n",
- "Here's how the new chat function looks:"
+ "gr.ChatInterface(fn=chat, type=\"messages\").launch()"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "ce9b0744-9c78-408d-b9df-9f6fd9ed78cf",
+ "id": "c91d012e",
"metadata": {},
"outputs": [],
"source": [
"def chat(message, history):\n",
+ " history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history]\n",
" messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
" response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
"\n",
- " if response.choices[0].finish_reason==\"tool_calls\":\n",
+ " while response.choices[0].finish_reason==\"tool_calls\":\n",
" message = response.choices[0].message\n",
- " response, city = handle_tool_call(message)\n",
+ " responses = handle_tool_calls(message)\n",
" messages.append(message)\n",
- " messages.append(response)\n",
- " response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
+ " messages.extend(responses)\n",
+ " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
" \n",
" return response.choices[0].message.content"
]
@@ -195,35 +158,59 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "b0992986-ea09-4912-a076-8e5603ee631f",
+ "id": "956c3b61",
"metadata": {},
"outputs": [],
"source": [
- "# We have to write that function handle_tool_call:\n",
- "\n",
- "def handle_tool_call(message):\n",
- " tool_call = message.tool_calls[0]\n",
- " arguments = json.loads(tool_call.function.arguments)\n",
- " city = arguments.get('destination_city')\n",
- " price = get_ticket_price(city)\n",
- " response = {\n",
- " \"role\": \"tool\",\n",
- " \"content\": json.dumps({\"destination_city\": city,\"price\": price}),\n",
- " \"tool_call_id\": tool_call.id\n",
- " }\n",
- " return response, city"
+ "def handle_tool_calls(message):\n",
+ " responses = []\n",
+ " for tool_call in message.tool_calls:\n",
+ " if tool_call.function.name == \"get_ticket_price\":\n",
+ " arguments = json.loads(tool_call.function.arguments)\n",
+ " city = arguments.get('destination_city')\n",
+ " price_details = get_ticket_price(city)\n",
+ " responses.append({\n",
+ " \"role\": \"tool\",\n",
+ " \"content\": price_details,\n",
+ " \"tool_call_id\": tool_call.id\n",
+ " })\n",
+ " return responses"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "f4be8a71-b19e-4c2f-80df-f59ff2661f14",
+ "id": "8eca803e",
"metadata": {},
"outputs": [],
"source": [
"gr.ChatInterface(fn=chat, type=\"messages\").launch()"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "b369bf10",
+ "metadata": {},
+ "source": [
+ "## A bit more about what Gradio actually does:\n",
+ "\n",
+ "1. Gradio constructs a frontend Svelte app based on our Python description of the UI\n",
+ "2. Gradio starts a server built upon the Starlette web framework listening on a free port that serves this React app\n",
+ "3. Gradio creates backend routes for our callbacks, like chat(), which calls our functions\n",
+ "\n",
+ "And of course when Gradio generates the frontend app, it ensures that the the Submit button calls the right backend route.\n",
+ "\n",
+ "That's it!\n",
+ "\n",
+ "It's simple, and it has a resut that feels magical."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "863aac34",
+ "metadata": {},
+ "source": []
+ },
{
"cell_type": "markdown",
"id": "473e5b39-da8f-4db1-83ae-dbaca2e9531e",
@@ -289,414 +276,128 @@
"id": "728a12c5-adc3-415d-bb05-82beb73b079b",
"metadata": {},
"outputs": [],
- "source": []
- },
- {
- "cell_type": "markdown",
- "id": "f4975b87-19e9-4ade-a232-9b809ec75c9a",
- "metadata": {},
"source": [
- "## Audio (NOTE - Audio is optional for this course - feel free to skip Audio if it causes trouble!)\n",
- "\n",
- "And let's make a function talker that uses OpenAI's speech model to generate Audio\n",
- "\n",
- "### Troubleshooting Audio issues\n",
- "\n",
- "If you have any problems running this code below (like a FileNotFound error, or a warning of a missing package), you may need to install FFmpeg, a very popular audio utility.\n",
- "\n",
- "**For PC Users**\n",
- "\n",
- "Detailed instructions are [here](https://chatgpt.com/share/6724efee-6b0c-8012-ac5e-72e2e3885905) and summary instructions:\n",
- "\n",
- "1. Download FFmpeg from the official website: https://ffmpeg.org/download.html\n",
- "\n",
- "2. Extract the downloaded files to a location on your computer (e.g., `C:\\ffmpeg`)\n",
- "\n",
- "3. Add the FFmpeg bin folder to your system PATH:\n",
- "- Right-click on 'This PC' or 'My Computer' and select 'Properties'\n",
- "- Click on 'Advanced system settings'\n",
- "- Click on 'Environment Variables'\n",
- "- Under 'System variables', find and edit 'Path'\n",
- "- Add a new entry with the path to your FFmpeg bin folder (e.g., `C:\\ffmpeg\\bin`)\n",
- "- Restart your command prompt, and within Jupyter Lab do Kernel -> Restart kernel, to pick up the changes\n",
- "\n",
- "4. Open a new command prompt and run this to make sure it's installed OK\n",
- "`ffmpeg -version`\n",
- "\n",
- "**For Mac Users**\n",
- "\n",
- "1. Install homebrew if you don't have it already by running this in a Terminal window and following any instructions: \n",
- "`/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"`\n",
- "\n",
- "2. Then install FFmpeg with `brew install ffmpeg`\n",
- "\n",
- "3. Verify your installation with `ffmpeg -version` and if everything is good, within Jupyter Lab do Kernel -> Restart kernel to pick up the changes\n",
- "\n",
- "Message me or email me at ed@edwarddonner.com with any problems!"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4cc90e80-c96e-4dd4-b9d6-386fe2b7e797",
- "metadata": {},
- "source": [
- "## To check you now have ffmpeg and can access it here\n",
- "\n",
- "Excecute the next cell to see if you get a version number. (Putting an exclamation mark before something in Jupyter Lab tells it to run it as a terminal command rather than python code).\n",
- "\n",
- "If this doesn't work, you may need to actually save and close down your Jupyter lab, and start it again from a new Terminal window (Mac) or Anaconda prompt (PC), remembering to activate the llms environment. This ensures you pick up ffmpeg.\n",
- "\n",
- "And if that doesn't work, please contact me!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7b3be0fb-1d34-4693-ab6f-dbff190afcd7",
- "metadata": {},
- "outputs": [],
- "source": [
- "!ffmpeg -version\n",
- "!ffprobe -version\n",
- "!ffplay -version"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "d91d3f8f-e505-4e3c-a87c-9e42ed823db6",
- "metadata": {},
- "source": [
- "# For Mac users - and possibly many PC users too\n",
- "\n",
- "This version should work fine for you. It might work for Windows users too, but you might get a Permissions error writing to a temp file. If so, see the next section!\n",
- "\n",
- "As always, if you have problems, please contact me! (You could also comment out the audio talker() in the later code if you're less interested in audio generation)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ffbfe93b-5e86-4e68-ba71-b301cd5230db",
- "metadata": {},
- "outputs": [],
- "source": [
- "from pydub import AudioSegment\n",
- "from pydub.playback import play\n",
- "\n",
"def talker(message):\n",
" response = openai.audio.speech.create(\n",
- " model=\"tts-1\",\n",
- " voice=\"onyx\", # Also, try replacing onyx with alloy\n",
+ " model=\"gpt-4o-mini-tts\",\n",
+ " voice=\"onyx\", # Also, try replacing onyx with alloy or coral\n",
" input=message\n",
" )\n",
- " \n",
- " audio_stream = BytesIO(response.content)\n",
- " audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n",
- " play(audio)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "b88d775d-d357-4292-a1ad-5dc5ed567281",
- "metadata": {},
- "outputs": [],
- "source": [
- "talker(\"Well, hi there\")"
+ " return response.content"
]
},
{
"cell_type": "markdown",
- "id": "ad89a9bd-bb1e-4bbb-a49a-83af5f500c24",
+ "id": "3bc7580b",
"metadata": {},
"source": [
- "# For Windows users (or any Mac users with problems above)\n",
+ "## Let's bring this home:\n",
"\n",
- "## First try the Mac version above, but if you get a permissions error writing to a temp file, then this code should work instead.\n",
- "\n",
- "A collaboration between students Mark M. and Patrick H. and Claude got this resolved!\n",
- "\n",
- "Below are 4 variations - hopefully one of them will work on your PC. If not, message me please!\n",
- "\n",
- "And for Mac people - all 3 of the below work on my Mac too - please try these if the Mac version gave you problems.\n",
- "\n",
- "## PC Variation 1"
+ "1. A multi-modal AI assistant with image and audio generation\n",
+ "2. Tool callling with database lookup\n",
+ "3. A step towards an Agentic workflow\n"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "d104b96a-02ca-4159-82fe-88e0452aa479",
- "metadata": {},
- "outputs": [],
- "source": [
- "import base64\n",
- "from io import BytesIO\n",
- "from PIL import Image\n",
- "from IPython.display import Audio, display\n",
- "\n",
- "def talker(message):\n",
- " response = openai.audio.speech.create(\n",
- " model=\"tts-1\",\n",
- " voice=\"onyx\",\n",
- " input=message)\n",
- "\n",
- " audio_stream = BytesIO(response.content)\n",
- " output_filename = \"output_audio.mp3\"\n",
- " with open(output_filename, \"wb\") as f:\n",
- " f.write(audio_stream.read())\n",
- "\n",
- " # Play the generated audio\n",
- " display(Audio(output_filename, autoplay=True))\n",
- "\n",
- "talker(\"Well, hi there\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "3a5d11f4-bbd3-43a1-904d-f684eb5f3e3a",
- "metadata": {},
- "source": [
- "## PC Variation 2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "d59c8ebd-79c5-498a-bdf2-3a1c50d91aa0",
- "metadata": {},
- "outputs": [],
- "source": [
- "import tempfile\n",
- "import subprocess\n",
- "from io import BytesIO\n",
- "from pydub import AudioSegment\n",
- "import time\n",
- "\n",
- "def play_audio(audio_segment):\n",
- " temp_dir = tempfile.gettempdir()\n",
- " temp_path = os.path.join(temp_dir, \"temp_audio.wav\")\n",
- " try:\n",
- " audio_segment.export(temp_path, format=\"wav\")\n",
- " time.sleep(3) # Student Dominic found that this was needed. You could also try commenting out to see if not needed on your PC\n",
- " subprocess.call([\n",
- " \"ffplay\",\n",
- " \"-nodisp\",\n",
- " \"-autoexit\",\n",
- " \"-hide_banner\",\n",
- " temp_path\n",
- " ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)\n",
- " finally:\n",
- " try:\n",
- " os.remove(temp_path)\n",
- " except Exception:\n",
- " pass\n",
- " \n",
- "def talker(message):\n",
- " response = openai.audio.speech.create(\n",
- " model=\"tts-1\",\n",
- " voice=\"onyx\", # Also, try replacing onyx with alloy\n",
- " input=message\n",
- " )\n",
- " audio_stream = BytesIO(response.content)\n",
- " audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n",
- " play_audio(audio)\n",
- "\n",
- "talker(\"Well hi there\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "96f90e35-f71e-468e-afea-07b98f74dbcf",
- "metadata": {},
- "source": [
- "## PC Variation 3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "8597c7f8-7b50-44ad-9b31-db12375cd57b",
- "metadata": {},
- "outputs": [],
- "source": [
- "import os\n",
- "from pydub import AudioSegment\n",
- "from pydub.playback import play\n",
- "from io import BytesIO\n",
- "\n",
- "def talker(message):\n",
- " # Set a custom directory for temporary files on Windows\n",
- " custom_temp_dir = os.path.expanduser(\"~/Documents/temp_audio\")\n",
- " os.environ['TEMP'] = custom_temp_dir # You can also use 'TMP' if necessary\n",
- " \n",
- " # Create the folder if it doesn't exist\n",
- " if not os.path.exists(custom_temp_dir):\n",
- " os.makedirs(custom_temp_dir)\n",
- " \n",
- " response = openai.audio.speech.create(\n",
- " model=\"tts-1\",\n",
- " voice=\"onyx\", # Also, try replacing onyx with alloy\n",
- " input=message\n",
- " )\n",
- " \n",
- " audio_stream = BytesIO(response.content)\n",
- " audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n",
- "\n",
- " play(audio)\n",
- "\n",
- "talker(\"Well hi there\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e821224c-b069-4f9b-9535-c15fdb0e411c",
- "metadata": {},
- "source": [
- "## PC Variation 4\n",
- "\n",
- "### Let's try a completely different sound library\n",
- "\n",
- "First run the next cell to install a new library, then try the cell below it."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "69d3c0d9-afcc-49e3-b829-9c9869d8b472",
- "metadata": {},
- "outputs": [],
- "source": [
- "!pip install simpleaudio"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "28f9cc99-36b7-4554-b3f4-f2012f614a13",
- "metadata": {},
- "outputs": [],
- "source": [
- "from pydub import AudioSegment\n",
- "from io import BytesIO\n",
- "import tempfile\n",
- "import os\n",
- "import simpleaudio as sa\n",
- "\n",
- "def talker(message):\n",
- " response = openai.audio.speech.create(\n",
- " model=\"tts-1\",\n",
- " voice=\"onyx\", # Also, try replacing onyx with alloy\n",
- " input=message\n",
- " )\n",
- " \n",
- " audio_stream = BytesIO(response.content)\n",
- " audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n",
- "\n",
- " # Create a temporary file in a folder where you have write permissions\n",
- " with tempfile.NamedTemporaryFile(suffix=\".wav\", delete=False, dir=os.path.expanduser(\"~/Documents\")) as temp_audio_file:\n",
- " temp_file_name = temp_audio_file.name\n",
- " audio.export(temp_file_name, format=\"wav\")\n",
- " \n",
- " # Load and play audio using simpleaudio\n",
- " wave_obj = sa.WaveObject.from_wave_file(temp_file_name)\n",
- " play_obj = wave_obj.play()\n",
- " play_obj.wait_done() # Wait for playback to finish\n",
- "\n",
- " # Clean up the temporary file afterward\n",
- " os.remove(temp_file_name)\n",
- " \n",
- "talker(\"Well hi there\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7986176b-cd04-495f-a47f-e057b0e462ed",
- "metadata": {},
- "source": [
- "## PC Users - if none of those 4 variations worked!\n",
- "\n",
- "Please get in touch with me. I'm sorry this is causing problems! We'll figure it out.\n",
- "\n",
- "Alternatively: playing audio from your PC isn't super-critical for this course, and you can feel free to focus on image generation and skip audio for now, or come back to it later."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "1d48876d-c4fa-46a8-a04f-f9fadf61fb0d",
- "metadata": {},
- "source": [
- "# Our Agent Framework\n",
- "\n",
- "The term 'Agentic AI' and Agentization is an umbrella term that refers to a number of techniques, such as:\n",
- "\n",
- "1. Breaking a complex problem into smaller steps, with multiple LLMs carrying out specialized tasks\n",
- "2. The ability for LLMs to use Tools to give them additional capabilities\n",
- "3. The 'Agent Environment' which allows Agents to collaborate\n",
- "4. An LLM can act as the Planner, dividing bigger tasks into smaller ones for the specialists\n",
- "5. The concept of an Agent having autonomy / agency, beyond just responding to a prompt - such as Memory\n",
- "\n",
- "We're showing 1 and 2 here, and to a lesser extent 3 and 5. In week 8 we will do the lot!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ba820c95-02f5-499e-8f3c-8727ee0a6c0c",
+ "id": "b119ed1b",
"metadata": {},
"outputs": [],
"source": [
"def chat(history):\n",
+ " history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history]\n",
" messages = [{\"role\": \"system\", \"content\": system_message}] + history\n",
" response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
+ " cities = []\n",
" image = None\n",
- " \n",
- " if response.choices[0].finish_reason==\"tool_calls\":\n",
+ "\n",
+ " while response.choices[0].finish_reason==\"tool_calls\":\n",
" message = response.choices[0].message\n",
- " response, city = handle_tool_call(message)\n",
+ " responses, cities = handle_tool_calls_and_return_cities(message)\n",
" messages.append(message)\n",
- " messages.append(response)\n",
- " image = artist(city)\n",
- " response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
- " \n",
+ " messages.extend(responses)\n",
+ " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
+ "\n",
" reply = response.choices[0].message.content\n",
" history += [{\"role\":\"assistant\", \"content\":reply}]\n",
"\n",
- " # Comment out or delete the next line if you'd rather skip Audio for now..\n",
- " talker(reply)\n",
+ " voice = talker(reply)\n",
+ "\n",
+ " if cities:\n",
+ " image = artist(cities[0])\n",
" \n",
- " return history, image"
+ " return history, voice, image\n"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "f38d0d27-33bf-4992-a2e5-5dbed973cde7",
+ "id": "5846bc77",
"metadata": {},
"outputs": [],
"source": [
- "# More involved Gradio code as we're not using the preset Chat interface!\n",
- "# Passing in inbrowser=True in the last line will cause a Gradio window to pop up immediately.\n",
+ "def handle_tool_calls_and_return_cities(message):\n",
+ " responses = []\n",
+ " cities = []\n",
+ " for tool_call in message.tool_calls:\n",
+ " if tool_call.function.name == \"get_ticket_price\":\n",
+ " arguments = json.loads(tool_call.function.arguments)\n",
+ " city = arguments.get('destination_city')\n",
+ " cities.append(city)\n",
+ " price_details = get_ticket_price(city)\n",
+ " responses.append({\n",
+ " \"role\": \"tool\",\n",
+ " \"content\": price_details,\n",
+ " \"tool_call_id\": tool_call.id\n",
+ " })\n",
+ " return responses, cities"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e520161",
+ "metadata": {},
+ "source": [
+ "## The 3 types of Gradio UI\n",
+ "\n",
+ "`gr.Interface` is for standard, simple UIs\n",
+ "\n",
+ "`gr.ChatInterface` is for standard ChatBot UIs\n",
+ "\n",
+ "`gr.Blocks` is for custom UIs where you control the components and the callbacks"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9f250915",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Callbacks (along with the chat() function above)\n",
+ "\n",
+ "def put_message_in_chatbot(message, history):\n",
+ " return \"\", history + [{\"role\":\"user\", \"content\":message}]\n",
+ "\n",
+ "# UI definition\n",
"\n",
"with gr.Blocks() as ui:\n",
" with gr.Row():\n",
" chatbot = gr.Chatbot(height=500, type=\"messages\")\n",
- " image_output = gr.Image(height=500)\n",
+ " image_output = gr.Image(height=500, interactive=False)\n",
" with gr.Row():\n",
- " entry = gr.Textbox(label=\"Chat with our AI Assistant:\")\n",
+ " audio_output = gr.Audio(autoplay=True)\n",
" with gr.Row():\n",
- " clear = gr.Button(\"Clear\")\n",
+ " message = gr.Textbox(label=\"Chat with our AI Assistant:\")\n",
"\n",
- " def do_entry(message, history):\n",
- " history += [{\"role\":\"user\", \"content\":message}]\n",
- " return \"\", history\n",
+ "# Hooking up events to callbacks\n",
"\n",
- " entry.submit(do_entry, inputs=[entry, chatbot], outputs=[entry, chatbot]).then(\n",
- " chat, inputs=chatbot, outputs=[chatbot, image_output]\n",
+ " message.submit(put_message_in_chatbot, inputs=[message, chatbot], outputs=[message, chatbot]).then(\n",
+ " chat, inputs=chatbot, outputs=[chatbot, audio_output, image_output]\n",
" )\n",
- " clear.click(lambda: None, inputs=None, outputs=chatbot, queue=False)\n",
"\n",
- "ui.launch(inbrowser=True)"
+ "ui.launch(inbrowser=True, auth=(\"ed\", \"bananas\"))"
]
},
{
@@ -719,7 +420,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" I have a special request for you\n",
@@ -734,7 +435,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -748,7 +449,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.13"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/week2/hamlet.txt b/week2/hamlet.txt
new file mode 100644
index 0000000..f4cb520
--- /dev/null
+++ b/week2/hamlet.txt
@@ -0,0 +1,4459 @@
+THE TRAGEDY OF HAMLET, PRINCE OF DENMARK
+
+
+by William Shakespeare
+
+
+
+Dramatis Personae
+
+ Claudius, King of Denmark.
+ Marcellus, Officer.
+ Hamlet, son to the former, and nephew to the present king.
+ Polonius, Lord Chamberlain.
+ Horatio, friend to Hamlet.
+ Laertes, son to Polonius.
+ Voltemand, courtier.
+ Cornelius, courtier.
+ Rosencrantz, courtier.
+ Guildenstern, courtier.
+ Osric, courtier.
+ A Gentleman, courtier.
+ A Priest.
+ Marcellus, officer.
+ Bernardo, officer.
+ Francisco, a soldier
+ Reynaldo, servant to Polonius.
+ Players.
+ Two Clowns, gravediggers.
+ Fortinbras, Prince of Norway.
+ A Norwegian Captain.
+ English Ambassadors.
+
+ Getrude, Queen of Denmark, mother to Hamlet.
+ Ophelia, daughter to Polonius.
+
+ Ghost of Hamlet's Father.
+
+ Lords, ladies, Officers, Soldiers, Sailors, Messengers, Attendants.
+
+
+
+
+
+SCENE.- Elsinore.
+
+
+ACT I. Scene I.
+Elsinore. A platform before the Castle.
+
+Enter two Sentinels-[first,] Francisco, [who paces up and down
+at his post; then] Bernardo, [who approaches him].
+
+ Ber. Who's there.?
+ Fran. Nay, answer me. Stand and unfold yourself.
+ Ber. Long live the King!
+ Fran. Bernardo?
+ Ber. He.
+ Fran. You come most carefully upon your hour.
+ Ber. 'Tis now struck twelve. Get thee to bed, Francisco.
+ Fran. For this relief much thanks. 'Tis bitter cold,
+ And I am sick at heart.
+ Ber. Have you had quiet guard?
+ Fran. Not a mouse stirring.
+ Ber. Well, good night.
+ If you do meet Horatio and Marcellus,
+ The rivals of my watch, bid them make haste.
+
+ Enter Horatio and Marcellus.
+
+ Fran. I think I hear them. Stand, ho! Who is there?
+ Hor. Friends to this ground.
+ Mar. And liegemen to the Dane.
+ Fran. Give you good night.
+ Mar. O, farewell, honest soldier.
+ Who hath reliev'd you?
+ Fran. Bernardo hath my place.
+ Give you good night. Exit.
+ Mar. Holla, Bernardo!
+ Ber. Say-
+ What, is Horatio there ?
+ Hor. A piece of him.
+ Ber. Welcome, Horatio. Welcome, good Marcellus.
+ Mar. What, has this thing appear'd again to-night?
+ Ber. I have seen nothing.
+ Mar. Horatio says 'tis but our fantasy,
+ And will not let belief take hold of him
+ Touching this dreaded sight, twice seen of us.
+ Therefore I have entreated him along,
+ With us to watch the minutes of this night,
+ That, if again this apparition come,
+ He may approve our eyes and speak to it.
+ Hor. Tush, tush, 'twill not appear.
+ Ber. Sit down awhile,
+ And let us once again assail your ears,
+ That are so fortified against our story,
+ What we two nights have seen.
+ Hor. Well, sit we down,
+ And let us hear Bernardo speak of this.
+ Ber. Last night of all,
+ When yond same star that's westward from the pole
+ Had made his course t' illume that part of heaven
+ Where now it burns, Marcellus and myself,
+ The bell then beating one-
+
+ Enter Ghost.
+
+ Mar. Peace! break thee off! Look where it comes again!
+ Ber. In the same figure, like the King that's dead.
+ Mar. Thou art a scholar; speak to it, Horatio.
+ Ber. Looks it not like the King? Mark it, Horatio.
+ Hor. Most like. It harrows me with fear and wonder.
+ Ber. It would be spoke to.
+ Mar. Question it, Horatio.
+ Hor. What art thou that usurp'st this time of night
+ Together with that fair and warlike form
+ In which the majesty of buried Denmark
+ Did sometimes march? By heaven I charge thee speak!
+ Mar. It is offended.
+ Ber. See, it stalks away!
+ Hor. Stay! Speak, speak! I charge thee speak!
+ Exit Ghost.
+ Mar. 'Tis gone and will not answer.
+ Ber. How now, Horatio? You tremble and look pale.
+ Is not this something more than fantasy?
+ What think you on't?
+ Hor. Before my God, I might not this believe
+ Without the sensible and true avouch
+ Of mine own eyes.
+ Mar. Is it not like the King?
+ Hor. As thou art to thyself.
+ Such was the very armour he had on
+ When he th' ambitious Norway combated.
+ So frown'd he once when, in an angry parle,
+ He smote the sledded Polacks on the ice.
+ 'Tis strange.
+ Mar. Thus twice before, and jump at this dead hour,
+ With martial stalk hath he gone by our watch.
+ Hor. In what particular thought to work I know not;
+ But, in the gross and scope of my opinion,
+ This bodes some strange eruption to our state.
+ Mar. Good now, sit down, and tell me he that knows,
+ Why this same strict and most observant watch
+ So nightly toils the subject of the land,
+ And why such daily cast of brazen cannon
+ And foreign mart for implements of war;
+ Why such impress of shipwrights, whose sore task
+ Does not divide the Sunday from the week.
+ What might be toward, that this sweaty haste
+ Doth make the night joint-labourer with the day?
+ Who is't that can inform me?
+ Hor. That can I.
+ At least, the whisper goes so. Our last king,
+ Whose image even but now appear'd to us,
+ Was, as you know, by Fortinbras of Norway,
+ Thereto prick'd on by a most emulate pride,
+ Dar'd to the combat; in which our valiant Hamlet
+ (For so this side of our known world esteem'd him)
+ Did slay this Fortinbras; who, by a seal'd compact,
+ Well ratified by law and heraldry,
+ Did forfeit, with his life, all those his lands
+ Which he stood seiz'd of, to the conqueror;
+ Against the which a moiety competent
+ Was gaged by our king; which had return'd
+ To the inheritance of Fortinbras,
+ Had he been vanquisher, as, by the same comart
+ And carriage of the article design'd,
+ His fell to Hamlet. Now, sir, young Fortinbras,
+ Of unimproved mettle hot and full,
+ Hath in the skirts of Norway, here and there,
+ Shark'd up a list of lawless resolutes,
+ For food and diet, to some enterprise
+ That hath a stomach in't; which is no other,
+ As it doth well appear unto our state,
+ But to recover of us, by strong hand
+ And terms compulsatory, those foresaid lands
+ So by his father lost; and this, I take it,
+ Is the main motive of our preparations,
+ The source of this our watch, and the chief head
+ Of this post-haste and romage in the land.
+ Ber. I think it be no other but e'en so.
+ Well may it sort that this portentous figure
+ Comes armed through our watch, so like the King
+ That was and is the question of these wars.
+ Hor. A mote it is to trouble the mind's eye.
+ In the most high and palmy state of Rome,
+ A little ere the mightiest Julius fell,
+ The graves stood tenantless, and the sheeted dead
+ Did squeak and gibber in the Roman streets;
+ As stars with trains of fire, and dews of blood,
+ Disasters in the sun; and the moist star
+ Upon whose influence Neptune's empire stands
+ Was sick almost to doomsday with eclipse.
+ And even the like precurse of fierce events,
+ As harbingers preceding still the fates
+ And prologue to the omen coming on,
+ Have heaven and earth together demonstrated
+ Unto our climature and countrymen.
+
+ Enter Ghost again.
+
+ But soft! behold! Lo, where it comes again!
+ I'll cross it, though it blast me.- Stay illusion!
+ Spreads his arms.
+ If thou hast any sound, or use of voice,
+ Speak to me.
+ If there be any good thing to be done,
+ That may to thee do ease, and, race to me,
+ Speak to me.
+ If thou art privy to thy country's fate,
+ Which happily foreknowing may avoid,
+ O, speak!
+ Or if thou hast uphoarded in thy life
+ Extorted treasure in the womb of earth
+ (For which, they say, you spirits oft walk in death),
+ The cock crows.
+ Speak of it! Stay, and speak!- Stop it, Marcellus!
+ Mar. Shall I strike at it with my partisan?
+ Hor. Do, if it will not stand.
+ Ber. 'Tis here!
+ Hor. 'Tis here!
+ Mar. 'Tis gone!
+ Exit Ghost.
+ We do it wrong, being so majestical,
+ To offer it the show of violence;
+ For it is as the air, invulnerable,
+ And our vain blows malicious mockery.
+ Ber. It was about to speak, when the cock crew.
+ Hor. And then it started, like a guilty thing
+ Upon a fearful summons. I have heard
+ The cock, that is the trumpet to the morn,
+ Doth with his lofty and shrill-sounding throat
+ Awake the god of day; and at his warning,
+ Whether in sea or fire, in earth or air,
+ Th' extravagant and erring spirit hies
+ To his confine; and of the truth herein
+ This present object made probation.
+ Mar. It faded on the crowing of the cock.
+ Some say that ever, 'gainst that season comes
+ Wherein our Saviour's birth is celebrated,
+ The bird of dawning singeth all night long;
+ And then, they say, no spirit dare stir abroad,
+ The nights are wholesome, then no planets strike,
+ No fairy takes, nor witch hath power to charm,
+ So hallow'd and so gracious is the time.
+ Hor. So have I heard and do in part believe it.
+ But look, the morn, in russet mantle clad,
+ Walks o'er the dew of yon high eastward hill.
+ Break we our watch up; and by my advice
+ Let us impart what we have seen to-night
+ Unto young Hamlet; for, upon my life,
+ This spirit, dumb to us, will speak to him.
+ Do you consent we shall acquaint him with it,
+ As needful in our loves, fitting our duty?
+ Let's do't, I pray; and I this morning know
+ Where we shall find him most conveniently. Exeunt.
+
+
+
+
+Scene II.
+Elsinore. A room of state in the Castle.
+
+Flourish. [Enter Claudius, King of Denmark, Gertrude the Queen, Hamlet,
+Polonius, Laertes and his sister Ophelia, [Voltemand, Cornelius,]
+Lords Attendant.
+
+ King. Though yet of Hamlet our dear brother's death
+ The memory be green, and that it us befitted
+ To bear our hearts in grief, and our whole kingdom
+ To be contracted in one brow of woe,
+ Yet so far hath discretion fought with nature
+ That we with wisest sorrow think on him
+ Together with remembrance of ourselves.
+ Therefore our sometime sister, now our queen,
+ Th' imperial jointress to this warlike state,
+ Have we, as 'twere with a defeated joy,
+ With an auspicious, and a dropping eye,
+ With mirth in funeral, and with dirge in marriage,
+ In equal scale weighing delight and dole,
+ Taken to wife; nor have we herein barr'd
+ Your better wisdoms, which have freely gone
+ With this affair along. For all, our thanks.
+ Now follows, that you know, young Fortinbras,
+ Holding a weak supposal of our worth,
+ Or thinking by our late dear brother's death
+ Our state to be disjoint and out of frame,
+ Colleagued with this dream of his advantage,
+ He hath not fail'd to pester us with message
+ Importing the surrender of those lands
+ Lost by his father, with all bands of law,
+ To our most valiant brother. So much for him.
+ Now for ourself and for this time of meeting.
+ Thus much the business is: we have here writ
+ To Norway, uncle of young Fortinbras,
+ Who, impotent and bedrid, scarcely hears
+ Of this his nephew's purpose, to suppress
+ His further gait herein, in that the levies,
+ The lists, and full proportions are all made
+ Out of his subject; and we here dispatch
+ You, good Cornelius, and you, Voltemand,
+ For bearers of this greeting to old Norway,
+ Giving to you no further personal power
+ To business with the King, more than the scope
+ Of these dilated articles allow. [Gives a paper.]
+ Farewell, and let your haste commend your duty.
+ Cor., Volt. In that, and all things, will we show our duty.
+ King. We doubt it nothing. Heartily farewell.
+ Exeunt Voltemand and Cornelius.
+ And now, Laertes, what's the news with you?
+ You told us of some suit. What is't, Laertes?
+ You cannot speak of reason to the Dane
+ And lose your voice. What wouldst thou beg, Laertes,
+ That shall not be my offer, not thy asking?
+ The head is not more native to the heart,
+ The hand more instrumental to the mouth,
+ Than is the throne of Denmark to thy father.
+ What wouldst thou have, Laertes?
+ Laer. My dread lord,
+ Your leave and favour to return to France;
+ From whence though willingly I came to Denmark
+ To show my duty in your coronation,
+ Yet now I must confess, that duty done,
+ My thoughts and wishes bend again toward France
+ And bow them to your gracious leave and pardon.
+ King. Have you your father's leave? What says Polonius?
+ Pol. He hath, my lord, wrung from me my slow leave
+ By laboursome petition, and at last
+ Upon his will I seal'd my hard consent.
+ I do beseech you give him leave to go.
+ King. Take thy fair hour, Laertes. Time be thine,
+ And thy best graces spend it at thy will!
+ But now, my cousin Hamlet, and my son-
+ Ham. [aside] A little more than kin, and less than kind!
+ King. How is it that the clouds still hang on you?
+ Ham. Not so, my lord. I am too much i' th' sun.
+ Queen. Good Hamlet, cast thy nighted colour off,
+ And let thine eye look like a friend on Denmark.
+ Do not for ever with thy vailed lids
+ Seek for thy noble father in the dust.
+ Thou know'st 'tis common. All that lives must die,
+ Passing through nature to eternity.
+ Ham. Ay, madam, it is common.
+ Queen. If it be,
+ Why seems it so particular with thee?
+ Ham. Seems, madam, Nay, it is. I know not 'seems.'
+ 'Tis not alone my inky cloak, good mother,
+ Nor customary suits of solemn black,
+ Nor windy suspiration of forc'd breath,
+ No, nor the fruitful river in the eye,
+ Nor the dejected havior of the visage,
+ Together with all forms, moods, shapes of grief,
+ 'That can denote me truly. These indeed seem,
+ For they are actions that a man might play;
+ But I have that within which passeth show-
+ These but the trappings and the suits of woe.
+ King. 'Tis sweet and commendable in your nature, Hamlet,
+ To give these mourning duties to your father;
+ But you must know, your father lost a father;
+ That father lost, lost his, and the survivor bound
+ In filial obligation for some term
+ To do obsequious sorrow. But to persever
+ In obstinate condolement is a course
+ Of impious stubbornness. 'Tis unmanly grief;
+ It shows a will most incorrect to heaven,
+ A heart unfortified, a mind impatient,
+ An understanding simple and unschool'd;
+ For what we know must be, and is as common
+ As any the most vulgar thing to sense,
+ Why should we in our peevish opposition
+ Take it to heart? Fie! 'tis a fault to heaven,
+ A fault against the dead, a fault to nature,
+ To reason most absurd, whose common theme
+ Is death of fathers, and who still hath cried,
+ From the first corse till he that died to-day,
+ 'This must be so.' We pray you throw to earth
+ This unprevailing woe, and think of us
+ As of a father; for let the world take note
+ You are the most immediate to our throne,
+ And with no less nobility of love
+ Than that which dearest father bears his son
+ Do I impart toward you. For your intent
+ In going back to school in Wittenberg,
+ It is most retrograde to our desire;
+ And we beseech you, bend you to remain
+ Here in the cheer and comfort of our eye,
+ Our chiefest courtier, cousin, and our son.
+ Queen. Let not thy mother lose her prayers, Hamlet.
+ I pray thee stay with us, go not to Wittenberg.
+ Ham. I shall in all my best obey you, madam.
+ King. Why, 'tis a loving and a fair reply.
+ Be as ourself in Denmark. Madam, come.
+ This gentle and unforc'd accord of Hamlet
+ Sits smiling to my heart; in grace whereof,
+ No jocund health that Denmark drinks to-day
+ But the great cannon to the clouds shall tell,
+ And the King's rouse the heaven shall bruit again,
+ Respeaking earthly thunder. Come away.
+ Flourish. Exeunt all but Hamlet.
+ Ham. O that this too too solid flesh would melt,
+ Thaw, and resolve itself into a dew!
+ Or that the Everlasting had not fix'd
+ His canon 'gainst self-slaughter! O God! God!
+ How weary, stale, flat, and unprofitable
+ Seem to me all the uses of this world!
+ Fie on't! ah, fie! 'Tis an unweeded garden
+ That grows to seed; things rank and gross in nature
+ Possess it merely. That it should come to this!
+ But two months dead! Nay, not so much, not two.
+ So excellent a king, that was to this
+ Hyperion to a satyr; so loving to my mother
+ That he might not beteem the winds of heaven
+ Visit her face too roughly. Heaven and earth!
+ Must I remember? Why, she would hang on him
+ As if increase of appetite had grown
+ By what it fed on; and yet, within a month-
+ Let me not think on't! Frailty, thy name is woman!-
+ A little month, or ere those shoes were old
+ With which she followed my poor father's body
+ Like Niobe, all tears- why she, even she
+ (O God! a beast that wants discourse of reason
+ Would have mourn'd longer) married with my uncle;
+ My father's brother, but no more like my father
+ Than I to Hercules. Within a month,
+ Ere yet the salt of most unrighteous tears
+ Had left the flushing in her galled eyes,
+ She married. O, most wicked speed, to post
+ With such dexterity to incestuous sheets!
+ It is not, nor it cannot come to good.
+ But break my heart, for I must hold my tongue!
+
+ Enter Horatio, Marcellus, and Bernardo.
+
+ Hor. Hail to your lordship!
+ Ham. I am glad to see you well.
+ Horatio!- or I do forget myself.
+ Hor. The same, my lord, and your poor servant ever.
+ Ham. Sir, my good friend- I'll change that name with you.
+ And what make you from Wittenberg, Horatio?
+ Marcellus?
+ Mar. My good lord!
+ Ham. I am very glad to see you.- [To Bernardo] Good even, sir.-
+ But what, in faith, make you from Wittenberg?
+ Hor. A truant disposition, good my lord.
+ Ham. I would not hear your enemy say so,
+ Nor shall you do my ear that violence
+ To make it truster of your own report
+ Against yourself. I know you are no truant.
+ But what is your affair in Elsinore?
+ We'll teach you to drink deep ere you depart.
+ Hor. My lord, I came to see your father's funeral.
+ Ham. I prithee do not mock me, fellow student.
+ I think it was to see my mother's wedding.
+ Hor. Indeed, my lord, it followed hard upon.
+ Ham. Thrift, thrift, Horatio! The funeral bak'd meats
+ Did coldly furnish forth the marriage tables.
+ Would I had met my dearest foe in heaven
+ Or ever I had seen that day, Horatio!
+ My father- methinks I see my father.
+ Hor. O, where, my lord?
+ Ham. In my mind's eye, Horatio.
+ Hor. I saw him once. He was a goodly king.
+ Ham. He was a man, take him for all in all.
+ I shall not look upon his like again.
+ Hor. My lord, I think I saw him yesternight.
+ Ham. Saw? who?
+ Hor. My lord, the King your father.
+ Ham. The King my father?
+ Hor. Season your admiration for a while
+ With an attent ear, till I may deliver
+ Upon the witness of these gentlemen,
+ This marvel to you.
+ Ham. For God's love let me hear!
+ Hor. Two nights together had these gentlemen
+ (Marcellus and Bernardo) on their watch
+ In the dead vast and middle of the night
+ Been thus encount'red. A figure like your father,
+ Armed at point exactly, cap-a-pe,
+ Appears before them and with solemn march
+ Goes slow and stately by them. Thrice he walk'd
+ By their oppress'd and fear-surprised eyes,
+ Within his truncheon's length; whilst they distill'd
+ Almost to jelly with the act of fear,
+ Stand dumb and speak not to him. This to me
+ In dreadful secrecy impart they did,
+ And I with them the third night kept the watch;
+ Where, as they had deliver'd, both in time,
+ Form of the thing, each word made true and good,
+ The apparition comes. I knew your father.
+ These hands are not more like.
+ Ham. But where was this?
+ Mar. My lord, upon the platform where we watch'd.
+ Ham. Did you not speak to it?
+ Hor. My lord, I did;
+ But answer made it none. Yet once methought
+ It lifted up it head and did address
+ Itself to motion, like as it would speak;
+ But even then the morning cock crew loud,
+ And at the sound it shrunk in haste away
+ And vanish'd from our sight.
+ Ham. 'Tis very strange.
+ Hor. As I do live, my honour'd lord, 'tis true;
+ And we did think it writ down in our duty
+ To let you know of it.
+ Ham. Indeed, indeed, sirs. But this troubles me.
+ Hold you the watch to-night?
+ Both [Mar. and Ber.] We do, my lord.
+ Ham. Arm'd, say you?
+ Both. Arm'd, my lord.
+ Ham. From top to toe?
+ Both. My lord, from head to foot.
+ Ham. Then saw you not his face?
+ Hor. O, yes, my lord! He wore his beaver up.
+ Ham. What, look'd he frowningly.
+ Hor. A countenance more in sorrow than in anger.
+ Ham. Pale or red?
+ Hor. Nay, very pale.
+ Ham. And fix'd his eyes upon you?
+ Hor. Most constantly.
+ Ham. I would I had been there.
+ Hor. It would have much amaz'd you.
+ Ham. Very like, very like. Stay'd it long?
+ Hor. While one with moderate haste might tell a hundred.
+ Both. Longer, longer.
+ Hor. Not when I saw't.
+ Ham. His beard was grizzled- no?
+ Hor. It was, as I have seen it in his life,
+ A sable silver'd.
+ Ham. I will watch to-night.
+ Perchance 'twill walk again.
+ Hor. I warr'nt it will.
+ Ham. If it assume my noble father's person,
+ I'll speak to it, though hell itself should gape
+ And bid me hold my peace. I pray you all,
+ If you have hitherto conceal'd this sight,
+ Let it be tenable in your silence still;
+ And whatsoever else shall hap to-night,
+ Give it an understanding but no tongue.
+ I will requite your loves. So, fare you well.
+ Upon the platform, 'twixt eleven and twelve,
+ I'll visit you.
+ All. Our duty to your honour.
+ Ham. Your loves, as mine to you. Farewell.
+ Exeunt [all but Hamlet].
+ My father's spirit- in arms? All is not well.
+ I doubt some foul play. Would the night were come!
+ Till then sit still, my soul. Foul deeds will rise,
+ Though all the earth o'erwhelm them, to men's eyes.
+Exit.
+
+
+
+
+Scene III.
+Elsinore. A room in the house of Polonius.
+
+Enter Laertes and Ophelia.
+
+ Laer. My necessaries are embark'd. Farewell.
+ And, sister, as the winds give benefit
+ And convoy is assistant, do not sleep,
+ But let me hear from you.
+ Oph. Do you doubt that?
+ Laer. For Hamlet, and the trifling of his favour,
+ Hold it a fashion, and a toy in blood;
+ A violet in the youth of primy nature,
+ Forward, not permanent- sweet, not lasting;
+ The perfume and suppliance of a minute;
+ No more.
+ Oph. No more but so?
+ Laer. Think it no more.
+ For nature crescent does not grow alone
+ In thews and bulk; but as this temple waxes,
+ The inward service of the mind and soul
+ Grows wide withal. Perhaps he loves you now,
+ And now no soil nor cautel doth besmirch
+ The virtue of his will; but you must fear,
+ His greatness weigh'd, his will is not his own;
+ For he himself is subject to his birth.
+ He may not, as unvalued persons do,
+ Carve for himself, for on his choice depends
+ The safety and health of this whole state,
+ And therefore must his choice be circumscrib'd
+ Unto the voice and yielding of that body
+ Whereof he is the head. Then if he says he loves you,
+ It fits your wisdom so far to believe it
+ As he in his particular act and place
+ May give his saying deed; which is no further
+ Than the main voice of Denmark goes withal.
+ Then weigh what loss your honour may sustain
+ If with too credent ear you list his songs,
+ Or lose your heart, or your chaste treasure open
+ To his unmast'red importunity.
+ Fear it, Ophelia, fear it, my dear sister,
+ And keep you in the rear of your affection,
+ Out of the shot and danger of desire.
+ The chariest maid is prodigal enough
+ If she unmask her beauty to the moon.
+ Virtue itself scopes not calumnious strokes.
+ The canker galls the infants of the spring
+ Too oft before their buttons be disclos'd,
+ And in the morn and liquid dew of youth
+ Contagious blastments are most imminent.
+ Be wary then; best safety lies in fear.
+ Youth to itself rebels, though none else near.
+ Oph. I shall th' effect of this good lesson keep
+ As watchman to my heart. But, good my brother,
+ Do not as some ungracious pastors do,
+ Show me the steep and thorny way to heaven,
+ Whiles, like a puff'd and reckless libertine,
+ Himself the primrose path of dalliance treads
+ And recks not his own rede.
+ Laer. O, fear me not!
+
+ Enter Polonius.
+
+ I stay too long. But here my father comes.
+ A double blessing is a double grace;
+ Occasion smiles upon a second leave.
+ Pol. Yet here, Laertes? Aboard, aboard, for shame!
+ The wind sits in the shoulder of your sail,
+ And you are stay'd for. There- my blessing with thee!
+ And these few precepts in thy memory
+ Look thou character. Give thy thoughts no tongue,
+ Nor any unproportion'd thought his act.
+ Be thou familiar, but by no means vulgar:
+ Those friends thou hast, and their adoption tried,
+ Grapple them unto thy soul with hoops of steel;
+ But do not dull thy palm with entertainment
+ Of each new-hatch'd, unfledg'd comrade. Beware
+ Of entrance to a quarrel; but being in,
+ Bear't that th' opposed may beware of thee.
+ Give every man thine ear, but few thy voice;
+ Take each man's censure, but reserve thy judgment.
+ Costly thy habit as thy purse can buy,
+ But not express'd in fancy; rich, not gaudy;
+ For the apparel oft proclaims the man,
+ And they in France of the best rank and station
+ Are most select and generous, chief in that.
+ Neither a borrower nor a lender be;
+ For loan oft loses both itself and friend,
+ And borrowing dulls the edge of husbandry.
+ This above all- to thine own self be true,
+ And it must follow, as the night the day,
+ Thou canst not then be false to any man.
+ Farewell. My blessing season this in thee!
+ Laer. Most humbly do I take my leave, my lord.
+ Pol. The time invites you. Go, your servants tend.
+ Laer. Farewell, Ophelia, and remember well
+ What I have said to you.
+ Oph. 'Tis in my memory lock'd,
+ And you yourself shall keep the key of it.
+ Laer. Farewell. Exit.
+ Pol. What is't, Ophelia, he hath said to you?
+ Oph. So please you, something touching the Lord Hamlet.
+ Pol. Marry, well bethought!
+ 'Tis told me he hath very oft of late
+ Given private time to you, and you yourself
+ Have of your audience been most free and bounteous.
+ If it be so- as so 'tis put on me,
+ And that in way of caution- I must tell you
+ You do not understand yourself so clearly
+ As it behooves my daughter and your honour.
+ What is between you? Give me up the truth.
+ Oph. He hath, my lord, of late made many tenders
+ Of his affection to me.
+ Pol. Affection? Pooh! You speak like a green girl,
+ Unsifted in such perilous circumstance.
+ Do you believe his tenders, as you call them?
+ Oph. I do not know, my lord, what I should think,
+ Pol. Marry, I will teach you! Think yourself a baby
+ That you have ta'en these tenders for true pay,
+ Which are not sterling. Tender yourself more dearly,
+ Or (not to crack the wind of the poor phrase,
+ Running it thus) you'll tender me a fool.
+ Oph. My lord, he hath importun'd me with love
+ In honourable fashion.
+ Pol. Ay, fashion you may call it. Go to, go to!
+ Oph. And hath given countenance to his speech, my lord,
+ With almost all the holy vows of heaven.
+ Pol. Ay, springes to catch woodcocks! I do know,
+ When the blood burns, how prodigal the soul
+ Lends the tongue vows. These blazes, daughter,
+ Giving more light than heat, extinct in both
+ Even in their promise, as it is a-making,
+ You must not take for fire. From this time
+ Be something scanter of your maiden presence.
+ Set your entreatments at a higher rate
+ Than a command to parley. For Lord Hamlet,
+ Believe so much in him, that he is young,
+ And with a larger tether may he walk
+ Than may be given you. In few, Ophelia,
+ Do not believe his vows; for they are brokers,
+ Not of that dye which their investments show,
+ But mere implorators of unholy suits,
+ Breathing like sanctified and pious bawds,
+ The better to beguile. This is for all:
+ I would not, in plain terms, from this time forth
+ Have you so slander any moment leisure
+ As to give words or talk with the Lord Hamlet.
+ Look to't, I charge you. Come your ways.
+ Oph. I shall obey, my lord.
+ Exeunt.
+
+
+
+
+Scene IV.
+Elsinore. The platform before the Castle.
+
+Enter Hamlet, Horatio, and Marcellus.
+
+ Ham. The air bites shrewdly; it is very cold.
+ Hor. It is a nipping and an eager air.
+ Ham. What hour now?
+ Hor. I think it lacks of twelve.
+ Mar. No, it is struck.
+ Hor. Indeed? I heard it not. It then draws near the season
+ Wherein the spirit held his wont to walk.
+ A flourish of trumpets, and two pieces go off.
+ What does this mean, my lord?
+ Ham. The King doth wake to-night and takes his rouse,
+ Keeps wassail, and the swagg'ring upspring reels,
+ And, as he drains his draughts of Rhenish down,
+ The kettledrum and trumpet thus bray out
+ The triumph of his pledge.
+ Hor. Is it a custom?
+ Ham. Ay, marry, is't;
+ But to my mind, though I am native here
+ And to the manner born, it is a custom
+ More honour'd in the breach than the observance.
+ This heavy-headed revel east and west
+ Makes us traduc'd and tax'd of other nations;
+ They clip us drunkards and with swinish phrase
+ Soil our addition; and indeed it takes
+ From our achievements, though perform'd at height,
+ The pith and marrow of our attribute.
+ So oft it chances in particular men
+ That, for some vicious mole of nature in them,
+ As in their birth,- wherein they are not guilty,
+ Since nature cannot choose his origin,-
+ By the o'ergrowth of some complexion,
+ Oft breaking down the pales and forts of reason,
+ Or by some habit that too much o'erleavens
+ The form of plausive manners, that these men
+ Carrying, I say, the stamp of one defect,
+ Being nature's livery, or fortune's star,
+ Their virtues else- be they as pure as grace,
+ As infinite as man may undergo-
+ Shall in the general censure take corruption
+ From that particular fault. The dram of e'il
+ Doth all the noble substance often dout To his own scandal.
+
+ Enter Ghost.
+
+ Hor. Look, my lord, it comes!
+ Ham. Angels and ministers of grace defend us!
+ Be thou a spirit of health or goblin damn'd,
+ Bring with thee airs from heaven or blasts from hell,
+ Be thy intents wicked or charitable,
+ Thou com'st in such a questionable shape
+ That I will speak to thee. I'll call thee Hamlet,
+ King, father, royal Dane. O, answer me?
+ Let me not burst in ignorance, but tell
+ Why thy canoniz'd bones, hearsed in death,
+ Have burst their cerements; why the sepulchre
+ Wherein we saw thee quietly inurn'd,
+ Hath op'd his ponderous and marble jaws
+ To cast thee up again. What may this mean
+ That thou, dead corse, again in complete steel,
+ Revisits thus the glimpses of the moon,
+ Making night hideous, and we fools of nature
+ So horridly to shake our disposition
+ With thoughts beyond the reaches of our souls?
+ Say, why is this? wherefore? What should we do?
+ Ghost beckons Hamlet.
+ Hor. It beckons you to go away with it,
+ As if it some impartment did desire
+ To you alone.
+ Mar. Look with what courteous action
+ It waves you to a more removed ground.
+ But do not go with it!
+ Hor. No, by no means!
+ Ham. It will not speak. Then will I follow it.
+ Hor. Do not, my lord!
+ Ham. Why, what should be the fear?
+ I do not set my life at a pin's fee;
+ And for my soul, what can it do to that,
+ Being a thing immortal as itself?
+ It waves me forth again. I'll follow it.
+ Hor. What if it tempt you toward the flood, my lord,
+ Or to the dreadful summit of the cliff
+ That beetles o'er his base into the sea,
+ And there assume some other, horrible form
+ Which might deprive your sovereignty of reason
+ And draw you into madness? Think of it.
+ The very place puts toys of desperation,
+ Without more motive, into every brain
+ That looks so many fadoms to the sea
+ And hears it roar beneath.
+ Ham. It waves me still.
+ Go on. I'll follow thee.
+ Mar. You shall not go, my lord.
+ Ham. Hold off your hands!
+ Hor. Be rul'd. You shall not go.
+ Ham. My fate cries out
+ And makes each petty artire in this body
+ As hardy as the Nemean lion's nerve.
+ [Ghost beckons.]
+ Still am I call'd. Unhand me, gentlemen.
+ By heaven, I'll make a ghost of him that lets me!-
+ I say, away!- Go on. I'll follow thee.
+ Exeunt Ghost and Hamlet.
+ Hor. He waxes desperate with imagination.
+ Mar. Let's follow. 'Tis not fit thus to obey him.
+ Hor. Have after. To what issue wail this come?
+ Mar. Something is rotten in the state of Denmark.
+ Hor. Heaven will direct it.
+ Mar. Nay, let's follow him.
+ Exeunt.
+
+
+
+
+Scene V.
+Elsinore. The Castle. Another part of the fortifications.
+
+Enter Ghost and Hamlet.
+
+ Ham. Whither wilt thou lead me? Speak! I'll go no further.
+ Ghost. Mark me.
+ Ham. I will.
+ Ghost. My hour is almost come,
+ When I to sulph'rous and tormenting flames
+ Must render up myself.
+ Ham. Alas, poor ghost!
+ Ghost. Pity me not, but lend thy serious hearing
+ To what I shall unfold.
+ Ham. Speak. I am bound to hear.
+ Ghost. So art thou to revenge, when thou shalt hear.
+ Ham. What?
+ Ghost. I am thy father's spirit,
+ Doom'd for a certain term to walk the night,
+ And for the day confin'd to fast in fires,
+ Till the foul crimes done in my days of nature
+ Are burnt and purg'd away. But that I am forbid
+ To tell the secrets of my prison house,
+ I could a tale unfold whose lightest word
+ Would harrow up thy soul, freeze thy young blood,
+ Make thy two eyes, like stars, start from their spheres,
+ Thy knotted and combined locks to part,
+ And each particular hair to stand an end
+ Like quills upon the fretful porpentine.
+ But this eternal blazon must not be
+ To ears of flesh and blood. List, list, O, list!
+ If thou didst ever thy dear father love-
+ Ham. O God!
+ Ghost. Revenge his foul and most unnatural murther.
+ Ham. Murther?
+ Ghost. Murther most foul, as in the best it is;
+ But this most foul, strange, and unnatural.
+ Ham. Haste me to know't, that I, with wings as swift
+ As meditation or the thoughts of love,
+ May sweep to my revenge.
+ Ghost. I find thee apt;
+ And duller shouldst thou be than the fat weed
+ That rots itself in ease on Lethe wharf,
+ Wouldst thou not stir in this. Now, Hamlet, hear.
+ 'Tis given out that, sleeping in my orchard,
+ A serpent stung me. So the whole ear of Denmark
+ Is by a forged process of my death
+ Rankly abus'd. But know, thou noble youth,
+ The serpent that did sting thy father's life
+ Now wears his crown.
+ Ham. O my prophetic soul!
+ My uncle?
+ Ghost. Ay, that incestuous, that adulterate beast,
+ With witchcraft of his wit, with traitorous gifts-
+ O wicked wit and gifts, that have the power
+ So to seduce!- won to his shameful lust
+ The will of my most seeming-virtuous queen.
+ O Hamlet, what a falling-off was there,
+ From me, whose love was of that dignity
+ That it went hand in hand even with the vow
+ I made to her in marriage, and to decline
+ Upon a wretch whose natural gifts were poor
+ To those of mine!
+ But virtue, as it never will be mov'd,
+ Though lewdness court it in a shape of heaven,
+ So lust, though to a radiant angel link'd,
+ Will sate itself in a celestial bed
+ And prey on garbage.
+ But soft! methinks I scent the morning air.
+ Brief let me be. Sleeping within my orchard,
+ My custom always of the afternoon,
+ Upon my secure hour thy uncle stole,
+ With juice of cursed hebona in a vial,
+ And in the porches of my ears did pour
+ The leperous distilment; whose effect
+ Holds such an enmity with blood of man
+ That swift as quicksilverr it courses through
+ The natural gates and alleys of the body,
+ And with a sudden vigour it doth posset
+ And curd, like eager droppings into milk,
+ The thin and wholesome blood. So did it mine;
+ And a most instant tetter bark'd about,
+ Most lazar-like, with vile and loathsome crust
+ All my smooth body.
+ Thus was I, sleeping, by a brother's hand
+ Of life, of crown, of queen, at once dispatch'd;
+ Cut off even in the blossoms of my sin,
+ Unhous'led, disappointed, unanel'd,
+ No reckoning made, but sent to my account
+ With all my imperfections on my head.
+ Ham. O, horrible! O, horrible! most horrible!
+ Ghost. If thou hast nature in thee, bear it not.
+ Let not the royal bed of Denmark be
+ A couch for luxury and damned incest.
+ But, howsoever thou pursuest this act,
+ Taint not thy mind, nor let thy soul contrive
+ Against thy mother aught. Leave her to heaven,
+ And to those thorns that in her bosom lodge
+ To prick and sting her. Fare thee well at once.
+ The glowworm shows the matin to be near
+ And gins to pale his uneffectual fire.
+ Adieu, adieu, adieu! Remember me. Exit.
+ Ham. O all you host of heaven! O earth! What else?
+ And shall I couple hell? Hold, hold, my heart!
+ And you, my sinews, grow not instant old,
+ But bear me stiffly up. Remember thee?
+ Ay, thou poor ghost, while memory holds a seat
+ In this distracted globe. Remember thee?
+ Yea, from the table of my memory
+ I'll wipe away all trivial fond records,
+ All saws of books, all forms, all pressures past
+ That youth and observation copied there,
+ And thy commandment all alone shall live
+ Within the book and volume of my brain,
+ Unmix'd with baser matter. Yes, by heaven!
+ O most pernicious woman!
+ O villain, villain, smiling, damned villain!
+ My tables! Meet it is I set it down
+ That one may smile, and smile, and be a villain;
+ At least I am sure it may be so in Denmark. [Writes.]
+ So, uncle, there you are. Now to my word:
+ It is 'Adieu, adieu! Remember me.'
+ I have sworn't.
+ Hor. (within) My lord, my lord!
+
+ Enter Horatio and Marcellus.
+
+ Mar. Lord Hamlet!
+ Hor. Heaven secure him!
+ Ham. So be it!
+ Mar. Illo, ho, ho, my lord!
+ Ham. Hillo, ho, ho, boy! Come, bird, come.
+ Mar. How is't, my noble lord?
+ Hor. What news, my lord?
+ Mar. O, wonderful!
+ Hor. Good my lord, tell it.
+ Ham. No, you will reveal it.
+ Hor. Not I, my lord, by heaven!
+ Mar. Nor I, my lord.
+ Ham. How say you then? Would heart of man once think it?
+ But you'll be secret?
+ Both. Ay, by heaven, my lord.
+ Ham. There's neer a villain dwelling in all Denmark
+ But he's an arrant knave.
+ Hor. There needs no ghost, my lord, come from the grave
+ To tell us this.
+ Ham. Why, right! You are in the right!
+ And so, without more circumstance at all,
+ I hold it fit that we shake hands and part;
+ You, as your business and desires shall point you,
+ For every man hath business and desire,
+ Such as it is; and for my own poor part,
+ Look you, I'll go pray.
+ Hor. These are but wild and whirling words, my lord.
+ Ham. I am sorry they offend you, heartily;
+ Yes, faith, heartily.
+ Hor. There's no offence, my lord.
+ Ham. Yes, by Saint Patrick, but there is, Horatio,
+ And much offence too. Touching this vision here,
+ It is an honest ghost, that let me tell you.
+ For your desire to know what is between us,
+ O'ermaster't as you may. And now, good friends,
+ As you are friends, scholars, and soldiers,
+ Give me one poor request.
+ Hor. What is't, my lord? We will.
+ Ham. Never make known what you have seen to-night.
+ Both. My lord, we will not.
+ Ham. Nay, but swear't.
+ Hor. In faith,
+ My lord, not I.
+ Mar. Nor I, my lord- in faith.
+ Ham. Upon my sword.
+ Mar. We have sworn, my lord, already.
+ Ham. Indeed, upon my sword, indeed.
+
+ Ghost cries under the stage.
+
+ Ghost. Swear.
+ Ham. Aha boy, say'st thou so? Art thou there, truepenny?
+ Come on! You hear this fellow in the cellarage.
+ Consent to swear.
+ Hor. Propose the oath, my lord.
+ Ham. Never to speak of this that you have seen.
+ Swear by my sword.
+ Ghost. [beneath] Swear.
+ Ham. Hic et ubique? Then we'll shift our ground.
+ Come hither, gentlemen,
+ And lay your hands again upon my sword.
+ Never to speak of this that you have heard:
+ Swear by my sword.
+ Ghost. [beneath] Swear by his sword.
+ Ham. Well said, old mole! Canst work i' th' earth so fast?
+ A worthy pioner! Once more remove, good friends."
+ Hor. O day and night, but this is wondrous strange!
+ Ham. And therefore as a stranger give it welcome.
+ There are more things in heaven and earth, Horatio,
+ Than are dreamt of in your philosophy.
+ But come!
+ Here, as before, never, so help you mercy,
+ How strange or odd soe'er I bear myself
+ (As I perchance hereafter shall think meet
+ To put an antic disposition on),
+ That you, at such times seeing me, never shall,
+ With arms encumb'red thus, or this head-shake,
+ Or by pronouncing of some doubtful phrase,
+ As 'Well, well, we know,' or 'We could, an if we would,'
+ Or 'If we list to speak,' or 'There be, an if they might,'
+ Or such ambiguous giving out, to note
+ That you know aught of me- this is not to do,
+ So grace and mercy at your most need help you,
+ Swear.
+ Ghost. [beneath] Swear.
+ [They swear.]
+ Ham. Rest, rest, perturbed spirit! So, gentlemen,
+ With all my love I do commend me to you;
+ And what so poor a man as Hamlet is
+ May do t' express his love and friending to you,
+ God willing, shall not lack. Let us go in together;
+ And still your fingers on your lips, I pray.
+ The time is out of joint. O cursed spite
+ That ever I was born to set it right!
+ Nay, come, let's go together.
+ Exeunt.
+
+
+
+
+Act II. Scene I.
+Elsinore. A room in the house of Polonius.
+
+Enter Polonius and Reynaldo.
+
+ Pol. Give him this money and these notes, Reynaldo.
+ Rey. I will, my lord.
+ Pol. You shall do marvell's wisely, good Reynaldo,
+ Before You visit him, to make inquire
+ Of his behaviour.
+ Rey. My lord, I did intend it.
+ Pol. Marry, well said, very well said. Look you, sir,
+ Enquire me first what Danskers are in Paris;
+ And how, and who, what means, and where they keep,
+ What company, at what expense; and finding
+ By this encompassment and drift of question
+ That they do know my son, come you more nearer
+ Than your particular demands will touch it.
+ Take you, as 'twere, some distant knowledge of him;
+ As thus, 'I know his father and his friends,
+ And in part him.' Do you mark this, Reynaldo?
+ Rey. Ay, very well, my lord.
+ Pol. 'And in part him, but,' you may say, 'not well.
+ But if't be he I mean, he's very wild
+ Addicted so and so'; and there put on him
+ What forgeries you please; marry, none so rank
+ As may dishonour him- take heed of that;
+ But, sir, such wanton, wild, and usual slips
+ As are companions noted and most known
+ To youth and liberty.
+ Rey. As gaming, my lord.
+ Pol. Ay, or drinking, fencing, swearing, quarrelling,
+ Drabbing. You may go so far.
+ Rey. My lord, that would dishonour him.
+ Pol. Faith, no, as you may season it in the charge.
+ You must not put another scandal on him,
+ That he is open to incontinency.
+ That's not my meaning. But breathe his faults so quaintly
+ That they may seem the taints of liberty,
+ The flash and outbreak of a fiery mind,
+ A savageness in unreclaimed blood,
+ Of general assault.
+ Rey. But, my good lord-
+ Pol. Wherefore should you do this?
+ Rey. Ay, my lord,
+ I would know that.
+ Pol. Marry, sir, here's my drift,
+ And I believe it is a fetch of warrant.
+ You laying these slight sullies on my son
+ As 'twere a thing a little soil'd i' th' working,
+ Mark you,
+ Your party in converse, him you would sound,
+ Having ever seen in the prenominate crimes
+ The youth you breathe of guilty, be assur'd
+ He closes with you in this consequence:
+ 'Good sir,' or so, or 'friend,' or 'gentleman'-
+ According to the phrase or the addition
+ Of man and country-
+ Rey. Very good, my lord.
+ Pol. And then, sir, does 'a this- 'a does- What was I about to say?
+ By the mass, I was about to say something! Where did I leave?
+ Rey. At 'closes in the consequence,' at 'friend or so,' and
+ gentleman.'
+ Pol. At 'closes in the consequence'- Ay, marry!
+ He closes thus: 'I know the gentleman.
+ I saw him yesterday, or t'other day,
+ Or then, or then, with such or such; and, as you say,
+ There was 'a gaming; there o'ertook in's rouse;
+ There falling out at tennis'; or perchance,
+ 'I saw him enter such a house of sale,'
+ Videlicet, a brothel, or so forth.
+ See you now-
+ Your bait of falsehood takes this carp of truth;
+ And thus do we of wisdom and of reach,
+ With windlasses and with assays of bias,
+ By indirections find directions out.
+ So, by my former lecture and advice,
+ Shall you my son. You have me, have you not
+ Rey. My lord, I have.
+ Pol. God b' wi' ye, fare ye well!
+ Rey. Good my lord! [Going.]
+ Pol. Observe his inclination in yourself.
+ Rey. I shall, my lord.
+ Pol. And let him ply his music.
+ Rey. Well, my lord.
+ Pol. Farewell!
+ Exit Reynaldo.
+
+ Enter Ophelia.
+
+ How now, Ophelia? What's the matter?
+ Oph. O my lord, my lord, I have been so affrighted!
+ Pol. With what, i' th' name of God I
+ Oph. My lord, as I was sewing in my closet,
+ Lord Hamlet, with his doublet all unbrac'd,
+ No hat upon his head, his stockings foul'd,
+ Ungart'red, and down-gyved to his ankle;
+ Pale as his shirt, his knees knocking each other,
+ And with a look so piteous in purport
+ As if he had been loosed out of hell
+ To speak of horrors- he comes before me.
+ Pol. Mad for thy love?
+ Oph. My lord, I do not know,
+ But truly I do fear it.
+ Pol. What said he?
+ Oph. He took me by the wrist and held me hard;
+ Then goes he to the length of all his arm,
+ And, with his other hand thus o'er his brow,
+ He falls to such perusal of my face
+ As he would draw it. Long stay'd he so.
+ At last, a little shaking of mine arm,
+ And thrice his head thus waving up and down,
+ He rais'd a sigh so piteous and profound
+ As it did seem to shatter all his bulk
+ And end his being. That done, he lets me go,
+ And with his head over his shoulder turn'd
+ He seem'd to find his way without his eyes,
+ For out o' doors he went without their help
+ And to the last bended their light on me.
+ Pol. Come, go with me. I will go seek the King.
+ This is the very ecstasy of love,
+ Whose violent property fordoes itself
+ And leads the will to desperate undertakings
+ As oft as any passion under heaven
+ That does afflict our natures. I am sorry.
+ What, have you given him any hard words of late?
+ Oph. No, my good lord; but, as you did command,
+ I did repel his letters and denied
+ His access to me.
+ Pol. That hath made him mad.
+ I am sorry that with better heed and judgment
+ I had not quoted him. I fear'd he did but trifle
+ And meant to wrack thee; but beshrew my jealousy!
+ By heaven, it is as proper to our age
+ To cast beyond ourselves in our opinions
+ As it is common for the younger sort
+ To lack discretion. Come, go we to the King.
+ This must be known; which, being kept close, might move
+ More grief to hide than hate to utter love.
+ Come.
+ Exeunt.
+
+Scene II.
+Elsinore. A room in the Castle.
+
+Flourish. [Enter King and Queen, Rosencrantz and Guildenstern, cum aliis.
+
+ King. Welcome, dear Rosencrantz and Guildenstern.
+ Moreover that we much did long to see you,
+ The need we have to use you did provoke
+ Our hasty sending. Something have you heard
+ Of Hamlet's transformation. So I call it,
+ Sith nor th' exterior nor the inward man
+ Resembles that it was. What it should be,
+ More than his father's death, that thus hath put him
+ So much from th' understanding of himself,
+ I cannot dream of. I entreat you both
+ That, being of so young clays brought up with him,
+ And since so neighbour'd to his youth and haviour,
+ That you vouchsafe your rest here in our court
+ Some little time; so by your companies
+ To draw him on to pleasures, and to gather
+ So much as from occasion you may glean,
+ Whether aught to us unknown afflicts him thus
+ That, open'd, lies within our remedy.
+ Queen. Good gentlemen, he hath much talk'd of you,
+ And sure I am two men there are not living
+ To whom he more adheres. If it will please you
+ To show us so much gentry and good will
+ As to expend your time with us awhile
+ For the supply and profit of our hope,
+ Your visitation shall receive such thanks
+ As fits a king's remembrance.
+ Ros. Both your Majesties
+ Might, by the sovereign power you have of us,
+ Put your dread pleasures more into command
+ Than to entreaty.
+ Guil. But we both obey,
+ And here give up ourselves, in the full bent,
+ To lay our service freely at your feet,
+ To be commanded.
+ King. Thanks, Rosencrantz and gentle Guildenstern.
+ Queen. Thanks, Guildenstern and gentle Rosencrantz.
+ And I beseech you instantly to visit
+ My too much changed son.- Go, some of you,
+ And bring these gentlemen where Hamlet is.
+ Guil. Heavens make our presence and our practices
+ Pleasant and helpful to him!
+ Queen. Ay, amen!
+ Exeunt Rosencrantz and Guildenstern, [with some
+ Attendants].
+
+ Enter Polonius.
+
+ Pol. Th' ambassadors from Norway, my good lord,
+ Are joyfully return'd.
+ King. Thou still hast been the father of good news.
+ Pol. Have I, my lord? Assure you, my good liege,
+ I hold my duty as I hold my soul,
+ Both to my God and to my gracious king;
+ And I do think- or else this brain of mine
+ Hunts not the trail of policy so sure
+ As it hath us'd to do- that I have found
+ The very cause of Hamlet's lunacy.
+ King. O, speak of that! That do I long to hear.
+ Pol. Give first admittance to th' ambassadors.
+ My news shall be the fruit to that great feast.
+ King. Thyself do grace to them, and bring them in.
+ [Exit Polonius.]
+ He tells me, my dear Gertrude, he hath found
+ The head and source of all your son's distemper.
+ Queen. I doubt it is no other but the main,
+ His father's death and our o'erhasty marriage.
+ King. Well, we shall sift him.
+
+ Enter Polonius, Voltemand, and Cornelius.
+
+ Welcome, my good friends.
+ Say, Voltemand, what from our brother Norway?
+ Volt. Most fair return of greetings and desires.
+ Upon our first, he sent out to suppress
+ His nephew's levies; which to him appear'd
+ To be a preparation 'gainst the Polack,
+ But better look'd into, he truly found
+ It was against your Highness; whereat griev'd,
+ That so his sickness, age, and impotence
+ Was falsely borne in hand, sends out arrests
+ On Fortinbras; which he, in brief, obeys,
+ Receives rebuke from Norway, and, in fine,
+ Makes vow before his uncle never more
+ To give th' assay of arms against your Majesty.
+ Whereon old Norway, overcome with joy,
+ Gives him three thousand crowns in annual fee
+ And his commission to employ those soldiers,
+ So levied as before, against the Polack;
+ With an entreaty, herein further shown,
+ [Gives a paper.]
+ That it might please you to give quiet pass
+ Through your dominions for this enterprise,
+ On such regards of safety and allowance
+ As therein are set down.
+ King. It likes us well;
+ And at our more consider'd time we'll read,
+ Answer, and think upon this business.
+ Meantime we thank you for your well-took labour.
+ Go to your rest; at night we'll feast together.
+ Most welcome home! Exeunt Ambassadors.
+ Pol. This business is well ended.
+ My liege, and madam, to expostulate
+ What majesty should be, what duty is,
+ Why day is day, night is night, and time is time.
+ Were nothing but to waste night, day, and time.
+ Therefore, since brevity is the soul of wit,
+ And tediousness the limbs and outward flourishes,
+ I will be brief. Your noble son is mad.
+ Mad call I it; for, to define true madness,
+ What is't but to be nothing else but mad?
+ But let that go.
+ Queen. More matter, with less art.
+ Pol. Madam, I swear I use no art at all.
+ That he is mad, 'tis true: 'tis true 'tis pity;
+ And pity 'tis 'tis true. A foolish figure!
+ But farewell it, for I will use no art.
+ Mad let us grant him then. And now remains
+ That we find out the cause of this effect-
+ Or rather say, the cause of this defect,
+ For this effect defective comes by cause.
+ Thus it remains, and the remainder thus.
+ Perpend.
+ I have a daughter (have while she is mine),
+ Who in her duty and obedience, mark,
+ Hath given me this. Now gather, and surmise.
+ [Reads] the letter.
+ 'To the celestial, and my soul's idol, the most beautified
+ Ophelia,'-
+
+ That's an ill phrase, a vile phrase; 'beautified' is a vile
+ phrase.
+ But you shall hear. Thus:
+ [Reads.]
+ 'In her excellent white bosom, these, &c.'
+ Queen. Came this from Hamlet to her?
+ Pol. Good madam, stay awhile. I will be faithful. [Reads.]
+
+ 'Doubt thou the stars are fire;
+ Doubt that the sun doth move;
+ Doubt truth to be a liar;
+ But never doubt I love.
+ 'O dear Ophelia, I am ill at these numbers; I have not art to
+ reckon my groans; but that I love thee best, O most best, believe
+ it. Adieu.
+ 'Thine evermore, most dear lady, whilst this machine is to him,
+ HAMLET.'
+
+ This, in obedience, hath my daughter shown me;
+ And more above, hath his solicitings,
+ As they fell out by time, by means, and place,
+ All given to mine ear.
+ King. But how hath she
+ Receiv'd his love?
+ Pol. What do you think of me?
+ King. As of a man faithful and honourable.
+ Pol. I would fain prove so. But what might you think,
+ When I had seen this hot love on the wing
+ (As I perceiv'd it, I must tell you that,
+ Before my daughter told me), what might you,
+ Or my dear Majesty your queen here, think,
+ If I had play'd the desk or table book,
+ Or given my heart a winking, mute and dumb,
+ Or look'd upon this love with idle sight?
+ What might you think? No, I went round to work
+ And my young mistress thus I did bespeak:
+ 'Lord Hamlet is a prince, out of thy star.
+ This must not be.' And then I prescripts gave her,
+ That she should lock herself from his resort,
+ Admit no messengers, receive no tokens.
+ Which done, she took the fruits of my advice,
+ And he, repulsed, a short tale to make,
+ Fell into a sadness, then into a fast,
+ Thence to a watch, thence into a weakness,
+ Thence to a lightness, and, by this declension,
+ Into the madness wherein now he raves,
+ And all we mourn for.
+ King. Do you think 'tis this?
+ Queen. it may be, very like.
+ Pol. Hath there been such a time- I would fain know that-
+ That I have Positively said ''Tis so,'
+ When it prov'd otherwise.?
+ King. Not that I know.
+ Pol. [points to his head and shoulder] Take this from this, if this
+ be otherwise.
+ If circumstances lead me, I will find
+ Where truth is hid, though it were hid indeed
+ Within the centre.
+ King. How may we try it further?
+ Pol. You know sometimes he walks four hours together
+ Here in the lobby.
+ Queen. So he does indeed.
+ Pol. At such a time I'll loose my daughter to him.
+ Be you and I behind an arras then.
+ Mark the encounter. If he love her not,
+ And he not from his reason fall'n thereon
+ Let me be no assistant for a state,
+ But keep a farm and carters.
+ King. We will try it.
+
+ Enter Hamlet, reading on a book.
+
+ Queen. But look where sadly the poor wretch comes reading.
+ Pol. Away, I do beseech you, both away
+ I'll board him presently. O, give me leave.
+ Exeunt King and Queen, [with Attendants].
+ How does my good Lord Hamlet?
+ Ham. Well, God-a-mercy.
+ Pol. Do you know me, my lord?
+ Ham. Excellent well. You are a fishmonger.
+ Pol. Not I, my lord.
+ Ham. Then I would you were so honest a man.
+ Pol. Honest, my lord?
+ Ham. Ay, sir. To be honest, as this world goes, is to be one man
+ pick'd out of ten thousand.
+ Pol. That's very true, my lord.
+ Ham. For if the sun breed maggots in a dead dog, being a god
+ kissing carrion- Have you a daughter?
+ Pol. I have, my lord.
+ Ham. Let her not walk i' th' sun. Conception is a blessing, but not
+ as your daughter may conceive. Friend, look to't.
+ Pol. [aside] How say you by that? Still harping on my daughter. Yet
+ he knew me not at first. He said I was a fishmonger. He is far
+ gone, far gone! And truly in my youth I suff'red much extremity
+ for love- very near this. I'll speak to him again.- What do you
+ read, my lord?
+ Ham. Words, words, words.
+ Pol. What is the matter, my lord?
+ Ham. Between who?
+ Pol. I mean, the matter that you read, my lord.
+ Ham. Slanders, sir; for the satirical rogue says here that old men
+ have grey beards; that their faces are wrinkled; their eyes
+ purging thick amber and plum-tree gum; and that they have a
+ plentiful lack of wit, together with most weak hams. All which,
+ sir, though I most powerfully and potently believe, yet I hold it
+ not honesty to have it thus set down; for you yourself, sir,
+ should be old as I am if, like a crab, you could go backward.
+ Pol. [aside] Though this be madness, yet there is a method in't.-
+ Will You walk out of the air, my lord?
+ Ham. Into my grave?
+ Pol. Indeed, that is out o' th' air. [Aside] How pregnant sometimes
+ his replies are! a happiness that often madness hits on, which
+ reason and sanity could not so prosperously be delivered of. I
+ will leave him and suddenly contrive the means of meeting between
+ him and my daughter.- My honourable lord, I will most humbly take
+ my leave of you.
+ Ham. You cannot, sir, take from me anything that I will more
+ willingly part withal- except my life, except my life, except my
+ life,
+
+ Enter Rosencrantz and Guildenstern.
+
+ Pol. Fare you well, my lord.
+ Ham. These tedious old fools!
+ Pol. You go to seek the Lord Hamlet. There he is.
+ Ros. [to Polonius] God save you, sir!
+ Exit [Polonius].
+ Guil. My honour'd lord!
+ Ros. My most dear lord!
+ Ham. My excellent good friends! How dost thou, Guildenstern? Ah,
+ Rosencrantz! Good lads, how do ye both?
+ Ros. As the indifferent children of the earth.
+ Guil. Happy in that we are not over-happy.
+ On Fortune's cap we are not the very button.
+ Ham. Nor the soles of her shoe?
+ Ros. Neither, my lord.
+ Ham. Then you live about her waist, or in the middle of her
+ favours?
+ Guil. Faith, her privates we.
+ Ham. In the secret parts of Fortune? O! most true! she is a
+ strumpet. What news ?
+ Ros. None, my lord, but that the world's grown honest.
+ Ham. Then is doomsday near! But your news is not true. Let me
+ question more in particular. What have you, my good friends,
+ deserved at the hands of Fortune that she sends you to prison
+ hither?
+ Guil. Prison, my lord?
+ Ham. Denmark's a prison.
+ Ros. Then is the world one.
+ Ham. A goodly one; in which there are many confines, wards, and
+ dungeons, Denmark being one o' th' worst.
+ Ros. We think not so, my lord.
+ Ham. Why, then 'tis none to you; for there is nothing either good
+ or bad but thinking makes it so. To me it is a prison.
+ Ros. Why, then your ambition makes it one. 'Tis too narrow for your
+ mind.
+ Ham. O God, I could be bounded in a nutshell and count myself a
+ king of infinite space, were it not that I have bad dreams.
+ Guil. Which dreams indeed are ambition; for the very substance of
+ the ambitious is merely the shadow of a dream.
+ Ham. A dream itself is but a shadow.
+ Ros. Truly, and I hold ambition of so airy and light a quality that
+ it is but a shadow's shadow.
+ Ham. Then are our beggars bodies, and our monarchs and outstretch'd
+ heroes the beggars' shadows. Shall we to th' court? for, by my
+ fay, I cannot reason.
+ Both. We'll wait upon you.
+ Ham. No such matter! I will not sort you with the rest of my
+ servants; for, to speak to you like an honest man, I am most
+ dreadfully attended. But in the beaten way of friendship, what
+ make you at Elsinore?
+ Ros. To visit you, my lord; no other occasion.
+ Ham. Beggar that I am, I am even poor in thanks; but I thank you;
+ and sure, dear friends, my thanks are too dear a halfpenny. Were
+ you not sent for? Is it your own inclining? Is it a free
+ visitation? Come, deal justly with me. Come, come! Nay, speak.
+ Guil. What should we say, my lord?
+ Ham. Why, anything- but to th' purpose. You were sent for; and
+ there is a kind of confession in your looks, which your modesties
+ have not craft enough to colour. I know the good King and Queen
+ have sent for you.
+ Ros. To what end, my lord?
+ Ham. That you must teach me. But let me conjure you by the rights
+ of our fellowship, by the consonancy of our youth, by the
+ obligation of our ever-preserved love, and by what more dear a
+ better proposer could charge you withal, be even and direct with
+ me, whether you were sent for or no.
+ Ros. [aside to Guildenstern] What say you?
+ Ham. [aside] Nay then, I have an eye of you.- If you love me, hold
+ not off.
+ Guil. My lord, we were sent for.
+ Ham. I will tell you why. So shall my anticipation prevent your
+ discovery, and your secrecy to the King and Queen moult no
+ feather. I have of late- but wherefore I know not- lost all my
+ mirth, forgone all custom of exercises; and indeed, it goes so
+ heavily with my disposition that this goodly frame, the earth,
+ seems to me a sterile promontory; this most excellent canopy, the
+ air, look you, this brave o'erhanging firmament, this majestical
+ roof fretted with golden fire- why, it appeareth no other thing
+ to me than a foul and pestilent congregation of vapours. What a
+ piece of work is a man! how noble in reason! how infinite in
+ faculties! in form and moving how express and admirable! in
+ action how like an angel! in apprehension how like a god! the
+ beauty of the world, the paragon of animals! And yet to me what
+ is this quintessence of dust? Man delights not me- no, nor woman
+ neither, though by your smiling you seem to say so.
+ Ros. My lord, there was no such stuff in my thoughts.
+ Ham. Why did you laugh then, when I said 'Man delights not me'?
+ Ros. To think, my lord, if you delight not in man, what lenten
+ entertainment the players shall receive from you. We coted them
+ on the way, and hither are they coming to offer you service.
+ Ham. He that plays the king shall be welcome- his Majesty shall
+ have tribute of me; the adventurous knight shall use his foil and
+ target; the lover shall not sigh gratis; the humorous man shall
+ end his part in peace; the clown shall make those laugh whose
+ lungs are tickle o' th' sere; and the lady shall say her mind
+ freely, or the blank verse shall halt fort. What players are
+ they?
+ Ros. Even those you were wont to take such delight in, the
+ tragedians of the city.
+ Ham. How chances it they travel? Their residence, both in
+ reputation and profit, was better both ways.
+ Ros. I think their inhibition comes by the means of the late
+ innovation.
+ Ham. Do they hold the same estimation they did when I was in the
+ city? Are they so follow'd?
+ Ros. No indeed are they not.
+ Ham. How comes it? Do they grow rusty?
+ Ros. Nay, their endeavour keeps in the wonted pace; but there is,
+ sir, an eyrie of children, little eyases, that cry out on the top
+ of question and are most tyrannically clapp'd fort. These are now
+ the fashion, and so berattle the common stages (so they call
+ them) that many wearing rapiers are afraid of goosequills and
+ dare scarce come thither.
+ Ham. What, are they children? Who maintains 'em? How are they
+ escoted? Will they pursue the quality no longer than they can
+ sing? Will they not say afterwards, if they should grow
+ themselves to common players (as it is most like, if their means
+ are no better), their writers do them wrong to make them exclaim
+ against their own succession.
+ Ros. Faith, there has been much to do on both sides; and the nation
+ holds it no sin to tarre them to controversy. There was, for a
+ while, no money bid for argument unless the poet and the player
+ went to cuffs in the question.
+ Ham. Is't possible?
+ Guil. O, there has been much throwing about of brains.
+ Ham. Do the boys carry it away?
+ Ros. Ay, that they do, my lord- Hercules and his load too.
+ Ham. It is not very strange; for my uncle is King of Denmark, and
+ those that would make mows at him while my father lived give
+ twenty, forty, fifty, a hundred ducats apiece for his picture in
+ little. 'Sblood, there is something in this more than natural, if
+ philosophy could find it out.
+
+ Flourish for the Players.
+
+ Guil. There are the players.
+ Ham. Gentlemen, you are welcome to Elsinore. Your hands, come! Th'
+ appurtenance of welcome is fashion and ceremony. Let me comply
+ with you in this garb, lest my extent to the players (which I
+ tell you must show fairly outwards) should more appear like
+ entertainment than yours. You are welcome. But my uncle-father
+ and aunt-mother are deceiv'd.
+ Guil. In what, my dear lord?
+ Ham. I am but mad north-north-west. When the wind is southerly I
+ know a hawk from a handsaw.
+
+ Enter Polonius.
+
+ Pol. Well be with you, gentlemen!
+ Ham. Hark you, Guildenstern- and you too- at each ear a hearer!
+ That great baby you see there is not yet out of his swaddling
+ clouts.
+ Ros. Happily he's the second time come to them; for they say an old
+ man is twice a child.
+ Ham. I will prophesy he comes to tell me of the players. Mark it.-
+ You say right, sir; a Monday morning; twas so indeed.
+ Pol. My lord, I have news to tell you.
+ Ham. My lord, I have news to tell you. When Roscius was an actor in
+ Rome-
+ Pol. The actors are come hither, my lord.
+ Ham. Buzz, buzz!
+ Pol. Upon my honour-
+ Ham. Then came each actor on his ass-
+ Pol. The best actors in the world, either for tragedy, comedy,
+ history, pastoral, pastoral-comical, historical-pastoral,
+ tragical-historical, tragical-comical-historical-pastoral; scene
+ individable, or poem unlimited. Seneca cannot be too heavy, nor
+ Plautus too light. For the law of writ and the liberty, these are
+ the only men.
+ Ham. O Jephthah, judge of Israel, what a treasure hadst thou!
+ Pol. What treasure had he, my lord?
+ Ham. Why,
+
+ 'One fair daughter, and no more,
+ The which he loved passing well.'
+
+ Pol. [aside] Still on my daughter.
+ Ham. Am I not i' th' right, old Jephthah?
+ Pol. If you call me Jephthah, my lord, I have a daughter that I
+ love passing well.
+ Ham. Nay, that follows not.
+ Pol. What follows then, my lord?
+ Ham. Why,
+
+ 'As by lot, God wot,'
+
+ and then, you know,
+
+ 'It came to pass, as most like it was.'
+
+ The first row of the pious chanson will show you more; for look
+ where my abridgment comes.
+
+ Enter four or five Players.
+
+ You are welcome, masters; welcome, all.- I am glad to see thee
+ well.- Welcome, good friends.- O, my old friend? Why, thy face is
+ valanc'd since I saw thee last. Com'st' thou to' beard me in
+ Denmark?- What, my young lady and mistress? By'r Lady, your
+ ladyship is nearer to heaven than when I saw you last by the
+ altitude of a chopine. Pray God your voice, like a piece of
+ uncurrent gold, be not crack'd within the ring.- Masters, you are
+ all welcome. We'll e'en to't like French falconers, fly at
+ anything we see. We'll have a speech straight. Come, give us a
+ taste of your quality. Come, a passionate speech.
+ 1. Play. What speech, my good lord?
+ Ham. I heard thee speak me a speech once, but it was never acted;
+ or if it was, not above once; for the play, I remember, pleas'd
+ not the million, 'twas caviary to the general; but it was (as I
+ receiv'd it, and others, whose judgments in such matters cried in
+ the top of mine) an excellent play, well digested in the scenes,
+ set down with as much modesty as cunning. I remember one said
+ there were no sallets in the lines to make the matter savoury,
+ nor no matter in the phrase that might indict the author of
+ affectation; but call'd it an honest method, as wholesome as
+ sweet, and by very much more handsome than fine. One speech in't
+ I chiefly lov'd. 'Twas AEneas' tale to Dido, and thereabout of it
+ especially where he speaks of Priam's slaughter. If it live in
+ your memory, begin at this line- let me see, let me see:
+
+ 'The rugged Pyrrhus, like th' Hyrcanian beast-'
+
+ 'Tis not so; it begins with Pyrrhus:
+
+ 'The rugged Pyrrhus, he whose sable arms,
+ Black as his purpose, did the night resemble
+ When he lay couched in the ominous horse,
+ Hath now this dread and black complexion smear'd
+ With heraldry more dismal. Head to foot
+ Now is be total gules, horridly trick'd
+ With blood of fathers, mothers, daughters, sons,
+ Bak'd and impasted with the parching streets,
+ That lend a tyrannous and a damned light
+ To their lord's murther. Roasted in wrath and fire,
+ And thus o'ersized with coagulate gore,
+ With eyes like carbuncles, the hellish Pyrrhus
+ Old grandsire Priam seeks.'
+
+ So, proceed you.
+ Pol. Fore God, my lord, well spoken, with good accent and good
+ discretion.
+
+ 1. Play. 'Anon he finds him,
+ Striking too short at Greeks. His antique sword,
+ Rebellious to his arm, lies where it falls,
+ Repugnant to command. Unequal match'd,
+ Pyrrhus at Priam drives, in rage strikes wide;
+ But with the whiff and wind of his fell sword
+ Th' unnerved father falls. Then senseless Ilium,
+ Seeming to feel this blow, with flaming top
+ Stoops to his base, and with a hideous crash
+ Takes prisoner Pyrrhus' ear. For lo! his sword,
+ Which was declining on the milky head
+ Of reverend Priam, seem'd i' th' air to stick.
+ So, as a painted tyrant, Pyrrhus stood,
+ And, like a neutral to his will and matter,
+ Did nothing.
+ But, as we often see, against some storm,
+ A silence in the heavens, the rack stand still,
+ The bold winds speechless, and the orb below
+ As hush as death- anon the dreadful thunder
+ Doth rend the region; so, after Pyrrhus' pause,
+ Aroused vengeance sets him new awork;
+ And never did the Cyclops' hammers fall
+ On Mars's armour, forg'd for proof eterne,
+ With less remorse than Pyrrhus' bleeding sword
+ Now falls on Priam.
+ Out, out, thou strumpet Fortune! All you gods,
+ In general synod take away her power;
+ Break all the spokes and fellies from her wheel,
+ And bowl the round nave down the hill of heaven,
+ As low as to the fiends!
+
+ Pol. This is too long.
+ Ham. It shall to the barber's, with your beard.- Prithee say on.
+ He's for a jig or a tale of bawdry, or he sleeps. Say on; come to
+ Hecuba.
+
+ 1. Play. 'But who, O who, had seen the mobled queen-'
+
+ Ham. 'The mobled queen'?
+ Pol. That's good! 'Mobled queen' is good.
+
+ 1. Play. 'Run barefoot up and down, threat'ning the flames
+ With bisson rheum; a clout upon that head
+ Where late the diadem stood, and for a robe,
+ About her lank and all o'erteemed loins,
+ A blanket, in the alarm of fear caught up-
+ Who this had seen, with tongue in venom steep'd
+ 'Gainst Fortune's state would treason have pronounc'd.
+ But if the gods themselves did see her then,
+ When she saw Pyrrhus make malicious sport
+ In Mincing with his sword her husband's limbs,
+ The instant burst of clamour that she made
+ (Unless things mortal move them not at all)
+ Would have made milch the burning eyes of heaven
+ And passion in the gods.'
+
+ Pol. Look, whe'r he has not turn'd his colour, and has tears in's
+ eyes. Prithee no more!
+ Ham. 'Tis well. I'll have thee speak out the rest of this soon.-
+ Good my lord, will you see the players well bestow'd? Do you
+ hear? Let them be well us'd; for they are the abstract and brief
+ chronicles of the time. After your death you were better have a
+ bad epitaph than their ill report while you live.
+ Pol. My lord, I will use them according to their desert.
+ Ham. God's bodykins, man, much better! Use every man after his
+ desert, and who should scape whipping? Use them after your own
+ honour and dignity. The less they deserve, the more merit is in
+ your bounty. Take them in.
+ Pol. Come, sirs.
+ Ham. Follow him, friends. We'll hear a play to-morrow.
+ Exeunt Polonius and Players [except the First].
+ Dost thou hear me, old friend? Can you play 'The Murther of
+ Gonzago'?
+ 1. Play. Ay, my lord.
+ Ham. We'll ha't to-morrow night. You could, for a need, study a
+ speech of some dozen or sixteen lines which I would set down and
+ insert in't, could you not?
+ 1. Play. Ay, my lord.
+ Ham. Very well. Follow that lord- and look you mock him not.
+ [Exit First Player.]
+ My good friends, I'll leave you till night. You are welcome to
+ Elsinore.
+ Ros. Good my lord!
+ Ham. Ay, so, God b' wi' ye!
+ [Exeunt Rosencrantz and Guildenstern
+ Now I am alone.
+ O what a rogue and peasant slave am I!
+ Is it not monstrous that this player here,
+ But in a fiction, in a dream of passion,
+ Could force his soul so to his own conceit
+ That, from her working, all his visage wann'd,
+ Tears in his eyes, distraction in's aspect,
+ A broken voice, and his whole function suiting
+ With forms to his conceit? And all for nothing!
+ For Hecuba!
+ What's Hecuba to him, or he to Hecuba,
+ That he should weep for her? What would he do,
+ Had he the motive and the cue for passion
+ That I have? He would drown the stage with tears
+ And cleave the general ear with horrid speech;
+ Make mad the guilty and appal the free,
+ Confound the ignorant, and amaze indeed
+ The very faculties of eyes and ears.
+ Yet I,
+ A dull and muddy-mettled rascal, peak
+ Like John-a-dreams, unpregnant of my cause,
+ And can say nothing! No, not for a king,
+ Upon whose property and most dear life
+ A damn'd defeat was made. Am I a coward?
+ Who calls me villain? breaks my pate across?
+ Plucks off my beard and blows it in my face?
+ Tweaks me by th' nose? gives me the lie i' th' throat
+ As deep as to the lungs? Who does me this, ha?
+ 'Swounds, I should take it! for it cannot be
+ But I am pigeon-liver'd and lack gall
+ To make oppression bitter, or ere this
+ I should have fatted all the region kites
+ With this slave's offal. Bloody bawdy villain!
+ Remorseless, treacherous, lecherous, kindless villain!
+ O, vengeance!
+ Why, what an ass am I! This is most brave,
+ That I, the son of a dear father murther'd,
+ Prompted to my revenge by heaven and hell,
+ Must (like a whore) unpack my heart with words
+ And fall a-cursing like a very drab,
+ A scullion!
+ Fie upon't! foh! About, my brain! Hum, I have heard
+ That guilty creatures, sitting at a play,
+ Have by the very cunning of the scene
+ Been struck so to the soul that presently
+ They have proclaim'd their malefactions;
+ For murther, though it have no tongue, will speak
+ With most miraculous organ, I'll have these Players
+ Play something like the murther of my father
+ Before mine uncle. I'll observe his looks;
+ I'll tent him to the quick. If he but blench,
+ I know my course. The spirit that I have seen
+ May be a devil; and the devil hath power
+ T' assume a pleasing shape; yea, and perhaps
+ Out of my weakness and my melancholy,
+ As he is very potent with such spirits,
+ Abuses me to damn me. I'll have grounds
+ More relative than this. The play's the thing
+ Wherein I'll catch the conscience of the King. Exit.
+
+
+
+
+
+ACT III. Scene I.
+Elsinore. A room in the Castle.
+
+Enter King, Queen, Polonius, Ophelia, Rosencrantz, Guildenstern, and Lords.
+
+ King. And can you by no drift of circumstance
+ Get from him why he puts on this confusion,
+ Grating so harshly all his days of quiet
+ With turbulent and dangerous lunacy?
+ Ros. He does confess he feels himself distracted,
+ But from what cause he will by no means speak.
+ Guil. Nor do we find him forward to be sounded,
+ But with a crafty madness keeps aloof
+ When we would bring him on to some confession
+ Of his true state.
+ Queen. Did he receive you well?
+ Ros. Most like a gentleman.
+ Guil. But with much forcing of his disposition.
+ Ros. Niggard of question, but of our demands
+ Most free in his reply.
+ Queen. Did you assay him
+ To any pastime?
+ Ros. Madam, it so fell out that certain players
+ We o'erraught on the way. Of these we told him,
+ And there did seem in him a kind of joy
+ To hear of it. They are here about the court,
+ And, as I think, they have already order
+ This night to play before him.
+ Pol. 'Tis most true;
+ And he beseech'd me to entreat your Majesties
+ To hear and see the matter.
+ King. With all my heart, and it doth much content me
+ To hear him so inclin'd.
+ Good gentlemen, give him a further edge
+ And drive his purpose on to these delights.
+ Ros. We shall, my lord.
+ Exeunt Rosencrantz and Guildenstern.
+ King. Sweet Gertrude, leave us too;
+ For we have closely sent for Hamlet hither,
+ That he, as 'twere by accident, may here
+ Affront Ophelia.
+ Her father and myself (lawful espials)
+ Will so bestow ourselves that, seeing unseen,
+ We may of their encounter frankly judge
+ And gather by him, as he is behav'd,
+ If't be th' affliction of his love, or no,
+ That thus he suffers for.
+ Queen. I shall obey you;
+ And for your part, Ophelia, I do wish
+ That your good beauties be the happy cause
+ Of Hamlet's wildness. So shall I hope your virtues
+ Will bring him to his wonted way again,
+ To both your honours.
+ Oph. Madam, I wish it may.
+ [Exit Queen.]
+ Pol. Ophelia, walk you here.- Gracious, so please you,
+ We will bestow ourselves.- [To Ophelia] Read on this book,
+ That show of such an exercise may colour
+ Your loneliness.- We are oft to blame in this,
+ 'Tis too much prov'd, that with devotion's visage
+ And pious action we do sugar o'er
+ The Devil himself.
+ King. [aside] O, 'tis too true!
+ How smart a lash that speech doth give my conscience!
+ The harlot's cheek, beautied with plast'ring art,
+ Is not more ugly to the thing that helps it
+ Than is my deed to my most painted word.
+ O heavy burthen!
+ Pol. I hear him coming. Let's withdraw, my lord.
+ Exeunt King and Polonius].
+
+ Enter Hamlet.
+
+ Ham. To be, or not to be- that is the question:
+ Whether 'tis nobler in the mind to suffer
+ The slings and arrows of outrageous fortune
+ Or to take arms against a sea of troubles,
+ And by opposing end them. To die- to sleep-
+ No more; and by a sleep to say we end
+ The heartache, and the thousand natural shocks
+ That flesh is heir to. 'Tis a consummation
+ Devoutly to be wish'd. To die- to sleep.
+ To sleep- perchance to dream: ay, there's the rub!
+ For in that sleep of death what dreams may come
+ When we have shuffled off this mortal coil,
+ Must give us pause. There's the respect
+ That makes calamity of so long life.
+ For who would bear the whips and scorns of time,
+ Th' oppressor's wrong, the proud man's contumely,
+ The pangs of despis'd love, the law's delay,
+ The insolence of office, and the spurns
+ That patient merit of th' unworthy takes,
+ When he himself might his quietus make
+ With a bare bodkin? Who would these fardels bear,
+ To grunt and sweat under a weary life,
+ But that the dread of something after death-
+ The undiscover'd country, from whose bourn
+ No traveller returns- puzzles the will,
+ And makes us rather bear those ills we have
+ Than fly to others that we know not of?
+ Thus conscience does make cowards of us all,
+ And thus the native hue of resolution
+ Is sicklied o'er with the pale cast of thought,
+ And enterprises of great pith and moment
+ With this regard their currents turn awry
+ And lose the name of action.- Soft you now!
+ The fair Ophelia!- Nymph, in thy orisons
+ Be all my sins rememb'red.
+ Oph. Good my lord,
+ How does your honour for this many a day?
+ Ham. I humbly thank you; well, well, well.
+ Oph. My lord, I have remembrances of yours
+ That I have longed long to re-deliver.
+ I pray you, now receive them.
+ Ham. No, not I!
+ I never gave you aught.
+ Oph. My honour'd lord, you know right well you did,
+ And with them words of so sweet breath compos'd
+ As made the things more rich. Their perfume lost,
+ Take these again; for to the noble mind
+ Rich gifts wax poor when givers prove unkind.
+ There, my lord.
+ Ham. Ha, ha! Are you honest?
+ Oph. My lord?
+ Ham. Are you fair?
+ Oph. What means your lordship?
+ Ham. That if you be honest and fair, your honesty should admit no
+ discourse to your beauty.
+ Oph. Could beauty, my lord, have better commerce than with honesty?
+ Ham. Ay, truly; for the power of beauty will sooner transform
+ honesty from what it is to a bawd than the force of honesty can
+ translate beauty into his likeness. This was sometime a paradox,
+ but now the time gives it proof. I did love you once.
+ Oph. Indeed, my lord, you made me believe so.
+ Ham. You should not have believ'd me; for virtue cannot so
+ inoculate our old stock but we shall relish of it. I loved you
+ not.
+ Oph. I was the more deceived.
+ Ham. Get thee to a nunnery! Why wouldst thou be a breeder of
+ sinners? I am myself indifferent honest, but yet I could accuse
+ me of such things that it were better my mother had not borne me.
+ I am very proud, revengeful, ambitious; with more offences at my
+ beck than I have thoughts to put them in, imagination to give
+ them shape, or time to act them in. What should such fellows as I
+ do, crawling between earth and heaven? We are arrant knaves all;
+ believe none of us. Go thy ways to a nunnery. Where's your
+ father?
+ Oph. At home, my lord.
+ Ham. Let the doors be shut upon him, that he may play the fool
+ nowhere but in's own house. Farewell.
+ Oph. O, help him, you sweet heavens!
+ Ham. If thou dost marry, I'll give thee this plague for thy dowry:
+ be thou as chaste as ice, as pure as snow, thou shalt not escape
+ calumny. Get thee to a nunnery. Go, farewell. Or if thou wilt
+ needs marry, marry a fool; for wise men know well enough what
+ monsters you make of them. To a nunnery, go; and quickly too.
+ Farewell.
+ Oph. O heavenly powers, restore him!
+ Ham. I have heard of your paintings too, well enough. God hath
+ given you one face, and you make yourselves another. You jig, you
+ amble, and you lisp; you nickname God's creatures and make your
+ wantonness your ignorance. Go to, I'll no more on't! it hath made
+ me mad. I say, we will have no moe marriages. Those that are
+ married already- all but one- shall live; the rest shall keep as
+ they are. To a nunnery, go. Exit.
+ Oph. O, what a noble mind is here o'erthrown!
+ The courtier's, scholar's, soldier's, eye, tongue, sword,
+ Th' expectancy and rose of the fair state,
+ The glass of fashion and the mould of form,
+ Th' observ'd of all observers- quite, quite down!
+ And I, of ladies most deject and wretched,
+ That suck'd the honey of his music vows,
+ Now see that noble and most sovereign reason,
+ Like sweet bells jangled, out of tune and harsh;
+ That unmatch'd form and feature of blown youth
+ Blasted with ecstasy. O, woe is me
+ T' have seen what I have seen, see what I see!
+
+ Enter King and Polonius.
+
+ King. Love? his affections do not that way tend;
+ Nor what he spake, though it lack'd form a little,
+ Was not like madness. There's something in his soul
+ O'er which his melancholy sits on brood;
+ And I do doubt the hatch and the disclose
+ Will be some danger; which for to prevent,
+ I have in quick determination
+ Thus set it down: he shall with speed to England
+ For the demand of our neglected tribute.
+ Haply the seas, and countries different,
+ With variable objects, shall expel
+ This something-settled matter in his heart,
+ Whereon his brains still beating puts him thus
+ From fashion of himself. What think you on't?
+ Pol. It shall do well. But yet do I believe
+ The origin and commencement of his grief
+ Sprung from neglected love.- How now, Ophelia?
+ You need not tell us what Lord Hamlet said.
+ We heard it all.- My lord, do as you please;
+ But if you hold it fit, after the play
+ Let his queen mother all alone entreat him
+ To show his grief. Let her be round with him;
+ And I'll be plac'd so please you, in the ear
+ Of all their conference. If she find him not,
+ To England send him; or confine him where
+ Your wisdom best shall think.
+ King. It shall be so.
+ Madness in great ones must not unwatch'd go. Exeunt.
+
+
+
+
+Scene II.
+Elsinore. hall in the Castle.
+
+Enter Hamlet and three of the Players.
+
+ Ham. Speak the speech, I pray you, as I pronounc'd it to you,
+ trippingly on the tongue. But if you mouth it, as many of our
+ players do, I had as live the town crier spoke my lines. Nor do
+ not saw the air too much with your hand, thus, but use all
+ gently; for in the very torrent, tempest, and (as I may say)
+ whirlwind of your passion, you must acquire and beget a
+ temperance that may give it smoothness. O, it offends me to the
+ soul to hear a robustious periwig-pated fellow tear a passion to
+ tatters, to very rags, to split the cars of the groundlings, who
+ (for the most part) are capable of nothing but inexplicable dumb
+ shows and noise. I would have such a fellow whipp'd for o'erdoing
+ Termagant. It out-herods Herod. Pray you avoid it.
+ Player. I warrant your honour.
+ Ham. Be not too tame neither; but let your own discretion be your
+ tutor. Suit the action to the word, the word to the action; with
+ this special observance, that you o'erstep not the modesty of
+ nature: for anything so overdone is from the purpose of playing,
+ whose end, both at the first and now, was and is, to hold, as
+ 'twere, the mirror up to nature; to show Virtue her own feature,
+ scorn her own image, and the very age and body of the time his
+ form and pressure. Now this overdone, or come tardy off, though
+ it make the unskilful laugh, cannot but make the judicious
+ grieve; the censure of the which one must in your allowance
+ o'erweigh a whole theatre of others. O, there be players that I
+ have seen play, and heard others praise, and that highly (not to
+ speak it profanely), that, neither having the accent of
+ Christians, nor the gait of Christian, pagan, nor man, have so
+ strutted and bellowed that I have thought some of Nature's
+ journeymen had made men, and not made them well, they imitated
+ humanity so abominably.
+ Player. I hope we have reform'd that indifferently with us, sir.
+ Ham. O, reform it altogether! And let those that play your clowns
+ speak no more than is set down for them. For there be of them
+ that will themselves laugh, to set on some quantity of barren
+ spectators to laugh too, though in the mean time some necessary
+ question of the play be then to be considered. That's villanous
+ and shows a most pitiful ambition in the fool that uses it. Go
+ make you ready.
+ Exeunt Players.
+
+ Enter Polonius, Rosencrantz, and Guildenstern.
+
+ How now, my lord? Will the King hear this piece of work?
+ Pol. And the Queen too, and that presently.
+ Ham. Bid the players make haste, [Exit Polonius.] Will you two
+ help to hasten them?
+ Both. We will, my lord. Exeunt they two.
+ Ham. What, ho, Horatio!
+
+ Enter Horatio.
+
+ Hor. Here, sweet lord, at your service.
+ Ham. Horatio, thou art e'en as just a man
+ As e'er my conversation cop'd withal.
+ Hor. O, my dear lord!
+ Ham. Nay, do not think I flatter;
+ For what advancement may I hope from thee,
+ That no revenue hast but thy good spirits
+ To feed and clothe thee? Why should the poor be flatter'd?
+ No, let the candied tongue lick absurd pomp,
+ And crook the pregnant hinges of the knee
+ Where thrift may follow fawning. Dost thou hear?
+ Since my dear soul was mistress of her choice
+ And could of men distinguish, her election
+ Hath scald thee for herself. For thou hast been
+ As one, in suff'ring all, that suffers nothing;
+ A man that Fortune's buffets and rewards
+ Hast ta'en with equal thanks; and blest are those
+ Whose blood and judgment are so well commingled
+ That they are not a pipe for Fortune's finger
+ To sound what stop she please. Give me that man
+ That is not passion's slave, and I will wear him
+ In my heart's core, ay, in my heart of heart,
+ As I do thee. Something too much of this I
+ There is a play to-night before the King.
+ One scene of it comes near the circumstance,
+ Which I have told thee, of my father's death.
+ I prithee, when thou seest that act afoot,
+ Even with the very comment of thy soul
+ Observe my uncle. If his occulted guilt
+ Do not itself unkennel in one speech,
+ It is a damned ghost that we have seen,
+ And my imaginations are as foul
+ As Vulcan's stithy. Give him heedful note;
+ For I mine eyes will rivet to his face,
+ And after we will both our judgments join
+ In censure of his seeming.
+ Hor. Well, my lord.
+ If he steal aught the whilst this play is playing,
+ And scape detecting, I will pay the theft.
+
+ Sound a flourish. [Enter Trumpets and Kettledrums. Danish
+ march. [Enter King, Queen, Polonius, Ophelia, Rosencrantz,
+ Guildenstern, and other Lords attendant, with the Guard
+ carrying torches.
+
+ Ham. They are coming to the play. I must be idle.
+ Get you a place.
+ King. How fares our cousin Hamlet?
+ Ham. Excellent, i' faith; of the chameleon's dish. I eat the air,
+ promise-cramm'd. You cannot feed capons so.
+ King. I have nothing with this answer, Hamlet. These words are not
+ mine.
+ Ham. No, nor mine now. [To Polonius] My lord, you play'd once
+ i' th' university, you say?
+ Pol. That did I, my lord, and was accounted a good actor.
+ Ham. What did you enact?
+ Pol. I did enact Julius Caesar; I was kill'd i' th' Capitol; Brutus
+ kill'd me.
+ Ham. It was a brute part of him to kill so capital a calf there. Be
+ the players ready.
+ Ros. Ay, my lord. They stay upon your patience.
+ Queen. Come hither, my dear Hamlet, sit by me.
+ Ham. No, good mother. Here's metal more attractive.
+ Pol. [to the King] O, ho! do you mark that?
+ Ham. Lady, shall I lie in your lap?
+ [Sits down at Ophelia's feet.]
+ Oph. No, my lord.
+ Ham. I mean, my head upon your lap?
+ Oph. Ay, my lord.
+ Ham. Do you think I meant country matters?
+ Oph. I think nothing, my lord.
+ Ham. That's a fair thought to lie between maids' legs.
+ Oph. What is, my lord?
+ Ham. Nothing.
+ Oph. You are merry, my lord.
+ Ham. Who, I?
+ Oph. Ay, my lord.
+ Ham. O God, your only jig-maker! What should a man do but be merry?
+ For look you how cheerfully my mother looks, and my father died
+ within 's two hours.
+ Oph. Nay 'tis twice two months, my lord.
+ Ham. So long? Nay then, let the devil wear black, for I'll have a
+ suit of sables. O heavens! die two months ago, and not forgotten
+ yet? Then there's hope a great man's memory may outlive his life
+ half a year. But, by'r Lady, he must build churches then; or else
+ shall he suffer not thinking on, with the hobby-horse, whose
+ epitaph is 'For O, for O, the hobby-horse is forgot!'
+
+ Hautboys play. The dumb show enters.
+
+ Enter a King and a Queen very lovingly; the Queen embracing
+ him and he her. She kneels, and makes show of protestation
+ unto him. He takes her up, and declines his head upon her
+ neck. He lays him down upon a bank of flowers. She, seeing
+ him asleep, leaves him. Anon comes in a fellow, takes off his
+ crown, kisses it, pours poison in the sleeper's ears, and
+ leaves him. The Queen returns, finds the King dead, and makes
+ passionate action. The Poisoner with some three or four Mutes,
+ comes in again, seem to condole with her. The dead body is
+ carried away. The Poisoner wooes the Queen with gifts; she
+ seems harsh and unwilling awhile, but in the end accepts
+ his love.
+ Exeunt.
+
+ Oph. What means this, my lord?
+ Ham. Marry, this is miching malhecho; it means mischief.
+ Oph. Belike this show imports the argument of the play.
+
+ Enter Prologue.
+
+ Ham. We shall know by this fellow. The players cannot keep counsel;
+ they'll tell all.
+ Oph. Will he tell us what this show meant?
+ Ham. Ay, or any show that you'll show him. Be not you asham'd to
+ show, he'll not shame to tell you what it means.
+ Oph. You are naught, you are naught! I'll mark the play.
+
+ Pro. For us, and for our tragedy,
+ Here stooping to your clemency,
+ We beg your hearing patiently. [Exit.]
+
+ Ham. Is this a prologue, or the posy of a ring?
+ Oph. 'Tis brief, my lord.
+ Ham. As woman's love.
+
+ Enter [two Players as] King and Queen.
+
+ King. Full thirty times hath Phoebus' cart gone round
+ Neptune's salt wash and Tellus' orbed ground,
+ And thirty dozed moons with borrowed sheen
+ About the world have times twelve thirties been,
+ Since love our hearts, and Hymen did our hands,
+ Unite comutual in most sacred bands.
+ Queen. So many journeys may the sun and moon
+ Make us again count o'er ere love be done!
+ But woe is me! you are so sick of late,
+ So far from cheer and from your former state.
+ That I distrust you. Yet, though I distrust,
+ Discomfort you, my lord, it nothing must;
+ For women's fear and love holds quantity,
+ In neither aught, or in extremity.
+ Now what my love is, proof hath made you know;
+ And as my love is siz'd, my fear is so.
+ Where love is great, the littlest doubts are fear;
+ Where little fears grow great, great love grows there.
+ King. Faith, I must leave thee, love, and shortly too;
+ My operant powers their functions leave to do.
+ And thou shalt live in this fair world behind,
+ Honour'd, belov'd, and haply one as kind
+ For husband shalt thou-
+ Queen. O, confound the rest!
+ Such love must needs be treason in my breast.
+ When second husband let me be accurst!
+ None wed the second but who killed the first.
+
+ Ham. [aside] Wormwood, wormwood!
+
+ Queen. The instances that second marriage move
+ Are base respects of thrift, but none of love.
+ A second time I kill my husband dead
+ When second husband kisses me in bed.
+ King. I do believe you think what now you speak;
+ But what we do determine oft we break.
+ Purpose is but the slave to memory,
+ Of violent birth, but poor validity;
+ Which now, like fruit unripe, sticks on the tree,
+ But fill unshaken when they mellow be.
+ Most necessary 'tis that we forget
+ To pay ourselves what to ourselves is debt.
+ What to ourselves in passion we propose,
+ The passion ending, doth the purpose lose.
+ The violence of either grief or joy
+ Their own enactures with themselves destroy.
+ Where joy most revels, grief doth most lament;
+ Grief joys, joy grieves, on slender accident.
+ This world is not for aye, nor 'tis not strange
+ That even our loves should with our fortunes change;
+ For 'tis a question left us yet to prove,
+ Whether love lead fortune, or else fortune love.
+ The great man down, you mark his favourite flies,
+ The poor advanc'd makes friends of enemies;
+ And hitherto doth love on fortune tend,
+ For who not needs shall never lack a friend,
+ And who in want a hollow friend doth try,
+ Directly seasons him his enemy.
+ But, orderly to end where I begun,
+ Our wills and fates do so contrary run
+ That our devices still are overthrown;
+ Our thoughts are ours, their ends none of our own.
+ So think thou wilt no second husband wed;
+ But die thy thoughts when thy first lord is dead.
+ Queen. Nor earth to me give food, nor heaven light,
+ Sport and repose lock from me day and night,
+ To desperation turn my trust and hope,
+ An anchor's cheer in prison be my scope,
+ Each opposite that blanks the face of joy
+ Meet what I would have well, and it destroy,
+ Both here and hence pursue me lasting strife,
+ If, once a widow, ever I be wife!
+
+ Ham. If she should break it now!
+
+ King. 'Tis deeply sworn. Sweet, leave me here awhile.
+ My spirits grow dull, and fain I would beguile
+ The tedious day with sleep.
+ Queen. Sleep rock thy brain,
+ [He] sleeps.
+ And never come mischance between us twain!
+Exit.
+
+ Ham. Madam, how like you this play?
+ Queen. The lady doth protest too much, methinks.
+ Ham. O, but she'll keep her word.
+ King. Have you heard the argument? Is there no offence in't?
+ Ham. No, no! They do but jest, poison in jest; no offence i' th'
+ world.
+ King. What do you call the play?
+ Ham. 'The Mousetrap.' Marry, how? Tropically. This play is the
+ image of a murther done in Vienna. Gonzago is the duke's name;
+ his wife, Baptista. You shall see anon. 'Tis a knavish piece of
+ work; but what o' that? Your Majesty, and we that have free
+ souls, it touches us not. Let the gall'd jade winch; our withers
+ are unwrung.
+
+ Enter Lucianus.
+
+ This is one Lucianus, nephew to the King.
+ Oph. You are as good as a chorus, my lord.
+ Ham. I could interpret between you and your love, if I could see
+ the puppets dallying.
+ Oph. You are keen, my lord, you are keen.
+ Ham. It would cost you a groaning to take off my edge.
+ Oph. Still better, and worse.
+ Ham. So you must take your husbands.- Begin, murtherer. Pox, leave
+ thy damnable faces, and begin! Come, the croaking raven doth
+ bellow for revenge.
+
+ Luc. Thoughts black, hands apt, drugs fit, and time agreeing;
+ Confederate season, else no creature seeing;
+ Thou mixture rank, of midnight weeds collected,
+ With Hecate's ban thrice blasted, thrice infected,
+ Thy natural magic and dire property
+ On wholesome life usurp immediately.
+ Pours the poison in his ears.
+
+ Ham. He poisons him i' th' garden for's estate. His name's Gonzago.
+ The story is extant, and written in very choice Italian. You
+ shall see anon how the murtherer gets the love of Gonzago's wife.
+ Oph. The King rises.
+ Ham. What, frighted with false fire?
+ Queen. How fares my lord?
+ Pol. Give o'er the play.
+ King. Give me some light! Away!
+ All. Lights, lights, lights!
+ Exeunt all but Hamlet and Horatio.
+ Ham. Why, let the strucken deer go weep,
+ The hart ungalled play;
+ For some must watch, while some must sleep:
+ Thus runs the world away.
+ Would not this, sir, and a forest of feathers- if the rest of my
+ fortunes turn Turk with me-with two Provincial roses on my raz'd
+ shoes, get me a fellowship in a cry of players, sir?
+ Hor. Half a share.
+ Ham. A whole one I!
+ For thou dost know, O Damon dear,
+ This realm dismantled was
+ Of Jove himself; and now reigns here
+ A very, very- pajock.
+ Hor. You might have rhym'd.
+ Ham. O good Horatio, I'll take the ghost's word for a thousand
+ pound! Didst perceive?
+ Hor. Very well, my lord.
+ Ham. Upon the talk of the poisoning?
+ Hor. I did very well note him.
+ Ham. Aha! Come, some music! Come, the recorders!
+ For if the King like not the comedy,
+ Why then, belike he likes it not, perdy.
+ Come, some music!
+
+ Enter Rosencrantz and Guildenstern.
+
+ Guil. Good my lord, vouchsafe me a word with you.
+ Ham. Sir, a whole history.
+ Guil. The King, sir-
+ Ham. Ay, sir, what of him?
+ Guil. Is in his retirement, marvellous distemper'd.
+ Ham. With drink, sir?
+ Guil. No, my lord; rather with choler.
+ Ham. Your wisdom should show itself more richer to signify this to
+ the doctor; for me to put him to his purgation would perhaps
+ plunge him into far more choler.
+ Guil. Good my lord, put your discourse into some frame, and start
+ not so wildly from my affair.
+ Ham. I am tame, sir; pronounce.
+ Guil. The Queen, your mother, in most great affliction of spirit
+ hath sent me to you.
+ Ham. You are welcome.
+ Guil. Nay, good my lord, this courtesy is not of the right breed.
+ If it shall please you to make me a wholesome answer, I will do
+ your mother's commandment; if not, your pardon and my return
+ shall be the end of my business.
+ Ham. Sir, I cannot.
+ Guil. What, my lord?
+ Ham. Make you a wholesome answer; my wit's diseas'd. But, sir, such
+ answer is I can make, you shall command; or rather, as you say,
+ my mother. Therefore no more, but to the matter! My mother, you
+ say-
+ Ros. Then thus she says: your behaviour hath struck her into
+ amazement and admiration.
+ Ham. O wonderful son, that can so stonish a mother! But is there no
+ sequel at the heels of this mother's admiration? Impart.
+ Ros. She desires to speak with you in her closet ere you go to bed.
+ Ham. We shall obey, were she ten times our mother. Have you any
+ further trade with us?
+ Ros. My lord, you once did love me.
+ Ham. And do still, by these pickers and stealers!
+ Ros. Good my lord, what is your cause of distemper? You do surely
+ bar the door upon your own liberty, if you deny your griefs to
+ your friend.
+ Ham. Sir, I lack advancement.
+ Ros. How can that be, when you have the voice of the King himself
+ for your succession in Denmark?
+ Ham. Ay, sir, but 'while the grass grows'- the proverb is something
+ musty.
+
+ Enter the Players with recorders.
+
+ O, the recorders! Let me see one. To withdraw with you- why do
+ you go about to recover the wind of me, as if you would drive me
+ into a toil?
+ Guil. O my lord, if my duty be too bold, my love is too unmannerly.
+ Ham. I do not well understand that. Will you play upon this pipe?
+ Guil. My lord, I cannot.
+ Ham. I pray you.
+ Guil. Believe me, I cannot.
+ Ham. I do beseech you.
+ Guil. I know, no touch of it, my lord.
+ Ham. It is as easy as lying. Govern these ventages with your
+ fingers and thumbs, give it breath with your mouth, and it will
+ discourse most eloquent music. Look you, these are the stops.
+ Guil. But these cannot I command to any utt'rance of harmony. I
+ have not the skill.
+ Ham. Why, look you now, how unworthy a thing you make of me! You
+ would play upon me; you would seem to know my stops; you would
+ pluck out the heart of my mystery; you would sound me from my
+ lowest note to the top of my compass; and there is much music,
+ excellent voice, in this little organ, yet cannot you make it
+ speak. 'Sblood, do you think I am easier to be play'd on than a
+ pipe? Call me what instrument you will, though you can fret me,
+ you cannot play upon me.
+
+ Enter Polonius.
+
+ God bless you, sir!
+ Pol. My lord, the Queen would speak with you, and presently.
+ Ham. Do you see yonder cloud that's almost in shape of a camel?
+ Pol. By th' mass, and 'tis like a camel indeed.
+ Ham. Methinks it is like a weasel.
+ Pol. It is back'd like a weasel.
+ Ham. Or like a whale.
+ Pol. Very like a whale.
+ Ham. Then will I come to my mother by-and-by.- They fool me to the
+ top of my bent.- I will come by-and-by.
+ Pol. I will say so. Exit.
+ Ham. 'By-and-by' is easily said.- Leave me, friends.
+ [Exeunt all but Hamlet.]
+ 'Tis now the very witching time of night,
+ When churchyards yawn, and hell itself breathes out
+ Contagion to this world. Now could I drink hot blood
+ And do such bitter business as the day
+ Would quake to look on. Soft! now to my mother!
+ O heart, lose not thy nature; let not ever
+ The soul of Nero enter this firm bosom.
+ Let me be cruel, not unnatural;
+ I will speak daggers to her, but use none.
+ My tongue and soul in this be hypocrites-
+ How in my words somever she be shent,
+ To give them seals never, my soul, consent! Exit.
+
+
+
+
+Scene III.
+A room in the Castle.
+
+Enter King, Rosencrantz, and Guildenstern.
+
+ King. I like him not, nor stands it safe with us
+ To let his madness range. Therefore prepare you;
+ I your commission will forthwith dispatch,
+ And he to England shall along with you.
+ The terms of our estate may not endure
+ Hazard so near us as doth hourly grow
+ Out of his lunacies.
+ Guil. We will ourselves provide.
+ Most holy and religious fear it is
+ To keep those many many bodies safe
+ That live and feed upon your Majesty.
+ Ros. The single and peculiar life is bound
+ With all the strength and armour of the mind
+ To keep itself from noyance; but much more
+ That spirit upon whose weal depends and rests
+ The lives of many. The cesse of majesty
+ Dies not alone, but like a gulf doth draw
+ What's near it with it. It is a massy wheel,
+ Fix'd on the summit of the highest mount,
+ To whose huge spokes ten thousand lesser things
+ Are mortis'd and adjoin'd; which when it falls,
+ Each small annexment, petty consequence,
+ Attends the boist'rous ruin. Never alone
+ Did the king sigh, but with a general groan.
+ King. Arm you, I pray you, to th', speedy voyage;
+ For we will fetters put upon this fear,
+ Which now goes too free-footed.
+ Both. We will haste us.
+ Exeunt Gentlemen.
+
+ Enter Polonius.
+
+ Pol. My lord, he's going to his mother's closet.
+ Behind the arras I'll convey myself
+ To hear the process. I'll warrant she'll tax him home;
+ And, as you said, and wisely was it said,
+ 'Tis meet that some more audience than a mother,
+ Since nature makes them partial, should o'erhear
+ The speech, of vantage. Fare you well, my liege.
+ I'll call upon you ere you go to bed
+ And tell you what I know.
+ King. Thanks, dear my lord.
+ Exit [Polonius].
+ O, my offence is rank, it smells to heaven;
+ It hath the primal eldest curse upon't,
+ A brother's murther! Pray can I not,
+ Though inclination be as sharp as will.
+ My stronger guilt defeats my strong intent,
+ And, like a man to double business bound,
+ I stand in pause where I shall first begin,
+ And both neglect. What if this cursed hand
+ Were thicker than itself with brother's blood,
+ Is there not rain enough in the sweet heavens
+ To wash it white as snow? Whereto serves mercy
+ But to confront the visage of offence?
+ And what's in prayer but this twofold force,
+ To be forestalled ere we come to fall,
+ Or pardon'd being down? Then I'll look up;
+ My fault is past. But, O, what form of prayer
+ Can serve my turn? 'Forgive me my foul murther'?
+ That cannot be; since I am still possess'd
+ Of those effects for which I did the murther-
+ My crown, mine own ambition, and my queen.
+ May one be pardon'd and retain th' offence?
+ In the corrupted currents of this world
+ Offence's gilded hand may shove by justice,
+ And oft 'tis seen the wicked prize itself
+ Buys out the law; but 'tis not so above.
+ There is no shuffling; there the action lies
+ In his true nature, and we ourselves compell'd,
+ Even to the teeth and forehead of our faults,
+ To give in evidence. What then? What rests?
+ Try what repentance can. What can it not?
+ Yet what can it when one cannot repent?
+ O wretched state! O bosom black as death!
+ O limed soul, that, struggling to be free,
+ Art more engag'd! Help, angels! Make assay.
+ Bow, stubborn knees; and heart with strings of steel,
+ Be soft as sinews of the new-born babe!
+ All may be well. He kneels.
+
+ Enter Hamlet.
+
+ Ham. Now might I do it pat, now he is praying;
+ And now I'll do't. And so he goes to heaven,
+ And so am I reveng'd. That would be scann'd.
+ A villain kills my father; and for that,
+ I, his sole son, do this same villain send
+ To heaven.
+ Why, this is hire and salary, not revenge!
+ He took my father grossly, full of bread,
+ With all his crimes broad blown, as flush as May;
+ And how his audit stands, who knows save heaven?
+ But in our circumstance and course of thought,
+ 'Tis heavy with him; and am I then reveng'd,
+ To take him in the purging of his soul,
+ When he is fit and seasoned for his passage?
+ No.
+ Up, sword, and know thou a more horrid hent.
+ When he is drunk asleep; or in his rage;
+ Or in th' incestuous pleasure of his bed;
+ At gaming, swearing, or about some act
+ That has no relish of salvation in't-
+ Then trip him, that his heels may kick at heaven,
+ And that his soul may be as damn'd and black
+ As hell, whereto it goes. My mother stays.
+ This physic but prolongs thy sickly days. Exit.
+ King. [rises] My words fly up, my thoughts remain below.
+ Words without thoughts never to heaven go. Exit.
+
+
+
+
+Scene IV.
+The Queen's closet.
+
+Enter Queen and Polonius.
+
+ Pol. He will come straight. Look you lay home to him.
+ Tell him his pranks have been too broad to bear with,
+ And that your Grace hath screen'd and stood between
+ Much heat and him. I'll silence me even here.
+ Pray you be round with him.
+ Ham. (within) Mother, mother, mother!
+ Queen. I'll warrant you; fear me not. Withdraw; I hear him coming.
+ [Polonius hides behind the arras.]
+
+ Enter Hamlet.
+
+ Ham. Now, mother, what's the matter?
+ Queen. Hamlet, thou hast thy father much offended.
+ Ham. Mother, you have my father much offended.
+ Queen. Come, come, you answer with an idle tongue.
+ Ham. Go, go, you question with a wicked tongue.
+ Queen. Why, how now, Hamlet?
+ Ham. What's the matter now?
+ Queen. Have you forgot me?
+ Ham. No, by the rood, not so!
+ You are the Queen, your husband's brother's wife,
+ And (would it were not so!) you are my mother.
+ Queen. Nay, then I'll set those to you that can speak.
+ Ham. Come, come, and sit you down. You shall not budge I
+ You go not till I set you up a glass
+ Where you may see the inmost part of you.
+ Queen. What wilt thou do? Thou wilt not murther me?
+ Help, help, ho!
+ Pol. [behind] What, ho! help, help, help!
+ Ham. [draws] How now? a rat? Dead for a ducat, dead!
+ [Makes a pass through the arras and] kills Polonius.
+ Pol. [behind] O, I am slain!
+ Queen. O me, what hast thou done?
+ Ham. Nay, I know not. Is it the King?
+ Queen. O, what a rash and bloody deed is this!
+ Ham. A bloody deed- almost as bad, good mother,
+ As kill a king, and marry with his brother.
+ Queen. As kill a king?
+ Ham. Ay, lady, it was my word.
+ [Lifts up the arras and sees Polonius.]
+ Thou wretched, rash, intruding fool, farewell!
+ I took thee for thy better. Take thy fortune.
+ Thou find'st to be too busy is some danger.
+ Leave wringing of your hinds. Peace! sit you down
+ And let me wring your heart; for so I shall
+ If it be made of penetrable stuff;
+ If damned custom have not braz'd it so
+ That it is proof and bulwark against sense.
+ Queen. What have I done that thou dar'st wag thy tongue
+ In noise so rude against me?
+ Ham. Such an act
+ That blurs the grace and blush of modesty;
+ Calls virtue hypocrite; takes off the rose
+ From the fair forehead of an innocent love,
+ And sets a blister there; makes marriage vows
+ As false as dicers' oaths. O, such a deed
+ As from the body of contraction plucks
+ The very soul, and sweet religion makes
+ A rhapsody of words! Heaven's face doth glow;
+ Yea, this solidity and compound mass,
+ With tristful visage, as against the doom,
+ Is thought-sick at the act.
+ Queen. Ay me, what act,
+ That roars so loud and thunders in the index?
+ Ham. Look here upon th's picture, and on this,
+ The counterfeit presentment of two brothers.
+ See what a grace was seated on this brow;
+ Hyperion's curls; the front of Jove himself;
+ An eye like Mars, to threaten and command;
+ A station like the herald Mercury
+ New lighted on a heaven-kissing hill:
+ A combination and a form indeed
+ Where every god did seem to set his seal
+ To give the world assurance of a man.
+ This was your husband. Look you now what follows.
+ Here is your husband, like a mildew'd ear
+ Blasting his wholesome brother. Have you eyes?
+ Could you on this fair mountain leave to feed,
+ And batten on this moor? Ha! have you eyes
+ You cannot call it love; for at your age
+ The heyday in the blood is tame, it's humble,
+ And waits upon the judgment; and what judgment
+ Would step from this to this? Sense sure you have,
+ Else could you not have motion; but sure that sense
+ Is apoplex'd; for madness would not err,
+ Nor sense to ecstacy was ne'er so thrall'd
+ But it reserv'd some quantity of choice
+ To serve in such a difference. What devil was't
+ That thus hath cozen'd you at hoodman-blind?
+ Eyes without feeling, feeling without sight,
+ Ears without hands or eyes, smelling sans all,
+ Or but a sickly part of one true sense
+ Could not so mope.
+ O shame! where is thy blush? Rebellious hell,
+ If thou canst mutine in a matron's bones,
+ To flaming youth let virtue be as wax
+ And melt in her own fire. Proclaim no shame
+ When the compulsive ardour gives the charge,
+ Since frost itself as actively doth burn,
+ And reason panders will.
+ Queen. O Hamlet, speak no more!
+ Thou turn'st mine eyes into my very soul,
+ And there I see such black and grained spots
+ As will not leave their tinct.
+ Ham. Nay, but to live
+ In the rank sweat of an enseamed bed,
+ Stew'd in corruption, honeying and making love
+ Over the nasty sty!
+ Queen. O, speak to me no more!
+ These words like daggers enter in mine ears.
+ No more, sweet Hamlet!
+ Ham. A murtherer and a villain!
+ A slave that is not twentieth part the tithe
+ Of your precedent lord; a vice of kings;
+ A cutpurse of the empire and the rule,
+ That from a shelf the precious diadem stole
+ And put it in his pocket!
+ Queen. No more!
+
+ Enter the Ghost in his nightgown.
+
+ Ham. A king of shreds and patches!-
+ Save me and hover o'er me with your wings,
+ You heavenly guards! What would your gracious figure?
+ Queen. Alas, he's mad!
+ Ham. Do you not come your tardy son to chide,
+ That, laps'd in time and passion, lets go by
+ Th' important acting of your dread command?
+ O, say!
+ Ghost. Do not forget. This visitation
+ Is but to whet thy almost blunted purpose.
+ But look, amazement on thy mother sits.
+ O, step between her and her fighting soul
+ Conceit in weakest bodies strongest works.
+ Speak to her, Hamlet.
+ Ham. How is it with you, lady?
+ Queen. Alas, how is't with you,
+ That you do bend your eye on vacancy,
+ And with th' encorporal air do hold discourse?
+ Forth at your eyes your spirits wildly peep;
+ And, as the sleeping soldiers in th' alarm,
+ Your bedded hairs, like life in excrements,
+ Start up and stand an end. O gentle son,
+ Upon the beat and flame of thy distemper
+ Sprinkle cool patience! Whereon do you look?
+ Ham. On him, on him! Look you how pale he glares!
+ His form and cause conjoin'd, preaching to stones,
+ Would make them capable.- Do not look upon me,
+ Lest with this piteous action you convert
+ My stern effects. Then what I have to do
+ Will want true colour- tears perchance for blood.
+ Queen. To whom do you speak this?
+ Ham. Do you see nothing there?
+ Queen. Nothing at all; yet all that is I see.
+ Ham. Nor did you nothing hear?
+ Queen. No, nothing but ourselves.
+ Ham. Why, look you there! Look how it steals away!
+ My father, in his habit as he liv'd!
+ Look where he goes even now out at the portal!
+ Exit Ghost.
+ Queen. This is the very coinage of your brain.
+ This bodiless creation ecstasy
+ Is very cunning in.
+ Ham. Ecstasy?
+ My pulse as yours doth temperately keep time
+ And makes as healthful music. It is not madness
+ That I have utt'red. Bring me to the test,
+ And I the matter will reword; which madness
+ Would gambol from. Mother, for love of grace,
+ Lay not that flattering unction to your soul
+ That not your trespass but my madness speaks.
+ It will but skin and film the ulcerous place,
+ Whiles rank corruption, mining all within,
+ Infects unseen. Confess yourself to heaven;
+ Repent what's past; avoid what is to come;
+ And do not spread the compost on the weeds
+ To make them ranker. Forgive me this my virtue;
+ For in the fatness of these pursy times
+ Virtue itself of vice must pardon beg-
+ Yea, curb and woo for leave to do him good.
+ Queen. O Hamlet, thou hast cleft my heart in twain.
+ Ham. O, throw away the worser part of it,
+ And live the purer with the other half,
+ Good night- but go not to my uncle's bed.
+ Assume a virtue, if you have it not.
+ That monster, custom, who all sense doth eat
+ Of habits evil, is angel yet in this,
+ That to the use of actions fair and good
+ He likewise gives a frock or livery,
+ That aptly is put on. Refrain to-night,
+ And that shall lend a kind of easiness
+ To the next abstinence; the next more easy;
+ For use almost can change the stamp of nature,
+ And either [master] the devil, or throw him out
+ With wondrous potency. Once more, good night;
+ And when you are desirous to be blest,
+ I'll blessing beg of you.- For this same lord,
+ I do repent; but heaven hath pleas'd it so,
+ To punish me with this, and this with me,
+ That I must be their scourge and minister.
+ I will bestow him, and will answer well
+ The death I gave him. So again, good night.
+ I must be cruel, only to be kind;
+ Thus bad begins, and worse remains behind.
+ One word more, good lady.
+ Queen. What shall I do?
+ Ham. Not this, by no means, that I bid you do:
+ Let the bloat King tempt you again to bed;
+ Pinch wanton on your cheek; call you his mouse;
+ And let him, for a pair of reechy kisses,
+ Or paddling in your neck with his damn'd fingers,
+ Make you to ravel all this matter out,
+ That I essentially am not in madness,
+ But mad in craft. 'Twere good you let him know;
+ For who that's but a queen, fair, sober, wise,
+ Would from a paddock, from a bat, a gib
+ Such dear concernings hide? Who would do so?
+ No, in despite of sense and secrecy,
+ Unpeg the basket on the house's top,
+ Let the birds fly, and like the famous ape,
+ To try conclusions, in the basket creep
+ And break your own neck down.
+ Queen. Be thou assur'd, if words be made of breath,
+ And breath of life, I have no life to breathe
+ What thou hast said to me.
+ Ham. I must to England; you know that?
+ Queen. Alack,
+ I had forgot! 'Tis so concluded on.
+ Ham. There's letters seal'd; and my two schoolfellows,
+ Whom I will trust as I will adders fang'd,
+ They bear the mandate; they must sweep my way
+ And marshal me to knavery. Let it work;
+ For 'tis the sport to have the enginer
+ Hoist with his own petar; and 't shall go hard
+ But I will delve one yard below their mines
+ And blow them at the moon. O, 'tis most sweet
+ When in one line two crafts directly meet.
+ This man shall set me packing.
+ I'll lug the guts into the neighbour room.-
+ Mother, good night.- Indeed, this counsellor
+ Is now most still, most secret, and most grave,
+ Who was in life a foolish peating knave.
+ Come, sir, to draw toward an end with you.
+ Good night, mother.
+ [Exit the Queen. Then] Exit Hamlet, tugging in
+ Polonius.
+
+
+
+
+
+ACT IV. Scene I.
+Elsinore. A room in the Castle.
+
+Enter King and Queen, with Rosencrantz and Guildenstern.
+
+ King. There's matter in these sighs. These profound heaves
+ You must translate; 'tis fit we understand them.
+ Where is your son?
+ Queen. Bestow this place on us a little while.
+ [Exeunt Rosencrantz and Guildenstern.]
+ Ah, mine own lord, what have I seen to-night!
+ King. What, Gertrude? How does Hamlet?
+ Queen. Mad as the sea and wind when both contend
+ Which is the mightier. In his lawless fit
+ Behind the arras hearing something stir,
+ Whips out his rapier, cries 'A rat, a rat!'
+ And in this brainish apprehension kills
+ The unseen good old man.
+ King. O heavy deed!
+ It had been so with us, had we been there.
+ His liberty is full of threats to all-
+ To you yourself, to us, to every one.
+ Alas, how shall this bloody deed be answer'd?
+ It will be laid to us, whose providence
+ Should have kept short, restrain'd, and out of haunt
+ This mad young man. But so much was our love
+ We would not understand what was most fit,
+ But, like the owner of a foul disease,
+ To keep it from divulging, let it feed
+ Even on the pith of life. Where is he gone?
+ Queen. To draw apart the body he hath kill'd;
+ O'er whom his very madness, like some ore
+ Among a mineral of metals base,
+ Shows itself pure. He weeps for what is done.
+ King. O Gertrude, come away!
+ The sun no sooner shall the mountains touch
+ But we will ship him hence; and this vile deed
+ We must with all our majesty and skill
+ Both countenance and excuse. Ho, Guildenstern!
+
+ Enter Rosencrantz and Guildenstern.
+
+ Friends both, go join you with some further aid.
+ Hamlet in madness hath Polonius slain,
+ And from his mother's closet hath he dragg'd him.
+ Go seek him out; speak fair, and bring the body
+ Into the chapel. I pray you haste in this.
+ Exeunt [Rosencrantz and Guildenstern].
+ Come, Gertrude, we'll call up our wisest friends
+ And let them know both what we mean to do
+ And what's untimely done. [So haply slander-]
+ Whose whisper o'er the world's diameter,
+ As level as the cannon to his blank,
+ Transports his poisoned shot- may miss our name
+ And hit the woundless air.- O, come away!
+ My soul is full of discord and dismay.
+ Exeunt.
+
+
+
+
+Scene II.
+Elsinore. A passage in the Castle.
+
+Enter Hamlet.
+
+ Ham. Safely stow'd.
+ Gentlemen. (within) Hamlet! Lord Hamlet!
+ Ham. But soft! What noise? Who calls on Hamlet? O, here they come.
+
+ Enter Rosencrantz and Guildenstern.
+
+ Ros. What have you done, my lord, with the dead body?
+ Ham. Compounded it with dust, whereto 'tis kin.
+ Ros. Tell us where 'tis, that we may take it thence
+ And bear it to the chapel.
+ Ham. Do not believe it.
+ Ros. Believe what?
+ Ham. That I can keep your counsel, and not mine own. Besides, to be
+ demanded of a sponge, what replication should be made by the son
+ of a king?
+ Ros. Take you me for a sponge, my lord?
+ Ham. Ay, sir; that soaks up the King's countenance, his rewards,
+ his authorities. But such officers do the King best service in
+ the end. He keeps them, like an ape, in the corner of his jaw;
+ first mouth'd, to be last Swallowed. When he needs what you have
+ glean'd, it is but squeezing you and, sponge, you shall be dry
+ again.
+ Ros. I understand you not, my lord.
+ Ham. I am glad of it. A knavish speech sleeps in a foolish ear.
+ Ros. My lord, you must tell us where the body is and go with us to
+ the King.
+ Ham. The body is with the King, but the King is not with the body.
+ The King is a thing-
+ Guil. A thing, my lord?
+ Ham. Of nothing. Bring me to him. Hide fox, and all after.
+ Exeunt.
+
+
+
+
+Scene III.
+Elsinore. A room in the Castle.
+
+Enter King.
+
+ King. I have sent to seek him and to find the body.
+ How dangerous is it that this man goes loose!
+ Yet must not we put the strong law on him.
+ He's lov'd of the distracted multitude,
+ Who like not in their judgment, but their eyes;
+ And where 'tis so, th' offender's scourge is weigh'd,
+ But never the offence. To bear all smooth and even,
+ This sudden sending him away must seem
+ Deliberate pause. Diseases desperate grown
+ By desperate appliance are reliev'd,
+ Or not at all.
+
+ Enter Rosencrantz.
+
+ How now O What hath befall'n?
+ Ros. Where the dead body is bestow'd, my lord,
+ We cannot get from him.
+ King. But where is he?
+ Ros. Without, my lord; guarded, to know your pleasure.
+ King. Bring him before us.
+ Ros. Ho, Guildenstern! Bring in my lord.
+
+ Enter Hamlet and Guildenstern [with Attendants].
+
+ King. Now, Hamlet, where's Polonius?
+ Ham. At supper.
+ King. At supper? Where?
+ Ham. Not where he eats, but where he is eaten. A certain
+ convocation of politic worms are e'en at him. Your worm is your
+ only emperor for diet. We fat all creatures else to fat us, and
+ we fat ourselves for maggots. Your fat king and your lean beggar
+ is but variable service- two dishes, but to one table. That's the
+ end.
+ King. Alas, alas!
+ Ham. A man may fish with the worm that hath eat of a king, and eat
+ of the fish that hath fed of that worm.
+ King. What dost thou mean by this?
+ Ham. Nothing but to show you how a king may go a progress through
+ the guts of a beggar.
+ King. Where is Polonius?
+ Ham. In heaven. Send thither to see. If your messenger find him not
+ there, seek him i' th' other place yourself. But indeed, if you
+ find him not within this month, you shall nose him as you go up
+ the stair, into the lobby.
+ King. Go seek him there. [To Attendants.]
+ Ham. He will stay till you come.
+ [Exeunt Attendants.]
+ King. Hamlet, this deed, for thine especial safety,-
+ Which we do tender as we dearly grieve
+ For that which thou hast done,- must send thee hence
+ With fiery quickness. Therefore prepare thyself.
+ The bark is ready and the wind at help,
+ Th' associates tend, and everything is bent
+ For England.
+ Ham. For England?
+ King. Ay, Hamlet.
+ Ham. Good.
+ King. So is it, if thou knew'st our purposes.
+ Ham. I see a cherub that sees them. But come, for England!
+ Farewell, dear mother.
+ King. Thy loving father, Hamlet.
+ Ham. My mother! Father and mother is man and wife; man and wife is
+ one flesh; and so, my mother. Come, for England!
+Exit.
+ King. Follow him at foot; tempt him with speed aboard.
+ Delay it not; I'll have him hence to-night.
+ Away! for everything is seal'd and done
+ That else leans on th' affair. Pray you make haste.
+ Exeunt Rosencrantz and Guildenstern]
+ And, England, if my love thou hold'st at aught,-
+ As my great power thereof may give thee sense,
+ Since yet thy cicatrice looks raw and red
+ After the Danish sword, and thy free awe
+ Pays homage to us,- thou mayst not coldly set
+ Our sovereign process, which imports at full,
+ By letters congruing to that effect,
+ The present death of Hamlet. Do it, England;
+ For like the hectic in my blood he rages,
+ And thou must cure me. Till I know 'tis done,
+ Howe'er my haps, my joys were ne'er begun. Exit.
+
+
+
+
+
+Scene IV.
+Near Elsinore.
+
+Enter Fortinbras with his Army over the stage.
+
+ For. Go, Captain, from me greet the Danish king.
+ Tell him that by his license Fortinbras
+ Craves the conveyance of a promis'd march
+ Over his kingdom. You know the rendezvous.
+ if that his Majesty would aught with us,
+ We shall express our duty in his eye;
+ And let him know so.
+ Capt. I will do't, my lord.
+ For. Go softly on.
+ Exeunt [all but the Captain].
+
+ Enter Hamlet, Rosencrantz, [Guildenstern,] and others.
+
+ Ham. Good sir, whose powers are these?
+ Capt. They are of Norway, sir.
+ Ham. How purpos'd, sir, I pray you?
+ Capt. Against some part of Poland.
+ Ham. Who commands them, sir?
+ Capt. The nephew to old Norway, Fortinbras.
+ Ham. Goes it against the main of Poland, sir,
+ Or for some frontier?
+ Capt. Truly to speak, and with no addition,
+ We go to gain a little patch of ground
+ That hath in it no profit but the name.
+ To pay five ducats, five, I would not farm it;
+ Nor will it yield to Norway or the Pole
+ A ranker rate, should it be sold in fee.
+ Ham. Why, then the Polack never will defend it.
+ Capt. Yes, it is already garrison'd.
+ Ham. Two thousand souls and twenty thousand ducats
+ Will not debate the question of this straw.
+ This is th' imposthume of much wealth and peace,
+ That inward breaks, and shows no cause without
+ Why the man dies.- I humbly thank you, sir.
+ Capt. God b' wi' you, sir. [Exit.]
+ Ros. Will't please you go, my lord?
+ Ham. I'll be with you straight. Go a little before.
+ [Exeunt all but Hamlet.]
+ How all occasions do inform against me
+ And spur my dull revenge! What is a man,
+ If his chief good and market of his time
+ Be but to sleep and feed? A beast, no more.
+ Sure he that made us with such large discourse,
+ Looking before and after, gave us not
+ That capability and godlike reason
+ To fust in us unus'd. Now, whether it be
+ Bestial oblivion, or some craven scruple
+ Of thinking too precisely on th' event,-
+ A thought which, quarter'd, hath but one part wisdom
+ And ever three parts coward,- I do not know
+ Why yet I live to say 'This thing's to do,'
+ Sith I have cause, and will, and strength, and means
+ To do't. Examples gross as earth exhort me.
+ Witness this army of such mass and charge,
+ Led by a delicate and tender prince,
+ Whose spirit, with divine ambition puff'd,
+ Makes mouths at the invisible event,
+ Exposing what is mortal and unsure
+ To all that fortune, death, and danger dare,
+ Even for an eggshell. Rightly to be great
+ Is not to stir without great argument,
+ But greatly to find quarrel in a straw
+ When honour's at the stake. How stand I then,
+ That have a father klll'd, a mother stain'd,
+ Excitements of my reason and my blood,
+ And let all sleep, while to my shame I see
+ The imminent death of twenty thousand men
+ That for a fantasy and trick of fame
+ Go to their graves like beds, fight for a plot
+ Whereon the numbers cannot try the cause,
+ Which is not tomb enough and continent
+ To hide the slain? O, from this time forth,
+ My thoughts be bloody, or be nothing worth! Exit.
+
+
+
+
+
+Scene V.
+Elsinore. A room in the Castle.
+
+Enter Horatio, Queen, and a Gentleman.
+
+ Queen. I will not speak with her.
+ Gent. She is importunate, indeed distract.
+ Her mood will needs be pitied.
+ Queen. What would she have?
+ Gent. She speaks much of her father; says she hears
+ There's tricks i' th' world, and hems, and beats her heart;
+ Spurns enviously at straws; speaks things in doubt,
+ That carry but half sense. Her speech is nothing,
+ Yet the unshaped use of it doth move
+ The hearers to collection; they aim at it,
+ And botch the words up fit to their own thoughts;
+ Which, as her winks and nods and gestures yield them,
+ Indeed would make one think there might be thought,
+ Though nothing sure, yet much unhappily.
+ Hor. 'Twere good she were spoken with; for she may strew
+ Dangerous conjectures in ill-breeding minds.
+ Queen. Let her come in.
+ [Exit Gentleman.]
+ [Aside] To my sick soul (as sin's true nature is)
+ Each toy seems Prologue to some great amiss.
+ So full of artless jealousy is guilt
+ It spills itself in fearing to be spilt.
+
+ Enter Ophelia distracted.
+
+ Oph. Where is the beauteous Majesty of Denmark?
+ Queen. How now, Ophelia?
+ Oph. (sings)
+ How should I your true-love know
+ From another one?
+ By his cockle bat and' staff
+ And his sandal shoon.
+
+ Queen. Alas, sweet lady, what imports this song?
+ Oph. Say you? Nay, pray You mark.
+
+ (Sings) He is dead and gone, lady,
+ He is dead and gone;
+ At his head a grass-green turf,
+ At his heels a stone.
+
+ O, ho!
+ Queen. Nay, but Ophelia-
+ Oph. Pray you mark.
+
+ (Sings) White his shroud as the mountain snow-
+
+ Enter King.
+
+ Queen. Alas, look here, my lord!
+ Oph. (Sings)
+ Larded all with sweet flowers;
+ Which bewept to the grave did not go
+ With true-love showers.
+
+ King. How do you, pretty lady?
+ Oph. Well, God dild you! They say the owl was a baker's daughter.
+ Lord, we know what we are, but know not what we may be. God be at
+ your table!
+ King. Conceit upon her father.
+ Oph. Pray let's have no words of this; but when they ask, you what
+ it means, say you this:
+
+ (Sings) To-morrow is Saint Valentine's day,
+ All in the morning bedtime,
+ And I a maid at your window,
+ To be your Valentine.
+
+ Then up he rose and donn'd his clo'es
+ And dupp'd the chamber door,
+ Let in the maid, that out a maid
+ Never departed more.
+
+ King. Pretty Ophelia!
+ Oph. Indeed, la, without an oath, I'll make an end on't!
+
+ [Sings] By Gis and by Saint Charity,
+ Alack, and fie for shame!
+ Young men will do't if they come to't
+ By Cock, they are to blame.
+
+ Quoth she, 'Before you tumbled me,
+ You promis'd me to wed.'
+
+ He answers:
+
+ 'So would I 'a' done, by yonder sun,
+ An thou hadst not come to my bed.'
+
+ King. How long hath she been thus?
+ Oph. I hope all will be well. We must be patient; but I cannot
+ choose but weep to think they would lay him i' th' cold ground.
+ My brother shall know of it; and so I thank you for your good
+ counsel. Come, my coach! Good night, ladies. Good night, sweet
+ ladies. Good night, good night. Exit
+ King. Follow her close; give her good watch, I pray you.
+ [Exit Horatio.]
+ O, this is the poison of deep grief; it springs
+ All from her father's death. O Gertrude, Gertrude,
+ When sorrows come, they come not single spies.
+ But in battalions! First, her father slain;
+ Next, Your son gone, and he most violent author
+ Of his own just remove; the people muddied,
+ Thick and and unwholesome in their thoughts and whispers
+ For good Polonius' death, and we have done but greenly
+ In hugger-mugger to inter him; Poor Ophelia
+ Divided from herself and her fair-judgment,
+ Without the which we are Pictures or mere beasts;
+ Last, and as such containing as all these,
+ Her brother is in secret come from France;
+ And wants not buzzers to infect his ear
+ Feeds on his wonder, keep, himself in clouds,
+ With pestilent speeches of his father's death,
+ Wherein necessity, of matter beggar'd,
+ Will nothing stick Our person to arraign
+ In ear and ear. O my dear Gertrude, this,
+ Like to a murd'ring piece, in many places
+ Give, me superfluous death. A noise within.
+ Queen. Alack, what noise is this?
+ King. Where are my Switzers? Let them guard the door.
+
+ Enter a Messenger.
+
+ What is the matter?
+ Mess. Save Yourself, my lord:
+ The ocean, overpeering of his list,
+ Eats not the flats with more impetuous haste
+ Than Young Laertes, in a riotous head,
+ O'erbears Your offices. The rabble call him lord;
+ And, as the world were now but to begin,
+ Antiquity forgot, custom not known,
+ The ratifiers and props of every word,
+ They cry 'Choose we! Laertes shall be king!'
+ Caps, hands, and tongues applaud it to the clouds,
+ 'Laertes shall be king! Laertes king!'
+ A noise within.
+ Queen. How cheerfully on the false trail they cry!
+ O, this is counter, you false Danish dogs!
+ King. The doors are broke.
+
+ Enter Laertes with others.
+
+ Laer. Where is this king?- Sirs, staid you all without.
+ All. No, let's come in!
+ Laer. I pray you give me leave.
+ All. We will, we will!
+ Laer. I thank you. Keep the door. [Exeunt his Followers.]
+ O thou vile king,
+ Give me my father!
+ Queen. Calmly, good Laertes.
+ Laer. That drop of blood that's calm proclaims me bastard;
+ Cries cuckold to my father; brands the harlot
+ Even here between the chaste unsmirched brows
+ Of my true mother.
+ King. What is the cause, Laertes,
+ That thy rebellion looks so giantlike?
+ Let him go, Gertrude. Do not fear our person.
+ There's such divinity doth hedge a king
+ That treason can but peep to what it would,
+ Acts little of his will. Tell me, Laertes,
+ Why thou art thus incens'd. Let him go, Gertrude.
+ Speak, man.
+ Laer. Where is my father?
+ King. Dead.
+ Queen. But not by him!
+ King. Let him demand his fill.
+ Laer. How came he dead? I'll not be juggled with:
+ To hell, allegiance! vows, to the blackest devil
+ Conscience and grace, to the profoundest pit!
+ I dare damnation. To this point I stand,
+ That both the world, I give to negligence,
+ Let come what comes; only I'll be reveng'd
+ Most throughly for my father.
+ King. Who shall stay you?
+ Laer. My will, not all the world!
+ And for my means, I'll husband them so well
+ They shall go far with little.
+ King. Good Laertes,
+ If you desire to know the certainty
+ Of your dear father's death, is't writ in Your revenge
+ That swoopstake you will draw both friend and foe,
+ Winner and loser?
+ Laer. None but his enemies.
+ King. Will you know them then?
+ Laer. To his good friends thus wide I'll ope my arms
+ And, like the kind life-rend'ring pelican,
+ Repast them with my blood.
+ King. Why, now You speak
+ Like a good child and a true gentleman.
+ That I am guiltless of your father's death,
+ And am most sensibly in grief for it,
+ It shall as level to your judgment pierce
+ As day does to your eye.
+ A noise within: 'Let her come in.'
+ Laer. How now? What noise is that?
+
+ Enter Ophelia.
+
+ O heat, dry up my brains! Tears seven times salt
+ Burn out the sense and virtue of mine eye!
+ By heaven, thy madness shall be paid by weight
+ Till our scale turn the beam. O rose of May!
+ Dear maid, kind sister, sweet Ophelia!
+ O heavens! is't possible a young maid's wits
+ Should be as mortal as an old man's life?
+ Nature is fine in love, and where 'tis fine,
+ It sends some precious instance of itself
+ After the thing it loves.
+
+ Oph. (sings)
+ They bore him barefac'd on the bier
+ (Hey non nony, nony, hey nony)
+ And in his grave rain'd many a tear.
+
+ Fare you well, my dove!
+ Laer. Hadst thou thy wits, and didst persuade revenge,
+ It could not move thus.
+ Oph. You must sing 'A-down a-down, and you call him a-down-a.' O,
+ how the wheel becomes it! It is the false steward, that stole his
+ master's daughter.
+ Laer. This nothing's more than matter.
+ Oph. There's rosemary, that's for remembrance. Pray you, love,
+ remember. And there is pansies, that's for thoughts.
+ Laer. A document in madness! Thoughts and remembrance fitted.
+ Oph. There's fennel for you, and columbines. There's rue for you,
+ and here's some for me. We may call it herb of grace o' Sundays.
+ O, you must wear your rue with a difference! There's a daisy. I
+ would give you some violets, but they wither'd all when my father
+ died. They say he made a good end.
+
+ [Sings] For bonny sweet Robin is all my joy.
+
+ Laer. Thought and affliction, passion, hell itself,
+ She turns to favour and to prettiness.
+ Oph. (sings)
+ And will he not come again?
+ And will he not come again?
+ No, no, he is dead;
+ Go to thy deathbed;
+ He never will come again.
+
+ His beard was as white as snow,
+ All flaxen was his poll.
+ He is gone, he is gone,
+ And we cast away moan.
+ God 'a'mercy on his soul!
+
+ And of all Christian souls, I pray God. God b' wi', you.
+Exit.
+ Laer. Do you see this, O God?
+ King. Laertes, I must commune with your grief,
+ Or you deny me right. Go but apart,
+ Make choice of whom your wisest friends you will,
+ And they shall hear and judge 'twixt you and me.
+ If by direct or by collateral hand
+ They find us touch'd, we will our kingdom give,
+ Our crown, our life, and all that we call ours,
+ To you in satisfaction; but if not,
+ Be you content to lend your patience to us,
+ And we shall jointly labour with your soul
+ To give it due content.
+ Laer. Let this be so.
+ His means of death, his obscure funeral-
+ No trophy, sword, nor hatchment o'er his bones,
+ No noble rite nor formal ostentation,-
+ Cry to be heard, as 'twere from heaven to earth,
+ That I must call't in question.
+ King. So you shall;
+ And where th' offence is let the great axe fall.
+ I pray you go with me.
+ Exeunt
+
+
+
+
+
+Scene VI.
+Elsinore. Another room in the Castle.
+
+Enter Horatio with an Attendant.
+
+ Hor. What are they that would speak with me?
+ Servant. Seafaring men, sir. They say they have letters for you.
+ Hor. Let them come in.
+ [Exit Attendant.]
+ I do not know from what part of the world
+ I should be greeted, if not from Lord Hamlet.
+
+ Enter Sailors.
+
+ Sailor. God bless you, sir.
+ Hor. Let him bless thee too.
+ Sailor. 'A shall, sir, an't please him. There's a letter for you,
+ sir,- it comes from th' ambassador that was bound for England- if
+ your name be Horatio, as I am let to know it is.
+ Hor. (reads the letter) 'Horatio, when thou shalt have overlook'd
+ this, give these fellows some means to the King. They have
+ letters for him. Ere we were two days old at sea, a pirate of
+ very warlike appointment gave us chase. Finding ourselves too
+ slow of sail, we put on a compelled valour, and in the grapple I
+ boarded them. On the instant they got clear of our ship; so I
+ alone became their prisoner. They have dealt with me like thieves
+ of mercy; but they knew what they did: I am to do a good turn for
+ them. Let the King have the letters I have sent, and repair thou
+ to me with as much speed as thou wouldst fly death. I have words
+ to speak in thine ear will make thee dumb; yet are they much too
+ light for the bore of the matter. These good fellows will bring
+ thee where I am. Rosencrantz and Guildenstern hold their course
+ for England. Of them I have much to tell thee. Farewell.
+ 'He that thou knowest thine, HAMLET.'
+
+ Come, I will give you way for these your letters,
+ And do't the speedier that you may direct me
+ To him from whom you brought them. Exeunt.
+
+
+
+
+
+Scene VII.
+Elsinore. Another room in the Castle.
+
+Enter King and Laertes.
+
+ King. Now must your conscience my acquittance seal,
+ And You must put me in your heart for friend,
+ Sith you have heard, and with a knowing ear,
+ That he which hath your noble father slain
+ Pursued my life.
+ Laer. It well appears. But tell me
+ Why you proceeded not against these feats
+ So crimeful and so capital in nature,
+ As by your safety, wisdom, all things else,
+ You mainly were stirr'd up.
+ King. O, for two special reasons,
+ Which may to you, perhaps, seein much unsinew'd,
+ But yet to me they are strong. The Queen his mother
+ Lives almost by his looks; and for myself,-
+ My virtue or my plague, be it either which,-
+ She's so conjunctive to my life and soul
+ That, as the star moves not but in his sphere,
+ I could not but by her. The other motive
+ Why to a public count I might not go
+ Is the great love the general gender bear him,
+ Who, dipping all his faults in their affection,
+ Would, like the spring that turneth wood to stone,
+ Convert his gives to graces; so that my arrows,
+ Too slightly timber'd for so loud a wind,
+ Would have reverted to my bow again,
+ And not where I had aim'd them.
+ Laer. And so have I a noble father lost;
+ A sister driven into desp'rate terms,
+ Whose worth, if praises may go back again,
+ Stood challenger on mount of all the age
+ For her perfections. But my revenge will come.
+ King. Break not your sleeps for that. You must not think
+ That we are made of stuff so flat and dull
+ That we can let our beard be shook with danger,
+ And think it pastime. You shortly shall hear more.
+ I lov'd your father, and we love ourself,
+ And that, I hope, will teach you to imagine-
+
+ Enter a Messenger with letters.
+
+ How now? What news?
+ Mess. Letters, my lord, from Hamlet:
+ This to your Majesty; this to the Queen.
+ King. From Hamlet? Who brought them?
+ Mess. Sailors, my lord, they say; I saw them not.
+ They were given me by Claudio; he receiv'd them
+ Of him that brought them.
+ King. Laertes, you shall hear them.
+ Leave us.
+ Exit Messenger.
+ [Reads]'High and Mighty,-You shall know I am set naked on your
+ kingdom. To-morrow shall I beg leave to see your kingly eyes;
+ when I shall (first asking your pardon thereunto) recount the
+ occasion of my sudden and more strange return.
+ 'HAMLET.'
+ What should this mean? Are all the rest come back?
+ Or is it some abuse, and no such thing?
+ Laer. Know you the hand?
+ King. 'Tis Hamlet's character. 'Naked!'
+ And in a postscript here, he says 'alone.'
+ Can you advise me?
+ Laer. I am lost in it, my lord. But let him come!
+ It warms the very sickness in my heart
+ That I shall live and tell him to his teeth,
+ 'Thus didest thou.'
+ King. If it be so, Laertes
+ (As how should it be so? how otherwise?),
+ Will you be rul'd by me?
+ Laer. Ay my lord,
+ So you will not o'errule me to a peace.
+ King. To thine own peace. If he be now return'd
+ As checking at his voyage, and that he means
+ No more to undertake it, I will work him
+ To exploit now ripe in my device,
+ Under the which he shall not choose but fall;
+ And for his death no wind
+ But even his mother shall uncharge the practice
+ And call it accident.
+ Laer. My lord, I will be rul'd;
+ The rather, if you could devise it so
+ That I might be the organ.
+ King. It falls right.
+ You have been talk'd of since your travel much,
+ And that in Hamlet's hearing, for a quality
+ Wherein they say you shine, Your sun of parts
+ Did not together pluck such envy from him
+ As did that one; and that, in my regard,
+ Of the unworthiest siege.
+ Laer. What part is that, my lord?
+ King. A very riband in the cap of youth-
+ Yet needfull too; for youth no less becomes
+ The light and careless livery that it wears
+ Thin settled age his sables and his weeds,
+ Importing health and graveness. Two months since
+ Here was a gentleman of Normandy.
+ I have seen myself, and serv'd against, the French,
+ And they can well on horseback; but this gallant
+ Had witchcraft in't. He grew unto his seat,
+ And to such wondrous doing brought his horse
+ As had he been incorps'd and demi-natur'd
+ With the brave beast. So far he topp'd my thought
+ That I, in forgery of shapes and tricks,
+ Come short of what he did.
+ Laer. A Norman was't?
+ King. A Norman.
+ Laer. Upon my life, Lamound.
+ King. The very same.
+ Laer. I know him well. He is the broach indeed
+ And gem of all the nation.
+ King. He made confession of you;
+ And gave you such a masterly report
+ For art and exercise in your defence,
+ And for your rapier most especially,
+ That he cried out 'twould be a sight indeed
+ If one could match you. The scrimers of their nation
+ He swore had neither motion, guard, nor eye,
+ If you oppos'd them. Sir, this report of his
+ Did Hamlet so envenom with his envy
+ That he could nothing do but wish and beg
+ Your sudden coming o'er to play with you.
+ Now, out of this-
+ Laer. What out of this, my lord?
+ King. Laertes, was your father dear to you?
+ Or are you like the painting of a sorrow,
+ A face without a heart,'
+ Laer. Why ask you this?
+ King. Not that I think you did not love your father;
+ But that I know love is begun by time,
+ And that I see, in passages of proof,
+ Time qualifies the spark and fire of it.
+ There lives within the very flame of love
+ A kind of wick or snuff that will abate it;
+ And nothing is at a like goodness still;
+ For goodness, growing to a plurisy,
+ Dies in his own too-much. That we would do,
+ We should do when we would; for this 'would' changes,
+ And hath abatements and delays as many
+ As there are tongues, are hands, are accidents;
+ And then this 'should' is like a spendthrift sigh,
+ That hurts by easing. But to the quick o' th' ulcer!
+ Hamlet comes back. What would you undertake
+ To show yourself your father's son in deed
+ More than in words?
+ Laer. To cut his throat i' th' church!
+ King. No place indeed should murther sanctuarize;
+ Revenge should have no bounds. But, good Laertes,
+ Will you do this? Keep close within your chamber.
+ Will return'd shall know you are come home.
+ We'll put on those shall praise your excellence
+ And set a double varnish on the fame
+ The Frenchman gave you; bring you in fine together
+ And wager on your heads. He, being remiss,
+ Most generous, and free from all contriving,
+ Will not peruse the foils; so that with ease,
+ Or with a little shuffling, you may choose
+ A sword unbated, and, in a pass of practice,
+ Requite him for your father.
+ Laer. I will do't!
+ And for that purpose I'll anoint my sword.
+ I bought an unction of a mountebank,
+ So mortal that, but dip a knife in it,
+ Where it draws blood no cataplasm so rare,
+ Collected from all simples that have virtue
+ Under the moon, can save the thing from death
+ This is but scratch'd withal. I'll touch my point
+ With this contagion, that, if I gall him slightly,
+ It may be death.
+ King. Let's further think of this,
+ Weigh what convenience both of time and means
+ May fit us to our shape. If this should fall,
+ And that our drift look through our bad performance.
+ 'Twere better not assay'd. Therefore this project
+ Should have a back or second, that might hold
+ If this did blast in proof. Soft! let me see.
+ We'll make a solemn wager on your cunnings-
+ I ha't!
+ When in your motion you are hot and dry-
+ As make your bouts more violent to that end-
+ And that he calls for drink, I'll have prepar'd him
+ A chalice for the nonce; whereon but sipping,
+ If he by chance escape your venom'd stuck,
+ Our purpose may hold there.- But stay, what noise,
+
+ Enter Queen.
+
+ How now, sweet queen?
+ Queen. One woe doth tread upon another's heel,
+ So fast they follow. Your sister's drown'd, Laertes.
+ Laer. Drown'd! O, where?
+ Queen. There is a willow grows aslant a brook,
+ That shows his hoar leaves in the glassy stream.
+ There with fantastic garlands did she come
+ Of crowflowers, nettles, daisies, and long purples,
+ That liberal shepherds give a grosser name,
+ But our cold maids do dead men's fingers call them.
+ There on the pendant boughs her coronet weeds
+ Clamb'ring to hang, an envious sliver broke,
+ When down her weedy trophies and herself
+ Fell in the weeping brook. Her clothes spread wide
+ And, mermaid-like, awhile they bore her up;
+ Which time she chaunted snatches of old tunes,
+ As one incapable of her own distress,
+ Or like a creature native and indued
+ Unto that element; but long it could not be
+ Till that her garments, heavy with their drink,
+ Pull'd the poor wretch from her melodious lay
+ To muddy death.
+ Laer. Alas, then she is drown'd?
+ Queen. Drown'd, drown'd.
+ Laer. Too much of water hast thou, poor Ophelia,
+ And therefore I forbid my tears; but yet
+ It is our trick; nature her custom holds,
+ Let shame say what it will. When these are gone,
+ The woman will be out. Adieu, my lord.
+ I have a speech of fire, that fain would blaze
+ But that this folly douts it. Exit.
+ King. Let's follow, Gertrude.
+ How much I had to do to calm his rage I
+ Now fear I this will give it start again;
+ Therefore let's follow.
+ Exeunt.
+
+
+
+
+
+ACT V. Scene I.
+Elsinore. A churchyard.
+
+Enter two Clowns, [with spades and pickaxes].
+
+ Clown. Is she to be buried in Christian burial when she wilfully
+ seeks her own salvation?
+ Other. I tell thee she is; therefore make her grave straight.
+ The crowner hath sate on her, and finds it Christian burial.
+ Clown. How can that be, unless she drown'd herself in her own
+ defence?
+ Other. Why, 'tis found so.
+ Clown. It must be se offendendo; it cannot be else. For here lies
+ the point: if I drown myself wittingly, it argues an act; and an
+ act hath three branches-it is to act, to do, and to perform;
+ argal, she drown'd herself wittingly.
+ Other. Nay, but hear you, Goodman Delver!
+ Clown. Give me leave. Here lies the water; good. Here stands the
+ man; good. If the man go to this water and drown himself, it is,
+ will he nill he, he goes- mark you that. But if the water come to
+ him and drown him, he drowns not himself. Argal, he that is not
+ guilty of his own death shortens not his own life.
+ Other. But is this law?
+ Clown. Ay, marry, is't- crowner's quest law.
+ Other. Will you ha' the truth an't? If this had not been a
+ gentlewoman, she should have been buried out o' Christian burial.
+ Clown. Why, there thou say'st! And the more pity that great folk
+ should have count'nance in this world to drown or hang themselves
+ more than their even-Christen. Come, my spade! There is no
+ ancient gentlemen but gard'ners, ditchers, and grave-makers. They
+ hold up Adam's profession.
+ Other. Was he a gentleman?
+ Clown. 'A was the first that ever bore arms.
+ Other. Why, he had none.
+ Clown. What, art a heathen? How dost thou understand the Scripture?
+ The Scripture says Adam digg'd. Could he dig without arms? I'll
+ put another question to thee. If thou answerest me not to the
+ purpose, confess thyself-
+ Other. Go to!
+ Clown. What is he that builds stronger than either the mason, the
+ shipwright, or the carpenter?
+ Other. The gallows-maker; for that frame outlives a thousand
+ tenants.
+ Clown. I like thy wit well, in good faith. The gallows does well.
+ But how does it well? It does well to those that do ill. Now,
+ thou dost ill to say the gallows is built stronger than the
+ church. Argal, the gallows may do well to thee. To't again, come!
+ Other. Who builds stronger than a mason, a shipwright, or a
+ carpenter?
+ Clown. Ay, tell me that, and unyoke.
+ Other. Marry, now I can tell!
+ Clown. To't.
+ Other. Mass, I cannot tell.
+
+ Enter Hamlet and Horatio afar off.
+
+ Clown. Cudgel thy brains no more about it, for your dull ass will
+ not mend his pace with beating; and when you are ask'd this
+ question next, say 'a grave-maker.' The houses he makes lasts
+ till doomsday. Go, get thee to Yaughan; fetch me a stoup of
+ liquor.
+ [Exit Second Clown.]
+
+ [Clown digs and] sings.
+
+ In youth when I did love, did love,
+ Methought it was very sweet;
+ To contract- O- the time for- a- my behove,
+ O, methought there- a- was nothing- a- meet.
+
+ Ham. Has this fellow no feeling of his business, that he sings at
+ grave-making?
+ Hor. Custom hath made it in him a Property of easiness.
+ Ham. 'Tis e'en so. The hand of little employment hath the daintier
+ sense.
+ Clown. (sings)
+ But age with his stealing steps
+ Hath clawed me in his clutch,
+ And hath shipped me intil the land,
+ As if I had never been such.
+ [Throws up a skull.]
+
+ Ham. That skull had a tongue in it, and could sing once. How the
+ knave jowls it to the ground,as if 'twere Cain's jawbone, that
+ did the first murther! This might be the pate of a Politician,
+ which this ass now o'erreaches; one that would circumvent God,
+ might it not?
+ Hor. It might, my lord.
+ Ham. Or of a courtier, which could say 'Good morrow, sweet lord!
+ How dost thou, good lord?' This might be my Lord Such-a-one, that
+ prais'd my Lord Such-a-one's horse when he meant to beg it- might
+ it not?
+ Hor. Ay, my lord.
+ Ham. Why, e'en so! and now my Lady Worm's, chapless, and knock'd
+ about the mazzard with a sexton's spade. Here's fine revolution,
+ and we had the trick to see't. Did these bones cost no more the
+ breeding but to play at loggets with 'em? Mine ache to think
+ on't.
+ Clown. (Sings)
+ A pickaxe and a spade, a spade,
+ For and a shrouding sheet;
+ O, a Pit of clay for to be made
+ For such a guest is meet.
+ Throws up [another skull].
+
+ Ham. There's another. Why may not that be the skull of a lawyer?
+ Where be his quiddits now, his quillets, his cases, his tenures,
+ and his tricks? Why does he suffer this rude knave now to knock
+ him about the sconce with a dirty shovel, and will not tell him
+ of his action of battery? Hum! This fellow might be in's time a
+ great buyer of land, with his statutes, his recognizances, his
+ fines, his double vouchers, his recoveries. Is this the fine of
+ his fines, and the recovery of his recoveries, to have his fine
+ pate full of fine dirt? Will his vouchers vouch him no more of
+ his purchases, and double ones too, than the length and breadth
+ of a pair of indentures? The very conveyances of his lands will
+ scarcely lie in this box; and must th' inheritor himself have no
+ more, ha?
+ Hor. Not a jot more, my lord.
+ Ham. Is not parchment made of sheepskins?
+ Hor. Ay, my lord, And of calveskins too.
+ Ham. They are sheep and calves which seek out assurance in that. I
+ will speak to this fellow. Whose grave's this, sirrah?
+ Clown. Mine, sir.
+
+ [Sings] O, a pit of clay for to be made
+ For such a guest is meet.
+
+ Ham. I think it be thine indeed, for thou liest in't.
+ Clown. You lie out on't, sir, and therefore 'tis not yours.
+ For my part, I do not lie in't, yet it is mine.
+ Ham. Thou dost lie in't, to be in't and say it is thine. 'Tis for
+ the dead, not for the quick; therefore thou liest.
+ Clown. 'Tis a quick lie, sir; 'twill away again from me to you.
+ Ham. What man dost thou dig it for?
+ Clown. For no man, sir.
+ Ham. What woman then?
+ Clown. For none neither.
+ Ham. Who is to be buried in't?
+ Clown. One that was a woman, sir; but, rest her soul, she's dead.
+ Ham. How absolute the knave is! We must speak by the card, or
+ equivocation will undo us. By the Lord, Horatio, this three years
+ I have taken note of it, the age is grown so picked that the toe
+ of the peasant comes so near the heel of the courtier he galls
+ his kibe.- How long hast thou been a grave-maker?
+ Clown. Of all the days i' th' year, I came to't that day that our
+ last king Hamlet overcame Fortinbras.
+ Ham. How long is that since?
+ Clown. Cannot you tell that? Every fool can tell that. It was the
+ very day that young Hamlet was born- he that is mad, and sent
+ into England.
+ Ham. Ay, marry, why was be sent into England?
+ Clown. Why, because 'a was mad. 'A shall recover his wits there;
+ or, if 'a do not, 'tis no great matter there.
+ Ham. Why?
+ Clown. 'Twill not he seen in him there. There the men are as mad as
+ he.
+ Ham. How came he mad?
+ Clown. Very strangely, they say.
+ Ham. How strangely?
+ Clown. Faith, e'en with losing his wits.
+ Ham. Upon what ground?
+ Clown. Why, here in Denmark. I have been sexton here, man and boy
+ thirty years.
+ Ham. How long will a man lie i' th' earth ere he rot?
+ Clown. Faith, if 'a be not rotten before 'a die (as we have many
+ pocky corses now-a-days that will scarce hold the laying in, I
+ will last you some eight year or nine year. A tanner will last
+ you nine year.
+ Ham. Why he more than another?
+ Clown. Why, sir, his hide is so tann'd with his trade that 'a will
+ keep out water a great while; and your water is a sore decayer of
+ your whoreson dead body. Here's a skull now. This skull hath lien
+ you i' th' earth three-and-twenty years.
+ Ham. Whose was it?
+ Clown. A whoreson, mad fellow's it was. Whose do you think it was?
+ Ham. Nay, I know not.
+ Clown. A pestilence on him for a mad rogue! 'A pour'd a flagon of
+ Rhenish on my head once. This same skull, sir, was Yorick's
+ skull, the King's jester.
+ Ham. This?
+ Clown. E'en that.
+ Ham. Let me see. [Takes the skull.] Alas, poor Yorick! I knew him,
+ Horatio. A fellow of infinite jest, of most excellent fancy. He
+ hath borne me on his back a thousand tunes. And now how abhorred
+ in my imagination it is! My gorge rises at it. Here hung those
+ lips that I have kiss'd I know not how oft. Where be your gibes
+ now? your gambols? your songs? your flashes of merriment that
+ were wont to set the table on a roar? Not one now, to mock your
+ own grinning? Quite chap- fall'n? Now get you to my lady's
+ chamber, and tell her, let her paint an inch thick, to this
+ favour she must come. Make her laugh at that. Prithee, Horatio,
+ tell me one thing.
+ Hor. What's that, my lord?
+ Ham. Dost thou think Alexander look'd o' this fashion i' th' earth?
+ Hor. E'en so.
+ Ham. And smelt so? Pah!
+ [Puts down the skull.]
+ Hor. E'en so, my lord.
+ Ham. To what base uses we may return, Horatio! Why may not
+ imagination trace the noble dust of Alexander till he find it
+ stopping a bunghole?
+ Hor. 'Twere to consider too curiously, to consider so.
+ Ham. No, faith, not a jot; but to follow him thither with modesty
+ enough, and likelihood to lead it; as thus: Alexander died,
+ Alexander was buried, Alexander returneth into dust; the dust is
+ earth; of earth we make loam; and why of that loam (whereto he
+ was converted) might they not stop a beer barrel?
+ Imperious Caesar, dead and turn'd to clay,
+ Might stop a hole to keep the wind away.
+ O, that that earth which kept the world in awe
+ Should patch a wall t' expel the winter's flaw!
+ But soft! but soft! aside! Here comes the King-
+
+ Enter [priests with] a coffin [in funeral procession], King,
+ Queen, Laertes, with Lords attendant.]
+
+ The Queen, the courtiers. Who is this they follow?
+ And with such maimed rites? This doth betoken
+ The corse they follow did with desp'rate hand
+ Fordo it own life. 'Twas of some estate.
+ Couch we awhile, and mark.
+ [Retires with Horatio.]
+ Laer. What ceremony else?
+ Ham. That is Laertes,
+ A very noble youth. Mark.
+ Laer. What ceremony else?
+ Priest. Her obsequies have been as far enlarg'd
+ As we have warranty. Her death was doubtful;
+ And, but that great command o'ersways the order,
+ She should in ground unsanctified have lodg'd
+ Till the last trumpet. For charitable prayers,
+ Shards, flints, and pebbles should be thrown on her.
+ Yet here she is allow'd her virgin crants,
+ Her maiden strewments, and the bringing home
+ Of bell and burial.
+ Laer. Must there no more be done?
+ Priest. No more be done.
+ We should profane the service of the dead
+ To sing a requiem and such rest to her
+ As to peace-parted souls.
+ Laer. Lay her i' th' earth;
+ And from her fair and unpolluted flesh
+ May violets spring! I tell thee, churlish priest,
+ A minist'ring angel shall my sister be
+ When thou liest howling.
+ Ham. What, the fair Ophelia?
+ Queen. Sweets to the sweet! Farewell.
+ [Scatters flowers.]
+ I hop'd thou shouldst have been my Hamlet's wife;
+ I thought thy bride-bed to have deck'd, sweet maid,
+ And not have strew'd thy grave.
+ Laer. O, treble woe
+ Fall ten times treble on that cursed head
+ Whose wicked deed thy most ingenious sense
+ Depriv'd thee of! Hold off the earth awhile,
+ Till I have caught her once more in mine arms.
+ Leaps in the grave.
+ Now pile your dust upon the quick and dead
+ Till of this flat a mountain you have made
+ T' o'ertop old Pelion or the skyish head
+ Of blue Olympus.
+ Ham. [comes forward] What is he whose grief
+ Bears such an emphasis? whose phrase of sorrow
+ Conjures the wand'ring stars, and makes them stand
+ Like wonder-wounded hearers? This is I,
+ Hamlet the Dane. [Leaps in after Laertes.
+ Laer. The devil take thy soul!
+ [Grapples with him].
+ Ham. Thou pray'st not well.
+ I prithee take thy fingers from my throat;
+ For, though I am not splenitive and rash,
+ Yet have I in me something dangerous,
+ Which let thy wisdom fear. Hold off thy hand!
+ King. Pluck thein asunder.
+ Queen. Hamlet, Hamlet!
+ All. Gentlemen!
+ Hor. Good my lord, be quiet.
+ [The Attendants part them, and they come out of the
+ grave.]
+ Ham. Why, I will fight with him upon this theme
+ Until my eyelids will no longer wag.
+ Queen. O my son, what theme?
+ Ham. I lov'd Ophelia. Forty thousand brothers
+ Could not (with all their quantity of love)
+ Make up my sum. What wilt thou do for her?
+ King. O, he is mad, Laertes.
+ Queen. For love of God, forbear him!
+ Ham. 'Swounds, show me what thou't do.
+ Woo't weep? woo't fight? woo't fast? woo't tear thyself?
+ Woo't drink up esill? eat a crocodile?
+ I'll do't. Dost thou come here to whine?
+ To outface me with leaping in her grave?
+ Be buried quick with her, and so will I.
+ And if thou prate of mountains, let them throw
+ Millions of acres on us, till our ground,
+ Singeing his pate against the burning zone,
+ Make Ossa like a wart! Nay, an thou'lt mouth,
+ I'll rant as well as thou.
+ Queen. This is mere madness;
+ And thus a while the fit will work on him.
+ Anon, as patient as the female dove
+ When that her golden couplets are disclos'd,
+ His silence will sit drooping.
+ Ham. Hear you, sir!
+ What is the reason that you use me thus?
+ I lov'd you ever. But it is no matter.
+ Let Hercules himself do what he may,
+ The cat will mew, and dog will have his day.
+Exit.
+ King. I pray thee, good Horatio, wait upon him.
+ Exit Horatio.
+ [To Laertes] Strengthen your patience in our last night's speech.
+ We'll put the matter to the present push.-
+ Good Gertrude, set some watch over your son.-
+ This grave shall have a living monument.
+ An hour of quiet shortly shall we see;
+ Till then in patience our proceeding be.
+ Exeunt.
+
+
+
+
+Scene II.
+Elsinore. A hall in the Castle.
+
+Enter Hamlet and Horatio.
+
+ Ham. So much for this, sir; now shall you see the other.
+ You do remember all the circumstance?
+ Hor. Remember it, my lord!
+ Ham. Sir, in my heart there was a kind of fighting
+ That would not let me sleep. Methought I lay
+ Worse than the mutinies in the bilboes. Rashly-
+ And prais'd be rashness for it; let us know,
+ Our indiscretion sometime serves us well
+ When our deep plots do pall; and that should learn us
+ There's a divinity that shapes our ends,
+ Rough-hew them how we will-
+ Hor. That is most certain.
+ Ham. Up from my cabin,
+ My sea-gown scarf'd about me, in the dark
+ Grop'd I to find out them; had my desire,
+ Finger'd their packet, and in fine withdrew
+ To mine own room again; making so bold
+ (My fears forgetting manners) to unseal
+ Their grand commission; where I found, Horatio
+ (O royal knavery!), an exact command,
+ Larded with many several sorts of reasons,
+ Importing Denmark's health, and England's too,
+ With, hoo! such bugs and goblins in my life-
+ That, on the supervise, no leisure bated,
+ No, not to stay the finding of the axe,
+ My head should be struck off.
+ Hor. Is't possible?
+ Ham. Here's the commission; read it at more leisure.
+ But wilt thou bear me how I did proceed?
+ Hor. I beseech you.
+ Ham. Being thus benetted round with villanies,
+ Or I could make a prologue to my brains,
+ They had begun the play. I sat me down;
+ Devis'd a new commission; wrote it fair.
+ I once did hold it, as our statists do,
+ A baseness to write fair, and labour'd much
+ How to forget that learning; but, sir, now
+ It did me yeoman's service. Wilt thou know
+ Th' effect of what I wrote?
+ Hor. Ay, good my lord.
+ Ham. An earnest conjuration from the King,
+ As England was his faithful tributary,
+ As love between them like the palm might flourish,
+ As peace should still her wheaten garland wear
+ And stand a comma 'tween their amities,
+ And many such-like as's of great charge,
+ That, on the view and knowing of these contents,
+ Without debatement further, more or less,
+ He should the bearers put to sudden death,
+ Not shriving time allow'd.
+ Hor. How was this seal'd?
+ Ham. Why, even in that was heaven ordinant.
+ I had my father's signet in my purse,
+ which was the model of that Danish seal;
+ Folded the writ up in the form of th' other,
+ Subscrib'd it, gave't th' impression, plac'd it safely,
+ The changeling never known. Now, the next day
+ Was our sea-fight; and what to this was sequent
+ Thou know'st already.
+ Hor. So Guildenstern and Rosencrantz go to't.
+ Ham. Why, man, they did make love to this employment!
+ They are not near my conscience; their defeat
+ Does by their own insinuation grow.
+ 'Tis dangerous when the baser nature comes
+ Between the pass and fell incensed points
+ Of mighty opposites.
+ Hor. Why, what a king is this!
+ Ham. Does it not, thinks't thee, stand me now upon-
+ He that hath kill'd my king, and whor'd my mother;
+ Popp'd in between th' election and my hopes;
+ Thrown out his angle for my Proper life,
+ And with such coz'nage- is't not perfect conscience
+ To quit him with this arm? And is't not to be damn'd
+ To let this canker of our nature come
+ In further evil?
+ Hor. It must be shortly known to him from England
+ What is the issue of the business there.
+ Ham. It will be short; the interim is mine,
+ And a man's life is no more than to say 'one.'
+ But I am very sorry, good Horatio,
+ That to Laertes I forgot myself,
+ For by the image of my cause I see
+ The portraiture of his. I'll court his favours.
+ But sure the bravery of his grief did put me
+ Into a tow'ring passion.
+ Hor. Peace! Who comes here?
+
+ Enter young Osric, a courtier.
+
+ Osr. Your lordship is right welcome back to Denmark.
+ Ham. I humbly thank you, sir. [Aside to Horatio] Dost know this
+ waterfly?
+ Hor. [aside to Hamlet] No, my good lord.
+ Ham. [aside to Horatio] Thy state is the more gracious; for 'tis a
+ vice to know him. He hath much land, and fertile. Let a beast be
+ lord of beasts, and his crib shall stand at the king's mess. 'Tis
+ a chough; but, as I say, spacious in the possession of dirt.
+ Osr. Sweet lord, if your lordship were at leisure, I should impart
+ a thing to you from his Majesty.
+ Ham. I will receive it, sir, with all diligence of spirit. Put your
+ bonnet to his right use. 'Tis for the head.
+ Osr. I thank your lordship, it is very hot.
+ Ham. No, believe me, 'tis very cold; the wind is northerly.
+ Osr. It is indifferent cold, my lord, indeed.
+ Ham. But yet methinks it is very sultry and hot for my complexion.
+ Osr. Exceedingly, my lord; it is very sultry, as 'twere- I cannot
+ tell how. But, my lord, his Majesty bade me signify to you that
+ he has laid a great wager on your head. Sir, this is the matter-
+ Ham. I beseech you remember.
+ [Hamlet moves him to put on his hat.]
+ Osr. Nay, good my lord; for mine ease, in good faith. Sir, here is
+ newly come to court Laertes; believe me, an absolute gentleman,
+ full of most excellent differences, of very soft society and
+ great showing. Indeed, to speak feelingly of him, he is the card
+ or calendar of gentry; for you shall find in him the continent of
+ what part a gentleman would see.
+ Ham. Sir, his definement suffers no perdition in you; though, I
+ know, to divide him inventorially would dozy th' arithmetic of
+ memory, and yet but yaw neither in respect of his quick sail.
+ But, in the verity of extolment, I take him to be a soul of great
+ article, and his infusion of such dearth and rareness as, to make
+ true diction of him, his semblable is his mirror, and who else
+ would trace him, his umbrage, nothing more.
+ Osr. Your lordship speaks most infallibly of him.
+ Ham. The concernancy, sir? Why do we wrap the gentleman in our more
+ rawer breath
+ Osr. Sir?
+ Hor [aside to Hamlet] Is't not possible to understand in another
+ tongue? You will do't, sir, really.
+ Ham. What imports the nomination of this gentleman
+ Osr. Of Laertes?
+ Hor. [aside] His purse is empty already. All's golden words are
+ spent.
+ Ham. Of him, sir.
+ Osr. I know you are not ignorant-
+ Ham. I would you did, sir; yet, in faith, if you did, it would not
+ much approve me. Well, sir?
+ Osr. You are not ignorant of what excellence Laertes is-
+ Ham. I dare not confess that, lest I should compare with him in
+ excellence; but to know a man well were to know himself.
+ Osr. I mean, sir, for his weapon; but in the imputation laid on him
+ by them, in his meed he's unfellowed.
+ Ham. What's his weapon?
+ Osr. Rapier and dagger.
+ Ham. That's two of his weapons- but well.
+ Osr. The King, sir, hath wager'd with him six Barbary horses;
+ against the which he has impon'd, as I take it, six French
+ rapiers and poniards, with their assigns, as girdle, hangers, and
+ so. Three of the carriages, in faith, are very dear to fancy,
+ very responsive to the hilts, most delicate carriages, and of
+ very liberal conceit.
+ Ham. What call you the carriages?
+ Hor. [aside to Hamlet] I knew you must be edified by the margent
+ ere you had done.
+ Osr. The carriages, sir, are the hangers.
+ Ham. The phrase would be more germane to the matter if we could
+ carry cannon by our sides. I would it might be hangers till then.
+ But on! Six Barbary horses against six French swords, their
+ assigns, and three liberal-conceited carriages: that's the French
+ bet against the Danish. Why is this all impon'd, as you call it?
+ Osr. The King, sir, hath laid that, in a dozen passes between
+ yourself and him, he shall not exceed you three hits; he hath
+ laid on twelve for nine, and it would come to immediate trial
+ if your lordship would vouchsafe the answer.
+ Ham. How if I answer no?
+ Osr. I mean, my lord, the opposition of your person in trial.
+ Ham. Sir, I will walk here in the hall. If it please his Majesty,
+ it is the breathing time of day with me. Let the foils be
+ brought, the gentleman willing, and the King hold his purpose,
+ I will win for him if I can; if not, I will gain nothing but my
+ shame and the odd hits.
+ Osr. Shall I redeliver you e'en so?
+ Ham. To this effect, sir, after what flourish your nature will.
+ Osr. I commend my duty to your lordship.
+ Ham. Yours, yours. [Exit Osric.] He does well to commend it
+ himself; there are no tongues else for's turn.
+ Hor. This lapwing runs away with the shell on his head.
+ Ham. He did comply with his dug before he suck'd it. Thus has he,
+ and many more of the same bevy that I know the drossy age dotes
+ on, only got the tune of the time and outward habit of encounter-
+ a kind of yesty collection, which carries them through and
+ through the most fann'd and winnowed opinions; and do but blow
+ them to their trial-the bubbles are out,
+
+ Enter a Lord.
+
+ Lord. My lord, his Majesty commended him to you by young Osric, who
+ brings back to him, that you attend him in the hall. He sends to
+ know if your pleasure hold to play with Laertes, or that you will
+ take longer time.
+ Ham. I am constant to my purposes; they follow the King's pleasure.
+ If his fitness speaks, mine is ready; now or whensoever, provided
+ I be so able as now.
+ Lord. The King and Queen and all are coming down.
+ Ham. In happy time.
+ Lord. The Queen desires you to use some gentle entertainment to
+ Laertes before you fall to play.
+ Ham. She well instructs me.
+ [Exit Lord.]
+ Hor. You will lose this wager, my lord.
+ Ham. I do not think so. Since he went into France I have been in
+ continual practice. I shall win at the odds. But thou wouldst not
+ think how ill all's here about my heart. But it is no matter.
+ Hor. Nay, good my lord -
+ Ham. It is but foolery; but it is such a kind of gaingiving as
+ would perhaps trouble a woman.
+ Hor. If your mind dislike anything, obey it. I will forestall their
+ repair hither and say you are not fit.
+ Ham. Not a whit, we defy augury; there's a special providence in
+ the fall of a sparrow. If it be now, 'tis not to come', if it be
+ not to come, it will be now; if it be not now, yet it will come:
+ the readiness is all. Since no man knows aught of what he leaves,
+ what is't to leave betimes? Let be.
+
+ Enter King, Queen, Laertes, Osric, and Lords, with other
+ Attendants with foils and gauntlets.
+ A table and flagons of wine on it.
+
+ King. Come, Hamlet, come, and take this hand from me.
+ [The King puts Laertes' hand into Hamlet's.]
+ Ham. Give me your pardon, sir. I have done you wrong;
+ But pardon't, as you are a gentleman.
+ This presence knows,
+ And you must needs have heard, how I am punish'd
+ With sore distraction. What I have done
+ That might your nature, honour, and exception
+ Roughly awake, I here proclaim was madness.
+ Was't Hamlet wrong'd Laertes? Never Hamlet.
+ If Hamlet from himself be taken away,
+ And when he's not himself does wrong Laertes,
+ Then Hamlet does it not, Hamlet denies it.
+ Who does it, then? His madness. If't be so,
+ Hamlet is of the faction that is wrong'd;
+ His madness is poor Hamlet's enemy.
+ Sir, in this audience,
+ Let my disclaiming from a purpos'd evil
+ Free me so far in your most generous thoughts
+ That I have shot my arrow o'er the house
+ And hurt my brother.
+ Laer. I am satisfied in nature,
+ Whose motive in this case should stir me most
+ To my revenge. But in my terms of honour
+ I stand aloof, and will no reconcilement
+ Till by some elder masters of known honour
+ I have a voice and precedent of peace
+ To keep my name ungor'd. But till that time
+ I do receive your offer'd love like love,
+ And will not wrong it.
+ Ham. I embrace it freely,
+ And will this brother's wager frankly play.
+ Give us the foils. Come on.
+ Laer. Come, one for me.
+ Ham. I'll be your foil, Laertes. In mine ignorance
+ Your skill shall, like a star i' th' darkest night,
+ Stick fiery off indeed.
+ Laer. You mock me, sir.
+ Ham. No, by this bad.
+ King. Give them the foils, young Osric. Cousin Hamlet,
+ You know the wager?
+ Ham. Very well, my lord.
+ Your Grace has laid the odds o' th' weaker side.
+ King. I do not fear it, I have seen you both;
+ But since he is better'd, we have therefore odds.
+ Laer. This is too heavy; let me see another.
+ Ham. This likes me well. These foils have all a length?
+ Prepare to play.
+ Osr. Ay, my good lord.
+ King. Set me the stoups of wine upon that table.
+ If Hamlet give the first or second hit,
+ Or quit in answer of the third exchange,
+ Let all the battlements their ordnance fire;
+ The King shall drink to Hamlet's better breath,
+ And in the cup an union shall he throw
+ Richer than that which four successive kings
+ In Denmark's crown have worn. Give me the cups;
+ And let the kettle to the trumpet speak,
+ The trumpet to the cannoneer without,
+ The cannons to the heavens, the heaven to earth,
+ 'Now the King drinks to Hamlet.' Come, begin.
+ And you the judges, bear a wary eye.
+ Ham. Come on, sir.
+ Laer. Come, my lord. They play.
+ Ham. One.
+ Laer. No.
+ Ham. Judgment!
+ Osr. A hit, a very palpable hit.
+ Laer. Well, again!
+ King. Stay, give me drink. Hamlet, this pearl is thine;
+ Here's to thy health.
+ [Drum; trumpets sound; a piece goes off [within].
+ Give him the cup.
+ Ham. I'll play this bout first; set it by awhile.
+ Come. (They play.) Another hit. What say you?
+ Laer. A touch, a touch; I do confess't.
+ King. Our son shall win.
+ Queen. He's fat, and scant of breath.
+ Here, Hamlet, take my napkin, rub thy brows.
+ The Queen carouses to thy fortune, Hamlet.
+ Ham. Good madam!
+ King. Gertrude, do not drink.
+ Queen. I will, my lord; I pray you pardon me. Drinks.
+ King. [aside] It is the poison'd cup; it is too late.
+ Ham. I dare not drink yet, madam; by-and-by.
+ Queen. Come, let me wipe thy face.
+ Laer. My lord, I'll hit him now.
+ King. I do not think't.
+ Laer. [aside] And yet it is almost against my conscience.
+ Ham. Come for the third, Laertes! You but dally.
+ pray You Pass with your best violence;
+ I am afeard You make a wanton of me.
+ Laer. Say you so? Come on. Play.
+ Osr. Nothing neither way.
+ Laer. Have at you now!
+ [Laertes wounds Hamlet; then] in scuffling, they
+ change rapiers, [and Hamlet wounds Laertes].
+ King. Part them! They are incens'd.
+ Ham. Nay come! again! The Queen falls.
+ Osr. Look to the Queen there, ho!
+ Hor. They bleed on both sides. How is it, my lord?
+ Osr. How is't, Laertes?
+ Laer. Why, as a woodcock to mine own springe, Osric.
+ I am justly kill'd with mine own treachery.
+ Ham. How does the Queen?
+ King. She sounds to see them bleed.
+ Queen. No, no! the drink, the drink! O my dear Hamlet!
+ The drink, the drink! I am poison'd. [Dies.]
+ Ham. O villany! Ho! let the door be lock'd.
+ Treachery! Seek it out.
+ [Laertes falls.]
+ Laer. It is here, Hamlet. Hamlet, thou art slain;
+ No medicine in the world can do thee good.
+ In thee there is not half an hour of life.
+ The treacherous instrument is in thy hand,
+ Unbated and envenom'd. The foul practice
+ Hath turn'd itself on me. Lo, here I lie,
+ Never to rise again. Thy mother's poison'd.
+ I can no more. The King, the King's to blame.
+ Ham. The point envenom'd too?
+ Then, venom, to thy work. Hurts the King.
+ All. Treason! treason!
+ King. O, yet defend me, friends! I am but hurt.
+ Ham. Here, thou incestuous, murd'rous, damned Dane,
+ Drink off this potion! Is thy union here?
+ Follow my mother. King dies.
+ Laer. He is justly serv'd.
+ It is a poison temper'd by himself.
+ Exchange forgiveness with me, noble Hamlet.
+ Mine and my father's death come not upon thee,
+ Nor thine on me! Dies.
+ Ham. Heaven make thee free of it! I follow thee.
+ I am dead, Horatio. Wretched queen, adieu!
+ You that look pale and tremble at this chance,
+ That are but mutes or audience to this act,
+ Had I but time (as this fell sergeant, Death,
+ Is strict in his arrest) O, I could tell you-
+ But let it be. Horatio, I am dead;
+ Thou liv'st; report me and my cause aright
+ To the unsatisfied.
+ Hor. Never believe it.
+ I am more an antique Roman than a Dane.
+ Here's yet some liquor left.
+ Ham. As th'art a man,
+ Give me the cup. Let go! By heaven, I'll ha't.
+ O good Horatio, what a wounded name
+ (Things standing thus unknown) shall live behind me!
+ If thou didst ever hold me in thy heart,
+ Absent thee from felicity awhile,
+ And in this harsh world draw thy breath in pain,
+ To tell my story. [March afar off, and shot within.]
+ What warlike noise is this?
+ Osr. Young Fortinbras, with conquest come from Poland,
+ To the ambassadors of England gives
+ This warlike volley.
+ Ham. O, I die, Horatio!
+ The potent poison quite o'ercrows my spirit.
+ I cannot live to hear the news from England,
+ But I do prophesy th' election lights
+ On Fortinbras. He has my dying voice.
+ So tell him, with th' occurrents, more and less,
+ Which have solicited- the rest is silence. Dies.
+ Hor. Now cracks a noble heart. Good night, sweet prince,
+ And flights of angels sing thee to thy rest!
+ [March within.]
+ Why does the drum come hither?
+
+ Enter Fortinbras and English Ambassadors, with Drum,
+ Colours, and Attendants.
+
+ Fort. Where is this sight?
+ Hor. What is it you will see?
+ If aught of woe or wonder, cease your search.
+ Fort. This quarry cries on havoc. O proud Death,
+ What feast is toward in thine eternal cell
+ That thou so many princes at a shot
+ So bloodily hast struck.
+ Ambassador. The sight is dismal;
+ And our affairs from England come too late.
+ The ears are senseless that should give us bearing
+ To tell him his commandment is fulfill'd
+ That Rosencrantz and Guildenstern are dead.
+ Where should We have our thanks?
+ Hor. Not from his mouth,
+ Had it th' ability of life to thank you.
+ He never gave commandment for their death.
+ But since, so jump upon this bloody question,
+ You from the Polack wars, and you from England,
+ Are here arriv'd, give order that these bodies
+ High on a stage be placed to the view;
+ And let me speak to the yet unknowing world
+ How these things came about. So shall You hear
+ Of carnal, bloody and unnatural acts;
+ Of accidental judgments, casual slaughters;
+ Of deaths put on by cunning and forc'd cause;
+ And, in this upshot, purposes mistook
+ Fall'n on th' inventors' heads. All this can I
+ Truly deliver.
+ Fort. Let us haste to hear it,
+ And call the noblest to the audience.
+ For me, with sorrow I embrace my fortune.
+ I have some rights of memory in this kingdom
+ Which now, to claim my vantage doth invite me.
+ Hor. Of that I shall have also cause to speak,
+ And from his mouth whose voice will draw on more.
+ But let this same be presently perform'd,
+ Even while men's minds are wild, lest more mischance
+ On plots and errors happen.
+ Fort. Let four captains
+ Bear Hamlet like a soldier to the stage;
+ For he was likely, had he been put on,
+ To have prov'd most royally; and for his passage
+ The soldiers' music and the rites of war
+ Speak loudly for him.
+ Take up the bodies. Such a sight as this
+ Becomes the field but here shows much amiss.
+ Go, bid the soldiers shoot.
+ Exeunt marching; after the which a peal of ordnance
+ are shot off.
+
+
+THE END
diff --git a/week2/scraper.py b/week2/scraper.py
new file mode 100644
index 0000000..1ecc209
--- /dev/null
+++ b/week2/scraper.py
@@ -0,0 +1,37 @@
+from bs4 import BeautifulSoup
+import requests
+
+
+# Standard headers to fetch a website
+headers = {
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"
+}
+
+
+def fetch_website_contents(url):
+ """
+ Return the title and contents of the website at the given url;
+ truncate to 2,000 characters as a sensible limit
+ """
+ response = requests.get(url, headers=headers)
+ soup = BeautifulSoup(response.content, "html.parser")
+ title = soup.title.string if soup.title else "No title found"
+ if soup.body:
+ for irrelevant in soup.body(["script", "style", "img", "input"]):
+ irrelevant.decompose()
+ text = soup.body.get_text(separator="\n", strip=True)
+ else:
+ text = ""
+ return (title + "\n\n" + text)[:2_000]
+
+
+def fetch_website_links(url):
+ """
+ Return the links on the webiste at the given url
+ I realize this is inefficient as we're parsing twice! This is to keep the code in the lab simple.
+ Feel free to use a class and optimize it!
+ """
+ response = requests.get(url, headers=headers)
+ soup = BeautifulSoup(response.content, "html.parser")
+ links = [link.get("href") for link in soup.find_all("a")]
+ return [link for link in links if link]
diff --git a/week3/day1.ipynb b/week3/day1.ipynb
index 2d76b3d..0bb319d 100644
--- a/week3/day1.ipynb
+++ b/week3/day1.ipynb
@@ -16,6 +16,12 @@
"https://colab.research.google.com/drive/1DjcrYDZldAXKJ08x1uYIVCtItoLPk1Wr?usp=sharing"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "0654c6f0",
+ "metadata": {},
+ "source": []
+ },
{
"cell_type": "code",
"execution_count": null,
diff --git a/week3/day5.ipynb b/week3/day5.ipynb
index d068f79..928f305 100644
--- a/week3/day5.ipynb
+++ b/week3/day5.ipynb
@@ -18,18 +18,45 @@
"This should run nicely on a low-cost or free T4 box."
]
},
+ {
+ "cell_type": "markdown",
+ "id": "501aa674",
+ "metadata": {},
+ "source": [
+ "### BUT FIRST - Something cool - really showing you how \"model inference\" works via OpenAI"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
"id": "e9289ba7-200c-43a9-b67a-c5ce826c9537",
"metadata": {},
"outputs": [],
+ "source": [
+ "from visualizer import TokenPredictor, create_token_graph, visualize_predictions\n",
+ "\n",
+ "message = \"In one sentence, describe the color orange to someone who has never been able to see\"\n",
+ "model_name = \"gpt-4.1-mini\"\n",
+ "\n",
+ "predictor = TokenPredictor(model_name)\n",
+ "predictions = predictor.predict_tokens(message)\n",
+ "G = create_token_graph(model_name, predictions)\n",
+ "plt = visualize_predictions(G)\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "540a8255",
+ "metadata": {},
+ "outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -43,7 +70,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.11"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/week3/visualizer.py b/week3/visualizer.py
new file mode 100644
index 0000000..89044ac
--- /dev/null
+++ b/week3/visualizer.py
@@ -0,0 +1,157 @@
+import networkx as nx
+import matplotlib.pyplot as plt
+from typing import List, Dict
+import math
+from openai import OpenAI
+from dotenv import load_dotenv
+
+load_dotenv(override=True)
+
+
+class TokenPredictor:
+ def __init__(self, model_name: str):
+ self.client = OpenAI()
+ self.messages = []
+ self.predictions = []
+ self.model_name = model_name
+
+ def predict_tokens(self, prompt: str, max_tokens: int = 100) -> List[Dict]:
+ """
+ Generate text token by token and track prediction probabilities.
+ Returns list of predictions with top token and alternatives.
+ """
+ response = self.client.chat.completions.create(
+ model=self.model_name,
+ messages=[{"role": "user", "content": prompt}],
+ max_tokens=max_tokens,
+ temperature=0, # Use temperature 0 for deterministic output
+ logprobs=True,
+ seed=42,
+ top_logprobs=3, # Get top 3 token predictions
+ stream=True, # Stream the response
+ )
+
+ predictions = []
+ for chunk in response:
+ if chunk.choices[0].delta.content:
+ token = chunk.choices[0].delta.content
+ logprobs = chunk.choices[0].logprobs.content[0].top_logprobs
+ logprob_dict = {item.token: item.logprob for item in logprobs}
+
+ # Get top predicted token and probability
+ top_token = token
+ top_prob = logprob_dict[token]
+
+ # Get alternative predictions
+ alternatives = []
+ for alt_token, alt_prob in logprob_dict.items():
+ if alt_token != token:
+ alternatives.append((alt_token, math.exp(alt_prob)))
+ alternatives.sort(key=lambda x: x[1], reverse=True)
+
+ prediction = {
+ "token": top_token,
+ "probability": math.exp(top_prob),
+ "alternatives": alternatives[:2], # Keep top 2 alternatives
+ }
+ predictions.append(prediction)
+
+ return predictions
+
+
+def create_token_graph(model_name: str, predictions: List[Dict]) -> nx.DiGraph:
+ """
+ Create a directed graph showing token predictions and alternatives.
+ """
+ G = nx.DiGraph()
+
+ G.add_node("START", token=model_name, prob="START", color="lightgreen", size=4000)
+
+ # First, create all main token nodes in sequence
+ for i, pred in enumerate(predictions):
+ token_id = f"t{i}"
+ G.add_node(
+ token_id,
+ token=pred["token"],
+ prob=f"{pred['probability'] * 100:.1f}%",
+ color="lightblue",
+ size=6000,
+ )
+
+ if i == 0:
+ G.add_edge("START", token_id)
+ else:
+ G.add_edge(f"t{i - 1}", token_id)
+
+ # Then add alternative nodes with a different y-position
+ last_id = None
+ for i, pred in enumerate(predictions):
+ parent_token = "START" if i == 0 else f"t{i - 1}"
+
+ # Add alternative token nodes slightly below main sequence
+ for j, (alt_token, alt_prob) in enumerate(pred["alternatives"]):
+ alt_id = f"t{i}_alt{j}"
+ G.add_node(
+ alt_id, token=alt_token, prob=f"{alt_prob * 100:.1f}%", color="lightgray", size=6000
+ )
+
+ # Add edge from main token to its alternatives only
+ G.add_edge(parent_token, alt_id)
+ last_id = parent_token
+
+ G.add_node("END", token="END", prob="100%", color="red", size=6000)
+ G.add_edge(last_id, "END")
+
+ return G
+
+
+def visualize_predictions(G: nx.DiGraph, figsize=(14, 80)):
+ """
+ Visualize the token prediction graph with vertical layout and alternating alternatives.
+ """
+ plt.figure(figsize=figsize)
+
+ # Create custom positioning for nodes
+ pos = {}
+ spacing_y = 5 # Vertical spacing between main tokens
+ spacing_x = 5 # Horizontal spacing for alternatives
+
+ # Position main token nodes in a vertical line
+ main_nodes = [n for n in G.nodes() if "_alt" not in n]
+ for i, node in enumerate(main_nodes):
+ pos[node] = (0, -i * spacing_y) # Center main tokens vertically
+
+ # Position alternative nodes to left and right of main tokens
+ for node in G.nodes():
+ if "_alt" in node:
+ main_token = node.split("_")[0]
+ alt_num = int(node.split("_alt")[1])
+ if main_token in pos:
+ # Place first alternative to left, second to right
+ x_offset = -spacing_x if alt_num == 0 else spacing_x
+ pos[node] = (x_offset, pos[main_token][1] + 0.05)
+
+ # Draw nodes
+ node_colors = [G.nodes[node]["color"] for node in G.nodes()]
+ node_sizes = [G.nodes[node]["size"] for node in G.nodes()]
+ nx.draw_networkx_nodes(G, pos, node_color=node_colors, node_size=node_sizes)
+
+ # Draw all edges as straight lines
+ nx.draw_networkx_edges(G, pos, edge_color="gray", arrows=True, arrowsize=20, alpha=0.7)
+
+ # Add labels with token and probability
+ labels = {node: f"{G.nodes[node]['token']}\n{G.nodes[node]['prob']}" for node in G.nodes()}
+ nx.draw_networkx_labels(G, pos, labels, font_size=14)
+
+ plt.title("Token prediction.")
+ plt.axis("off")
+
+ # Adjust plot limits to ensure all nodes are visible
+ margin = 8
+ x_values = [x for x, y in pos.values()]
+ y_values = [y for x, y in pos.values()]
+ plt.xlim(min(x_values) - margin, max(x_values) + margin)
+ plt.ylim(min(y_values) - margin, max(y_values) + margin)
+
+ # plt.tight_layout()
+ return plt
diff --git a/week4/day3.ipynb b/week4/day3.ipynb
index 68cca5b..fb67f49 100644
--- a/week4/day3.ipynb
+++ b/week4/day3.ipynb
@@ -18,18 +18,15 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Reminder: fetch latest code\n",
" I'm continually improving these labs, adding more examples and exercises.\n",
" At the start of each week, it's worth checking you have the latest code. \n",
" First do a git pull and merge your changes as needed. Any problems? Try asking ChatGPT to clarify how to merge - or contact me!
\n",
- " After you've pulled the code, from the llm_engineering directory, in an Anaconda prompt (PC) or Terminal (Mac), run: \n",
- " conda env update --f environment.yml --prune \n",
- " Or if you used virtualenv rather than Anaconda, then run this from your activated environment in a Powershell (PC) or Terminal (Mac): \n",
- " pip install -r requirements.txt\n",
- " Then restart the kernel (Kernel menu >> Restart Kernel and Clear Outputs Of All Cells) to pick up the changes.\n",
+ " After you've pulled the code, from the llm_engineering directory, in a Cursor Terminal, run: \n",
+ " uv sync \n",
" \n",
" | \n",
" \n",
@@ -44,12 +41,12 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Important Note\n",
" \n",
- " In this lab, I use GPT-4o and Claude-3.5-Sonnet, which are the slightly higher priced models. The costs are still low, but if you'd prefer to keep costs ultra low, please make the suggested switches to the models (3 cells down from here).\n",
+ " In this lab, I use high end models GPT 5, Claude 4.5 Sonnet, Gemini 2.5 Pro, Grok 4, which are the slightly higher priced models. The costs are still low, but if you'd prefer to keep costs ultra low, please pick lower cost models like gpt-5-nano.\n",
" \n",
" | \n",
" \n",
@@ -66,15 +63,10 @@
"# imports\n",
"\n",
"import os\n",
- "import io\n",
- "import sys\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI\n",
- "import google.generativeai\n",
- "import anthropic\n",
- "from IPython.display import Markdown, display, update_display\n",
- "import gradio as gr\n",
- "import subprocess"
+ "import subprocess\n",
+ "from IPython.display import Markdown, display"
]
},
{
@@ -84,11 +76,51 @@
"metadata": {},
"outputs": [],
"source": [
- "# environment\n",
- "\n",
"load_dotenv(override=True)\n",
- "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')\n",
- "os.environ['ANTHROPIC_API_KEY'] = os.getenv('ANTHROPIC_API_KEY', 'your-key-if-not-using-env')"
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
+ "grok_api_key = os.getenv('GROK_API_KEY')\n",
+ "\n",
+ "if openai_api_key:\n",
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
+ "else:\n",
+ " print(\"OpenAI API Key not set\")\n",
+ " \n",
+ "if anthropic_api_key:\n",
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
+ "else:\n",
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
+ "\n",
+ "if google_api_key:\n",
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
+ "else:\n",
+ " print(\"Google API Key not set (and this is optional)\")\n",
+ "\n",
+ "if grok_api_key:\n",
+ " print(f\"Grok API Key exists and begins {grok_api_key[:4]}\")\n",
+ "else:\n",
+ " print(\"Grok API Key not set (and this is optional)\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "59863df1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Connect to client libraries\n",
+ "\n",
+ "openai = OpenAI()\n",
+ "\n",
+ "anthropic_url = \"https://api.anthropic.com/v1/\"\n",
+ "gemini_url = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
+ "grok_url = \"https://api.x.ai/v1\"\n",
+ "\n",
+ "anthropic = OpenAI(api_key=anthropic_api_key, base_url=anthropic_url)\n",
+ "gemini = OpenAI(api_key=google_api_key, base_url=gemini_url)\n",
+ "grok = OpenAI(api_key=grok_api_key, base_url=grok_url)"
]
},
{
@@ -98,17 +130,110 @@
"metadata": {},
"outputs": [],
"source": [
- "# initialize\n",
- "# NOTE - option to use ultra-low cost models by uncommenting last 2 lines\n",
- "\n",
- "openai = OpenAI()\n",
- "claude = anthropic.Anthropic()\n",
- "OPENAI_MODEL = \"gpt-4o\"\n",
- "CLAUDE_MODEL = \"claude-3-5-sonnet-20240620\"\n",
+ "OPENAI_MODEL = \"gpt-5\"\n",
+ "CLAUDE_MODEL = \"claude-sonnet-4-5-20250929\"\n",
+ "GROK_MODEL = \"grok-4\"\n",
+ "GEMINI_MODEL = \"gemini-2.5-pro\"\n",
"\n",
"# Want to keep costs ultra-low? Uncomment these lines:\n",
- "# OPENAI_MODEL = \"gpt-4o-mini\"\n",
- "# CLAUDE_MODEL = \"claude-3-haiku-20240307\""
+ "\n",
+ "# OPENAI_MODEL = \"gpt-5-nano\"\n",
+ "# CLAUDE_MODEL = \"claude-3-5-haiku-latest\"\n",
+ "# GROK_MODEL = \"grok-4-fast-non-reasoning\"\n",
+ "# GEMINI_MODEL = \"gemini-2.5-flash-lite\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7eab38a7",
+ "metadata": {},
+ "source": [
+ "## PLEASE NOTE:\n",
+ "\n",
+ "We will be writing a solution to convert Python into efficient, optimized C++ code for your machine, which can be compiled to native machine code and executed.\n",
+ "\n",
+ "It is not necessary for you to execute the code yourself - that's not the point of the exercise!\n",
+ "\n",
+ "But if you would like to (because it's satisfying!) then I'm including the steps here. Very optional!\n",
+ "\n",
+ "As an alternative, I'll also show you a website where you can run the C++ code."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8a2fbb68",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from system_info import retrieve_system_info\n",
+ "\n",
+ "system_info = retrieve_system_info()\n",
+ "system_info"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c6d29a5f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "message = f\"\"\"\n",
+ "Here is a report of the system information for my computer.\n",
+ "I want to run a C++ compiler to compile a single C++ file called main.cpp and then execute it in the simplest way possible.\n",
+ "Please reply with whether I need to install any C++ compiler to do this. If so, please provide the simplest step by step instructions to do so.\n",
+ "\n",
+ "If I'm already set up to compile C++ code, then I'd like to run something like this in Python to compile and execute the code:\n",
+ "```python\n",
+ "compile_command = # something here - to achieve the fastest possible runtime performance\n",
+ "compile_result = subprocess.run(compile_command, check=True, text=True, capture_output=True)\n",
+ "run_command = # something here\n",
+ "run_result = subprocess.run(run_command, check=True, text=True, capture_output=True)\n",
+ "return run_result.stdout\n",
+ "```\n",
+ "Please tell me exactly what I should use for the compile_command and run_command.\n",
+ "\n",
+ "System information:\n",
+ "{system_info}\n",
+ "\"\"\"\n",
+ "\n",
+ "response = openai.chat.completions.create(model=OPENAI_MODEL, messages=[{\"role\": \"user\", \"content\": message}])\n",
+ "display(Markdown(response.choices[0].message.content))\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81e92c12",
+ "metadata": {},
+ "source": [
+ "## If you need to install something\n",
+ "\n",
+ "If you would like to, please follow GPTs instructions! Then rerun the analysis afterwards (you might need to Restart the notebook) to confirm you're set.\n",
+ "\n",
+ "You should now be equipped with the command to compile the code, and the command to run it!\n",
+ "\n",
+ "Enter that in the cell below:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d734a634",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "compile_command = [\"clang++\", \"-std=c++17\", \"-Ofast\", \"-mcpu=native\", \"-flto=thin\", \"-fvisibility=hidden\", \"-DNDEBUG\", \"main.cpp\", \"-o\", \"main\"]\n",
+ "run_command = [\"./main\"]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f0b0a437",
+ "metadata": {},
+ "source": [
+ "## And now, on with the main task"
]
},
{
@@ -118,9 +243,26 @@
"metadata": {},
"outputs": [],
"source": [
- "system_message = \"You are an assistant that reimplements Python code in high performance C++ for an M1 Mac. \"\n",
- "system_message += \"Respond only with C++ code; use comments sparingly and do not provide any explanation other than occasional comments. \"\n",
- "system_message += \"The C++ response needs to produce an identical output in the fastest possible time.\""
+ "system_prompt = \"\"\"\n",
+ "Your task is to convert Python code into high performance C++ code.\n",
+ "Respond only with C++ code. Do not provide any explanation other than occasional comments.\n",
+ "The C++ response needs to produce an identical output in the fastest possible time.\n",
+ "\"\"\"\n",
+ "\n",
+ "def user_prompt_for(python):\n",
+ " return f\"\"\"\n",
+ "Port this Python code to C++ with the fastest possible implementation that produces identical output in the least time.\n",
+ "The system information is:\n",
+ "{system_info}\n",
+ "Your response will be written to a file called main.cpp and then compiled and executed; the compilation command is:\n",
+ "{compile_command}\n",
+ "Respond only with C++ code.\n",
+ "Python code to port:\n",
+ "\n",
+ "```python\n",
+ "{python}\n",
+ "```\n",
+ "\"\"\""
]
},
{
@@ -130,12 +272,12 @@
"metadata": {},
"outputs": [],
"source": [
- "def user_prompt_for(python):\n",
- " user_prompt = \"Rewrite this Python code in C++ with the fastest possible implementation that produces identical output in the least time. \"\n",
- " user_prompt += \"Respond only with C++ code; do not explain your work other than a few comments. \"\n",
- " user_prompt += \"Pay attention to number types to ensure no int overflows. Remember to #include all necessary C++ packages such as iomanip.\\n\\n\"\n",
- " user_prompt += python\n",
- " return user_prompt"
+ "def messages_for(python):\n",
+ " return [\n",
+ " {\"role\": \"system\", \"content\": system_prompt},\n",
+ " {\"role\": \"user\", \"content\": user_prompt_for(python)}\n",
+ " ]\n",
+ " "
]
},
{
@@ -145,26 +287,9 @@
"metadata": {},
"outputs": [],
"source": [
- "def messages_for(python):\n",
- " return [\n",
- " {\"role\": \"system\", \"content\": system_message},\n",
- " {\"role\": \"user\", \"content\": user_prompt_for(python)}\n",
- " ]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "71e1ba8c-5b05-4726-a9f3-8d8c6257350b",
- "metadata": {},
- "outputs": [],
- "source": [
- "# write to a file called optimized.cpp\n",
- "\n",
"def write_output(cpp):\n",
- " code = cpp.replace(\"```cpp\",\"\").replace(\"```\",\"\")\n",
- " with open(\"optimized.cpp\", \"w\") as f:\n",
- " f.write(code)"
+ " with open(\"main.cpp\", \"w\", encoding=\"utf-8\") as f:\n",
+ " f.write(cpp)"
]
},
{
@@ -174,35 +299,11 @@
"metadata": {},
"outputs": [],
"source": [
- "def optimize_gpt(python): \n",
- " stream = openai.chat.completions.create(model=OPENAI_MODEL, messages=messages_for(python), stream=True)\n",
- " reply = \"\"\n",
- " for chunk in stream:\n",
- " fragment = chunk.choices[0].delta.content or \"\"\n",
- " reply += fragment\n",
- " print(fragment, end='', flush=True)\n",
- " write_output(reply)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7cd84ad8-d55c-4fe0-9eeb-1895c95c4a9d",
- "metadata": {},
- "outputs": [],
- "source": [
- "def optimize_claude(python):\n",
- " result = claude.messages.stream(\n",
- " model=CLAUDE_MODEL,\n",
- " max_tokens=2000,\n",
- " system=system_message,\n",
- " messages=[{\"role\": \"user\", \"content\": user_prompt_for(python)}],\n",
- " )\n",
- " reply = \"\"\n",
- " with result as stream:\n",
- " for text in stream.text_stream:\n",
- " reply += text\n",
- " print(text, end=\"\", flush=True)\n",
+ "def port(client, model, python):\n",
+ " reasoning_effort = \"high\" if 'gpt' in model else None\n",
+ " response = client.chat.completions.create(model=model, messages=messages_for(python), reasoning_effort=reasoning_effort)\n",
+ " reply = response.choices[0].message.content\n",
+ " reply = reply.replace('```cpp','').replace('```','')\n",
" write_output(reply)"
]
},
@@ -226,7 +327,7 @@
" return result\n",
"\n",
"start_time = time.time()\n",
- "result = calculate(100_000_000, 4, 1) * 4\n",
+ "result = calculate(200_000_000, 4, 1) * 4\n",
"end_time = time.time()\n",
"\n",
"print(f\"Result: {result:.12f}\")\n",
@@ -241,7 +342,19 @@
"metadata": {},
"outputs": [],
"source": [
- "exec(pi)"
+ "def run_python(code):\n",
+ " globals = {\"__builtins__\": __builtins__}\n",
+ " exec(code, globals)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7faa90da",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "run_python(pi)"
]
},
{
@@ -251,17 +364,7 @@
"metadata": {},
"outputs": [],
"source": [
- "optimize_gpt(pi)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "bf26ee95-0c77-491d-9a91-579a1e96a8a3",
- "metadata": {},
- "outputs": [],
- "source": [
- "exec(pi)"
+ "port(openai, OPENAI_MODEL, pi)"
]
},
{
@@ -271,18 +374,12 @@
"source": [
"# Compiling C++ and executing\n",
"\n",
- "This next cell contains the command to compile a C++ file on my M1 Mac. \n",
- "It compiles the file `optimized.cpp` into an executable called `optimized` \n",
- "Then it runs the program called `optimized`\n",
- "\n",
- "In the next lab (day4), a student has contributed a full solution that compiles to efficient code on Mac, PC and Linux!\n",
- "\n",
- "You can wait for this, or you can google (or ask ChatGPT!) for how to do this on your platform, then replace the lines below.\n",
- "If you're not comfortable with this step, you can skip it for sure - I'll show you exactly how it performs on my Mac.\n",
+ "This next cell contains the command to compile a C++ file based on the instructions from GPT.\n",
"\n",
+ "Again, it's not crucial to do this step if you don't wish to!\n",
"\n",
"OR alternatively: student Sandeep K.G. points out that you can run Python and C++ code online to test it out that way. Thank you Sandeep! \n",
- "> Not an exact comparison but you can still get the idea of performance difference.\n",
+ "> Not an exact comparison but you can still get the idea of performance difference. \n",
"> For example here: https://www.programiz.com/cpp-programming/online-compiler/"
]
},
@@ -293,10 +390,41 @@
"metadata": {},
"outputs": [],
"source": [
- "# Compile C++ and run the executable\n",
+ "# Use the commands from GPT 5\n",
"\n",
- "!clang++ -O3 -std=c++17 -march=armv8.3-a -o optimized optimized.cpp\n",
- "!./optimized"
+ "def compile_and_run():\n",
+ " subprocess.run(compile_command, check=True, text=True, capture_output=True)\n",
+ " print(subprocess.run(run_command, check=True, text=True, capture_output=True).stdout)\n",
+ " print(subprocess.run(run_command, check=True, text=True, capture_output=True).stdout)\n",
+ " print(subprocess.run(run_command, check=True, text=True, capture_output=True).stdout)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "22f8f43a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "compile_and_run()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "faaa39de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "19.178207/0.082168"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4f3b8ef9",
+ "metadata": {},
+ "source": [
+ "## OK let's try the other contenders!"
]
},
{
@@ -306,294 +434,79 @@
"metadata": {},
"outputs": [],
"source": [
- "optimize_claude(pi)"
+ "port(anthropic, CLAUDE_MODEL, pi)\n",
+ "compile_and_run()"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "d5a766f9-3d23-4bb4-a1d4-88ec44b61ddf",
+ "id": "138f63c8",
"metadata": {},
"outputs": [],
"source": [
- "# Repeat for Claude - again, use the right approach for your platform\n",
+ "port(grok, GROK_MODEL, pi)\n",
+ "compile_and_run()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0a0243c5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "port(gemini, GEMINI_MODEL, pi)\n",
+ "compile_and_run()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0689e200",
+ "metadata": {},
+ "source": [
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a6ffb0bb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(f\"\"\"\n",
+ "In Ed's experiments, the performance speedups were:\n",
"\n",
- "!clang++ -O3 -std=c++17 -march=armv8.3-a -o optimized optimized.cpp\n",
- "!./optimized"
+ "4th place: Claude Sonnet 4.5: {19.178207/0.104241:.0f}X speedup\n",
+ "3rd place: GPT-5: {19.178207/0.082168:.0f}X speedup\n",
+ "2nd place: Grok 4: {19.178207/0.018092:.0f}X speedup\n",
+ "1st place: Gemini 2.5 Pro: {19.178207/0.013314:.0f}X speedup\n",
+ "\"\"\")"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "c3b497b3-f569-420e-b92e-fb0f49957ce0",
+ "id": "8d58753b",
"metadata": {},
"outputs": [],
"source": [
- "python_hard = \"\"\"# Be careful to support large number sizes\n",
- "\n",
- "def lcg(seed, a=1664525, c=1013904223, m=2**32):\n",
- " value = seed\n",
- " while True:\n",
- " value = (a * value + c) % m\n",
- " yield value\n",
- " \n",
- "def max_subarray_sum(n, seed, min_val, max_val):\n",
- " lcg_gen = lcg(seed)\n",
- " random_numbers = [next(lcg_gen) % (max_val - min_val + 1) + min_val for _ in range(n)]\n",
- " max_sum = float('-inf')\n",
- " for i in range(n):\n",
- " current_sum = 0\n",
- " for j in range(i, n):\n",
- " current_sum += random_numbers[j]\n",
- " if current_sum > max_sum:\n",
- " max_sum = current_sum\n",
- " return max_sum\n",
- "\n",
- "def total_max_subarray_sum(n, initial_seed, min_val, max_val):\n",
- " total_sum = 0\n",
- " lcg_gen = lcg(initial_seed)\n",
- " for _ in range(20):\n",
- " seed = next(lcg_gen)\n",
- " total_sum += max_subarray_sum(n, seed, min_val, max_val)\n",
- " return total_sum\n",
- "\n",
- "# Parameters\n",
- "n = 10000 # Number of random numbers\n",
- "initial_seed = 42 # Initial seed for the LCG\n",
- "min_val = -10 # Minimum value of random numbers\n",
- "max_val = 10 # Maximum value of random numbers\n",
- "\n",
- "# Timing the function\n",
- "import time\n",
- "start_time = time.time()\n",
- "result = total_max_subarray_sum(n, initial_seed, min_val, max_val)\n",
- "end_time = time.time()\n",
- "\n",
- "print(\"Total Maximum Subarray Sum (20 runs):\", result)\n",
- "print(\"Execution Time: {:.6f} seconds\".format(end_time - start_time))\n",
- "\"\"\""
+ "\n"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "dab5e4bc-276c-4555-bd4c-12c699d5e899",
+ "id": "7202e513",
"metadata": {},
"outputs": [],
- "source": [
- "exec(python_hard)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e8d24ed5-2c15-4f55-80e7-13a3952b3cb8",
- "metadata": {},
- "outputs": [],
- "source": [
- "optimize_gpt(python_hard)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e0b3d073-88a2-40b2-831c-6f0c345c256f",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Replace this with the right C++ compile + execute command for your platform\n",
- "\n",
- "!clang++ -O3 -std=c++17 -march=armv8.3-a -o optimized optimized.cpp\n",
- "!./optimized"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e9305446-1d0c-4b51-866a-b8c1e299bf5c",
- "metadata": {},
- "outputs": [],
- "source": [
- "optimize_claude(python_hard)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "0c181036-8193-4fdd-aef3-fc513b218d43",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Replace this with the right C++ compile + execute command for your platform\n",
- "\n",
- "!clang++ -O3 -std=c++17 -march=armv8.3-a -o optimized optimized.cpp\n",
- "!./optimized"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "0be9f47d-5213-4700-b0e2-d444c7c738c0",
- "metadata": {},
- "outputs": [],
- "source": [
- "def stream_gpt(python): \n",
- " stream = openai.chat.completions.create(model=OPENAI_MODEL, messages=messages_for(python), stream=True)\n",
- " reply = \"\"\n",
- " for chunk in stream:\n",
- " fragment = chunk.choices[0].delta.content or \"\"\n",
- " reply += fragment\n",
- " yield reply.replace('```cpp\\n','').replace('```','')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "8669f56b-8314-4582-a167-78842caea131",
- "metadata": {},
- "outputs": [],
- "source": [
- "def stream_claude(python):\n",
- " result = claude.messages.stream(\n",
- " model=CLAUDE_MODEL,\n",
- " max_tokens=2000,\n",
- " system=system_message,\n",
- " messages=[{\"role\": \"user\", \"content\": user_prompt_for(python)}],\n",
- " )\n",
- " reply = \"\"\n",
- " with result as stream:\n",
- " for text in stream.text_stream:\n",
- " reply += text\n",
- " yield reply.replace('```cpp\\n','').replace('```','')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "2f1ae8f5-16c8-40a0-aa18-63b617df078d",
- "metadata": {},
- "outputs": [],
- "source": [
- "def optimize(python, model):\n",
- " if model==\"GPT\":\n",
- " result = stream_gpt(python)\n",
- " elif model==\"Claude\":\n",
- " result = stream_claude(python)\n",
- " else:\n",
- " raise ValueError(\"Unknown model\")\n",
- " for stream_so_far in result:\n",
- " yield stream_so_far "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f1ddb38e-6b0a-4c37-baa4-ace0b7de887a",
- "metadata": {},
- "outputs": [],
- "source": [
- "with gr.Blocks() as ui:\n",
- " with gr.Row():\n",
- " python = gr.Textbox(label=\"Python code:\", lines=10, value=python_hard)\n",
- " cpp = gr.Textbox(label=\"C++ code:\", lines=10)\n",
- " with gr.Row():\n",
- " model = gr.Dropdown([\"GPT\", \"Claude\"], label=\"Select model\", value=\"GPT\")\n",
- " convert = gr.Button(\"Convert code\")\n",
- "\n",
- " convert.click(optimize, inputs=[python, model], outputs=[cpp])\n",
- "\n",
- "ui.launch(inbrowser=True)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "19bf2bff-a822-4009-a539-f003b1651383",
- "metadata": {},
- "outputs": [],
- "source": [
- "def execute_python(code):\n",
- " try:\n",
- " output = io.StringIO()\n",
- " sys.stdout = output\n",
- " exec(code)\n",
- " finally:\n",
- " sys.stdout = sys.__stdout__\n",
- " return output.getvalue()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "77f3ab5d-fcfb-4d3f-8728-9cacbf833ea6",
- "metadata": {},
- "outputs": [],
- "source": [
- "# You'll need to change the code in the try block to compile the C++ code for your platform\n",
- "# I pasted this into Claude's chat UI with a request for it to give me a version for an Intel PC,\n",
- "# and it responded with something that looks perfect - you can try a similar approach for your platform.\n",
- "\n",
- "# M1 Mac version to compile and execute optimized C++ code:\n",
- "\n",
- "def execute_cpp(code):\n",
- " write_output(code)\n",
- " try:\n",
- " compile_cmd = [\"clang++\", \"-Ofast\", \"-std=c++17\", \"-march=armv8.5-a\", \"-mtune=apple-m1\", \"-mcpu=apple-m1\", \"-o\", \"optimized\", \"optimized.cpp\"]\n",
- " compile_result = subprocess.run(compile_cmd, check=True, text=True, capture_output=True)\n",
- " run_cmd = [\"./optimized\"]\n",
- " run_result = subprocess.run(run_cmd, check=True, text=True, capture_output=True)\n",
- " return run_result.stdout\n",
- " except subprocess.CalledProcessError as e:\n",
- " return f\"An error occurred:\\n{e.stderr}\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "9a2274f1-d03b-42c0-8dcc-4ce159b18442",
- "metadata": {},
- "outputs": [],
- "source": [
- "css = \"\"\"\n",
- ".python {background-color: #306998;}\n",
- ".cpp {background-color: #050;}\n",
- "\"\"\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f1303932-160c-424b-97a8-d28c816721b2",
- "metadata": {},
- "outputs": [],
- "source": [
- "with gr.Blocks(css=css) as ui:\n",
- " gr.Markdown(\"## Convert code from Python to C++\")\n",
- " with gr.Row():\n",
- " python = gr.Textbox(label=\"Python code:\", value=python_hard, lines=10)\n",
- " cpp = gr.Textbox(label=\"C++ code:\", lines=10)\n",
- " with gr.Row():\n",
- " model = gr.Dropdown([\"GPT\", \"Claude\"], label=\"Select model\", value=\"GPT\")\n",
- " with gr.Row():\n",
- " convert = gr.Button(\"Convert code\")\n",
- " with gr.Row():\n",
- " python_run = gr.Button(\"Run Python\")\n",
- " cpp_run = gr.Button(\"Run C++\")\n",
- " with gr.Row():\n",
- " python_out = gr.TextArea(label=\"Python result:\", elem_classes=[\"python\"])\n",
- " cpp_out = gr.TextArea(label=\"C++ result:\", elem_classes=[\"cpp\"])\n",
- "\n",
- " convert.click(optimize, inputs=[python, model], outputs=[cpp])\n",
- " python_run.click(execute_python, inputs=[python], outputs=[python_out])\n",
- " cpp_run.click(execute_cpp, inputs=[cpp], outputs=[cpp_out])\n",
- "\n",
- "ui.launch(inbrowser=True)"
- ]
+ "source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -607,7 +520,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.11"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/week4/day4.ipynb b/week4/day4.ipynb
index 91802cf..264ac3b 100644
--- a/week4/day4.ipynb
+++ b/week4/day4.ipynb
@@ -7,30 +7,41 @@
"source": [
"# Code Generator\n",
"\n",
- "The requirement: use an Open Source model to generate high performance C++ code from Python code\n",
- "\n",
- "To replicate this, you'll need to set up a HuggingFace endpoint as I do in the video. It's simple to do, and it's quite satisfying to see the results!\n",
- "\n",
- "It's also an important part of your learning; this is the first example of deploying an open source model to be behind an API. We'll return to this in Week 8, but this should plant a seed in your mind for what's involved in moving open source models into production."
+ "The requirement: use a Frontier model to generate high performance C++ code from Python code\n"
]
},
{
"cell_type": "markdown",
- "id": "22e1567b-33fd-49e7-866e-4b635d15715a",
+ "id": "d5ccb926-7b49-44a4-99ab-8ef20b5778c0",
"metadata": {},
"source": [
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
- " Important - Pause Endpoints when not in use\n",
+ " Reminder: OPTIONAL to execute C++ code\n",
+ " As an alternative, you can run it on the website given yesterday\n",
+ " | \n",
+ " \n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d90e04a2-5b8a-4fd5-9db8-27c02f033313",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " Important Note\n",
" \n",
- " If you do decide to use HuggingFace endpoints for this project, you should stop or pause the endpoints when you are done to avoid accruing unnecessary running cost. The costs are very low as long as you only run the endpoint when you're using it. Navigate to the HuggingFace endpoint UI here, open your endpoint, and click Pause to put it on pause so you no longer pay for it. \n",
- "Many thanks to student John L. for raising this.\n",
- "
\n",
- "In week 8 we will use Modal instead of HuggingFace endpoints; with Modal you only pay for the time that you use it and you should get free credits.\n",
+ " In this lab, I use free open source models on Ollama. I also use paid open-source models via Groq and OpenRouter. Only pick the models you want to!\n",
" \n",
" | \n",
" \n",
@@ -49,15 +60,10 @@
"import os\n",
"import io\n",
"import sys\n",
- "import json\n",
- "import requests\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI\n",
- "import google.generativeai\n",
- "import anthropic\n",
- "from IPython.display import Markdown, display, update_display\n",
"import gradio as gr\n",
- "import subprocess"
+ "import subprocess\n"
]
},
{
@@ -67,12 +73,70 @@
"metadata": {},
"outputs": [],
"source": [
- "# environment\n",
- "\n",
"load_dotenv(override=True)\n",
- "os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')\n",
- "os.environ['ANTHROPIC_API_KEY'] = os.getenv('ANTHROPIC_API_KEY', 'your-key-if-not-using-env')\n",
- "os.environ['HF_TOKEN'] = os.getenv('HF_TOKEN', 'your-key-if-not-using-env')"
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
+ "grok_api_key = os.getenv('GROK_API_KEY')\n",
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
+ "openrouter_api_key = os.getenv('OPENROUTER_API_KEY')\n",
+ "\n",
+ "if openai_api_key:\n",
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
+ "else:\n",
+ " print(\"OpenAI API Key not set\")\n",
+ " \n",
+ "if anthropic_api_key:\n",
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
+ "else:\n",
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
+ "\n",
+ "if google_api_key:\n",
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
+ "else:\n",
+ " print(\"Google API Key not set (and this is optional)\")\n",
+ "\n",
+ "if grok_api_key:\n",
+ " print(f\"Grok API Key exists and begins {grok_api_key[:4]}\")\n",
+ "else:\n",
+ " print(\"Grok API Key not set (and this is optional)\")\n",
+ "\n",
+ "if groq_api_key:\n",
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
+ "else:\n",
+ " print(\"Groq API Key not set (and this is optional)\")\n",
+ "\n",
+ "if openrouter_api_key:\n",
+ " print(f\"OpenRouter API Key exists and begins {openrouter_api_key[:6]}\")\n",
+ "else:\n",
+ " print(\"OpenRouter API Key not set (and this is optional)\")\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "59863df1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Connect to client libraries\n",
+ "\n",
+ "openai = OpenAI()\n",
+ "\n",
+ "anthropic_url = \"https://api.anthropic.com/v1/\"\n",
+ "gemini_url = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
+ "grok_url = \"https://api.x.ai/v1\"\n",
+ "groq_url = \"https://api.groq.com/openai/v1\"\n",
+ "ollama_url = \"http://localhost:11434/v1\"\n",
+ "openrouter_url = \"https://openrouter.ai/api/v1\"\n",
+ "\n",
+ "anthropic = OpenAI(api_key=anthropic_api_key, base_url=anthropic_url)\n",
+ "gemini = OpenAI(api_key=google_api_key, base_url=gemini_url)\n",
+ "grok = OpenAI(api_key=grok_api_key, base_url=grok_url)\n",
+ "groq = OpenAI(api_key=groq_api_key, base_url=groq_url)\n",
+ "ollama = OpenAI(api_key=\"ollama\", base_url=ollama_url)\n",
+ "openrouter = OpenAI(api_key=openrouter_api_key, base_url=openrouter_url)\n"
]
},
{
@@ -82,12 +146,55 @@
"metadata": {},
"outputs": [],
"source": [
- "# initialize\n",
+ "models = [\"gpt-5\", \"claude-sonnet-4-5-20250929\", \"grok-4\", \"gemini-2.5-pro\", \"qwen2.5-coder\", \"deepseek-coder-v2\", \"gpt-oss:20b\", \"qwen/qwen3-coder-30b-a3b-instruct\", \"openai/gpt-oss-120b\", ]\n",
"\n",
- "openai = OpenAI()\n",
- "claude = anthropic.Anthropic()\n",
- "OPENAI_MODEL = \"gpt-4o\"\n",
- "CLAUDE_MODEL = \"claude-3-5-sonnet-20240620\""
+ "clients = {\"gpt-5\": openai, \"claude-sonnet-4-5-20250929\": anthropic, \"grok-4\": grok, \"gemini-2.5-pro\": gemini, \"openai/gpt-oss-120b\": groq, \"qwen2.5-coder\": ollama, \"deepseek-coder-v2\": ollama, \"gpt-oss:20b\": ollama, \"qwen/qwen3-coder-30b-a3b-instruct\": openrouter}\n",
+ "\n",
+ "# Want to keep costs ultra-low? Replace this with models of your choice, using the examples from yesterday"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "68c1f1be",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from system_info import retrieve_system_info\n",
+ "\n",
+ "system_info = retrieve_system_info()\n",
+ "system_info"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81e92c12",
+ "metadata": {},
+ "source": [
+ "## Overwrite this with the commands from yesterday\n",
+ "\n",
+ "Or just use the website like yesterday:\n",
+ "\n",
+ " https://www.programiz.com/cpp-programming/online-compiler/"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d734a634",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "compile_command = [\"clang++\", \"-std=c++17\", \"-Ofast\", \"-mcpu=native\", \"-flto=thin\", \"-fvisibility=hidden\", \"-DNDEBUG\", \"main.cpp\", \"-o\", \"main\"]\n",
+ "run_command = [\"./main\"]\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f0b0a437",
+ "metadata": {},
+ "source": [
+ "## And now, on with the main task"
]
},
{
@@ -97,9 +204,26 @@
"metadata": {},
"outputs": [],
"source": [
- "system_message = \"You are an assistant that reimplements Python code in high performance C++ for an M1 Mac. \"\n",
- "system_message += \"Respond only with C++ code; use comments sparingly and do not provide any explanation other than occasional comments. \"\n",
- "system_message += \"The C++ response needs to produce an identical output in the fastest possible time. Keep implementations of random number generators identical so that results match exactly.\""
+ "system_prompt = \"\"\"\n",
+ "Your task is to convert Python code into high performance C++ code.\n",
+ "Respond only with C++ code. Do not provide any explanation other than occasional comments.\n",
+ "The C++ response needs to produce an identical output in the fastest possible time.\n",
+ "\"\"\"\n",
+ "\n",
+ "def user_prompt_for(python):\n",
+ " return f\"\"\"\n",
+ "Port this Python code to C++ with the fastest possible implementation that produces identical output in the least time.\n",
+ "The system information is:\n",
+ "{system_info}\n",
+ "Your response will be written to a file called main.cpp and then compiled and executed; the compilation command is:\n",
+ "{compile_command}\n",
+ "Respond only with C++ code.\n",
+ "Python code to port:\n",
+ "\n",
+ "```python\n",
+ "{python}\n",
+ "```\n",
+ "\"\"\""
]
},
{
@@ -109,12 +233,12 @@
"metadata": {},
"outputs": [],
"source": [
- "def user_prompt_for(python):\n",
- " user_prompt = \"Rewrite this Python code in C++ with the fastest possible implementation that produces identical output in the least time. \"\n",
- " user_prompt += \"Respond only with C++ code; do not explain your work other than a few comments. \"\n",
- " user_prompt += \"Pay attention to number types to ensure no int overflows. Remember to #include all necessary C++ packages such as iomanip.\\n\\n\"\n",
- " user_prompt += python\n",
- " return user_prompt"
+ "def messages_for(python):\n",
+ " return [\n",
+ " {\"role\": \"system\", \"content\": system_prompt},\n",
+ " {\"role\": \"user\", \"content\": user_prompt_for(python)}\n",
+ " ]\n",
+ " "
]
},
{
@@ -124,26 +248,9 @@
"metadata": {},
"outputs": [],
"source": [
- "def messages_for(python):\n",
- " return [\n",
- " {\"role\": \"system\", \"content\": system_message},\n",
- " {\"role\": \"user\", \"content\": user_prompt_for(python)}\n",
- " ]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "71e1ba8c-5b05-4726-a9f3-8d8c6257350b",
- "metadata": {},
- "outputs": [],
- "source": [
- "# write to a file called optimized.cpp\n",
- "\n",
"def write_output(cpp):\n",
- " code = cpp.replace(\"```cpp\",\"\").replace(\"```\",\"\")\n",
- " with open(\"optimized.cpp\", \"w\") as f:\n",
- " f.write(code)"
+ " with open(\"main.cpp\", \"w\") as f:\n",
+ " f.write(cpp)"
]
},
{
@@ -153,36 +260,14 @@
"metadata": {},
"outputs": [],
"source": [
- "def optimize_gpt(python): \n",
- " stream = openai.chat.completions.create(model=OPENAI_MODEL, messages=messages_for(python), stream=True)\n",
- " reply = \"\"\n",
- " for chunk in stream:\n",
- " fragment = chunk.choices[0].delta.content or \"\"\n",
- " reply += fragment\n",
- " print(fragment, end='', flush=True)\n",
- " write_output(reply)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7cd84ad8-d55c-4fe0-9eeb-1895c95c4a9d",
- "metadata": {},
- "outputs": [],
- "source": [
- "def optimize_claude(python):\n",
- " result = claude.messages.stream(\n",
- " model=CLAUDE_MODEL,\n",
- " max_tokens=2000,\n",
- " system=system_message,\n",
- " messages=[{\"role\": \"user\", \"content\": user_prompt_for(python)}],\n",
- " )\n",
- " reply = \"\"\n",
- " with result as stream:\n",
- " for text in stream.text_stream:\n",
- " reply += text\n",
- " print(text, end=\"\", flush=True)\n",
- " write_output(reply)"
+ "def port(model, python):\n",
+ " client = clients[model]\n",
+ " reasoning_effort = \"high\" if 'gpt' in model else None\n",
+ " response = client.chat.completions.create(model=model, messages=messages_for(python), reasoning_effort=reasoning_effort)\n",
+ " reply = response.choices[0].message.content\n",
+ " reply = reply.replace('```cpp','').replace('```','')\n",
+ " write_output(reply)\n",
+ " return reply"
]
},
{
@@ -205,7 +290,7 @@
" return result\n",
"\n",
"start_time = time.time()\n",
- "result = calculate(100_000_000, 4, 1) * 4\n",
+ "result = calculate(200_000_000, 4, 1) * 4\n",
"end_time = time.time()\n",
"\n",
"print(f\"Result: {result:.12f}\")\n",
@@ -220,27 +305,22 @@
"metadata": {},
"outputs": [],
"source": [
- "exec(pi)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "105db6f9-343c-491d-8e44-3a5328b81719",
- "metadata": {},
- "outputs": [],
- "source": [
- "optimize_gpt(pi)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "bf26ee95-0c77-491d-9a91-579a1e96a8a3",
- "metadata": {},
- "outputs": [],
- "source": [
- "exec(pi)"
+ "def run_python(code):\n",
+ " globals_dict = {\"__builtins__\": __builtins__}\n",
+ "\n",
+ " buffer = io.StringIO()\n",
+ " old_stdout = sys.stdout\n",
+ " sys.stdout = buffer\n",
+ "\n",
+ " try:\n",
+ " exec(code, globals_dict)\n",
+ " output = buffer.getvalue()\n",
+ " except Exception as e:\n",
+ " output = f\"Error: {e}\"\n",
+ " finally:\n",
+ " sys.stdout = old_stdout\n",
+ "\n",
+ " return output"
]
},
{
@@ -250,188 +330,14 @@
"metadata": {},
"outputs": [],
"source": [
- "!clang++ -O3 -std=c++17 -march=armv8.3-a -o optimized optimized.cpp\n",
- "!./optimized"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "983a11fe-e24d-4c65-8269-9802c5ef3ae6",
- "metadata": {},
- "outputs": [],
- "source": [
- "optimize_claude(pi)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "d5a766f9-3d23-4bb4-a1d4-88ec44b61ddf",
- "metadata": {},
- "outputs": [],
- "source": [
- "!clang++ -O3 -std=c++17 -march=armv8.3-a -o optimized optimized.cpp\n",
- "!./optimized"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "c3b497b3-f569-420e-b92e-fb0f49957ce0",
- "metadata": {},
- "outputs": [],
- "source": [
- "python_hard = \"\"\"# Be careful to support large number sizes\n",
- "\n",
- "def lcg(seed, a=1664525, c=1013904223, m=2**32):\n",
- " value = seed\n",
- " while True:\n",
- " value = (a * value + c) % m\n",
- " yield value\n",
- " \n",
- "def max_subarray_sum(n, seed, min_val, max_val):\n",
- " lcg_gen = lcg(seed)\n",
- " random_numbers = [next(lcg_gen) % (max_val - min_val + 1) + min_val for _ in range(n)]\n",
- " max_sum = float('-inf')\n",
- " for i in range(n):\n",
- " current_sum = 0\n",
- " for j in range(i, n):\n",
- " current_sum += random_numbers[j]\n",
- " if current_sum > max_sum:\n",
- " max_sum = current_sum\n",
- " return max_sum\n",
- "\n",
- "def total_max_subarray_sum(n, initial_seed, min_val, max_val):\n",
- " total_sum = 0\n",
- " lcg_gen = lcg(initial_seed)\n",
- " for _ in range(20):\n",
- " seed = next(lcg_gen)\n",
- " total_sum += max_subarray_sum(n, seed, min_val, max_val)\n",
- " return total_sum\n",
- "\n",
- "# Parameters\n",
- "n = 10000 # Number of random numbers\n",
- "initial_seed = 42 # Initial seed for the LCG\n",
- "min_val = -10 # Minimum value of random numbers\n",
- "max_val = 10 # Maximum value of random numbers\n",
- "\n",
- "# Timing the function\n",
- "import time\n",
- "start_time = time.time()\n",
- "result = total_max_subarray_sum(n, initial_seed, min_val, max_val)\n",
- "end_time = time.time()\n",
- "\n",
- "print(\"Total Maximum Subarray Sum (20 runs):\", result)\n",
- "print(\"Execution Time: {:.6f} seconds\".format(end_time - start_time))\n",
- "\"\"\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "dab5e4bc-276c-4555-bd4c-12c699d5e899",
- "metadata": {},
- "outputs": [],
- "source": [
- "exec(python_hard)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e8d24ed5-2c15-4f55-80e7-13a3952b3cb8",
- "metadata": {},
- "outputs": [],
- "source": [
- "optimize_gpt(python_hard)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e0b3d073-88a2-40b2-831c-6f0c345c256f",
- "metadata": {},
- "outputs": [],
- "source": [
- "!clang++ -O3 -std=c++17 -march=armv8.3-a -o optimized optimized.cpp\n",
- "!./optimized"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e9305446-1d0c-4b51-866a-b8c1e299bf5c",
- "metadata": {},
- "outputs": [],
- "source": [
- "optimize_claude(python_hard)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "0c181036-8193-4fdd-aef3-fc513b218d43",
- "metadata": {},
- "outputs": [],
- "source": [
- "!clang++ -O3 -std=c++17 -march=armv8.3-a -o optimized optimized.cpp\n",
- "!./optimized"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "0be9f47d-5213-4700-b0e2-d444c7c738c0",
- "metadata": {},
- "outputs": [],
- "source": [
- "def stream_gpt(python): \n",
- " stream = openai.chat.completions.create(model=OPENAI_MODEL, messages=messages_for(python), stream=True)\n",
- " reply = \"\"\n",
- " for chunk in stream:\n",
- " fragment = chunk.choices[0].delta.content or \"\"\n",
- " reply += fragment\n",
- " yield reply.replace('```cpp\\n','').replace('```','')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "8669f56b-8314-4582-a167-78842caea131",
- "metadata": {},
- "outputs": [],
- "source": [
- "def stream_claude(python):\n",
- " result = claude.messages.stream(\n",
- " model=CLAUDE_MODEL,\n",
- " max_tokens=2000,\n",
- " system=system_message,\n",
- " messages=[{\"role\": \"user\", \"content\": user_prompt_for(python)}],\n",
- " )\n",
- " reply = \"\"\n",
- " with result as stream:\n",
- " for text in stream.text_stream:\n",
- " reply += text\n",
- " yield reply.replace('```cpp\\n','').replace('```','')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "2f1ae8f5-16c8-40a0-aa18-63b617df078d",
- "metadata": {},
- "outputs": [],
- "source": [
- "def optimize(python, model):\n",
- " if model==\"GPT\":\n",
- " result = stream_gpt(python)\n",
- " elif model==\"Claude\":\n",
- " result = stream_claude(python)\n",
- " else:\n",
- " raise ValueError(\"Unknown model\")\n",
- " for stream_so_far in result:\n",
- " yield stream_so_far "
+ "def compile_and_run():\n",
+ " try:\n",
+ " subprocess.run(compile_command, check=True, text=True, capture_output=True)\n",
+ " print(subprocess.run(run_command, check=True, text=True, capture_output=True).stdout)\n",
+ " print(subprocess.run(run_command, check=True, text=True, capture_output=True).stdout)\n",
+ " print(subprocess.run(run_command, check=True, text=True, capture_output=True).stdout)\n",
+ " except subprocess.CalledProcessError as e:\n",
+ " print(f\"An error occurred:\\n{e.stderr}\")"
]
},
{
@@ -443,13 +349,13 @@
"source": [
"with gr.Blocks() as ui:\n",
" with gr.Row():\n",
- " python = gr.Textbox(label=\"Python code:\", lines=10, value=python_hard)\n",
- " cpp = gr.Textbox(label=\"C++ code:\", lines=10)\n",
+ " python = gr.Textbox(label=\"Python code:\", lines=28, value=pi)\n",
+ " cpp = gr.Textbox(label=\"C++ code:\", lines=28)\n",
" with gr.Row():\n",
- " model = gr.Dropdown([\"GPT\", \"Claude\"], label=\"Select model\", value=\"GPT\")\n",
+ " model = gr.Dropdown(models, label=\"Select model\", value=models[0])\n",
" convert = gr.Button(\"Convert code\")\n",
"\n",
- " convert.click(optimize, inputs=[python, model], outputs=[cpp])\n",
+ " convert.click(port, inputs=[model, python], outputs=[cpp])\n",
"\n",
"ui.launch(inbrowser=True)"
]
@@ -457,376 +363,63 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "19bf2bff-a822-4009-a539-f003b1651383",
+ "id": "28969928",
"metadata": {},
"outputs": [],
- "source": [
- "def execute_python(code):\n",
- " try:\n",
- " output = io.StringIO()\n",
- " sys.stdout = output\n",
- " exec(code)\n",
- " finally:\n",
- " sys.stdout = sys.__stdout__\n",
- " return output.getvalue()"
- ]
+ "source": []
},
{
"cell_type": "code",
"execution_count": null,
- "id": "77f3ab5d-fcfb-4d3f-8728-9cacbf833ea6",
+ "id": "d9cc1c03",
"metadata": {},
"outputs": [],
"source": [
- "def execute_cpp(code):\n",
- " write_output(code)\n",
- " compiler_cmd = [\"clang++\", \"-O3\", \"-std=c++17\", \"-march=armv8.3-a\", \"-o\", \"optimized\", \"optimized.cpp\"]\n",
- " try:\n",
- " compile_result = subprocess.run(compiler_cmd, check=True, text=True, capture_output=True)\n",
- " run_cmd = [\"./optimized\"]\n",
- " run_result = subprocess.run(run_cmd, check=True, text=True, capture_output=True)\n",
- " return run_result.stdout\n",
- " except subprocess.CalledProcessError as e:\n",
- " return f\"An error occurred:\\n{e.stderr}\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "9a2274f1-d03b-42c0-8dcc-4ce159b18442",
- "metadata": {},
- "outputs": [],
- "source": [
- "css = \"\"\"\n",
- ".python {background-color: #306998;}\n",
- ".cpp {background-color: #050;}\n",
- "\"\"\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f1303932-160c-424b-97a8-d28c816721b2",
- "metadata": {},
- "outputs": [],
- "source": [
- "with gr.Blocks(css=css) as ui:\n",
- " gr.Markdown(\"## Convert code from Python to C++\")\n",
- " with gr.Row():\n",
- " python = gr.Textbox(label=\"Python code:\", value=python_hard, lines=10)\n",
- " cpp = gr.Textbox(label=\"C++ code:\", lines=10)\n",
- " with gr.Row():\n",
- " model = gr.Dropdown([\"GPT\", \"Claude\"], label=\"Select model\", value=\"GPT\")\n",
- " with gr.Row():\n",
- " convert = gr.Button(\"Convert code\")\n",
- " with gr.Row():\n",
- " python_run = gr.Button(\"Run Python\")\n",
- " cpp_run = gr.Button(\"Run C++\")\n",
- " with gr.Row():\n",
- " python_out = gr.TextArea(label=\"Python result:\", elem_classes=[\"python\"])\n",
- " cpp_out = gr.TextArea(label=\"C++ result:\", elem_classes=[\"cpp\"])\n",
- "\n",
- " convert.click(optimize, inputs=[python, model], outputs=[cpp])\n",
- " python_run.click(execute_python, inputs=[python], outputs=[python_out])\n",
- " cpp_run.click(execute_cpp, inputs=[cpp], outputs=[cpp_out])\n",
- "\n",
- "ui.launch(inbrowser=True)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "bb8c5b4e-ec51-4f21-b3f8-6aa94fede86d",
- "metadata": {},
- "outputs": [],
- "source": [
- "from huggingface_hub import login, InferenceClient\n",
- "from transformers import AutoTokenizer"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "13347633-4606-4e38-9927-80c39e65c1f1",
- "metadata": {},
- "outputs": [],
- "source": [
- "hf_token = os.environ['HF_TOKEN']\n",
- "login(hf_token, add_to_git_credential=True)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ef60a4df-6267-4ebd-8eed-dcb917af0a5e",
- "metadata": {},
- "outputs": [],
- "source": [
- "code_qwen = \"Qwen/CodeQwen1.5-7B-Chat\"\n",
- "code_gemma = \"google/codegemma-7b-it\"\n",
- "CODE_QWEN_URL = \"https://h1vdol7jxhje3mpn.us-east-1.aws.endpoints.huggingface.cloud\"\n",
- "CODE_GEMMA_URL = \"https://c5hggiyqachmgnqg.us-east-1.aws.endpoints.huggingface.cloud\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "695ce389-a903-4533-a2f1-cd9e2a6af8f2",
- "metadata": {},
- "outputs": [],
- "source": [
- "tokenizer = AutoTokenizer.from_pretrained(code_qwen)\n",
- "messages = messages_for(pi)\n",
- "text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "d4548e96-0b32-4793-bdd6-1b072c2f26ab",
- "metadata": {},
- "outputs": [],
- "source": [
- "print(text)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "bb2a126b-09e7-4966-bc97-0ef5c2cc7896",
- "metadata": {},
- "outputs": [],
- "source": [
- "client = InferenceClient(CODE_QWEN_URL, token=hf_token)\n",
- "stream = client.text_generation(text, stream=True, details=True, max_new_tokens=3000)\n",
- "for r in stream:\n",
- " print(r.token.text, end = \"\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "127a52e5-ad85-42b7-a0f5-9afda5efe090",
- "metadata": {},
- "outputs": [],
- "source": [
- "def stream_code_qwen(python):\n",
- " tokenizer = AutoTokenizer.from_pretrained(code_qwen)\n",
- " messages = messages_for(python)\n",
- " text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)\n",
- " client = InferenceClient(CODE_QWEN_URL, token=hf_token)\n",
- " stream = client.text_generation(text, stream=True, details=True, max_new_tokens=3000)\n",
- " result = \"\"\n",
- " for r in stream:\n",
- " result += r.token.text\n",
- " yield result "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "a82387d1-7651-4923-995b-fe18356fcaa6",
- "metadata": {},
- "outputs": [],
- "source": [
- "def optimize(python, model):\n",
- " if model==\"GPT\":\n",
- " result = stream_gpt(python)\n",
- " elif model==\"Claude\":\n",
- " result = stream_claude(python)\n",
- " elif model==\"CodeQwen\":\n",
- " result = stream_code_qwen(python)\n",
- " else:\n",
- " raise ValueError(\"Unknown model\")\n",
- " for stream_so_far in result:\n",
- " yield stream_so_far "
+ "compile_and_run()"
]
},
{
"cell_type": "markdown",
- "id": "4b0a6a97-5b8a-4a9b-8ee0-7561e0ced673",
+ "id": "80037156",
"metadata": {},
"source": [
- "\n",
- " \n",
- " \n",
- " \n",
- " | \n",
- " \n",
- " Thank you to @CloudLlama for an amazing contribution\n",
- " \n",
- " A student has contributed a chunk of code to improve this, in the next 2 cells. You can now select which Python porgram to run,\n",
- " and a compiler is automatically selected that will work on PC, Windows and Mac. Massive thank you @CloudLlama!\n",
- " \n",
- " | \n",
- " \n",
- " "
+ "Qwen 2.5 Coder: Fail \n",
+ "DeepSeek Coder v2: 0.114050084 \n",
+ "OpenAI gpt-oss 20B: 0.080438 \n",
+ "Qwen 30B: 0.113734 \n",
+ "OpenAI gpt-oss 120B: 1.407383\n",
+ "\n",
+ "\n"
]
},
{
- "cell_type": "code",
- "execution_count": null,
- "id": "4ba311ec-c16a-4fe0-946b-4b940704cf65",
+ "cell_type": "markdown",
+ "id": "ad8d4e52",
"metadata": {},
- "outputs": [],
"source": [
- "def select_sample_program(sample_program):\n",
- " if sample_program==\"pi\":\n",
- " return pi\n",
- " elif sample_program==\"python_hard\":\n",
- " return python_hard\n",
- " else:\n",
- " return \"Type your Python program here\""
+ "In Ed's experiments, the performance speedups were:\n",
+ "\n",
+ "9th place: Qwen 2.5 Coder: Fail \n",
+ "8th place: OpenAI GPT-OSS 120B: 14X speedup \n",
+ "7th place: DeepSeek Coder v2: 168X speedup \n",
+ "6th place: Qwen3 Coder 30B: 168X speedup \n",
+ "5th place: Claude Sonnet 4.5: 184X speedup \n",
+ "4th place: GPT-5: 233X speedup \n",
+ "**3rd place: oss-20B: 238X speedup** \n",
+ "2nd place: Grok 4: 1060X speedup \n",
+ "1st place: Gemini 2.5 Pro: 1440X speedup "
]
},
{
- "cell_type": "code",
- "execution_count": null,
- "id": "e42286bc-085c-45dc-b101-234308e58269",
+ "cell_type": "markdown",
+ "id": "6e617df9",
"metadata": {},
- "outputs": [],
- "source": [
- "import platform\n",
- "\n",
- "VISUAL_STUDIO_2022_TOOLS = \"C:\\\\Program Files\\\\Microsoft Visual Studio\\\\2022\\\\Community\\\\Common7\\Tools\\\\VsDevCmd.bat\"\n",
- "VISUAL_STUDIO_2019_TOOLS = \"C:\\\\Program Files (x86)\\\\Microsoft Visual Studio\\\\2019\\\\BuildTools\\\\Common7\\\\Tools\\\\VsDevCmd.bat\"\n",
- "\n",
- "simple_cpp = \"\"\"\n",
- "#include \n",
- "\n",
- "int main() {\n",
- " std::cout << \"Hello\";\n",
- " return 0;\n",
- "}\n",
- "\"\"\"\n",
- "\n",
- "def run_cmd(command_to_run):\n",
- " try:\n",
- " run_result = subprocess.run(command_to_run, check=True, text=True, capture_output=True)\n",
- " return run_result.stdout if run_result.stdout else \"SUCCESS\"\n",
- " except:\n",
- " return \"\"\n",
- "\n",
- "def c_compiler_cmd(filename_base):\n",
- " my_platform = platform.system()\n",
- " my_compiler = []\n",
- "\n",
- " try:\n",
- " with open(\"simple.cpp\", \"w\") as f:\n",
- " f.write(simple_cpp)\n",
- " \n",
- " if my_platform == \"Windows\":\n",
- " if os.path.isfile(VISUAL_STUDIO_2022_TOOLS):\n",
- " if os.path.isfile(\"./simple.exe\"):\n",
- " os.remove(\"./simple.exe\")\n",
- " compile_cmd = [\"cmd\", \"/c\", VISUAL_STUDIO_2022_TOOLS, \"&\", \"cl\", \"simple.cpp\"]\n",
- " if run_cmd(compile_cmd):\n",
- " if run_cmd([\"./simple.exe\"]) == \"Hello\":\n",
- " my_compiler = [\"Windows\", \"Visual Studio 2022\", [\"cmd\", \"/c\", VISUAL_STUDIO_2022_TOOLS, \"&\", \"cl\", f\"{filename_base}.cpp\"]]\n",
- " \n",
- " if not my_compiler:\n",
- " if os.path.isfile(VISUAL_STUDIO_2019_TOOLS):\n",
- " if os.path.isfile(\"./simple.exe\"):\n",
- " os.remove(\"./simple.exe\")\n",
- " compile_cmd = [\"cmd\", \"/c\", VISUAL_STUDIO_2019_TOOLS, \"&\", \"cl\", \"simple.cpp\"]\n",
- " if run_cmd(compile_cmd):\n",
- " if run_cmd([\"./simple.exe\"]) == \"Hello\":\n",
- " my_compiler = [\"Windows\", \"Visual Studio 2019\", [\"cmd\", \"/c\", VISUAL_STUDIO_2019_TOOLS, \"&\", \"cl\", f\"{filename_base}.cpp\"]]\n",
- " \n",
- " if not my_compiler:\n",
- " my_compiler=[my_platform, \"Unavailable\", []]\n",
- " \n",
- " elif my_platform == \"Linux\":\n",
- " if os.path.isfile(\"./simple\"):\n",
- " os.remove(\"./simple\")\n",
- " compile_cmd = [\"g++\", \"simple.cpp\", \"-o\", \"simple\"]\n",
- " if run_cmd(compile_cmd):\n",
- " if run_cmd([\"./simple\"]) == \"Hello\":\n",
- " my_compiler = [\"Linux\", \"GCC (g++)\", [\"g++\", f\"{filename_base}.cpp\", \"-o\", f\"{filename_base}\" ]]\n",
- " \n",
- " if not my_compiler:\n",
- " if os.path.isfile(\"./simple\"):\n",
- " os.remove(\"./simple\")\n",
- " compile_cmd = [\"clang++\", \"simple.cpp\", \"-o\", \"simple\"]\n",
- " if run_cmd(compile_cmd):\n",
- " if run_cmd([\"./simple\"]) == \"Hello\":\n",
- " my_compiler = [\"Linux\", \"Clang++\", [\"clang++\", f\"{filename_base}.cpp\", \"-o\", f\"{filename_base}\"]]\n",
- " \n",
- " if not my_compiler:\n",
- " my_compiler=[my_platform, \"Unavailable\", []]\n",
- " \n",
- " elif my_platform == \"Darwin\":\n",
- " if os.path.isfile(\"./simple\"):\n",
- " os.remove(\"./simple\")\n",
- " compile_cmd = [\"clang++\", \"-Ofast\", \"-std=c++17\", \"-march=armv8.5-a\", \"-mtune=apple-m1\", \"-mcpu=apple-m1\", \"-o\", \"simple\", \"simple.cpp\"]\n",
- " if run_cmd(compile_cmd):\n",
- " if run_cmd([\"./simple\"]) == \"Hello\":\n",
- " my_compiler = [\"Macintosh\", \"Clang++\", [\"clang++\", \"-Ofast\", \"-std=c++17\", \"-march=armv8.5-a\", \"-mtune=apple-m1\", \"-mcpu=apple-m1\", \"-o\", f\"{filename_base}\", f\"{filename_base}.cpp\"]]\n",
- " \n",
- " if not my_compiler:\n",
- " my_compiler=[my_platform, \"Unavailable\", []]\n",
- " except:\n",
- " my_compiler=[my_platform, \"Unavailable\", []]\n",
- " \n",
- " if my_compiler:\n",
- " return my_compiler\n",
- " else:\n",
- " return [\"Unknown\", \"Unavailable\", []]\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f9ca2e6f-60c1-4e5f-b570-63c75b2d189b",
- "metadata": {},
- "outputs": [],
- "source": [
- "compiler_cmd = c_compiler_cmd(\"optimized\")\n",
- "\n",
- "with gr.Blocks(css=css) as ui:\n",
- " gr.Markdown(\"## Convert code from Python to C++\")\n",
- " with gr.Row():\n",
- " python = gr.Textbox(label=\"Python code:\", value=python_hard, lines=10)\n",
- " cpp = gr.Textbox(label=\"C++ code:\", lines=10)\n",
- " with gr.Row():\n",
- " with gr.Column():\n",
- " sample_program = gr.Radio([\"pi\", \"python_hard\"], label=\"Sample program\", value=\"python_hard\")\n",
- " model = gr.Dropdown([\"GPT\", \"Claude\", \"CodeQwen\"], label=\"Select model\", value=\"GPT\")\n",
- " with gr.Column():\n",
- " architecture = gr.Radio([compiler_cmd[0]], label=\"Architecture\", interactive=False, value=compiler_cmd[0])\n",
- " compiler = gr.Radio([compiler_cmd[1]], label=\"Compiler\", interactive=False, value=compiler_cmd[1])\n",
- " with gr.Row():\n",
- " convert = gr.Button(\"Convert code\")\n",
- " with gr.Row():\n",
- " python_run = gr.Button(\"Run Python\")\n",
- " if not compiler_cmd[1] == \"Unavailable\":\n",
- " cpp_run = gr.Button(\"Run C++\")\n",
- " else:\n",
- " cpp_run = gr.Button(\"No compiler to run C++\", interactive=False)\n",
- " with gr.Row():\n",
- " python_out = gr.TextArea(label=\"Python result:\", elem_classes=[\"python\"])\n",
- " cpp_out = gr.TextArea(label=\"C++ result:\", elem_classes=[\"cpp\"])\n",
- "\n",
- " sample_program.change(select_sample_program, inputs=[sample_program], outputs=[python])\n",
- " convert.click(optimize, inputs=[python, model], outputs=[cpp])\n",
- " python_run.click(execute_python, inputs=[python], outputs=[python_out])\n",
- " cpp_run.click(execute_cpp, inputs=[cpp], outputs=[cpp_out])\n",
- "\n",
- "ui.launch(inbrowser=True)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "9d0ad093-425b-488e-8c3f-67f729dd9c06",
- "metadata": {},
- "outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -840,7 +433,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.11"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/week4/day5.ipynb b/week4/day5.ipynb
new file mode 100644
index 0000000..2826a3d
--- /dev/null
+++ b/week4/day5.ipynb
@@ -0,0 +1,522 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "4a6ab9a2-28a2-445d-8512-a0dc8d1b54e9",
+ "metadata": {},
+ "source": [
+ "# Code Generator\n",
+ "\n",
+ "The requirement: use a Frontier model to generate high performance C++ code from Python code\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d5ccb926-7b49-44a4-99ab-8ef20b5778c0",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " Reminder: OPTIONAL to execute C++ code or Rust code\n",
+ " As an alternative, you can run it on the website given yesterday\n",
+ " | \n",
+ " \n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d90e04a2-5b8a-4fd5-9db8-27c02f033313",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " Important Note\n",
+ " \n",
+ " In this lab, I use high end models GPT 5, Claude 4.5 Sonnet, Gemini 2.5 Pro, Grok 4, which are the slightly higher priced models. The costs are still low, but if you'd prefer to keep costs ultra low, please pick lower cost models like gpt-5-nano.\n",
+ " \n",
+ " | \n",
+ " \n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e610bf56-a46e-4aff-8de1-ab49d62b1ad3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# imports\n",
+ "\n",
+ "import os\n",
+ "import io\n",
+ "import sys\n",
+ "from dotenv import load_dotenv\n",
+ "from openai import OpenAI\n",
+ "import gradio as gr\n",
+ "import subprocess\n",
+ "from IPython.display import Markdown, display\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4f672e1c-87e9-4865-b760-370fa605e614",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "load_dotenv(override=True)\n",
+ "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
+ "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
+ "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
+ "grok_api_key = os.getenv('GROK_API_KEY')\n",
+ "groq_api_key = os.getenv('GROQ_API_KEY')\n",
+ "openrouter_api_key = os.getenv('OPENROUTER_API_KEY')\n",
+ "\n",
+ "if openai_api_key:\n",
+ " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
+ "else:\n",
+ " print(\"OpenAI API Key not set\")\n",
+ " \n",
+ "if anthropic_api_key:\n",
+ " print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
+ "else:\n",
+ " print(\"Anthropic API Key not set (and this is optional)\")\n",
+ "\n",
+ "if google_api_key:\n",
+ " print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
+ "else:\n",
+ " print(\"Google API Key not set (and this is optional)\")\n",
+ "\n",
+ "if grok_api_key:\n",
+ " print(f\"Grok API Key exists and begins {grok_api_key[:4]}\")\n",
+ "else:\n",
+ " print(\"Grok API Key not set (and this is optional)\")\n",
+ "\n",
+ "if groq_api_key:\n",
+ " print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
+ "else:\n",
+ " print(\"Groq API Key not set (and this is optional)\")\n",
+ "\n",
+ "if openrouter_api_key:\n",
+ " print(f\"OpenRouter API Key exists and begins {openrouter_api_key[:6]}\")\n",
+ "else:\n",
+ " print(\"OpenRouter API Key not set (and this is optional)\")\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "59863df1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Connect to client libraries\n",
+ "\n",
+ "openai = OpenAI()\n",
+ "\n",
+ "anthropic_url = \"https://api.anthropic.com/v1/\"\n",
+ "gemini_url = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
+ "grok_url = \"https://api.x.ai/v1\"\n",
+ "groq_url = \"https://api.groq.com/openai/v1\"\n",
+ "ollama_url = \"http://localhost:11434/v1\"\n",
+ "openrouter_url = \"https://openrouter.ai/api/v1\"\n",
+ "\n",
+ "anthropic = OpenAI(api_key=anthropic_api_key, base_url=anthropic_url)\n",
+ "gemini = OpenAI(api_key=google_api_key, base_url=gemini_url)\n",
+ "grok = OpenAI(api_key=grok_api_key, base_url=grok_url)\n",
+ "groq = OpenAI(api_key=groq_api_key, base_url=groq_url)\n",
+ "ollama = OpenAI(api_key=\"ollama\", base_url=ollama_url)\n",
+ "openrouter = OpenAI(api_key=openrouter_api_key, base_url=openrouter_url)\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8aa149ed-9298-4d69-8fe2-8f5de0f667da",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "models = [\"gpt-5\", \"claude-sonnet-4-5-20250929\", \"grok-4\", \"gemini-2.5-pro\", \"qwen2.5-coder\", \"deepseek-coder-v2\", \"gpt-oss:20b\", \"qwen/qwen3-coder-30b-a3b-instruct\", \"openai/gpt-oss-120b\", ]\n",
+ "\n",
+ "clients = {\"gpt-5\": openai, \"claude-sonnet-4-5-20250929\": anthropic, \"grok-4\": grok, \"gemini-2.5-pro\": gemini, \"openai/gpt-oss-120b\": groq, \"qwen2.5-coder\": ollama, \"deepseek-coder-v2\": ollama, \"gpt-oss:20b\": ollama, \"qwen/qwen3-coder-30b-a3b-instruct\": openrouter}\n",
+ "\n",
+ "# Want to keep costs ultra-low? Replace this with models of your choice, using the examples from yesterday"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "68c1f1be",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from system_info import retrieve_system_info, rust_toolchain_info\n",
+ "\n",
+ "system_info = retrieve_system_info()\n",
+ "rust_info = rust_toolchain_info()\n",
+ "rust_info"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b8bd44f5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "message = f\"\"\"\n",
+ "Here is a report of the system information for my computer.\n",
+ "I want to run a Rust compiler to compile a single rust file called main.rs and then execute it in the simplest way possible.\n",
+ "Please reply with whether I need to install a Rust toolchain to do this. If so, please provide the simplest step by step instructions to do so.\n",
+ "\n",
+ "If I'm already set up to compile Rust code, then I'd like to run something like this in Python to compile and execute the code:\n",
+ "```python\n",
+ "compile_command = # something here - to achieve the fastest possible runtime performance\n",
+ "compile_result = subprocess.run(compile_command, check=True, text=True, capture_output=True)\n",
+ "run_command = # something here\n",
+ "run_result = subprocess.run(run_command, check=True, text=True, capture_output=True)\n",
+ "return run_result.stdout\n",
+ "```\n",
+ "Please tell me exactly what I should use for the compile_command and run_command.\n",
+ "Have the maximum possible runtime performance in mind; compile time can be slow. Fastest possible runtime performance for this platform is key.\n",
+ "Reply with the commands in markdown.\n",
+ "\n",
+ "System information:\n",
+ "{system_info}\n",
+ "\n",
+ "Rust toolchain information:\n",
+ "{rust_info}\n",
+ "\"\"\"\n",
+ "\n",
+ "response = openai.chat.completions.create(model=models[0], messages=[{\"role\": \"user\", \"content\": message}])\n",
+ "display(Markdown(response.choices[0].message.content))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81e92c12",
+ "metadata": {},
+ "source": [
+ "## For C++, overwrite this with the commands from yesterday, or for Rust, use the new commands\n",
+ "\n",
+ "Or just use the website like yesterday:\n",
+ "\n",
+ " https://www.programiz.com/cpp-programming/online-compiler/"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d734a634",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "compile_command = [\n",
+ " \"/Users/ed/.cargo/bin/rustc\",\n",
+ " \"main.rs\",\n",
+ " \"-C\", \"opt-level=3\",\n",
+ " \"-C\", \"target-cpu=native\",\n",
+ " \"-C\", \"codegen-units=1\",\n",
+ " \"-C\", \"lto=fat\",\n",
+ " \"-C\", \"panic=abort\",\n",
+ " \"-C\", \"strip=symbols\",\n",
+ " \"-o\", \"main\",\n",
+ "]\n",
+ "\n",
+ "run_command = [\"./main\"]\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f0b0a437",
+ "metadata": {},
+ "source": [
+ "## And now, on with the main task"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6896636f-923e-4a2c-9d6c-fac07828a201",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "language = \"Rust\" # or \"C++\"\n",
+ "extension = \"rs\" if language == \"Rust\" else \"cpp\"\n",
+ "\n",
+ "system_prompt = f\"\"\"\n",
+ "Your task is to convert Python code into high performance {language} code.\n",
+ "Respond only with {language} code. Do not provide any explanation other than occasional comments.\n",
+ "The {language} response needs to produce an identical output in the fastest possible time.\n",
+ "\"\"\"\n",
+ "\n",
+ "def user_prompt_for(python):\n",
+ " return f\"\"\"\n",
+ "Port this Python code to {language} with the fastest possible implementation that produces identical output in the least time.\n",
+ "The system information is:\n",
+ "{system_info}\n",
+ "Your response will be written to a file called main.{language} and then compiled and executed; the compilation command is:\n",
+ "{compile_command}\n",
+ "Respond only with {language} code.\n",
+ "Python code to port:\n",
+ "\n",
+ "```python\n",
+ "{python}\n",
+ "```\n",
+ "\"\"\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8e7b3546-57aa-4c29-bc5d-f211970d04eb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def messages_for(python):\n",
+ " return [\n",
+ " {\"role\": \"system\", \"content\": system_prompt},\n",
+ " {\"role\": \"user\", \"content\": user_prompt_for(python)}\n",
+ " ]\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c6190659-f54c-4951-bef4-4960f8e51cc4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def write_output(code):\n",
+ " with open(f\"main.{extension}\", \"w\") as f:\n",
+ " f.write(code)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e7d2fea8-74c6-4421-8f1e-0e76d5b201b9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def port(model, python):\n",
+ " client = clients[model]\n",
+ " reasoning_effort = \"high\" if 'gpt' in model else None\n",
+ " response = client.chat.completions.create(model=model, messages=messages_for(python), reasoning_effort=reasoning_effort)\n",
+ " reply = response.choices[0].message.content\n",
+ " reply = reply.replace('```cpp','').replace('```rust','').replace('```','')\n",
+ " return reply"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7fe1cd4b-d2c5-4303-afed-2115a3fef200",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def run_python(code):\n",
+ " globals_dict = {\"__builtins__\": __builtins__}\n",
+ "\n",
+ " buffer = io.StringIO()\n",
+ " old_stdout = sys.stdout\n",
+ " sys.stdout = buffer\n",
+ "\n",
+ " try:\n",
+ " exec(code, globals_dict)\n",
+ " output = buffer.getvalue()\n",
+ " except Exception as e:\n",
+ " output = f\"Error: {e}\"\n",
+ " finally:\n",
+ " sys.stdout = old_stdout\n",
+ "\n",
+ " return output"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4194e40c-04ab-4940-9d64-b4ad37c5bb40",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Use the commands from GPT 5\n",
+ "\n",
+ "def compile_and_run(code):\n",
+ " write_output(code)\n",
+ " try:\n",
+ " subprocess.run(compile_command, check=True, text=True, capture_output=True)\n",
+ " run_result = subprocess.run(run_command, check=True, text=True, capture_output=True)\n",
+ " return run_result.stdout\n",
+ " except subprocess.CalledProcessError as e:\n",
+ " return f\"An error occurred:\\n{e.stderr}\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c3b497b3-f569-420e-b92e-fb0f49957ce0",
+ "metadata": {},
+ "source": [
+ "python_hard = \"\"\"# Be careful to support large numbers\n",
+ "\n",
+ "def lcg(seed, a=1664525, c=1013904223, m=2**32):\n",
+ " value = seed\n",
+ " while True:\n",
+ " value = (a * value + c) % m\n",
+ " yield value\n",
+ " \n",
+ "def max_subarray_sum(n, seed, min_val, max_val):\n",
+ " lcg_gen = lcg(seed)\n",
+ " random_numbers = [next(lcg_gen) % (max_val - min_val + 1) + min_val for _ in range(n)]\n",
+ " max_sum = float('-inf')\n",
+ " for i in range(n):\n",
+ " current_sum = 0\n",
+ " for j in range(i, n):\n",
+ " current_sum += random_numbers[j]\n",
+ " if current_sum > max_sum:\n",
+ " max_sum = current_sum\n",
+ " return max_sum\n",
+ "\n",
+ "def total_max_subarray_sum(n, initial_seed, min_val, max_val):\n",
+ " total_sum = 0\n",
+ " lcg_gen = lcg(initial_seed)\n",
+ " for _ in range(20):\n",
+ " seed = next(lcg_gen)\n",
+ " total_sum += max_subarray_sum(n, seed, min_val, max_val)\n",
+ " return total_sum\n",
+ "\n",
+ "# Parameters\n",
+ "n = 10000 # Number of random numbers\n",
+ "initial_seed = 42 # Initial seed for the LCG\n",
+ "min_val = -10 # Minimum value of random numbers\n",
+ "max_val = 10 # Maximum value of random numbers\n",
+ "\n",
+ "# Timing the function\n",
+ "import time\n",
+ "start_time = time.time()\n",
+ "result = total_max_subarray_sum(n, initial_seed, min_val, max_val)\n",
+ "end_time = time.time()\n",
+ "\n",
+ "print(\"Total Maximum Subarray Sum (20 runs):\", result)\n",
+ "print(\"Execution Time: {:.6f} seconds\".format(end_time - start_time))\n",
+ "\"\"\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "465d6cad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from styles import CSS\n",
+ "\n",
+ "with gr.Blocks(css=CSS, theme=gr.themes.Monochrome(), title=f\"Port from Python to {language}\") as ui:\n",
+ " with gr.Row(equal_height=True):\n",
+ " with gr.Column(scale=6):\n",
+ " python = gr.Code(\n",
+ " label=\"Python (original)\",\n",
+ " value=python_hard,\n",
+ " language=\"python\",\n",
+ " lines=26\n",
+ " )\n",
+ " with gr.Column(scale=6):\n",
+ " cpp = gr.Code(\n",
+ " label=f\"{language} (generated)\",\n",
+ " value=\"\",\n",
+ " language=\"cpp\",\n",
+ " lines=26\n",
+ " )\n",
+ "\n",
+ " with gr.Row(elem_classes=[\"controls\"]):\n",
+ " python_run = gr.Button(\"Run Python\", elem_classes=[\"run-btn\", \"py\"])\n",
+ " model = gr.Dropdown(models, value=models[0], show_label=False)\n",
+ " convert = gr.Button(f\"Port to {language}\", elem_classes=[\"convert-btn\"])\n",
+ " cpp_run = gr.Button(f\"Run {language}\", elem_classes=[\"run-btn\", \"cpp\"])\n",
+ "\n",
+ " with gr.Row(equal_height=True):\n",
+ " with gr.Column(scale=6):\n",
+ " python_out = gr.TextArea(label=\"Python result\", lines=8, elem_classes=[\"py-out\"])\n",
+ " with gr.Column(scale=6):\n",
+ " cpp_out = gr.TextArea(label=f\"{language} result\", lines=8, elem_classes=[\"cpp-out\"])\n",
+ "\n",
+ " convert.click(fn=port, inputs=[model, python], outputs=[cpp])\n",
+ " python_run.click(fn=run_python, inputs=[python], outputs=[python_out])\n",
+ " cpp_run.click(fn=compile_and_run, inputs=[cpp], outputs=[cpp_out])\n",
+ "\n",
+ "ui.launch(inbrowser=True)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2311ada8",
+ "metadata": {},
+ "source": [
+ "## RESULTS!\n",
+ "\n",
+ "Qwen 2.5 Coder: FAIL \n",
+ "Gemini 2.5 Pro: FAIL \n",
+ "DeepSeek Coder v2: FAIL \n",
+ "Qwen3 Coder 30B: FAIL \n",
+ "Claude Sonnet 4.5: FAIL \n",
+ "GPT-5: FAIL \n",
+ "\n",
+ "3rd place: GPT-oss-20B: 0.000341 \n",
+ "2nd place: Grok 4: 0.000317 \n",
+ "**1st place: OpenAI GPT-OSS 120B: 0.000304** "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b9b51dc7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(f\"In Ed's experimenet, the GPT-OSS 120B model outcome is {33.755209/0.000304:,.0f} times faster than the Python code.\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6197bb97",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".venv",
+ "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.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/week4/optimized.cpp b/week4/optimized.cpp
deleted file mode 100644
index b76e850..0000000
--- a/week4/optimized.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-
-class LCG {
-private:
- uint64_t value;
- const uint64_t a = 1664525;
- const uint64_t c = 1013904223;
- const uint64_t m = 1ULL << 32;
-
-public:
- LCG(uint64_t seed) : value(seed) {}
-
- uint64_t next() {
- value = (a * value + c) % m;
- return value;
- }
-};
-
-int64_t max_subarray_sum(int n, uint64_t seed, int min_val, int max_val) {
- LCG lcg(seed);
- std::vector random_numbers(n);
- for (int i = 0; i < n; ++i) {
- random_numbers[i] = static_cast(lcg.next() % (max_val - min_val + 1) + min_val);
- }
-
- int64_t max_sum = std::numeric_limits::min();
- int64_t current_sum = 0;
- for (int i = 0; i < n; ++i) {
- current_sum = std::max(static_cast(random_numbers[i]), current_sum + random_numbers[i]);
- max_sum = std::max(max_sum, current_sum);
- }
- return max_sum;
-}
-
-int64_t total_max_subarray_sum(int n, uint64_t initial_seed, int min_val, int max_val) {
- int64_t total_sum = 0;
- LCG lcg(initial_seed);
- for (int i = 0; i < 20; ++i) {
- uint64_t seed = lcg.next();
- total_sum += max_subarray_sum(n, seed, min_val, max_val);
- }
- return total_sum;
-}
-
-int main() {
- int n = 10000;
- uint64_t initial_seed = 42;
- int min_val = -10;
- int max_val = 10;
-
- auto start_time = std::chrono::high_resolution_clock::now();
- int64_t result = total_max_subarray_sum(n, initial_seed, min_val, max_val);
- auto end_time = std::chrono::high_resolution_clock::now();
-
- auto duration = std::chrono::duration_cast(end_time - start_time);
-
- std::cout << "Total Maximum Subarray Sum (20 runs): " << result << std::endl;
- std::cout << "Execution Time: " << std::fixed << std::setprecision(6) << duration.count() / 1e6 << " seconds" << std::endl;
-
- return 0;
-}
\ No newline at end of file
diff --git a/week4/simple.cpp b/week4/simple.cpp
deleted file mode 100644
index a580b59..0000000
--- a/week4/simple.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-
-#include
-
-int main() {
- std::cout << "Hello";
- return 0;
-}
diff --git a/week4/styles.py b/week4/styles.py
new file mode 100644
index 0000000..b299013
--- /dev/null
+++ b/week4/styles.py
@@ -0,0 +1,60 @@
+CSS = """
+:root {
+ --py-color: #209dd7;
+ --cpp-color: #ecad0a;
+ --accent: #753991;
+ --card: #161a22;
+ --text: #e9eef5;
+}
+
+/* Full-width layout */
+.gradio-container {
+ max-width: 100% !important;
+ padding: 0 40px !important;
+}
+
+/* Code card styling */
+.card {
+ background: var(--card);
+ border: 1px solid rgba(255,255,255,.08);
+ border-radius: 14px;
+ padding: 10px;
+}
+
+/* Buttons */
+.convert-btn button {
+ background: var(--accent) !important;
+ border-color: rgba(255,255,255,.12) !important;
+ color: white !important;
+ font-weight: 700;
+}
+.run-btn button {
+ background: #202631 !important;
+ color: var(--text) !important;
+ border-color: rgba(255,255,255,.12) !important;
+}
+.run-btn.py button:hover { box-shadow: 0 0 0 2px var(--py-color) inset; }
+.run-btn.cpp button:hover { box-shadow: 0 0 0 2px var(--cpp-color) inset; }
+.convert-btn button:hover { box-shadow: 0 0 0 2px var(--accent) inset; }
+
+/* Outputs with color tint */
+.py-out textarea {
+ background: linear-gradient(180deg, rgba(32,157,215,.18), rgba(32,157,215,.10));
+ border: 1px solid rgba(32,157,215,.35) !important;
+ color: rgba(32,157,215,1) !important;
+ font-weight: 600;
+}
+.cpp-out textarea {
+ background: linear-gradient(180deg, rgba(236,173,10,.22), rgba(236,173,10,.12));
+ border: 1px solid rgba(236,173,10,.45) !important;
+ color: rgba(236,173,10,1) !important;
+ font-weight: 600;
+}
+
+/* Align controls neatly */
+.controls .wrap {
+ gap: 10px;
+ justify-content: center;
+ align-items: center;
+}
+"""
diff --git a/week4/system_info.py b/week4/system_info.py
new file mode 100644
index 0000000..33a6c02
--- /dev/null
+++ b/week4/system_info.py
@@ -0,0 +1,359 @@
+import os
+import platform
+import shutil
+import subprocess
+
+# ------------------------- helpers -------------------------
+
+
+def _run(cmd, timeout=3):
+ """Run a command safely. Returns stdout text or ''.
+ Accepts either a string (shell) or list (no shell)."""
+ try:
+ if isinstance(cmd, str):
+ return subprocess.check_output(
+ cmd, shell=True, text=True, stderr=subprocess.DEVNULL, timeout=timeout
+ ).strip()
+ else:
+ return subprocess.check_output(
+ cmd, shell=False, text=True, stderr=subprocess.DEVNULL, timeout=timeout
+ ).strip()
+ except Exception:
+ return ""
+
+
+def _first_line(s: str) -> str:
+ s = (s or "").strip()
+ return s.splitlines()[0].strip() if s else ""
+
+
+def _which(name: str) -> str:
+ return shutil.which(name) or ""
+
+
+def _bool_from_output(s: str) -> bool:
+ return s.strip() in {"1", "true", "True", "YES", "Yes", "yes"}
+
+
+# ------------------------- OS & env -------------------------
+
+
+def _os_block():
+ sysname = platform.system() # 'Windows', 'Darwin', 'Linux'
+ machine = platform.machine() or ""
+ release = platform.release() or ""
+ version = platform.version() or ""
+ kernel = release if sysname == "Windows" else (_run(["uname", "-r"]) or release)
+
+ distro = {"name": "", "version": ""}
+ if sysname == "Linux":
+ # Best-effort parse of /etc/os-release
+ try:
+ with open("/etc/os-release", "r") as f:
+ data = {}
+ for line in f:
+ if "=" in line:
+ k, v = line.rstrip().split("=", 1)
+ data[k] = v.strip('"')
+ distro["name"] = data.get("PRETTY_NAME") or data.get("NAME", "")
+ distro["version"] = data.get("VERSION_ID") or data.get("VERSION", "")
+ except Exception:
+ pass
+
+ # WSL / Rosetta detection (harmless if not present)
+ wsl = False
+ if sysname != "Windows":
+ try:
+ with open("/proc/version", "r") as f:
+ v = f.read().lower()
+ wsl = ("microsoft" in v) or ("wsl" in v)
+ except Exception:
+ wsl = False
+
+ rosetta = False
+ if sysname == "Darwin":
+ rosetta = _bool_from_output(_run(["sysctl", "-in", "sysctl.proc_translated"]))
+
+ # Target triple (best effort)
+ target = ""
+ for cc in ("clang", "gcc"):
+ if _which(cc):
+ out = _run([cc, "-dumpmachine"])
+ if out:
+ target = _first_line(out)
+ break
+
+ return {
+ "system": sysname,
+ "arch": machine,
+ "release": release,
+ "version": version,
+ "kernel": kernel,
+ "distro": distro if sysname == "Linux" else None,
+ "wsl": wsl,
+ "rosetta2_translated": rosetta,
+ "target_triple": target,
+ }
+
+
+# ------------------------- package managers -------------------------
+
+
+def _package_managers():
+ sysname = platform.system()
+ pms = []
+ if sysname == "Windows":
+ for pm in ("winget", "choco", "scoop"):
+ if _which(pm):
+ pms.append(pm)
+ elif sysname == "Darwin":
+ if _run(["xcode-select", "-p"]):
+ pms.append("xcode-select (CLT)")
+ for pm in ("brew", "port"):
+ if _which(pm):
+ pms.append(pm)
+ else:
+ for pm in ("apt", "dnf", "yum", "pacman", "zypper", "apk", "emerge"):
+ if _which(pm):
+ pms.append(pm)
+ return pms
+
+
+# ------------------------- CPU (minimal) -------------------------
+
+
+def _cpu_block():
+ sysname = platform.system()
+ brand = ""
+ # A simple brand/model read per OS; ignore failures
+ if sysname == "Linux":
+ brand = _run("grep -m1 'model name' /proc/cpuinfo | cut -d: -f2").strip()
+ elif sysname == "Darwin":
+ brand = _run(["sysctl", "-n", "machdep.cpu.brand_string"])
+ elif sysname == "Windows":
+ brand = _run('powershell -NoProfile -Command "(Get-CimInstance Win32_Processor).Name"')
+ if not brand:
+ brand = _run("wmic cpu get Name /value").replace("Name=", "").strip()
+
+ # Logical cores always available; physical is best-effort
+ cores_logical = os.cpu_count() or 0
+ cores_physical = 0
+ if sysname == "Darwin":
+ cores_physical = int(_run(["sysctl", "-n", "hw.physicalcpu"]) or "0")
+ elif sysname == "Windows":
+ cores_physical = int(
+ _run('powershell -NoProfile -Command "(Get-CimInstance Win32_Processor).NumberOfCores"')
+ or "0"
+ )
+ elif sysname == "Linux":
+ # This is a quick approximation; fine for our use (parallel -j suggestions)
+ try:
+ # Count unique "core id" per physical id
+ mapping = _run("LC_ALL=C lscpu -p=CORE,SOCKET | grep -v '^#'").splitlines()
+ unique = set(tuple(line.split(",")) for line in mapping if "," in line)
+ cores_physical = len(unique) or 0
+ except Exception:
+ cores_physical = 0
+
+ # A tiny SIMD hint set (best-effort, optional)
+ simd = []
+ if sysname == "Linux":
+ flags = _run("grep -m1 'flags' /proc/cpuinfo | cut -d: -f2")
+ if flags:
+ fset = set(flags.upper().split())
+ for x in ("AVX512F", "AVX2", "AVX", "FMA", "SSE4_2", "NEON", "SVE"):
+ if x in fset:
+ simd.append(x)
+ elif sysname == "Darwin":
+ feats = (
+ (
+ _run(["sysctl", "-n", "machdep.cpu.features"])
+ + " "
+ + _run(["sysctl", "-n", "machdep.cpu.leaf7_features"])
+ )
+ .upper()
+ .split()
+ )
+ for x in ("AVX512F", "AVX2", "AVX", "FMA", "SSE4_2", "NEON", "SVE"):
+ if x in feats:
+ simd.append(x)
+ # On Windows, skip flags — brand typically suffices for MSVC /arch choice.
+
+ return {
+ "brand": brand.strip(),
+ "cores_logical": cores_logical,
+ "cores_physical": cores_physical,
+ "simd": sorted(set(simd)),
+ }
+
+
+# ------------------------- toolchain presence -------------------------
+
+
+def _toolchain_block():
+ def ver_line(exe, args=("--version",)):
+ p = _which(exe)
+ if not p:
+ return ""
+ out = _run([p, *args])
+ return _first_line(out)
+
+ gcc = ver_line("gcc")
+ gpp = ver_line("g++")
+ clang = ver_line("clang")
+
+ # MSVC cl (only available inside proper dev shell; handle gracefully)
+ msvc_cl = ""
+ cl_path = _which("cl")
+ if cl_path:
+ msvc_cl = _first_line(_run("cl 2>&1"))
+
+ # Build tools (presence + short version line)
+ cmake = ver_line("cmake")
+ ninja = _first_line(_run([_which("ninja"), "--version"])) if _which("ninja") else ""
+ make = ver_line("make")
+
+ # Linker (we only care if lld is available)
+ lld = ver_line("ld.lld")
+ return {
+ "compilers": {"gcc": gcc, "g++": gpp, "clang": clang, "msvc_cl": msvc_cl},
+ "build_tools": {"cmake": cmake, "ninja": ninja, "make": make},
+ "linkers": {"ld_lld": lld},
+ }
+
+
+# ------------------------- public API -------------------------
+
+
+def retrieve_system_info():
+ """
+ Returns a compact dict with enough info for an LLM to:
+ - Pick an install path (winget/choco/scoop, Homebrew/Xcode CLT, apt/dnf/...),
+ - Choose a compiler family (MSVC/clang/gcc),
+ - Suggest safe optimization flags (e.g., -O3/-march=native or MSVC /O2),
+ - Decide on a build system (cmake+ninja) and parallel -j value.
+ """
+ return {
+ "os": _os_block(),
+ "package_managers": _package_managers(),
+ "cpu": _cpu_block(),
+ "toolchain": _toolchain_block(),
+ }
+
+
+def rust_toolchain_info():
+ """
+ Return a dict with Rust-related settings:
+ - presence and paths for rustc / cargo / rustup / rust-analyzer
+ - versions
+ - active/default toolchain (if rustup is present)
+ - installed targets
+ - common env vars (CARGO_HOME, RUSTUP_HOME, RUSTFLAGS, CARGO_BUILD_TARGET)
+ - simple execution examples
+ Works on Windows, macOS, and Linux. Uses the existing helpers: _run, _which, _first_line.
+ """
+ info = {
+ "installed": False,
+ "rustc": {"path": "", "version": "", "host_triple": "", "release": "", "commit_hash": ""},
+ "cargo": {"path": "", "version": ""},
+ "rustup": {
+ "path": "",
+ "version": "",
+ "active_toolchain": "",
+ "default_toolchain": "",
+ "toolchains": [],
+ "targets_installed": [],
+ },
+ "rust_analyzer": {"path": ""},
+ "env": {
+ "CARGO_HOME": os.environ.get("CARGO_HOME", ""),
+ "RUSTUP_HOME": os.environ.get("RUSTUP_HOME", ""),
+ "RUSTFLAGS": os.environ.get("RUSTFLAGS", ""),
+ "CARGO_BUILD_TARGET": os.environ.get("CARGO_BUILD_TARGET", ""),
+ },
+ "execution_examples": [],
+ }
+
+ # Paths
+ rustc_path = _which("rustc")
+ cargo_path = _which("cargo")
+ rustup_path = _which("rustup")
+ ra_path = _which("rust-analyzer")
+
+ info["rustc"]["path"] = rustc_path or ""
+ info["cargo"]["path"] = cargo_path or ""
+ info["rustup"]["path"] = rustup_path or ""
+ info["rust_analyzer"]["path"] = ra_path or ""
+
+ # Versions & verbose details
+ if rustc_path:
+ ver_line = _first_line(_run([rustc_path, "--version"]))
+ info["rustc"]["version"] = ver_line
+ verbose = _run([rustc_path, "--version", "--verbose"])
+ host = release = commit = ""
+ for line in verbose.splitlines():
+ if line.startswith("host:"):
+ host = line.split(":", 1)[1].strip()
+ elif line.startswith("release:"):
+ release = line.split(":", 1)[1].strip()
+ elif line.startswith("commit-hash:"):
+ commit = line.split(":", 1)[1].strip()
+ info["rustc"]["host_triple"] = host
+ info["rustc"]["release"] = release
+ info["rustc"]["commit_hash"] = commit
+
+ if cargo_path:
+ info["cargo"]["version"] = _first_line(_run([cargo_path, "--version"]))
+
+ if rustup_path:
+ info["rustup"]["version"] = _first_line(_run([rustup_path, "--version"]))
+ # Active toolchain
+ active = _first_line(_run([rustup_path, "show", "active-toolchain"]))
+ info["rustup"]["active_toolchain"] = active
+
+ # Default toolchain (best effort)
+ # Try parsing `rustup toolchain list` and pick the line with "(default)"
+ tlist = _run([rustup_path, "toolchain", "list"]).splitlines()
+ info["rustup"]["toolchains"] = [t.strip() for t in tlist if t.strip()]
+ default_tc = ""
+ for line in tlist:
+ if "(default)" in line:
+ default_tc = line.strip()
+ break
+ if not default_tc:
+ # Fallback: sometimes `rustup show` includes "default toolchain: ..."
+ for line in _run([rustup_path, "show"]).splitlines():
+ if "default toolchain:" in line:
+ default_tc = line.split(":", 1)[1].strip()
+ break
+ info["rustup"]["default_toolchain"] = default_tc
+
+ # Installed targets
+ targets = _run([rustup_path, "target", "list", "--installed"]).split()
+ info["rustup"]["targets_installed"] = targets
+
+ # Execution examples (only include what will work on this system)
+ exec_examples = []
+ if cargo_path:
+ exec_examples.append(f'"{cargo_path}" build')
+ exec_examples.append(f'"{cargo_path}" run')
+ exec_examples.append(f'"{cargo_path}" test')
+ if rustc_path:
+ exec_examples.append(f'"{rustc_path}" hello.rs -o hello')
+ info["execution_examples"] = exec_examples
+
+ # Installed?
+ info["installed"] = bool(rustc_path or cargo_path or rustup_path)
+
+ # Fill in default homes if env vars are empty but typical locations exist
+ def _maybe_default_home(env_val, default_basename):
+ if env_val:
+ return env_val
+ home = os.path.expanduser("~") or ""
+ candidate = os.path.join(home, default_basename) if home else ""
+ return candidate if candidate and os.path.isdir(candidate) else ""
+
+ info["env"]["CARGO_HOME"] = _maybe_default_home(info["env"]["CARGO_HOME"], ".cargo")
+ info["env"]["RUSTUP_HOME"] = _maybe_default_home(info["env"]["RUSTUP_HOME"], ".rustup")
+
+ return info
diff --git a/week5/day4.5.ipynb b/week5/day4.5.ipynb
index ea3518c..f718a23 100644
--- a/week5/day4.5.ipynb
+++ b/week5/day4.5.ipynb
@@ -38,7 +38,9 @@
"# Mac users - this may fail if you don't have a recent version of MacOS\n",
"# In which case I recommend you skip this lab -- FAISS is not essential! (Or upgrade MacOS if you wish..)\n",
"\n",
- "!pip install faiss-cpu"
+ "!uv add faiss-cpu\n",
+ "\n",
+ "# Or use !pip install if you're on the Original version of the course and you're not using uv"
]
},
{
diff --git a/week5/day4.ipynb b/week5/day4.ipynb
index 5efc973..5834a31 100644
--- a/week5/day4.ipynb
+++ b/week5/day4.ipynb
@@ -313,7 +313,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" PLEASE READ ME! Ignoring the Deprecation Warning\n",
diff --git a/week8/day1.ipynb b/week8/day1.ipynb
index 6b89a75..d7bb361 100644
--- a/week8/day1.ipynb
+++ b/week8/day1.ipynb
@@ -20,7 +20,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Especially important this week: pull the latest\n",
@@ -40,7 +40,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 1,
"id": "bc0e1c1c-be6a-4395-bbbd-eeafc9330d7e",
"metadata": {},
"outputs": [],
@@ -298,10 +298,28 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 2,
"id": "f56d1e55-2a03-4ce2-bb47-2ab6b9175a02",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\u001b[2K\u001b[34m⠸\u001b[0m Creating objects.....\n",
+ "\u001b[38;5;244m└── \u001b[0m\u001b[34m⠋\u001b[0m Creating mount /Users/ed/dev/llm_engineering/week8/pricer_service2.py: \n",
+ "\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[34m⠴\u001b[0m Creating objects...\n",
+ "\u001b[38;5;244m├── \u001b[0m🔨 Created mount /Users/ed/dev/llm_engineering/week8/pricer_service2.py\n",
+ "\u001b[38;5;244m└── \u001b[0m🔨 Created function Pricer.*.\n",
+ "\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[32m✓\u001b[0m Created objects.\n",
+ "\u001b[38;5;244m├── \u001b[0m🔨 Created mount /Users/ed/dev/llm_engineering/week8/pricer_service2.py\n",
+ "\u001b[38;5;244m└── \u001b[0m🔨 Created function Pricer.*.\n",
+ "\u001b[32m✓\u001b[0m App deployed in 0.723s! 🎉\n",
+ "\n",
+ "View Deployment: \u001b[35mhttps://modal.com/apps/ed-donner/main/deployed/pricer-service\u001b[0m\n"
+ ]
+ }
+ ],
"source": [
"# You can also run \"modal deploy -m pricer_service2\" at the command line in an activated environment\n",
"\n",
@@ -394,7 +412,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.12"
+ "version": "3.11.13"
}
},
"nbformat": 4,
diff --git a/week8/day2.0.ipynb b/week8/day2.0.ipynb
index 4f3b049..84a6f0e 100644
--- a/week8/day2.0.ipynb
+++ b/week8/day2.0.ipynb
@@ -341,7 +341,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.12"
+ "version": "3.11.13"
}
},
"nbformat": 4,
diff --git a/week8/day2.3.ipynb b/week8/day2.3.ipynb
index c2eeb34..79bfba9 100644
--- a/week8/day2.3.ipynb
+++ b/week8/day2.3.ipynb
@@ -519,7 +519,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.12"
+ "version": "3.11.13"
}
},
"nbformat": 4,
diff --git a/week8/day2.4.ipynb b/week8/day2.4.ipynb
index c315c78..9d10e74 100644
--- a/week8/day2.4.ipynb
+++ b/week8/day2.4.ipynb
@@ -425,7 +425,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.12"
+ "version": "3.11.13"
}
},
"nbformat": 4,
diff --git a/week8/day4.ipynb b/week8/day4.ipynb
index 22385a8..c8a7874 100644
--- a/week8/day4.ipynb
+++ b/week8/day4.ipynb
@@ -74,7 +74,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" Additional resource: more sophisticated planning agent\n",
diff --git a/week8/day5.ipynb b/week8/day5.ipynb
index d42d181..b88d62f 100644
--- a/week8/day5.ipynb
+++ b/week8/day5.ipynb
@@ -164,7 +164,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" But wait!! There's more..\n",
@@ -186,7 +186,7 @@
"\n",
" \n",
" \n",
- " \n",
+ " \n",
" | \n",
" \n",
" CONGRATULATIONS AND THANK YOU!!!\n",
| | | | | | | | | | | | | | | | | | |