Michael Marks
commited on
Commit
·
3dd0806
1
Parent(s):
53732ef
initial commit
Browse files- README.md +8 -3
- bonus-unit1/.DS_Store +0 -0
- bonus-unit1/bonus-unit1.ipynb +0 -0
- dummy_agent_library.ipynb +719 -0
- unit2/langgraph/agent.ipynb +560 -0
- unit2/langgraph/mail_sorting.ipynb +1 -0
- unit2/llama-index/agents.ipynb +334 -0
- unit2/llama-index/components.ipynb +0 -0
- unit2/llama-index/tools.ipynb +229 -0
- unit2/llama-index/workflows.ipynb +395 -0
- unit2/smolagents/code_agents.ipynb +0 -0
- unit2/smolagents/multiagent_notebook.ipynb +0 -0
- unit2/smolagents/retrieval_agents.ipynb +0 -0
- unit2/smolagents/tool_calling_agents.ipynb +596 -0
- unit2/smolagents/tools.ipynb +0 -0
- unit2/smolagents/vision_agents.ipynb +535 -0
- unit2/smolagents/vision_web_browser.py +207 -0
README.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
| 1 |
-
---
|
| 2 |
-
license: apache-2.0
|
| 3 |
-
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
---
|
| 4 |
+
|
| 5 |
+
Example notebooks, part of the [Hugging Face Agents Course](https://huggingface.co/learn/agents-course/unit0/introduction).
|
| 6 |
+
|
| 7 |
+
* [Dummy Agent Library](https://huggingface.co/agents-course/notebooks/blob/main/dummy_agent_library.ipynb) – Creating an Agent from scratch. It's complicated!
|
| 8 |
+
*
|
bonus-unit1/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
bonus-unit1/bonus-unit1.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dummy_agent_library.ipynb
ADDED
|
@@ -0,0 +1,719 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"id": "fr8fVR1J_SdU",
|
| 6 |
+
"metadata": {
|
| 7 |
+
"id": "fr8fVR1J_SdU"
|
| 8 |
+
},
|
| 9 |
+
"source": [
|
| 10 |
+
"# Dummy Agent Library\n",
|
| 11 |
+
"\n",
|
| 12 |
+
"In this simple example, **we're going to code an Agent from scratch**.\n",
|
| 13 |
+
"\n",
|
| 14 |
+
"This notebook is part of the <a href=\"https://www.hf.co/learn/agents-course\">Hugging Face Agents Course</a>, a free Course from beginner to expert, where you learn to build Agents.\n",
|
| 15 |
+
"\n",
|
| 16 |
+
"<img src=\"https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/communication/share.png\" alt=\"Agent Course\"/>"
|
| 17 |
+
]
|
| 18 |
+
},
|
| 19 |
+
{
|
| 20 |
+
"cell_type": "code",
|
| 21 |
+
"execution_count": null,
|
| 22 |
+
"id": "ec657731-ac7a-41dd-a0bb-cc661d00d714",
|
| 23 |
+
"metadata": {
|
| 24 |
+
"id": "ec657731-ac7a-41dd-a0bb-cc661d00d714",
|
| 25 |
+
"tags": []
|
| 26 |
+
},
|
| 27 |
+
"outputs": [
|
| 28 |
+
{
|
| 29 |
+
"name": "stdout",
|
| 30 |
+
"output_type": "stream",
|
| 31 |
+
"text": [
|
| 32 |
+
"Note: you may need to restart the kernel to use updated packages.\n"
|
| 33 |
+
]
|
| 34 |
+
}
|
| 35 |
+
],
|
| 36 |
+
"source": [
|
| 37 |
+
"%pip install -q huggingface_hub"
|
| 38 |
+
]
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"cell_type": "code",
|
| 42 |
+
"execution_count": 4,
|
| 43 |
+
"id": "eda8b964",
|
| 44 |
+
"metadata": {},
|
| 45 |
+
"outputs": [
|
| 46 |
+
{
|
| 47 |
+
"name": "stdout",
|
| 48 |
+
"output_type": "stream",
|
| 49 |
+
"text": [
|
| 50 |
+
"Token was found\n"
|
| 51 |
+
]
|
| 52 |
+
}
|
| 53 |
+
],
|
| 54 |
+
"source": [
|
| 55 |
+
"import os\n",
|
| 56 |
+
"\n",
|
| 57 |
+
"token = os.getenv('HF_TOKEN')\n",
|
| 58 |
+
"if token is None:\n",
|
| 59 |
+
" raise ValueError('You must set the HF_TOKEN environment variable')\n",
|
| 60 |
+
"else:\n",
|
| 61 |
+
" print('Token was found')\n",
|
| 62 |
+
" #print('Token:', token)"
|
| 63 |
+
]
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"cell_type": "markdown",
|
| 67 |
+
"id": "8WOxyzcmAEfI",
|
| 68 |
+
"metadata": {
|
| 69 |
+
"id": "8WOxyzcmAEfI"
|
| 70 |
+
},
|
| 71 |
+
"source": [
|
| 72 |
+
"## Serverless API\n",
|
| 73 |
+
"\n",
|
| 74 |
+
"In the Hugging Face ecosystem, there is a convenient feature called Serverless API that allows you to easily run inference on many models. There's no installation or deployment required.\n",
|
| 75 |
+
"\n",
|
| 76 |
+
"To run this notebook, **you need a Hugging Face token** that you can get from https://hf.co/settings/tokens. If you are running this notebook on Google Colab, you can set it up in the \"settings\" tab under \"secrets\". Make sure to call it \"HF_TOKEN\".\n",
|
| 77 |
+
"\n",
|
| 78 |
+
"You also need to request access to [the Meta Llama models](meta-llama/Llama-3.2-3B-Instruct), if you haven't done it before. Approval usually takes up to an hour."
|
| 79 |
+
]
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"cell_type": "code",
|
| 83 |
+
"execution_count": null,
|
| 84 |
+
"id": "5af6ec14-bb7d-49a4-b911-0cf0ec084df5",
|
| 85 |
+
"metadata": {
|
| 86 |
+
"id": "5af6ec14-bb7d-49a4-b911-0cf0ec084df5",
|
| 87 |
+
"tags": []
|
| 88 |
+
},
|
| 89 |
+
"outputs": [],
|
| 90 |
+
"source": [
|
| 91 |
+
"import os\n",
|
| 92 |
+
"from huggingface_hub import InferenceClient\n",
|
| 93 |
+
"\n",
|
| 94 |
+
"# os.environ[\"HF_TOKEN\"]=\"hf_xxxxxxxxxxx\"\n",
|
| 95 |
+
"\n",
|
| 96 |
+
"client = InferenceClient(\"meta-llama/Llama-3.2-3B-Instruct\")\n",
|
| 97 |
+
"# if the outputs for next cells are wrong, the free model may be overloaded. You can also use this public endpoint that contains Llama-3.2-3B-Instruct\n",
|
| 98 |
+
"#client = InferenceClient(\"https://jc26mwg228mkj8dw.us-east-1.aws.endpoints.huggingface.cloud\")"
|
| 99 |
+
]
|
| 100 |
+
},
|
| 101 |
+
{
|
| 102 |
+
"cell_type": "code",
|
| 103 |
+
"execution_count": null,
|
| 104 |
+
"id": "c918666c-48ed-4d6d-ab91-c6ec3892d858",
|
| 105 |
+
"metadata": {
|
| 106 |
+
"colab": {
|
| 107 |
+
"base_uri": "https://localhost:8080/"
|
| 108 |
+
},
|
| 109 |
+
"id": "c918666c-48ed-4d6d-ab91-c6ec3892d858",
|
| 110 |
+
"outputId": "7282095c-c5e7-45e0-be81-8648c954a2f7",
|
| 111 |
+
"tags": []
|
| 112 |
+
},
|
| 113 |
+
"outputs": [
|
| 114 |
+
{
|
| 115 |
+
"name": "stdout",
|
| 116 |
+
"output_type": "stream",
|
| 117 |
+
"text": [
|
| 118 |
+
" Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris.\n"
|
| 119 |
+
]
|
| 120 |
+
}
|
| 121 |
+
],
|
| 122 |
+
"source": [
|
| 123 |
+
"# As seen in the LLM section, if we just do decoding, **the model will only stop when it predicts an EOS token**, \n",
|
| 124 |
+
"# and this does not happen here because this is a conversational (chat) model and we didn't apply the chat template it expects.\n",
|
| 125 |
+
"output = client.text_generation(\n",
|
| 126 |
+
" \"The capital of france is\",\n",
|
| 127 |
+
" max_new_tokens=100,\n",
|
| 128 |
+
")\n",
|
| 129 |
+
"\n",
|
| 130 |
+
"print(output)"
|
| 131 |
+
]
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"cell_type": "markdown",
|
| 135 |
+
"id": "w2C4arhyKAEk",
|
| 136 |
+
"metadata": {
|
| 137 |
+
"id": "w2C4arhyKAEk"
|
| 138 |
+
},
|
| 139 |
+
"source": [
|
| 140 |
+
"As seen in the LLM section, if we just do decoding, **the model will only stop when it predicts an EOS token**, and this does not happen here because this is a conversational (chat) model and **we didn't apply the chat template it expects**."
|
| 141 |
+
]
|
| 142 |
+
},
|
| 143 |
+
{
|
| 144 |
+
"cell_type": "markdown",
|
| 145 |
+
"id": "T9-6h-eVAWrR",
|
| 146 |
+
"metadata": {
|
| 147 |
+
"id": "T9-6h-eVAWrR"
|
| 148 |
+
},
|
| 149 |
+
"source": [
|
| 150 |
+
"If we now add the special tokens related to the <a href=\"https://huggingface.co/meta-llama/Llama-3.2-3B-Instruct\">Llama-3.2-3B-Instruct model</a> that we're using, the behavior changes and it now produces the expected EOS."
|
| 151 |
+
]
|
| 152 |
+
},
|
| 153 |
+
{
|
| 154 |
+
"cell_type": "code",
|
| 155 |
+
"execution_count": null,
|
| 156 |
+
"id": "ec0b95d7-8f6a-45fc-b477-c2f95153a001",
|
| 157 |
+
"metadata": {
|
| 158 |
+
"colab": {
|
| 159 |
+
"base_uri": "https://localhost:8080/"
|
| 160 |
+
},
|
| 161 |
+
"id": "ec0b95d7-8f6a-45fc-b477-c2f95153a001",
|
| 162 |
+
"outputId": "b56e3257-ff89-4cf7-de60-c2e65f78567b",
|
| 163 |
+
"tags": []
|
| 164 |
+
},
|
| 165 |
+
"outputs": [
|
| 166 |
+
{
|
| 167 |
+
"name": "stdout",
|
| 168 |
+
"output_type": "stream",
|
| 169 |
+
"text": [
|
| 170 |
+
"...Paris!\n"
|
| 171 |
+
]
|
| 172 |
+
}
|
| 173 |
+
],
|
| 174 |
+
"source": [
|
| 175 |
+
"# If we now add the special tokens related to Llama3.2 model, the behaviour changes and is now the expected one.\n",
|
| 176 |
+
"prompt=\"\"\"<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n",
|
| 177 |
+
"\n",
|
| 178 |
+
"The capital of france is<|eot_id|><|start_header_id|>assistent<|end_header_id|>\n",
|
| 179 |
+
"\n",
|
| 180 |
+
"\"\"\"\n",
|
| 181 |
+
"output = client.text_generation(\n",
|
| 182 |
+
" prompt,\n",
|
| 183 |
+
" max_new_tokens=100,\n",
|
| 184 |
+
")\n",
|
| 185 |
+
"\n",
|
| 186 |
+
"print(output)\n"
|
| 187 |
+
]
|
| 188 |
+
},
|
| 189 |
+
{
|
| 190 |
+
"cell_type": "markdown",
|
| 191 |
+
"id": "1uKapsiZAbH5",
|
| 192 |
+
"metadata": {
|
| 193 |
+
"id": "1uKapsiZAbH5"
|
| 194 |
+
},
|
| 195 |
+
"source": [
|
| 196 |
+
"Using the \"chat\" method is a much more convenient and reliable way to apply chat templates:"
|
| 197 |
+
]
|
| 198 |
+
},
|
| 199 |
+
{
|
| 200 |
+
"cell_type": "code",
|
| 201 |
+
"execution_count": null,
|
| 202 |
+
"id": "eb536eea-f316-4902-aabd-55710e6c4347",
|
| 203 |
+
"metadata": {
|
| 204 |
+
"colab": {
|
| 205 |
+
"base_uri": "https://localhost:8080/"
|
| 206 |
+
},
|
| 207 |
+
"id": "eb536eea-f316-4902-aabd-55710e6c4347",
|
| 208 |
+
"outputId": "6bf13836-36a8-4e21-f5cd-5d79ad2c92d9",
|
| 209 |
+
"tags": []
|
| 210 |
+
},
|
| 211 |
+
"outputs": [
|
| 212 |
+
{
|
| 213 |
+
"name": "stdout",
|
| 214 |
+
"output_type": "stream",
|
| 215 |
+
"text": [
|
| 216 |
+
"The capital of France is Paris.\n"
|
| 217 |
+
]
|
| 218 |
+
}
|
| 219 |
+
],
|
| 220 |
+
"source": [
|
| 221 |
+
"output = client.chat.completions.create(\n",
|
| 222 |
+
" messages=[\n",
|
| 223 |
+
" {\"role\": \"user\", \"content\": \"The capital of france is\"},\n",
|
| 224 |
+
" ],\n",
|
| 225 |
+
" stream=False,\n",
|
| 226 |
+
" max_tokens=1024,\n",
|
| 227 |
+
")\n",
|
| 228 |
+
"\n",
|
| 229 |
+
"print(output.choices[0].message.content)"
|
| 230 |
+
]
|
| 231 |
+
},
|
| 232 |
+
{
|
| 233 |
+
"cell_type": "markdown",
|
| 234 |
+
"id": "jtQHk9HHAkb8",
|
| 235 |
+
"metadata": {
|
| 236 |
+
"id": "jtQHk9HHAkb8"
|
| 237 |
+
},
|
| 238 |
+
"source": [
|
| 239 |
+
"The chat method is the RECOMMENDED method to use in order to ensure a **smooth transition between models but since this notebook is only educational**, we will keep using the \"text_generation\" method to understand the details.\n"
|
| 240 |
+
]
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"cell_type": "markdown",
|
| 244 |
+
"id": "wQ5FqBJuBUZp",
|
| 245 |
+
"metadata": {
|
| 246 |
+
"id": "wQ5FqBJuBUZp"
|
| 247 |
+
},
|
| 248 |
+
"source": [
|
| 249 |
+
"## Dummy Agent\n",
|
| 250 |
+
"\n",
|
| 251 |
+
"In the previous sections, we saw that the **core of an agent library is to append information in the system prompt**.\n",
|
| 252 |
+
"\n",
|
| 253 |
+
"This system prompt is a bit more complex than the one we saw earlier, but it already contains:\n",
|
| 254 |
+
"\n",
|
| 255 |
+
"1. **Information about the tools**\n",
|
| 256 |
+
"2. **Cycle instructions** (Thought → Action → Observation)"
|
| 257 |
+
]
|
| 258 |
+
},
|
| 259 |
+
{
|
| 260 |
+
"cell_type": "code",
|
| 261 |
+
"execution_count": null,
|
| 262 |
+
"id": "2c66e9cb-2c14-47d4-a7a1-da826b7fc62d",
|
| 263 |
+
"metadata": {
|
| 264 |
+
"id": "2c66e9cb-2c14-47d4-a7a1-da826b7fc62d",
|
| 265 |
+
"tags": []
|
| 266 |
+
},
|
| 267 |
+
"outputs": [],
|
| 268 |
+
"source": [
|
| 269 |
+
"# This system prompt is a bit more complex and actually contains the function description already appended.\n",
|
| 270 |
+
"# Here we suppose that the textual description of the tools has already been appended\n",
|
| 271 |
+
"SYSTEM_PROMPT = \"\"\"Answer the following questions as best you can. You have access to the following tools:\n",
|
| 272 |
+
"\n",
|
| 273 |
+
"get_weather: Get the current weather in a given location\n",
|
| 274 |
+
"\n",
|
| 275 |
+
"The way you use the tools is by specifying a json blob.\n",
|
| 276 |
+
"Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here).\n",
|
| 277 |
+
"\n",
|
| 278 |
+
"The only values that should be in the \"action\" field are:\n",
|
| 279 |
+
"get_weather: Get the current weather in a given location, args: {\"location\": {\"type\": \"string\"}}\n",
|
| 280 |
+
"example use :\n",
|
| 281 |
+
"```\n",
|
| 282 |
+
"{{\n",
|
| 283 |
+
" \"action\": \"get_weather\",\n",
|
| 284 |
+
" \"action_input\": {\"location\": \"New York\"}\n",
|
| 285 |
+
"}}\n",
|
| 286 |
+
"\n",
|
| 287 |
+
"ALWAYS use the following format:\n",
|
| 288 |
+
"\n",
|
| 289 |
+
"Question: the input question you must answer\n",
|
| 290 |
+
"Thought: you should always think about one action to take. Only one action at a time in this format:\n",
|
| 291 |
+
"Action:\n",
|
| 292 |
+
"```\n",
|
| 293 |
+
"$JSON_BLOB\n",
|
| 294 |
+
"```\n",
|
| 295 |
+
"Observation: the result of the action. This Observation is unique, complete, and the source of truth.\n",
|
| 296 |
+
"... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.)\n",
|
| 297 |
+
"\n",
|
| 298 |
+
"You must always end your output with the following format:\n",
|
| 299 |
+
"\n",
|
| 300 |
+
"Thought: I now know the final answer\n",
|
| 301 |
+
"Final Answer: the final answer to the original input question\n",
|
| 302 |
+
"\n",
|
| 303 |
+
"Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. \"\"\"\n"
|
| 304 |
+
]
|
| 305 |
+
},
|
| 306 |
+
{
|
| 307 |
+
"cell_type": "markdown",
|
| 308 |
+
"id": "UoanEUqQAxzE",
|
| 309 |
+
"metadata": {
|
| 310 |
+
"id": "UoanEUqQAxzE"
|
| 311 |
+
},
|
| 312 |
+
"source": [
|
| 313 |
+
"Since we are running the \"text_generation\" method, we need to add the right special tokens."
|
| 314 |
+
]
|
| 315 |
+
},
|
| 316 |
+
{
|
| 317 |
+
"cell_type": "code",
|
| 318 |
+
"execution_count": null,
|
| 319 |
+
"id": "78edbd65-d19b-42ef-8248-e01218470d28",
|
| 320 |
+
"metadata": {
|
| 321 |
+
"id": "78edbd65-d19b-42ef-8248-e01218470d28",
|
| 322 |
+
"tags": []
|
| 323 |
+
},
|
| 324 |
+
"outputs": [],
|
| 325 |
+
"source": [
|
| 326 |
+
"# Since we are running the \"text_generation\", we need to add the right special tokens.\n",
|
| 327 |
+
"prompt=f\"\"\"<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n",
|
| 328 |
+
"{SYSTEM_PROMPT}\n",
|
| 329 |
+
"<|eot_id|><|start_header_id|>user<|end_header_id|>\n",
|
| 330 |
+
"What's the weather in Zurich ?\n",
|
| 331 |
+
"<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n",
|
| 332 |
+
"\"\"\""
|
| 333 |
+
]
|
| 334 |
+
},
|
| 335 |
+
{
|
| 336 |
+
"cell_type": "markdown",
|
| 337 |
+
"id": "L-HaWxinA0XX",
|
| 338 |
+
"metadata": {
|
| 339 |
+
"id": "L-HaWxinA0XX"
|
| 340 |
+
},
|
| 341 |
+
"source": [
|
| 342 |
+
"This is equivalent to the following code that happens inside the chat method :\n",
|
| 343 |
+
"```\n",
|
| 344 |
+
"messages=[\n",
|
| 345 |
+
" {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
|
| 346 |
+
" {\"role\": \"user\", \"content\": \"What's the weather in London ?\"},\n",
|
| 347 |
+
"]\n",
|
| 348 |
+
"from transformers import AutoTokenizer\n",
|
| 349 |
+
"tokenizer = AutoTokenizer.from_pretrained(\"meta-llama/Llama-3.2-3B-Instruct\")\n",
|
| 350 |
+
"\n",
|
| 351 |
+
"tokenizer.apply_chat_template(messages, tokenize=False,add_generation_prompt=True)\n",
|
| 352 |
+
"```"
|
| 353 |
+
]
|
| 354 |
+
},
|
| 355 |
+
{
|
| 356 |
+
"cell_type": "markdown",
|
| 357 |
+
"id": "4jCyx4HZCIA8",
|
| 358 |
+
"metadata": {
|
| 359 |
+
"id": "4jCyx4HZCIA8"
|
| 360 |
+
},
|
| 361 |
+
"source": [
|
| 362 |
+
"The prompt is now:"
|
| 363 |
+
]
|
| 364 |
+
},
|
| 365 |
+
{
|
| 366 |
+
"cell_type": "code",
|
| 367 |
+
"execution_count": null,
|
| 368 |
+
"id": "Vc4YEtqBCJDK",
|
| 369 |
+
"metadata": {
|
| 370 |
+
"colab": {
|
| 371 |
+
"base_uri": "https://localhost:8080/"
|
| 372 |
+
},
|
| 373 |
+
"id": "Vc4YEtqBCJDK",
|
| 374 |
+
"outputId": "b9be74a7-be22-4826-d40a-bc5da33ce41c"
|
| 375 |
+
},
|
| 376 |
+
"outputs": [
|
| 377 |
+
{
|
| 378 |
+
"name": "stdout",
|
| 379 |
+
"output_type": "stream",
|
| 380 |
+
"text": [
|
| 381 |
+
"<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n",
|
| 382 |
+
"Answer the following questions as best you can. You have access to the following tools:\n",
|
| 383 |
+
"\n",
|
| 384 |
+
"get_weather: Get the current weather in a given location\n",
|
| 385 |
+
"\n",
|
| 386 |
+
"The way you use the tools is by specifying a json blob.\n",
|
| 387 |
+
"Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here).\n",
|
| 388 |
+
"\n",
|
| 389 |
+
"The only values that should be in the \"action\" field are:\n",
|
| 390 |
+
"get_weather: Get the current weather in a given location, args: {\"location\": {\"type\": \"string\"}}\n",
|
| 391 |
+
"example use :\n",
|
| 392 |
+
"```\n",
|
| 393 |
+
"{{\n",
|
| 394 |
+
" \"action\": \"get_weather\",\n",
|
| 395 |
+
" \"action_input\": {\"location\": \"New York\"}\n",
|
| 396 |
+
"}}\n",
|
| 397 |
+
"\n",
|
| 398 |
+
"ALWAYS use the following format:\n",
|
| 399 |
+
"\n",
|
| 400 |
+
"Question: the input question you must answer\n",
|
| 401 |
+
"Thought: you should always think about one action to take. Only one action at a time in this format:\n",
|
| 402 |
+
"Action:\n",
|
| 403 |
+
"```\n",
|
| 404 |
+
"$JSON_BLOB\n",
|
| 405 |
+
"```\n",
|
| 406 |
+
"Observation: the result of the action. This Observation is unique, complete, and the source of truth.\n",
|
| 407 |
+
"... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.)\n",
|
| 408 |
+
"\n",
|
| 409 |
+
"You must always end your output with the following format:\n",
|
| 410 |
+
"\n",
|
| 411 |
+
"Thought: I now know the final answer\n",
|
| 412 |
+
"Final Answer: the final answer to the original input question\n",
|
| 413 |
+
"\n",
|
| 414 |
+
"Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. \n",
|
| 415 |
+
"<|eot_id|><|start_header_id|>user<|end_header_id|>\n",
|
| 416 |
+
"What's the weather in Zurich ?\n",
|
| 417 |
+
"<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n",
|
| 418 |
+
"\n"
|
| 419 |
+
]
|
| 420 |
+
}
|
| 421 |
+
],
|
| 422 |
+
"source": [
|
| 423 |
+
"print(prompt)"
|
| 424 |
+
]
|
| 425 |
+
},
|
| 426 |
+
{
|
| 427 |
+
"cell_type": "markdown",
|
| 428 |
+
"id": "S6fosEhBCObv",
|
| 429 |
+
"metadata": {
|
| 430 |
+
"id": "S6fosEhBCObv"
|
| 431 |
+
},
|
| 432 |
+
"source": [
|
| 433 |
+
"Let’s decode!"
|
| 434 |
+
]
|
| 435 |
+
},
|
| 436 |
+
{
|
| 437 |
+
"cell_type": "code",
|
| 438 |
+
"execution_count": null,
|
| 439 |
+
"id": "e2b268d0-18bd-4877-bbed-a6b31ed71bc7",
|
| 440 |
+
"metadata": {
|
| 441 |
+
"colab": {
|
| 442 |
+
"base_uri": "https://localhost:8080/"
|
| 443 |
+
},
|
| 444 |
+
"id": "e2b268d0-18bd-4877-bbed-a6b31ed71bc7",
|
| 445 |
+
"outputId": "6933b02c-7895-4205-fec6-ca5122b54add",
|
| 446 |
+
"tags": []
|
| 447 |
+
},
|
| 448 |
+
"outputs": [
|
| 449 |
+
{
|
| 450 |
+
"name": "stdout",
|
| 451 |
+
"output_type": "stream",
|
| 452 |
+
"text": [
|
| 453 |
+
"Action:\n",
|
| 454 |
+
"```\n",
|
| 455 |
+
"{\n",
|
| 456 |
+
" \"action\": \"get_weather\",\n",
|
| 457 |
+
" \"action_input\": {\"location\": \"Zurich\"}\n",
|
| 458 |
+
"}\n",
|
| 459 |
+
"```\n",
|
| 460 |
+
"Observation: The current weather in Zurich is mostly sunny with a high of 22°C and a low of 12°C, with a gentle breeze from the west at 15 km/h.\n",
|
| 461 |
+
"\n",
|
| 462 |
+
"Thought: I now know the current weather in Zurich\n"
|
| 463 |
+
]
|
| 464 |
+
}
|
| 465 |
+
],
|
| 466 |
+
"source": [
|
| 467 |
+
"# Do you see the problem?\n",
|
| 468 |
+
"output = client.text_generation(\n",
|
| 469 |
+
" prompt,\n",
|
| 470 |
+
" max_new_tokens=200,\n",
|
| 471 |
+
")\n",
|
| 472 |
+
"\n",
|
| 473 |
+
"print(output)"
|
| 474 |
+
]
|
| 475 |
+
},
|
| 476 |
+
{
|
| 477 |
+
"cell_type": "markdown",
|
| 478 |
+
"id": "9NbUFRDECQ9N",
|
| 479 |
+
"metadata": {
|
| 480 |
+
"id": "9NbUFRDECQ9N"
|
| 481 |
+
},
|
| 482 |
+
"source": [
|
| 483 |
+
"Do you see the problem? \n",
|
| 484 |
+
"\n",
|
| 485 |
+
"The **answer was hallucinated by the model**. We need to stop to actually execute the function!"
|
| 486 |
+
]
|
| 487 |
+
},
|
| 488 |
+
{
|
| 489 |
+
"cell_type": "code",
|
| 490 |
+
"execution_count": null,
|
| 491 |
+
"id": "9fc783f2-66ac-42cf-8a57-51788f81d436",
|
| 492 |
+
"metadata": {
|
| 493 |
+
"colab": {
|
| 494 |
+
"base_uri": "https://localhost:8080/"
|
| 495 |
+
},
|
| 496 |
+
"id": "9fc783f2-66ac-42cf-8a57-51788f81d436",
|
| 497 |
+
"outputId": "52c62786-b5b1-42d1-bfd2-3f8e3a02dd6b",
|
| 498 |
+
"tags": []
|
| 499 |
+
},
|
| 500 |
+
"outputs": [
|
| 501 |
+
{
|
| 502 |
+
"name": "stdout",
|
| 503 |
+
"output_type": "stream",
|
| 504 |
+
"text": [
|
| 505 |
+
"Action:\n",
|
| 506 |
+
"```\n",
|
| 507 |
+
"{\n",
|
| 508 |
+
" \"action\": \"get_weather\",\n",
|
| 509 |
+
" \"action_input\": {\"location\": \"Zurich\"}\n",
|
| 510 |
+
"}\n",
|
| 511 |
+
"```\n",
|
| 512 |
+
"Observation:\n"
|
| 513 |
+
]
|
| 514 |
+
}
|
| 515 |
+
],
|
| 516 |
+
"source": [
|
| 517 |
+
"# The answer was hallucinated by the model. We need to stop to actually execute the function!\n",
|
| 518 |
+
"output = client.text_generation(\n",
|
| 519 |
+
" prompt,\n",
|
| 520 |
+
" max_new_tokens=200,\n",
|
| 521 |
+
" stop=[\"Observation:\"] # Let's stop before any actual function is called\n",
|
| 522 |
+
")\n",
|
| 523 |
+
"\n",
|
| 524 |
+
"print(output)"
|
| 525 |
+
]
|
| 526 |
+
},
|
| 527 |
+
{
|
| 528 |
+
"cell_type": "markdown",
|
| 529 |
+
"id": "yBKVfMIaK_R1",
|
| 530 |
+
"metadata": {
|
| 531 |
+
"id": "yBKVfMIaK_R1"
|
| 532 |
+
},
|
| 533 |
+
"source": [
|
| 534 |
+
"Much Better!\n",
|
| 535 |
+
"\n",
|
| 536 |
+
"Let's now create a **dummy get weather function**. In real situation you could call an API."
|
| 537 |
+
]
|
| 538 |
+
},
|
| 539 |
+
{
|
| 540 |
+
"cell_type": "code",
|
| 541 |
+
"execution_count": null,
|
| 542 |
+
"id": "4756ab9e-e319-4ba1-8281-c7170aca199c",
|
| 543 |
+
"metadata": {
|
| 544 |
+
"colab": {
|
| 545 |
+
"base_uri": "https://localhost:8080/",
|
| 546 |
+
"height": 35
|
| 547 |
+
},
|
| 548 |
+
"id": "4756ab9e-e319-4ba1-8281-c7170aca199c",
|
| 549 |
+
"outputId": "c3d05710-3382-4a18-c585-9665a105f37c",
|
| 550 |
+
"tags": []
|
| 551 |
+
},
|
| 552 |
+
"outputs": [
|
| 553 |
+
{
|
| 554 |
+
"data": {
|
| 555 |
+
"text/plain": [
|
| 556 |
+
"'The weather in London is sunny with low temperatures. \\n'"
|
| 557 |
+
]
|
| 558 |
+
},
|
| 559 |
+
"execution_count": 54,
|
| 560 |
+
"metadata": {},
|
| 561 |
+
"output_type": "execute_result"
|
| 562 |
+
}
|
| 563 |
+
],
|
| 564 |
+
"source": [
|
| 565 |
+
"# Dummy function\n",
|
| 566 |
+
"def get_weather(location):\n",
|
| 567 |
+
" return f\"The weather in {location} is sunny with low temperatures. \\n\"\n",
|
| 568 |
+
"\n",
|
| 569 |
+
"get_weather('London')"
|
| 570 |
+
]
|
| 571 |
+
},
|
| 572 |
+
{
|
| 573 |
+
"cell_type": "markdown",
|
| 574 |
+
"id": "IHL3bqhYLGQ6",
|
| 575 |
+
"metadata": {
|
| 576 |
+
"id": "IHL3bqhYLGQ6"
|
| 577 |
+
},
|
| 578 |
+
"source": [
|
| 579 |
+
"Let's concatenate the base prompt, the completion until function execution and the result of the function as an Observation and resume the generation."
|
| 580 |
+
]
|
| 581 |
+
},
|
| 582 |
+
{
|
| 583 |
+
"cell_type": "code",
|
| 584 |
+
"execution_count": null,
|
| 585 |
+
"id": "f07196e8-4ff1-41f4-8b2f-99dd550c6b27",
|
| 586 |
+
"metadata": {
|
| 587 |
+
"colab": {
|
| 588 |
+
"base_uri": "https://localhost:8080/"
|
| 589 |
+
},
|
| 590 |
+
"id": "f07196e8-4ff1-41f4-8b2f-99dd550c6b27",
|
| 591 |
+
"outputId": "044beac4-90ee-4104-f44b-66dd8146ff14",
|
| 592 |
+
"tags": []
|
| 593 |
+
},
|
| 594 |
+
"outputs": [
|
| 595 |
+
{
|
| 596 |
+
"name": "stdout",
|
| 597 |
+
"output_type": "stream",
|
| 598 |
+
"text": [
|
| 599 |
+
"<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n",
|
| 600 |
+
"Answer the following questions as best you can. You have access to the following tools:\n",
|
| 601 |
+
"\n",
|
| 602 |
+
"get_weather: Get the current weather in a given location\n",
|
| 603 |
+
"\n",
|
| 604 |
+
"The way you use the tools is by specifying a json blob.\n",
|
| 605 |
+
"Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here).\n",
|
| 606 |
+
"\n",
|
| 607 |
+
"The only values that should be in the \"action\" field are:\n",
|
| 608 |
+
"get_weather: Get the current weather in a given location, args: {\"location\": {\"type\": \"string\"}}\n",
|
| 609 |
+
"example use :\n",
|
| 610 |
+
"```\n",
|
| 611 |
+
"{{\n",
|
| 612 |
+
" \"action\": \"get_weather\",\n",
|
| 613 |
+
" \"action_input\": {\"location\": \"New York\"}\n",
|
| 614 |
+
"}}\n",
|
| 615 |
+
"\n",
|
| 616 |
+
"ALWAYS use the following format:\n",
|
| 617 |
+
"\n",
|
| 618 |
+
"Question: the input question you must answer\n",
|
| 619 |
+
"Thought: you should always think about one action to take. Only one action at a time in this format:\n",
|
| 620 |
+
"Action:\n",
|
| 621 |
+
"```\n",
|
| 622 |
+
"$JSON_BLOB\n",
|
| 623 |
+
"```\n",
|
| 624 |
+
"Observation: the result of the action. This Observation is unique, complete, and the source of truth.\n",
|
| 625 |
+
"... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.)\n",
|
| 626 |
+
"\n",
|
| 627 |
+
"You must always end your output with the following format:\n",
|
| 628 |
+
"\n",
|
| 629 |
+
"Thought: I now know the final answer\n",
|
| 630 |
+
"Final Answer: the final answer to the original input question\n",
|
| 631 |
+
"\n",
|
| 632 |
+
"Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. \n",
|
| 633 |
+
"<|eot_id|><|start_header_id|>user<|end_header_id|>\n",
|
| 634 |
+
"What's the weather in Zurich ?\n",
|
| 635 |
+
"<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n",
|
| 636 |
+
"Action:\n",
|
| 637 |
+
"```\n",
|
| 638 |
+
"{\n",
|
| 639 |
+
" \"action\": \"get_weather\",\n",
|
| 640 |
+
" \"action_input\": {\"location\": \"Zurich\"}\n",
|
| 641 |
+
"}\n",
|
| 642 |
+
"```\n",
|
| 643 |
+
"Observation:The weather in Zurich is sunny with low temperatures. \n",
|
| 644 |
+
"\n"
|
| 645 |
+
]
|
| 646 |
+
}
|
| 647 |
+
],
|
| 648 |
+
"source": [
|
| 649 |
+
"# Let's concatenate the base prompt, the completion until function execution and the result of the function as an Observation\n",
|
| 650 |
+
"new_prompt=prompt+output+get_weather('Zurich')\n",
|
| 651 |
+
"print(new_prompt)"
|
| 652 |
+
]
|
| 653 |
+
},
|
| 654 |
+
{
|
| 655 |
+
"cell_type": "markdown",
|
| 656 |
+
"id": "Cc7Jb8o3Lc_4",
|
| 657 |
+
"metadata": {
|
| 658 |
+
"id": "Cc7Jb8o3Lc_4"
|
| 659 |
+
},
|
| 660 |
+
"source": [
|
| 661 |
+
"Here is the new prompt:"
|
| 662 |
+
]
|
| 663 |
+
},
|
| 664 |
+
{
|
| 665 |
+
"cell_type": "code",
|
| 666 |
+
"execution_count": null,
|
| 667 |
+
"id": "0d5c6697-24ee-426c-acd4-614fba95cf1f",
|
| 668 |
+
"metadata": {
|
| 669 |
+
"colab": {
|
| 670 |
+
"base_uri": "https://localhost:8080/"
|
| 671 |
+
},
|
| 672 |
+
"id": "0d5c6697-24ee-426c-acd4-614fba95cf1f",
|
| 673 |
+
"outputId": "f2808dad-86a4-4244-8ac9-4d44ca1e4c08",
|
| 674 |
+
"tags": []
|
| 675 |
+
},
|
| 676 |
+
"outputs": [
|
| 677 |
+
{
|
| 678 |
+
"name": "stdout",
|
| 679 |
+
"output_type": "stream",
|
| 680 |
+
"text": [
|
| 681 |
+
"Final Answer: The current weather in Zurich is sunny with low temperatures.\n"
|
| 682 |
+
]
|
| 683 |
+
}
|
| 684 |
+
],
|
| 685 |
+
"source": [
|
| 686 |
+
"final_output = client.text_generation(\n",
|
| 687 |
+
" new_prompt,\n",
|
| 688 |
+
" max_new_tokens=200,\n",
|
| 689 |
+
")\n",
|
| 690 |
+
"\n",
|
| 691 |
+
"print(final_output)"
|
| 692 |
+
]
|
| 693 |
+
}
|
| 694 |
+
],
|
| 695 |
+
"metadata": {
|
| 696 |
+
"colab": {
|
| 697 |
+
"provenance": []
|
| 698 |
+
},
|
| 699 |
+
"kernelspec": {
|
| 700 |
+
"display_name": "Python 3",
|
| 701 |
+
"language": "python",
|
| 702 |
+
"name": "python3"
|
| 703 |
+
},
|
| 704 |
+
"language_info": {
|
| 705 |
+
"codemirror_mode": {
|
| 706 |
+
"name": "ipython",
|
| 707 |
+
"version": 3
|
| 708 |
+
},
|
| 709 |
+
"file_extension": ".py",
|
| 710 |
+
"mimetype": "text/x-python",
|
| 711 |
+
"name": "python",
|
| 712 |
+
"nbconvert_exporter": "python",
|
| 713 |
+
"pygments_lexer": "ipython3",
|
| 714 |
+
"version": "3.13.2"
|
| 715 |
+
}
|
| 716 |
+
},
|
| 717 |
+
"nbformat": 4,
|
| 718 |
+
"nbformat_minor": 5
|
| 719 |
+
}
|
unit2/langgraph/agent.ipynb
ADDED
|
@@ -0,0 +1,560 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"id": "98f5e36a-da49-4ae2-8c74-b910a2f992fc",
|
| 6 |
+
"metadata": {},
|
| 7 |
+
"source": [
|
| 8 |
+
"# Agent\n",
|
| 9 |
+
"\n",
|
| 10 |
+
"In this notebook, **we're going to build a simple agent using using LangGraph**.\n",
|
| 11 |
+
"\n",
|
| 12 |
+
"This notebook is part of the <a href=\"https://www.hf.co/learn/agents-course\">Hugging Face Agents Course</a>, a free course from beginner to expert, where you learn to build Agents.\n",
|
| 13 |
+
"\n",
|
| 14 |
+
"\n",
|
| 15 |
+
"\n",
|
| 16 |
+
"As seen in the Unit 1, an agent needs 3 steps as introduced in the ReAct architecture :\n",
|
| 17 |
+
"[ReAct](https://react-lm.github.io/), a general agent architecture.\n",
|
| 18 |
+
" \n",
|
| 19 |
+
"* `act` - let the model call specific tools \n",
|
| 20 |
+
"* `observe` - pass the tool output back to the model \n",
|
| 21 |
+
"* `reason` - let the model reason about the tool output to decide what to do next (e.g., call another tool or just respond directly)\n",
|
| 22 |
+
"\n",
|
| 23 |
+
"\n",
|
| 24 |
+
""
|
| 25 |
+
]
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"cell_type": "code",
|
| 29 |
+
"execution_count": 1,
|
| 30 |
+
"id": "63edff5a-724b-474d-9db8-37f0ae936c76",
|
| 31 |
+
"metadata": {
|
| 32 |
+
"tags": []
|
| 33 |
+
},
|
| 34 |
+
"outputs": [
|
| 35 |
+
{
|
| 36 |
+
"name": "stdout",
|
| 37 |
+
"output_type": "stream",
|
| 38 |
+
"text": [
|
| 39 |
+
"Note: you may need to restart the kernel to use updated packages.\n"
|
| 40 |
+
]
|
| 41 |
+
}
|
| 42 |
+
],
|
| 43 |
+
"source": [
|
| 44 |
+
"%pip install -q -U langchain_openai langchain_core langgraph"
|
| 45 |
+
]
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"cell_type": "code",
|
| 49 |
+
"execution_count": 2,
|
| 50 |
+
"id": "356a6482",
|
| 51 |
+
"metadata": {
|
| 52 |
+
"tags": []
|
| 53 |
+
},
|
| 54 |
+
"outputs": [],
|
| 55 |
+
"source": [
|
| 56 |
+
"import os\n",
|
| 57 |
+
"\n",
|
| 58 |
+
"# Please setp your own key.\n",
|
| 59 |
+
"os.environ[\"OPENAI_API_KEY\"]=\"sk-xxxxxx\""
|
| 60 |
+
]
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"cell_type": "code",
|
| 64 |
+
"execution_count": 65,
|
| 65 |
+
"id": "71795ff1-d6a7-448d-8b55-88bbd1ed3dbe",
|
| 66 |
+
"metadata": {
|
| 67 |
+
"tags": []
|
| 68 |
+
},
|
| 69 |
+
"outputs": [],
|
| 70 |
+
"source": [
|
| 71 |
+
"import base64\n",
|
| 72 |
+
"from typing import List\n",
|
| 73 |
+
"from langchain.schema import HumanMessage\n",
|
| 74 |
+
"from langchain_openai import ChatOpenAI\n",
|
| 75 |
+
"\n",
|
| 76 |
+
"\n",
|
| 77 |
+
"vision_llm = ChatOpenAI(model=\"gpt-4o\")\n",
|
| 78 |
+
"\n",
|
| 79 |
+
"def extract_text(img_path: str) -> str:\n",
|
| 80 |
+
" \"\"\"\n",
|
| 81 |
+
" Extract text from an image file using a multimodal model.\n",
|
| 82 |
+
"\n",
|
| 83 |
+
" Args:\n",
|
| 84 |
+
" img_path: A local image file path (strings).\n",
|
| 85 |
+
"\n",
|
| 86 |
+
" Returns:\n",
|
| 87 |
+
" A single string containing the concatenated text extracted from each image.\n",
|
| 88 |
+
" \"\"\"\n",
|
| 89 |
+
" all_text = \"\"\n",
|
| 90 |
+
" try:\n",
|
| 91 |
+
" \n",
|
| 92 |
+
" # Read image and encode as base64\n",
|
| 93 |
+
" with open(img_path, \"rb\") as image_file:\n",
|
| 94 |
+
" image_bytes = image_file.read()\n",
|
| 95 |
+
"\n",
|
| 96 |
+
" image_base64 = base64.b64encode(image_bytes).decode(\"utf-8\")\n",
|
| 97 |
+
"\n",
|
| 98 |
+
" # Prepare the prompt including the base64 image data\n",
|
| 99 |
+
" message = [\n",
|
| 100 |
+
" HumanMessage(\n",
|
| 101 |
+
" content=[\n",
|
| 102 |
+
" {\n",
|
| 103 |
+
" \"type\": \"text\",\n",
|
| 104 |
+
" \"text\": (\n",
|
| 105 |
+
" \"Extract all the text from this image. \"\n",
|
| 106 |
+
" \"Return only the extracted text, no explanations.\"\n",
|
| 107 |
+
" ),\n",
|
| 108 |
+
" },\n",
|
| 109 |
+
" {\n",
|
| 110 |
+
" \"type\": \"image_url\",\n",
|
| 111 |
+
" \"image_url\": {\n",
|
| 112 |
+
" \"url\": f\"data:image/png;base64,{image_base64}\"\n",
|
| 113 |
+
" },\n",
|
| 114 |
+
" },\n",
|
| 115 |
+
" ]\n",
|
| 116 |
+
" )\n",
|
| 117 |
+
" ]\n",
|
| 118 |
+
"\n",
|
| 119 |
+
" # Call the vision-capable model\n",
|
| 120 |
+
" response = vision_llm.invoke(message)\n",
|
| 121 |
+
"\n",
|
| 122 |
+
" # Append extracted text\n",
|
| 123 |
+
" all_text += response.content + \"\\n\\n\"\n",
|
| 124 |
+
"\n",
|
| 125 |
+
" return all_text.strip()\n",
|
| 126 |
+
" except Exception as e:\n",
|
| 127 |
+
" # You can choose whether to raise or just return an empty string / error message\n",
|
| 128 |
+
" error_msg = f\"Error extracting text: {str(e)}\"\n",
|
| 129 |
+
" print(error_msg)\n",
|
| 130 |
+
" return \"\"\n",
|
| 131 |
+
"\n",
|
| 132 |
+
"llm = ChatOpenAI(model=\"gpt-4o\")\n",
|
| 133 |
+
"\n",
|
| 134 |
+
"def divide(a: int, b: int) -> float:\n",
|
| 135 |
+
" \"\"\"Divide a and b.\"\"\"\n",
|
| 136 |
+
" return a / b\n",
|
| 137 |
+
"\n",
|
| 138 |
+
"tools = [\n",
|
| 139 |
+
" divide,\n",
|
| 140 |
+
" extract_text\n",
|
| 141 |
+
"]\n",
|
| 142 |
+
"llm_with_tools = llm.bind_tools(tools, parallel_tool_calls=False)"
|
| 143 |
+
]
|
| 144 |
+
},
|
| 145 |
+
{
|
| 146 |
+
"cell_type": "markdown",
|
| 147 |
+
"id": "a2cec014-3023-405c-be79-de8fc7adb346",
|
| 148 |
+
"metadata": {},
|
| 149 |
+
"source": [
|
| 150 |
+
"Let's create our LLM and prompt it with the overall desired agent behavior."
|
| 151 |
+
]
|
| 152 |
+
},
|
| 153 |
+
{
|
| 154 |
+
"cell_type": "code",
|
| 155 |
+
"execution_count": 66,
|
| 156 |
+
"id": "deb674bc-49b2-485a-b0c3-4d7b05a0bfac",
|
| 157 |
+
"metadata": {
|
| 158 |
+
"tags": []
|
| 159 |
+
},
|
| 160 |
+
"outputs": [],
|
| 161 |
+
"source": [
|
| 162 |
+
"from typing import TypedDict, Annotated, List, Any, Optional\n",
|
| 163 |
+
"from langchain_core.messages import AnyMessage\n",
|
| 164 |
+
"from langgraph.graph.message import add_messages\n",
|
| 165 |
+
"class AgentState(TypedDict):\n",
|
| 166 |
+
" # The input document\n",
|
| 167 |
+
" input_file: Optional[str] # Contains file path, type (PNG)\n",
|
| 168 |
+
" messages: Annotated[list[AnyMessage], add_messages]"
|
| 169 |
+
]
|
| 170 |
+
},
|
| 171 |
+
{
|
| 172 |
+
"cell_type": "code",
|
| 173 |
+
"execution_count": 76,
|
| 174 |
+
"id": "d061813f-ebc0-432c-91ec-3b42b15c30b6",
|
| 175 |
+
"metadata": {
|
| 176 |
+
"tags": []
|
| 177 |
+
},
|
| 178 |
+
"outputs": [],
|
| 179 |
+
"source": [
|
| 180 |
+
"from langchain_core.messages import HumanMessage, SystemMessage\n",
|
| 181 |
+
"from langchain_core.utils.function_calling import convert_to_openai_tool\n",
|
| 182 |
+
"\n",
|
| 183 |
+
"\n",
|
| 184 |
+
"# AgentState\n",
|
| 185 |
+
"def assistant(state: AgentState):\n",
|
| 186 |
+
" # System message\n",
|
| 187 |
+
" textual_description_of_tool=\"\"\"\n",
|
| 188 |
+
"extract_text(img_path: str) -> str:\n",
|
| 189 |
+
" Extract text from an image file using a multimodal model.\n",
|
| 190 |
+
"\n",
|
| 191 |
+
" Args:\n",
|
| 192 |
+
" img_path: A local image file path (strings).\n",
|
| 193 |
+
"\n",
|
| 194 |
+
" Returns:\n",
|
| 195 |
+
" A single string containing the concatenated text extracted from each image.\n",
|
| 196 |
+
"divide(a: int, b: int) -> float:\n",
|
| 197 |
+
" Divide a and b\n",
|
| 198 |
+
"\"\"\"\n",
|
| 199 |
+
" image=state[\"input_file\"]\n",
|
| 200 |
+
" sys_msg = SystemMessage(content=f\"You are an helpful agent that can analyse some images and run some computatio without provided tools :\\n{textual_description_of_tool} \\n You have access to some otpional images. Currently the loaded images is : {image}\")\n",
|
| 201 |
+
"\n",
|
| 202 |
+
"\n",
|
| 203 |
+
" return {\"messages\": [llm_with_tools.invoke([sys_msg] + state[\"messages\"])],\"input_file\":state[\"input_file\"]}"
|
| 204 |
+
]
|
| 205 |
+
},
|
| 206 |
+
{
|
| 207 |
+
"cell_type": "markdown",
|
| 208 |
+
"id": "4eb43343-9a6f-42cb-86e6-4380f928633c",
|
| 209 |
+
"metadata": {},
|
| 210 |
+
"source": [
|
| 211 |
+
"We define a `Tools` node with our list of tools.\n",
|
| 212 |
+
"\n",
|
| 213 |
+
"The `Assistant` node is just our model with bound tools.\n",
|
| 214 |
+
"\n",
|
| 215 |
+
"We create a graph with `Assistant` and `Tools` nodes.\n",
|
| 216 |
+
"\n",
|
| 217 |
+
"We add `tools_condition` edge, which routes to `End` or to `Tools` based on whether the `Assistant` calls a tool.\n",
|
| 218 |
+
"\n",
|
| 219 |
+
"Now, we add one new step:\n",
|
| 220 |
+
"\n",
|
| 221 |
+
"We connect the `Tools` node *back* to the `Assistant`, forming a loop.\n",
|
| 222 |
+
"\n",
|
| 223 |
+
"* After the `assistant` node executes, `tools_condition` checks if the model's output is a tool call.\n",
|
| 224 |
+
"* If it is a tool call, the flow is directed to the `tools` node.\n",
|
| 225 |
+
"* The `tools` node connects back to `assistant`.\n",
|
| 226 |
+
"* This loop continues as long as the model decides to call tools.\n",
|
| 227 |
+
"* If the model response is not a tool call, the flow is directed to END, terminating the process."
|
| 228 |
+
]
|
| 229 |
+
},
|
| 230 |
+
{
|
| 231 |
+
"cell_type": "code",
|
| 232 |
+
"execution_count": 77,
|
| 233 |
+
"id": "aef13cd4-05a6-4084-a620-2e7b91d9a72f",
|
| 234 |
+
"metadata": {
|
| 235 |
+
"tags": []
|
| 236 |
+
},
|
| 237 |
+
"outputs": [
|
| 238 |
+
{
|
| 239 |
+
"data": {
|
| 240 |
+
"image/png": "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",
|
| 241 |
+
"text/plain": [
|
| 242 |
+
"<IPython.core.display.Image object>"
|
| 243 |
+
]
|
| 244 |
+
},
|
| 245 |
+
"metadata": {},
|
| 246 |
+
"output_type": "display_data"
|
| 247 |
+
}
|
| 248 |
+
],
|
| 249 |
+
"source": [
|
| 250 |
+
"from langgraph.graph import START, StateGraph\n",
|
| 251 |
+
"from langgraph.prebuilt import tools_condition\n",
|
| 252 |
+
"from langgraph.prebuilt import ToolNode\n",
|
| 253 |
+
"from IPython.display import Image, display\n",
|
| 254 |
+
"\n",
|
| 255 |
+
"# Graph\n",
|
| 256 |
+
"builder = StateGraph(AgentState)\n",
|
| 257 |
+
"\n",
|
| 258 |
+
"# Define nodes: these do the work\n",
|
| 259 |
+
"builder.add_node(\"assistant\", assistant)\n",
|
| 260 |
+
"builder.add_node(\"tools\", ToolNode(tools))\n",
|
| 261 |
+
"\n",
|
| 262 |
+
"# Define edges: these determine how the control flow moves\n",
|
| 263 |
+
"builder.add_edge(START, \"assistant\")\n",
|
| 264 |
+
"builder.add_conditional_edges(\n",
|
| 265 |
+
" \"assistant\",\n",
|
| 266 |
+
" # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n",
|
| 267 |
+
" # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n",
|
| 268 |
+
" tools_condition,\n",
|
| 269 |
+
")\n",
|
| 270 |
+
"builder.add_edge(\"tools\", \"assistant\")\n",
|
| 271 |
+
"react_graph = builder.compile()\n",
|
| 272 |
+
"\n",
|
| 273 |
+
"# Show\n",
|
| 274 |
+
"display(Image(react_graph.get_graph(xray=True).draw_mermaid_png()))"
|
| 275 |
+
]
|
| 276 |
+
},
|
| 277 |
+
{
|
| 278 |
+
"cell_type": "code",
|
| 279 |
+
"execution_count": 78,
|
| 280 |
+
"id": "75602459-d8ca-47b4-9518-3f38343ebfe4",
|
| 281 |
+
"metadata": {
|
| 282 |
+
"tags": []
|
| 283 |
+
},
|
| 284 |
+
"outputs": [],
|
| 285 |
+
"source": [
|
| 286 |
+
"messages = [HumanMessage(content=\"Divide 6790 by 5\")]\n",
|
| 287 |
+
"\n",
|
| 288 |
+
"messages = react_graph.invoke({\"messages\": messages,\"input_file\":None})"
|
| 289 |
+
]
|
| 290 |
+
},
|
| 291 |
+
{
|
| 292 |
+
"cell_type": "code",
|
| 293 |
+
"execution_count": 79,
|
| 294 |
+
"id": "b517142d-c40c-48bf-a5b8-c8409427aa79",
|
| 295 |
+
"metadata": {
|
| 296 |
+
"tags": []
|
| 297 |
+
},
|
| 298 |
+
"outputs": [
|
| 299 |
+
{
|
| 300 |
+
"name": "stdout",
|
| 301 |
+
"output_type": "stream",
|
| 302 |
+
"text": [
|
| 303 |
+
"================================\u001b[1m Human Message \u001b[0m=================================\n",
|
| 304 |
+
"\n",
|
| 305 |
+
"Divide 6790 by 5\n",
|
| 306 |
+
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
|
| 307 |
+
"Tool Calls:\n",
|
| 308 |
+
" divide (call_s0G5ewtIQyHUCOv0fClsCpgh)\n",
|
| 309 |
+
" Call ID: call_s0G5ewtIQyHUCOv0fClsCpgh\n",
|
| 310 |
+
" Args:\n",
|
| 311 |
+
" a: 6790\n",
|
| 312 |
+
" b: 5\n",
|
| 313 |
+
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
|
| 314 |
+
"Name: divide\n",
|
| 315 |
+
"\n",
|
| 316 |
+
"1358.0\n",
|
| 317 |
+
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
|
| 318 |
+
"\n",
|
| 319 |
+
"The result of dividing 6790 by 5 is 1358.0.\n"
|
| 320 |
+
]
|
| 321 |
+
}
|
| 322 |
+
],
|
| 323 |
+
"source": [
|
| 324 |
+
"for m in messages['messages']:\n",
|
| 325 |
+
" m.pretty_print()"
|
| 326 |
+
]
|
| 327 |
+
},
|
| 328 |
+
{
|
| 329 |
+
"cell_type": "markdown",
|
| 330 |
+
"id": "08386393-c270-43a5-bde2-2b4075238971",
|
| 331 |
+
"metadata": {},
|
| 332 |
+
"source": [
|
| 333 |
+
"## Training program\n",
|
| 334 |
+
"MR Wayne left a note with his training program for the week. I came up with a recipe for dinner leaft in a note.\n",
|
| 335 |
+
"\n",
|
| 336 |
+
"you can find the document [HERE](https://huggingface.co/datasets/agents-course/course-images/blob/main/en/unit2/LangGraph/Batman_training_and_meals.png), so download it and upload it in the local folder.\n",
|
| 337 |
+
"\n",
|
| 338 |
+
""
|
| 339 |
+
]
|
| 340 |
+
},
|
| 341 |
+
{
|
| 342 |
+
"cell_type": "code",
|
| 343 |
+
"execution_count": 82,
|
| 344 |
+
"id": "f6e97e84-3b05-4aaf-a38f-1de9b73cd37f",
|
| 345 |
+
"metadata": {
|
| 346 |
+
"tags": []
|
| 347 |
+
},
|
| 348 |
+
"outputs": [],
|
| 349 |
+
"source": [
|
| 350 |
+
"messages = [HumanMessage(content=\"According the note provided by MR wayne in the provided images. What's the list of items I should buy for the dinner menu ?\")]\n",
|
| 351 |
+
"\n",
|
| 352 |
+
"messages = react_graph.invoke({\"messages\": messages,\"input_file\":\"Batman_training_and_meals.png\"})"
|
| 353 |
+
]
|
| 354 |
+
},
|
| 355 |
+
{
|
| 356 |
+
"cell_type": "code",
|
| 357 |
+
"execution_count": 83,
|
| 358 |
+
"id": "17686d52-c7ba-407b-a13f-f6c37668e5b0",
|
| 359 |
+
"metadata": {
|
| 360 |
+
"tags": []
|
| 361 |
+
},
|
| 362 |
+
"outputs": [
|
| 363 |
+
{
|
| 364 |
+
"name": "stdout",
|
| 365 |
+
"output_type": "stream",
|
| 366 |
+
"text": [
|
| 367 |
+
"================================\u001b[1m Human Message \u001b[0m=================================\n",
|
| 368 |
+
"\n",
|
| 369 |
+
"According the note provided by MR wayne in the provided images. What's the list of tiems I should buy for the dinner menu ?\n",
|
| 370 |
+
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
|
| 371 |
+
"Tool Calls:\n",
|
| 372 |
+
" extract_text (call_JalVBOR82hwRknFcplnLoTtG)\n",
|
| 373 |
+
" Call ID: call_JalVBOR82hwRknFcplnLoTtG\n",
|
| 374 |
+
" Args:\n",
|
| 375 |
+
" img_path: Batman_training_and_meals.png\n",
|
| 376 |
+
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
|
| 377 |
+
"Name: extract_text\n",
|
| 378 |
+
"\n",
|
| 379 |
+
"TRAINING SCHEDULE\n",
|
| 380 |
+
"For the week of 2/20-2/26\n",
|
| 381 |
+
"\n",
|
| 382 |
+
"SUNDAY 2/20\n",
|
| 383 |
+
"MORNING\n",
|
| 384 |
+
"30 minute jog\n",
|
| 385 |
+
"30 minute meditation\n",
|
| 386 |
+
"\n",
|
| 387 |
+
"EVENING\n",
|
| 388 |
+
"clean and jerk lifts—3 reps/8 sets. 262 lbs.\n",
|
| 389 |
+
"5 sets metabolic conditioning:\n",
|
| 390 |
+
"10 mile run\n",
|
| 391 |
+
"12 kettlebell swings\n",
|
| 392 |
+
"12 pull-ups\n",
|
| 393 |
+
"30 minutes flexibility\n",
|
| 394 |
+
"30 minutes sparring\n",
|
| 395 |
+
"\n",
|
| 396 |
+
"MONDAY 2/21\n",
|
| 397 |
+
"MORNING\n",
|
| 398 |
+
"30 minute jog\n",
|
| 399 |
+
"30 minutes traditional kata (focus on Japanese forms)\n",
|
| 400 |
+
"\n",
|
| 401 |
+
"EVENING\n",
|
| 402 |
+
"5 sets 20 foot rope climb\n",
|
| 403 |
+
"30 minutes gymnastics (work on muscle ups in\n",
|
| 404 |
+
"particular)\n",
|
| 405 |
+
"high bar jumps—12 reps/8 sets\n",
|
| 406 |
+
"crunches—50 reps/5 sets\n",
|
| 407 |
+
"30 minutes heavy bag\n",
|
| 408 |
+
"30 minutes flexibility\n",
|
| 409 |
+
"20 minutes target practice\n",
|
| 410 |
+
"\n",
|
| 411 |
+
"TUESDAY 2/22\n",
|
| 412 |
+
"MORNING\n",
|
| 413 |
+
"30 minute jog\n",
|
| 414 |
+
"30 minutes yoga\n",
|
| 415 |
+
"\n",
|
| 416 |
+
"EVENING\n",
|
| 417 |
+
"off day\n",
|
| 418 |
+
"leg heavy dead lift—5 reps/7 sets. 600 lbs.\n",
|
| 419 |
+
"clean and jerk lift—3 reps/10 sets\n",
|
| 420 |
+
"30 minutes sparring\n",
|
| 421 |
+
"\n",
|
| 422 |
+
"WEDNESDAY 2/23\n",
|
| 423 |
+
"OFF DAY\n",
|
| 424 |
+
"\n",
|
| 425 |
+
"MORNING\n",
|
| 426 |
+
"20-mile run—last week’s time was 4:50 per mile.\n",
|
| 427 |
+
"Need to better that time by a half a minute.\n",
|
| 428 |
+
"\n",
|
| 429 |
+
"EVENING\n",
|
| 430 |
+
"skill training only\n",
|
| 431 |
+
"30 minutes yoga\n",
|
| 432 |
+
"30 minutes meditation\n",
|
| 433 |
+
"30 minutes body basics\n",
|
| 434 |
+
"30 minutes bow basics\n",
|
| 435 |
+
"30 minutes sword basics\n",
|
| 436 |
+
"30 minutes observational\n",
|
| 437 |
+
"exercise\n",
|
| 438 |
+
"30 minutes kata\n",
|
| 439 |
+
"30 minutes pressure points\n",
|
| 440 |
+
"30 minutes modus and pressure points\n",
|
| 441 |
+
"\n",
|
| 442 |
+
"THURSDAY 2/24\n",
|
| 443 |
+
"MORNING\n",
|
| 444 |
+
"30 minute jog\n",
|
| 445 |
+
"30 minute meditation\n",
|
| 446 |
+
"30 minutes traditional kata\n",
|
| 447 |
+
"(focus on Japanese forms)\n",
|
| 448 |
+
"\n",
|
| 449 |
+
"EVENING\n",
|
| 450 |
+
"squats—10 reps/5 sets. 525 lbs.\n",
|
| 451 |
+
"30 minutes flexibility\n",
|
| 452 |
+
"crunches—50 reps/5 sets\n",
|
| 453 |
+
"20 minutes target practice\n",
|
| 454 |
+
"30 minutes heavy bag\n",
|
| 455 |
+
"\n",
|
| 456 |
+
"FRIDAY 2/25\n",
|
| 457 |
+
"MORNING\n",
|
| 458 |
+
"30 minute jog\n",
|
| 459 |
+
"30 minute meditation\n",
|
| 460 |
+
"\n",
|
| 461 |
+
"EVENING\n",
|
| 462 |
+
"clean and jerk lifts—3 reps/8 sets. 262 lbs.\n",
|
| 463 |
+
"5 sets metabolic conditioning:\n",
|
| 464 |
+
"10 mile run\n",
|
| 465 |
+
"12 kettlebell swings\n",
|
| 466 |
+
"12 pull-ups\n",
|
| 467 |
+
"30 minutes flexibility\n",
|
| 468 |
+
"30 minutes sparring\n",
|
| 469 |
+
"\n",
|
| 470 |
+
"SATURDAY 2/26)\n",
|
| 471 |
+
"MORNING\n",
|
| 472 |
+
"30 minute jog\n",
|
| 473 |
+
"30 minutes yoga\n",
|
| 474 |
+
"\n",
|
| 475 |
+
"EVENING\n",
|
| 476 |
+
"crunches—50 reps/5 sets\n",
|
| 477 |
+
"squats—(5 reps/10 sets. 525 lbs.\n",
|
| 478 |
+
"push-ups—60 reps/sets\n",
|
| 479 |
+
"30 minutes monkey bars\n",
|
| 480 |
+
"30 minute pommel horse\n",
|
| 481 |
+
"30 minutes heavy bag\n",
|
| 482 |
+
"2 mile swim\n",
|
| 483 |
+
"\n",
|
| 484 |
+
"In an effort to inspire the all- important Dark Knight to take time out of his busy schedule and actually consume a reasonable amount of sustenance, I have taken the liberty of composing a menu for today's scheduled natal to its my hope that these elegantly prepared courses will not share the fate of their predecessors -mated cold and untouched on a computer console.\n",
|
| 485 |
+
"-A\n",
|
| 486 |
+
"\n",
|
| 487 |
+
"W A Y N E M A N O R\n",
|
| 488 |
+
"\n",
|
| 489 |
+
"Tuesday's Menu\n",
|
| 490 |
+
"\n",
|
| 491 |
+
"Breakfast\n",
|
| 492 |
+
"six poached eggs laid over artichoke bottoms with a sage pesto sauce\n",
|
| 493 |
+
"thinly sliced baked ham\n",
|
| 494 |
+
"mixed organic fresh fruit bowl\n",
|
| 495 |
+
"freshly squeezed orange juice\n",
|
| 496 |
+
"organic, grass-fed milk\n",
|
| 497 |
+
"4 grams branched-chain amino acid\n",
|
| 498 |
+
"2 grams fish oil\n",
|
| 499 |
+
"\n",
|
| 500 |
+
"Lunch\n",
|
| 501 |
+
"local salmon with a ginger glaze\n",
|
| 502 |
+
"organic asparagus with lemon garlic dusting\n",
|
| 503 |
+
"Asian yam soup with diced onions\n",
|
| 504 |
+
"2 grams fish oil\n",
|
| 505 |
+
"\n",
|
| 506 |
+
"Dinner\n",
|
| 507 |
+
"grass-fed local sirloin steak\n",
|
| 508 |
+
"bed of organic spinach and piquillo peppers\n",
|
| 509 |
+
"oven-baked golden herb potato\n",
|
| 510 |
+
"2 grams fish oil\n",
|
| 511 |
+
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
|
| 512 |
+
"\n",
|
| 513 |
+
"For the dinner menu, you should buy the following items:\n",
|
| 514 |
+
"\n",
|
| 515 |
+
"1. Grass-fed local sirloin steak\n",
|
| 516 |
+
"2. Organic spinach\n",
|
| 517 |
+
"3. Piquillo peppers\n",
|
| 518 |
+
"4. Potatoes (for oven-baked golden herb potato)\n",
|
| 519 |
+
"5. Fish oil (2 grams)\n",
|
| 520 |
+
"\n",
|
| 521 |
+
"Ensure the steak is grass-fed and the spinach and peppers are organic for the best quality meal.\n"
|
| 522 |
+
]
|
| 523 |
+
}
|
| 524 |
+
],
|
| 525 |
+
"source": [
|
| 526 |
+
"for m in messages['messages']:\n",
|
| 527 |
+
" m.pretty_print()"
|
| 528 |
+
]
|
| 529 |
+
},
|
| 530 |
+
{
|
| 531 |
+
"cell_type": "code",
|
| 532 |
+
"execution_count": null,
|
| 533 |
+
"id": "b96c8456-4093-4cd6-bc5a-f611967ab709",
|
| 534 |
+
"metadata": {},
|
| 535 |
+
"outputs": [],
|
| 536 |
+
"source": []
|
| 537 |
+
}
|
| 538 |
+
],
|
| 539 |
+
"metadata": {
|
| 540 |
+
"kernelspec": {
|
| 541 |
+
"display_name": "Python 3 (ipykernel)",
|
| 542 |
+
"language": "python",
|
| 543 |
+
"name": "python3"
|
| 544 |
+
},
|
| 545 |
+
"language_info": {
|
| 546 |
+
"codemirror_mode": {
|
| 547 |
+
"name": "ipython",
|
| 548 |
+
"version": 3
|
| 549 |
+
},
|
| 550 |
+
"file_extension": ".py",
|
| 551 |
+
"mimetype": "text/x-python",
|
| 552 |
+
"name": "python",
|
| 553 |
+
"nbconvert_exporter": "python",
|
| 554 |
+
"pygments_lexer": "ipython3",
|
| 555 |
+
"version": "3.9.5"
|
| 556 |
+
}
|
| 557 |
+
},
|
| 558 |
+
"nbformat": 4,
|
| 559 |
+
"nbformat_minor": 5
|
| 560 |
+
}
|
unit2/langgraph/mail_sorting.ipynb
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"cells":[{"cell_type":"markdown","metadata":{},"source":["# Alfred the Mail Sorting Butler: A LangGraph Example\n","\n","In this notebook, **we're going to build a complete email processing workflow using LangGraph**.\n","\n","This notebook is part of the <a href=\"https://www.hf.co/learn/agents-course\">Hugging Face Agents Course</a>, a free course from beginner to expert, where you learn to build Agents.\n","\n","\n","\n","## What You'll Learn\n","\n","In this notebook, you'll learn how to:\n","1. Set up a LangGraph workflow\n","2. Define state and nodes for email processing\n","3. Create conditional branching in a graph\n","4. Connect an LLM for classification and content generation\n","5. Visualize the workflow graph\n","6. Execute the workflow with example data"]},{"cell_type":"code","execution_count":6,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["\u001b[33m WARNING: The script isympy is installed in '/Library/Frameworks/Python.framework/Versions/3.11/bin' which is not on PATH.\n"," Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.\u001b[0m\u001b[33m\n","\u001b[0m\u001b[33m WARNING: The script huggingface-cli is installed in '/Library/Frameworks/Python.framework/Versions/3.11/bin' which is not on PATH.\n"," Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.\u001b[0m\u001b[33m\n","\u001b[0m\u001b[33m WARNING: The scripts torchfrtrace and torchrun are installed in '/Library/Frameworks/Python.framework/Versions/3.11/bin' which is not on PATH.\n"," Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.\u001b[0m\u001b[33m\n","\u001b[0m\u001b[33m WARNING: The script transformers-cli is installed in '/Library/Frameworks/Python.framework/Versions/3.11/bin' which is not on PATH.\n"," Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.\u001b[0m\u001b[33m\n","\u001b[0m\n","\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m25.0.1\u001b[0m\n","\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython3 -m pip install --upgrade pip\u001b[0m\n","Note: you may need to restart the kernel to use updated packages.\n"]}],"source":["# Install the required packages\n","%pip install -q langgraph langchain_openai langchain_huggingface"]},{"cell_type":"markdown","metadata":{},"source":["## Setting Up Our Environment\n","\n","First, let's import all the necessary libraries. LangGraph provides the graph structure, while LangChain offers convenient interfaces for working with LLMs."]},{"cell_type":"code","execution_count":41,"metadata":{},"outputs":[],"source":["import os\n","from typing import TypedDict, List, Dict, Any, Optional\n","from langgraph.graph import StateGraph, END\n","from langchain_openai import ChatOpenAI\n","from langchain_core.messages import HumanMessage, AIMessage\n","\n","# Set your OpenAI API key here\n","os.environ[\"OPENAI_API_KEY\"] = \"sk-xxxxx\" # Replace with your actual API key\n","\n","# Initialize our LLM\n","model = ChatOpenAI(model=\"gpt-4o\", temperature=0)"]},{"cell_type":"markdown","metadata":{},"source":["## Step 1: Define Our State\n","\n","In LangGraph, **State** is the central concept. It represents all the information that flows through our workflow.\n","\n","For Alfred's email processing system, we need to track:\n","- The email being processed\n","- Whether it's spam or not\n","- The draft response (for legitimate emails)\n","- Conversation history with the LLM"]},{"cell_type":"code","execution_count":42,"metadata":{},"outputs":[],"source":["class EmailState(TypedDict):\n"," email: Dict[str, Any] \n"," is_spam: Optional[bool] \n"," spam_reason: Optional[str] \n"," email_category: Optional[str] \n"," draft_response: Optional[str] \n"," messages: List[Dict[str, Any]] "]},{"cell_type":"markdown","metadata":{},"source":["## Step 2: Define Our Nodes"]},{"cell_type":"code","execution_count":43,"metadata":{},"outputs":[{"data":{"text/plain":["<langgraph.graph.state.StateGraph at 0x123332fd0>"]},"execution_count":43,"metadata":{},"output_type":"execute_result"}],"source":["import os\n","from typing import TypedDict, List, Dict, Any, Optional\n","from langgraph.graph import StateGraph, START, END\n","from langchain_openai import ChatOpenAI\n","from langchain_core.messages import HumanMessage, AIMessage\n","from langchain_huggingface import ChatHuggingFace, HuggingFaceEndpoint\n","\n","\n","\n","# Initialize LLM\n","model = ChatOpenAI( model=\"gpt-4o\",temperature=0)\n","\n","class EmailState(TypedDict):\n"," email: Dict[str, Any]\n"," is_spam: Optional[bool]\n"," draft_response: Optional[str]\n"," messages: List[Dict[str, Any]]\n","\n","# Define nodes\n","def read_email(state: EmailState):\n"," email = state[\"email\"]\n"," print(f\"Alfred is processing an email from {email['sender']} with subject: {email['subject']}\")\n"," return {}\n","\n","def classify_email(state: EmailState):\n"," email = state[\"email\"]\n"," \n"," prompt = f\"\"\"\n","As Alfred the butler of Mr wayne and it's SECRET identity Batman, analyze this email and determine if it is spam or legitimate and should be brought to Mr wayne's attention.\n","\n","Email:\n","From: {email['sender']}\n","Subject: {email['subject']}\n","Body: {email['body']}\n","\n","First, determine if this email is spam.\n","answer with SPAM or HAM if it's legitimate. Only reurn the answer\n","Answer :\n"," \"\"\"\n"," messages = [HumanMessage(content=prompt)]\n"," response = model.invoke(messages)\n"," \n"," response_text = response.content.lower()\n"," print(response_text)\n"," is_spam = \"spam\" in response_text and \"ham\" not in response_text\n"," \n"," if not is_spam:\n"," new_messages = state.get(\"messages\", []) + [\n"," {\"role\": \"user\", \"content\": prompt},\n"," {\"role\": \"assistant\", \"content\": response.content}\n"," ]\n"," else :\n"," new_messages = state.get(\"messages\", [])\n"," \n"," return {\n"," \"is_spam\": is_spam,\n"," \"messages\": new_messages\n"," }\n","\n","def handle_spam(state: EmailState):\n"," print(f\"Alfred has marked the email as spam.\")\n"," print(\"The email has been moved to the spam folder.\")\n"," return {}\n","\n","def drafting_response(state: EmailState):\n"," email = state[\"email\"]\n"," \n"," prompt = f\"\"\"\n","As Alfred the butler, draft a polite preliminary response to this email.\n","\n","Email:\n","From: {email['sender']}\n","Subject: {email['subject']}\n","Body: {email['body']}\n","\n","Draft a brief, professional response that Mr. Wayne can review and personalize before sending.\n"," \"\"\"\n"," \n"," messages = [HumanMessage(content=prompt)]\n"," response = model.invoke(messages)\n"," \n"," new_messages = state.get(\"messages\", []) + [\n"," {\"role\": \"user\", \"content\": prompt},\n"," {\"role\": \"assistant\", \"content\": response.content}\n"," ]\n"," \n"," return {\n"," \"draft_response\": response.content,\n"," \"messages\": new_messages\n"," }\n","\n","def notify_mr_wayne(state: EmailState):\n"," email = state[\"email\"]\n"," \n"," print(\"\\n\" + \"=\"*50)\n"," print(f\"Sir, you've received an email from {email['sender']}.\")\n"," print(f\"Subject: {email['subject']}\")\n"," print(\"\\nI've prepared a draft response for your review:\")\n"," print(\"-\"*50)\n"," print(state[\"draft_response\"])\n"," print(\"=\"*50 + \"\\n\")\n"," \n"," return {}\n","\n","# Define routing logic\n","def route_email(state: EmailState) -> str:\n"," if state[\"is_spam\"]:\n"," return \"spam\"\n"," else:\n"," return \"legitimate\"\n","\n","# Create the graph\n","email_graph = StateGraph(EmailState)\n","\n","# Add nodes\n","email_graph.add_node(\"read_email\", read_email) # the read_email node executes the read_mail function\n","email_graph.add_node(\"classify_email\", classify_email) # the classify_email node will execute the classify_email function\n","email_graph.add_node(\"handle_spam\", handle_spam) #same logic \n","email_graph.add_node(\"drafting_response\", drafting_response) #same logic\n","email_graph.add_node(\"notify_mr_wayne\", notify_mr_wayne) # same logic\n"]},{"cell_type":"markdown","metadata":{},"source":["## Step 3: Define Our Routing Logic"]},{"cell_type":"code","execution_count":44,"metadata":{},"outputs":[{"data":{"text/plain":["<langgraph.graph.state.StateGraph at 0x123332fd0>"]},"execution_count":44,"metadata":{},"output_type":"execute_result"}],"source":["# Add edges\n","email_graph.add_edge(START, \"read_email\") # After starting we go to the \"read_email\" node\n","\n","email_graph.add_edge(\"read_email\", \"classify_email\") # after_reading we classify\n","\n","# Add conditional edges\n","email_graph.add_conditional_edges(\n"," \"classify_email\", # after classify, we run the \"route_email\" function\"\n"," route_email,\n"," {\n"," \"spam\": \"handle_spam\", # if it return \"Spam\", we go the \"handle_span\" node\n"," \"legitimate\": \"drafting_response\" # and if it's legitimate, we go to the \"drafting response\" node\n"," }\n",")\n","\n","# Add final edges\n","email_graph.add_edge(\"handle_spam\", END) # after handling spam we always end\n","email_graph.add_edge(\"drafting_response\", \"notify_mr_wayne\")\n","email_graph.add_edge(\"notify_mr_wayne\", END) # after notifyinf Me wayne, we can end too\n"]},{"cell_type":"markdown","metadata":{},"source":["## Step 4: Create the StateGraph and Define Edges"]},{"cell_type":"code","execution_count":45,"metadata":{},"outputs":[],"source":["# Compile the graph\n","compiled_graph = email_graph.compile()"]},{"cell_type":"code","execution_count":46,"metadata":{},"outputs":[{"data":{"image/png":"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","text/plain":["<IPython.core.display.Image object>"]},"metadata":{},"output_type":"display_data"}],"source":["\n","from IPython.display import Image, display\n","\n","display(Image(compiled_graph.get_graph().draw_mermaid_png()))"]},{"cell_type":"code","execution_count":47,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["\n","Processing legitimate email...\n","Alfred is processing an email from Joker with subject: Found you Batman ! \n","ham\n","\n","==================================================\n","Sir, you've received an email from Joker.\n","Subject: Found you Batman ! \n","\n","I've prepared a draft response for your review:\n","--------------------------------------------------\n","Subject: Re: Found you Batman!\n","\n","Dear Mr. Joker,\n","\n","Thank you for reaching out. Your message has been received and noted. Mr. Wayne is currently unavailable, but rest assured, your concerns will be addressed in due course.\n","\n","Kind regards,\n","\n","Alfred Pennyworth \n","Personal Assistant to Bruce Wayne\n","==================================================\n","\n","\n","Processing spam email...\n","Alfred is processing an email from Crypto bro with subject: The best investment of 2025\n","spam\n","Alfred has marked the email as spam.\n","The email has been moved to the spam folder.\n"]}],"source":[" # Example emails for testing\n","legitimate_email = {\n"," \"sender\": \"Joker\",\n"," \"subject\": \"Found you Batman ! \",\n"," \"body\": \"Mr. Wayne,I found your secret identity ! I know you're batman ! Ther's no denying it, I have proof of that and I'm coming to find you soon. I'll get my revenge. JOKER\"\n","}\n","\n","spam_email = {\n"," \"sender\": \"Crypto bro\",\n"," \"subject\": \"The best investment of 2025\",\n"," \"body\": \"Mr Wayne, I just launched an ALT coin and want you to buy some !\"\n","}\n","# Process legitimate email\n","print(\"\\nProcessing legitimate email...\")\n","legitimate_result = compiled_graph.invoke({\n"," \"email\": legitimate_email,\n"," \"is_spam\": None,\n"," \"draft_response\": None,\n"," \"messages\": []\n","})\n","\n","# Process spam email\n","print(\"\\nProcessing spam email...\")\n","spam_result = compiled_graph.invoke({\n"," \"email\": spam_email,\n"," \"is_spam\": None,\n"," \"draft_response\": None,\n"," \"messages\": []\n","}) "]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","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.6"}},"nbformat":4,"nbformat_minor":2}
|
unit2/llama-index/agents.ipynb
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {
|
| 6 |
+
"vscode": {
|
| 7 |
+
"languageId": "plaintext"
|
| 8 |
+
}
|
| 9 |
+
},
|
| 10 |
+
"source": [
|
| 11 |
+
"# Agents in LlamaIndex\n",
|
| 12 |
+
"\n",
|
| 13 |
+
"This notebook is part of the [Hugging Face Agents Course](https://www.hf.co/learn/agents-course), a free Course from beginner to expert, where you learn to build Agents.\n",
|
| 14 |
+
"\n",
|
| 15 |
+
"\n",
|
| 16 |
+
"\n",
|
| 17 |
+
"## Let's install the dependencies\n",
|
| 18 |
+
"\n",
|
| 19 |
+
"We will install the dependencies for this unit."
|
| 20 |
+
]
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"cell_type": "code",
|
| 24 |
+
"execution_count": 43,
|
| 25 |
+
"metadata": {},
|
| 26 |
+
"outputs": [],
|
| 27 |
+
"source": [
|
| 28 |
+
"!pip install llama-index datasets llama-index-callbacks-arize-phoenix llama-index-vector-stores-chroma llama-index-llms-huggingface-api -U -q"
|
| 29 |
+
]
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
"cell_type": "markdown",
|
| 33 |
+
"metadata": {},
|
| 34 |
+
"source": [
|
| 35 |
+
"And, let's log in to Hugging Face to use serverless Inference APIs."
|
| 36 |
+
]
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"cell_type": "code",
|
| 40 |
+
"execution_count": null,
|
| 41 |
+
"metadata": {},
|
| 42 |
+
"outputs": [],
|
| 43 |
+
"source": [
|
| 44 |
+
"from huggingface_hub import login\n",
|
| 45 |
+
"\n",
|
| 46 |
+
"login()"
|
| 47 |
+
]
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
"cell_type": "markdown",
|
| 51 |
+
"metadata": {
|
| 52 |
+
"vscode": {
|
| 53 |
+
"languageId": "plaintext"
|
| 54 |
+
}
|
| 55 |
+
},
|
| 56 |
+
"source": [
|
| 57 |
+
"## Initialising agents\n",
|
| 58 |
+
"\n",
|
| 59 |
+
"Let's start by initialising an agent. We will use the basic `AgentWorkflow` class to create an agent."
|
| 60 |
+
]
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"cell_type": "code",
|
| 64 |
+
"execution_count": null,
|
| 65 |
+
"metadata": {},
|
| 66 |
+
"outputs": [],
|
| 67 |
+
"source": [
|
| 68 |
+
"from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI\n",
|
| 69 |
+
"from llama_index.core.agent.workflow import AgentWorkflow, ToolCallResult, AgentStream\n",
|
| 70 |
+
"\n",
|
| 71 |
+
"\n",
|
| 72 |
+
"def add(a: int, b: int) -> int:\n",
|
| 73 |
+
" \"\"\"Add two numbers\"\"\"\n",
|
| 74 |
+
" return a + b\n",
|
| 75 |
+
"\n",
|
| 76 |
+
"\n",
|
| 77 |
+
"def subtract(a: int, b: int) -> int:\n",
|
| 78 |
+
" \"\"\"Subtract two numbers\"\"\"\n",
|
| 79 |
+
" return a - b\n",
|
| 80 |
+
"\n",
|
| 81 |
+
"\n",
|
| 82 |
+
"def multiply(a: int, b: int) -> int:\n",
|
| 83 |
+
" \"\"\"Multiply two numbers\"\"\"\n",
|
| 84 |
+
" return a * b\n",
|
| 85 |
+
"\n",
|
| 86 |
+
"\n",
|
| 87 |
+
"def divide(a: int, b: int) -> int:\n",
|
| 88 |
+
" \"\"\"Divide two numbers\"\"\"\n",
|
| 89 |
+
" return a / b\n",
|
| 90 |
+
"\n",
|
| 91 |
+
"\n",
|
| 92 |
+
"llm = HuggingFaceInferenceAPI(model_name=\"Qwen/Qwen2.5-Coder-32B-Instruct\")\n",
|
| 93 |
+
"\n",
|
| 94 |
+
"agent = AgentWorkflow.from_tools_or_functions(\n",
|
| 95 |
+
" tools_or_functions=[subtract, multiply, divide, add],\n",
|
| 96 |
+
" llm=llm,\n",
|
| 97 |
+
" system_prompt=\"You are a math agent that can add, subtract, multiply, and divide numbers using provided tools.\",\n",
|
| 98 |
+
")"
|
| 99 |
+
]
|
| 100 |
+
},
|
| 101 |
+
{
|
| 102 |
+
"cell_type": "markdown",
|
| 103 |
+
"metadata": {},
|
| 104 |
+
"source": [
|
| 105 |
+
"Then, we can run the agent and get the response and reasoning behind the tool calls."
|
| 106 |
+
]
|
| 107 |
+
},
|
| 108 |
+
{
|
| 109 |
+
"cell_type": "code",
|
| 110 |
+
"execution_count": null,
|
| 111 |
+
"metadata": {},
|
| 112 |
+
"outputs": [],
|
| 113 |
+
"source": [
|
| 114 |
+
"handler = agent.run(\"What is (2 + 2) * 2?\")\n",
|
| 115 |
+
"async for ev in handler.stream_events():\n",
|
| 116 |
+
" if isinstance(ev, ToolCallResult):\n",
|
| 117 |
+
" print(\"\")\n",
|
| 118 |
+
" print(\"Called tool: \", ev.tool_name, ev.tool_kwargs, \"=>\", ev.tool_output)\n",
|
| 119 |
+
" elif isinstance(ev, AgentStream): # showing the thought process\n",
|
| 120 |
+
" print(ev.delta, end=\"\", flush=True)\n",
|
| 121 |
+
"\n",
|
| 122 |
+
"resp = await handler\n",
|
| 123 |
+
"resp"
|
| 124 |
+
]
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
"cell_type": "markdown",
|
| 128 |
+
"metadata": {},
|
| 129 |
+
"source": [
|
| 130 |
+
"In a similar fashion, we can pass state and context to the agent.\n"
|
| 131 |
+
]
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"cell_type": "code",
|
| 135 |
+
"execution_count": 27,
|
| 136 |
+
"metadata": {},
|
| 137 |
+
"outputs": [
|
| 138 |
+
{
|
| 139 |
+
"data": {
|
| 140 |
+
"text/plain": [
|
| 141 |
+
"AgentOutput(response=ChatMessage(role=<MessageRole.ASSISTANT: 'assistant'>, additional_kwargs={}, blocks=[TextBlock(block_type='text', text='Your name is Bob.')]), tool_calls=[], raw={'id': 'chatcmpl-B5sDHfGpSwsVyzvMVH8EWokYwdIKT', 'choices': [{'delta': {'content': None, 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': 'stop', 'index': 0, 'logprobs': None}], 'created': 1740739735, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': 'default', 'system_fingerprint': 'fp_eb9dce56a8', 'usage': None}, current_agent_name='Agent')"
|
| 142 |
+
]
|
| 143 |
+
},
|
| 144 |
+
"execution_count": 27,
|
| 145 |
+
"metadata": {},
|
| 146 |
+
"output_type": "execute_result"
|
| 147 |
+
}
|
| 148 |
+
],
|
| 149 |
+
"source": [
|
| 150 |
+
"from llama_index.core.workflow import Context\n",
|
| 151 |
+
"\n",
|
| 152 |
+
"ctx = Context(agent)\n",
|
| 153 |
+
"\n",
|
| 154 |
+
"response = await agent.run(\"My name is Bob.\", ctx=ctx)\n",
|
| 155 |
+
"response = await agent.run(\"What was my name again?\", ctx=ctx)\n",
|
| 156 |
+
"response"
|
| 157 |
+
]
|
| 158 |
+
},
|
| 159 |
+
{
|
| 160 |
+
"cell_type": "markdown",
|
| 161 |
+
"metadata": {},
|
| 162 |
+
"source": [
|
| 163 |
+
"## Creating RAG Agents with QueryEngineTools\n",
|
| 164 |
+
"\n",
|
| 165 |
+
"Let's now re-use the `QueryEngine` we defined in the [previous unit on tools](/tools.ipynb) and convert it into a `QueryEngineTool`. We will pass it to the `AgentWorkflow` class to create a RAG agent."
|
| 166 |
+
]
|
| 167 |
+
},
|
| 168 |
+
{
|
| 169 |
+
"cell_type": "code",
|
| 170 |
+
"execution_count": 46,
|
| 171 |
+
"metadata": {},
|
| 172 |
+
"outputs": [],
|
| 173 |
+
"source": [
|
| 174 |
+
"import chromadb\n",
|
| 175 |
+
"\n",
|
| 176 |
+
"from llama_index.core import VectorStoreIndex\n",
|
| 177 |
+
"from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI\n",
|
| 178 |
+
"from llama_index.embeddings.huggingface_api import HuggingFaceInferenceAPIEmbedding\n",
|
| 179 |
+
"from llama_index.core.tools import QueryEngineTool\n",
|
| 180 |
+
"from llama_index.vector_stores.chroma import ChromaVectorStore\n",
|
| 181 |
+
"\n",
|
| 182 |
+
"# Create a vector store\n",
|
| 183 |
+
"db = chromadb.PersistentClient(path=\"./alfred_chroma_db\")\n",
|
| 184 |
+
"chroma_collection = db.get_or_create_collection(\"alfred\")\n",
|
| 185 |
+
"vector_store = ChromaVectorStore(chroma_collection=chroma_collection)\n",
|
| 186 |
+
"\n",
|
| 187 |
+
"# Create a query engine\n",
|
| 188 |
+
"embed_model = HuggingFaceInferenceAPIEmbedding(model_name=\"BAAI/bge-small-en-v1.5\")\n",
|
| 189 |
+
"llm = HuggingFaceInferenceAPI(model_name=\"Qwen/Qwen2.5-Coder-32B-Instruct\")\n",
|
| 190 |
+
"index = VectorStoreIndex.from_vector_store(\n",
|
| 191 |
+
" vector_store=vector_store, embed_model=embed_model\n",
|
| 192 |
+
")\n",
|
| 193 |
+
"query_engine = index.as_query_engine(llm=llm)\n",
|
| 194 |
+
"query_engine_tool = QueryEngineTool.from_defaults(\n",
|
| 195 |
+
" query_engine=query_engine,\n",
|
| 196 |
+
" name=\"personas\",\n",
|
| 197 |
+
" description=\"descriptions for various types of personas\",\n",
|
| 198 |
+
" return_direct=False,\n",
|
| 199 |
+
")\n",
|
| 200 |
+
"\n",
|
| 201 |
+
"# Create a RAG agent\n",
|
| 202 |
+
"query_engine_agent = AgentWorkflow.from_tools_or_functions(\n",
|
| 203 |
+
" tools_or_functions=[query_engine_tool],\n",
|
| 204 |
+
" llm=llm,\n",
|
| 205 |
+
" system_prompt=\"You are a helpful assistant that has access to a database containing persona descriptions. \",\n",
|
| 206 |
+
")"
|
| 207 |
+
]
|
| 208 |
+
},
|
| 209 |
+
{
|
| 210 |
+
"cell_type": "markdown",
|
| 211 |
+
"metadata": {},
|
| 212 |
+
"source": [
|
| 213 |
+
"And, we can once more get the response and reasoning behind the tool calls."
|
| 214 |
+
]
|
| 215 |
+
},
|
| 216 |
+
{
|
| 217 |
+
"cell_type": "code",
|
| 218 |
+
"execution_count": null,
|
| 219 |
+
"metadata": {},
|
| 220 |
+
"outputs": [],
|
| 221 |
+
"source": [
|
| 222 |
+
"handler = query_engine_agent.run(\n",
|
| 223 |
+
" \"Search the database for 'science fiction' and return some persona descriptions.\"\n",
|
| 224 |
+
")\n",
|
| 225 |
+
"async for ev in handler.stream_events():\n",
|
| 226 |
+
" if isinstance(ev, ToolCallResult):\n",
|
| 227 |
+
" print(\"\")\n",
|
| 228 |
+
" print(\"Called tool: \", ev.tool_name, ev.tool_kwargs, \"=>\", ev.tool_output)\n",
|
| 229 |
+
" elif isinstance(ev, AgentStream): # showing the thought process\n",
|
| 230 |
+
" print(ev.delta, end=\"\", flush=True)\n",
|
| 231 |
+
"\n",
|
| 232 |
+
"resp = await handler\n",
|
| 233 |
+
"resp"
|
| 234 |
+
]
|
| 235 |
+
},
|
| 236 |
+
{
|
| 237 |
+
"cell_type": "markdown",
|
| 238 |
+
"metadata": {},
|
| 239 |
+
"source": [
|
| 240 |
+
"## Creating multi-agent systems\n",
|
| 241 |
+
"\n",
|
| 242 |
+
"We can also create multi-agent systems by passing multiple agents to the `AgentWorkflow` class."
|
| 243 |
+
]
|
| 244 |
+
},
|
| 245 |
+
{
|
| 246 |
+
"cell_type": "code",
|
| 247 |
+
"execution_count": null,
|
| 248 |
+
"metadata": {},
|
| 249 |
+
"outputs": [],
|
| 250 |
+
"source": [
|
| 251 |
+
"from llama_index.core.agent.workflow import (\n",
|
| 252 |
+
" AgentWorkflow,\n",
|
| 253 |
+
" ReActAgent,\n",
|
| 254 |
+
")\n",
|
| 255 |
+
"\n",
|
| 256 |
+
"\n",
|
| 257 |
+
"# Define some tools\n",
|
| 258 |
+
"def add(a: int, b: int) -> int:\n",
|
| 259 |
+
" \"\"\"Add two numbers.\"\"\"\n",
|
| 260 |
+
" return a + b\n",
|
| 261 |
+
"\n",
|
| 262 |
+
"\n",
|
| 263 |
+
"def subtract(a: int, b: int) -> int:\n",
|
| 264 |
+
" \"\"\"Subtract two numbers.\"\"\"\n",
|
| 265 |
+
" return a - b\n",
|
| 266 |
+
"\n",
|
| 267 |
+
"\n",
|
| 268 |
+
"# Create agent configs\n",
|
| 269 |
+
"# NOTE: we can use FunctionAgent or ReActAgent here.\n",
|
| 270 |
+
"# FunctionAgent works for LLMs with a function calling API.\n",
|
| 271 |
+
"# ReActAgent works for any LLM.\n",
|
| 272 |
+
"calculator_agent = ReActAgent(\n",
|
| 273 |
+
" name=\"calculator\",\n",
|
| 274 |
+
" description=\"Performs basic arithmetic operations\",\n",
|
| 275 |
+
" system_prompt=\"You are a calculator assistant. Use your tools for any math operation.\",\n",
|
| 276 |
+
" tools=[add, subtract],\n",
|
| 277 |
+
" llm=llm,\n",
|
| 278 |
+
")\n",
|
| 279 |
+
"\n",
|
| 280 |
+
"query_agent = ReActAgent(\n",
|
| 281 |
+
" name=\"info_lookup\",\n",
|
| 282 |
+
" description=\"Looks up information about XYZ\",\n",
|
| 283 |
+
" system_prompt=\"Use your tool to query a RAG system to answer information about XYZ\",\n",
|
| 284 |
+
" tools=[query_engine_tool],\n",
|
| 285 |
+
" llm=llm,\n",
|
| 286 |
+
")\n",
|
| 287 |
+
"\n",
|
| 288 |
+
"# Create and run the workflow\n",
|
| 289 |
+
"agent = AgentWorkflow(agents=[calculator_agent, query_agent], root_agent=\"calculator\")\n",
|
| 290 |
+
"\n",
|
| 291 |
+
"# Run the system\n",
|
| 292 |
+
"handler = agent.run(user_msg=\"Can you add 5 and 3?\")"
|
| 293 |
+
]
|
| 294 |
+
},
|
| 295 |
+
{
|
| 296 |
+
"cell_type": "code",
|
| 297 |
+
"execution_count": null,
|
| 298 |
+
"metadata": {},
|
| 299 |
+
"outputs": [],
|
| 300 |
+
"source": [
|
| 301 |
+
"async for ev in handler.stream_events():\n",
|
| 302 |
+
" if isinstance(ev, ToolCallResult):\n",
|
| 303 |
+
" print(\"\")\n",
|
| 304 |
+
" print(\"Called tool: \", ev.tool_name, ev.tool_kwargs, \"=>\", ev.tool_output)\n",
|
| 305 |
+
" elif isinstance(ev, AgentStream): # showing the thought process\n",
|
| 306 |
+
" print(ev.delta, end=\"\", flush=True)\n",
|
| 307 |
+
"\n",
|
| 308 |
+
"resp = await handler\n",
|
| 309 |
+
"resp"
|
| 310 |
+
]
|
| 311 |
+
}
|
| 312 |
+
],
|
| 313 |
+
"metadata": {
|
| 314 |
+
"kernelspec": {
|
| 315 |
+
"display_name": ".venv",
|
| 316 |
+
"language": "python",
|
| 317 |
+
"name": "python3"
|
| 318 |
+
},
|
| 319 |
+
"language_info": {
|
| 320 |
+
"codemirror_mode": {
|
| 321 |
+
"name": "ipython",
|
| 322 |
+
"version": 3
|
| 323 |
+
},
|
| 324 |
+
"file_extension": ".py",
|
| 325 |
+
"mimetype": "text/x-python",
|
| 326 |
+
"name": "python",
|
| 327 |
+
"nbconvert_exporter": "python",
|
| 328 |
+
"pygments_lexer": "ipython3",
|
| 329 |
+
"version": "3.11.11"
|
| 330 |
+
}
|
| 331 |
+
},
|
| 332 |
+
"nbformat": 4,
|
| 333 |
+
"nbformat_minor": 2
|
| 334 |
+
}
|
unit2/llama-index/components.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
unit2/llama-index/tools.ipynb
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# Tools in LlamaIndex\n",
|
| 8 |
+
"\n",
|
| 9 |
+
"\n",
|
| 10 |
+
"This notebook is part of the [Hugging Face Agents Course](https://www.hf.co/learn/agents-course), a free Course from beginner to expert, where you learn to build Agents.\n",
|
| 11 |
+
"\n",
|
| 12 |
+
"\n",
|
| 13 |
+
"\n",
|
| 14 |
+
"## Let's install the dependencies\n",
|
| 15 |
+
"\n",
|
| 16 |
+
"We will install the dependencies for this unit."
|
| 17 |
+
]
|
| 18 |
+
},
|
| 19 |
+
{
|
| 20 |
+
"cell_type": "code",
|
| 21 |
+
"execution_count": 1,
|
| 22 |
+
"metadata": {},
|
| 23 |
+
"outputs": [],
|
| 24 |
+
"source": [
|
| 25 |
+
"!pip install llama-index datasets llama-index-callbacks-arize-phoenix llama-index-vector-stores-chroma llama-index-llms-huggingface-api -U -q"
|
| 26 |
+
]
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"cell_type": "markdown",
|
| 30 |
+
"metadata": {},
|
| 31 |
+
"source": [
|
| 32 |
+
"And, let's log in to Hugging Face to use serverless Inference APIs."
|
| 33 |
+
]
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"cell_type": "code",
|
| 37 |
+
"execution_count": null,
|
| 38 |
+
"metadata": {},
|
| 39 |
+
"outputs": [],
|
| 40 |
+
"source": [
|
| 41 |
+
"from huggingface_hub import login\n",
|
| 42 |
+
"\n",
|
| 43 |
+
"login()"
|
| 44 |
+
]
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"cell_type": "markdown",
|
| 48 |
+
"metadata": {},
|
| 49 |
+
"source": [
|
| 50 |
+
"## Creating a FunctionTool\n",
|
| 51 |
+
"\n",
|
| 52 |
+
"Let's create a basic `FunctionTool` and call it."
|
| 53 |
+
]
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"cell_type": "code",
|
| 57 |
+
"execution_count": 4,
|
| 58 |
+
"metadata": {},
|
| 59 |
+
"outputs": [],
|
| 60 |
+
"source": [
|
| 61 |
+
"from llama_index.core.tools import FunctionTool\n",
|
| 62 |
+
"\n",
|
| 63 |
+
"\n",
|
| 64 |
+
"def get_weather(location: str) -> str:\n",
|
| 65 |
+
" \"\"\"Useful for getting the weather for a given location.\"\"\"\n",
|
| 66 |
+
" print(f\"Getting weather for {location}\")\n",
|
| 67 |
+
" return f\"The weather in {location} is sunny\"\n",
|
| 68 |
+
"\n",
|
| 69 |
+
"\n",
|
| 70 |
+
"tool = FunctionTool.from_defaults(\n",
|
| 71 |
+
" get_weather,\n",
|
| 72 |
+
" name=\"my_weather_tool\",\n",
|
| 73 |
+
" description=\"Useful for getting the weather for a given location.\",\n",
|
| 74 |
+
")\n",
|
| 75 |
+
"tool.call(\"New York\")"
|
| 76 |
+
]
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"cell_type": "markdown",
|
| 80 |
+
"metadata": {},
|
| 81 |
+
"source": [
|
| 82 |
+
"## Creating a QueryEngineTool\n",
|
| 83 |
+
"\n",
|
| 84 |
+
"Let's now re-use the `QueryEngine` we defined in the [previous unit on tools](/tools.ipynb) and convert it into a `QueryEngineTool`. "
|
| 85 |
+
]
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
"cell_type": "code",
|
| 89 |
+
"execution_count": 8,
|
| 90 |
+
"metadata": {},
|
| 91 |
+
"outputs": [
|
| 92 |
+
{
|
| 93 |
+
"data": {
|
| 94 |
+
"text/plain": [
|
| 95 |
+
"ToolOutput(content=' As an anthropologist, I am intrigued by the potential implications of AI on the future of work and society. My research focuses on the cultural and social aspects of technological advancements, and I believe it is essential to understand how AI will shape the lives of Cypriot people and the broader society. I am particularly interested in exploring how AI will impact traditional industries, such as agriculture and tourism, and how it will affect the skills and knowledge required for future employment. As someone who has spent extensive time in Cyprus, I am well-positioned to investigate the unique cultural and historical context of the island and how it will influence the adoption and impact of AI. My research will not only provide valuable insights into the future of work but also contribute to the development of policies and strategies that support the well-being of Cypriot citizens and the broader society. \\n\\nAs an environmental historian or urban planner, I am more focused on the ecological and sustainability aspects of AI, particularly in the context of urban planning and conservation. I believe that AI has the potential to significantly impact the built environment and the natural world, and I am eager to explore how it can be used to create more sustainable and resilient cities. My research will focus on the intersection of AI, urban planning, and environmental conservation, and I', tool_name='some useful name', raw_input={'input': 'Responds about research on the impact of AI on the future of work and society?'}, raw_output=Response(response=' As an anthropologist, I am intrigued by the potential implications of AI on the future of work and society. My research focuses on the cultural and social aspects of technological advancements, and I believe it is essential to understand how AI will shape the lives of Cypriot people and the broader society. I am particularly interested in exploring how AI will impact traditional industries, such as agriculture and tourism, and how it will affect the skills and knowledge required for future employment. As someone who has spent extensive time in Cyprus, I am well-positioned to investigate the unique cultural and historical context of the island and how it will influence the adoption and impact of AI. My research will not only provide valuable insights into the future of work but also contribute to the development of policies and strategies that support the well-being of Cypriot citizens and the broader society. \\n\\nAs an environmental historian or urban planner, I am more focused on the ecological and sustainability aspects of AI, particularly in the context of urban planning and conservation. I believe that AI has the potential to significantly impact the built environment and the natural world, and I am eager to explore how it can be used to create more sustainable and resilient cities. My research will focus on the intersection of AI, urban planning, and environmental conservation, and I', source_nodes=[NodeWithScore(node=TextNode(id_='f0ea24d2-4ed3-4575-a41f-740a3fa8b521', embedding=None, metadata={'file_path': '/Users/davidberenstein/Documents/programming/huggingface/agents-course/notebooks/unit2/llama-index/data/persona_1.txt', 'file_name': 'persona_1.txt', 'file_type': 'text/plain', 'file_size': 266, 'creation_date': '2025-02-27', 'last_modified_date': '2025-02-27'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='d5db5bf4-daac-41e5-b5aa-271e8305da25', node_type='4', metadata={'file_path': '/Users/davidberenstein/Documents/programming/huggingface/agents-course/notebooks/unit2/llama-index/data/persona_1.txt', 'file_name': 'persona_1.txt', 'file_type': 'text/plain', 'file_size': 266, 'creation_date': '2025-02-27', 'last_modified_date': '2025-02-27'}, hash='e6c87149a97bf9e5dbdf33922a4e5023c6b72550ca0b63472bd5d25103b28e99')}, metadata_template='{key}: {value}', metadata_separator='\\n', text='An anthropologist or a cultural expert interested in the intricacies of Cypriot culture, history, and society, particularly someone who has spent considerable time researching and living in Cyprus to gain a deep understanding of its people, customs, and way of life.', mimetype='text/plain', start_char_idx=0, end_char_idx=266, metadata_seperator='\\n', text_template='{metadata_str}\\n\\n{content}'), score=0.3761845613489774), NodeWithScore(node=TextNode(id_='cebcd676-3180-4cda-be99-d535babc1b96', embedding=None, metadata={'file_path': '/Users/davidberenstein/Documents/programming/huggingface/agents-course/notebooks/unit2/llama-index/data/persona_1004.txt', 'file_name': 'persona_1004.txt', 'file_type': 'text/plain', 'file_size': 160, 'creation_date': '2025-02-27', 'last_modified_date': '2025-02-27'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='1347651d-7fc8-42d4-865c-a0151a534a1b', node_type='4', metadata={'file_path': '/Users/davidberenstein/Documents/programming/huggingface/agents-course/notebooks/unit2/llama-index/data/persona_1004.txt', 'file_name': 'persona_1004.txt', 'file_type': 'text/plain', 'file_size': 160, 'creation_date': '2025-02-27', 'last_modified_date': '2025-02-27'}, hash='19628b0ae4a0f0ebd63b75e13df7d9183f42e8bb84358fdc2c9049c016c4b67d')}, metadata_template='{key}: {value}', metadata_separator='\\n', text='An environmental historian or urban planner focused on ecological conservation and sustainability, likely working in local government or a related organization.', mimetype='text/plain', start_char_idx=0, end_char_idx=160, metadata_seperator='\\n', text_template='{metadata_str}\\n\\n{content}'), score=0.3733060058493167)], metadata={'f0ea24d2-4ed3-4575-a41f-740a3fa8b521': {'file_path': '/Users/davidberenstein/Documents/programming/huggingface/agents-course/notebooks/unit2/llama-index/data/persona_1.txt', 'file_name': 'persona_1.txt', 'file_type': 'text/plain', 'file_size': 266, 'creation_date': '2025-02-27', 'last_modified_date': '2025-02-27'}, 'cebcd676-3180-4cda-be99-d535babc1b96': {'file_path': '/Users/davidberenstein/Documents/programming/huggingface/agents-course/notebooks/unit2/llama-index/data/persona_1004.txt', 'file_name': 'persona_1004.txt', 'file_type': 'text/plain', 'file_size': 160, 'creation_date': '2025-02-27', 'last_modified_date': '2025-02-27'}}), is_error=False)"
|
| 96 |
+
]
|
| 97 |
+
},
|
| 98 |
+
"execution_count": 8,
|
| 99 |
+
"metadata": {},
|
| 100 |
+
"output_type": "execute_result"
|
| 101 |
+
}
|
| 102 |
+
],
|
| 103 |
+
"source": [
|
| 104 |
+
"import chromadb\n",
|
| 105 |
+
"\n",
|
| 106 |
+
"from llama_index.core import VectorStoreIndex\n",
|
| 107 |
+
"from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI\n",
|
| 108 |
+
"from llama_index.embeddings.huggingface_api import HuggingFaceInferenceAPIEmbedding\n",
|
| 109 |
+
"from llama_index.core.tools import QueryEngineTool\n",
|
| 110 |
+
"from llama_index.vector_stores.chroma import ChromaVectorStore\n",
|
| 111 |
+
"\n",
|
| 112 |
+
"db = chromadb.PersistentClient(path=\"./alfred_chroma_db\")\n",
|
| 113 |
+
"chroma_collection = db.get_or_create_collection(\"alfred\")\n",
|
| 114 |
+
"vector_store = ChromaVectorStore(chroma_collection=chroma_collection)\n",
|
| 115 |
+
"embed_model = HuggingFaceInferenceAPIEmbedding(model_name=\"BAAI/bge-small-en-v1.5\")\n",
|
| 116 |
+
"llm = HuggingFaceInferenceAPI(model_name=\"meta-llama/Llama-3.2-3B-Instruct\")\n",
|
| 117 |
+
"index = VectorStoreIndex.from_vector_store(\n",
|
| 118 |
+
" vector_store=vector_store, embed_model=embed_model\n",
|
| 119 |
+
")\n",
|
| 120 |
+
"query_engine = index.as_query_engine(llm=llm)\n",
|
| 121 |
+
"tool = QueryEngineTool.from_defaults(\n",
|
| 122 |
+
" query_engine=query_engine,\n",
|
| 123 |
+
" name=\"some useful name\",\n",
|
| 124 |
+
" description=\"some useful description\",\n",
|
| 125 |
+
")\n",
|
| 126 |
+
"await tool.acall(\n",
|
| 127 |
+
" \"Responds about research on the impact of AI on the future of work and society?\"\n",
|
| 128 |
+
")"
|
| 129 |
+
]
|
| 130 |
+
},
|
| 131 |
+
{
|
| 132 |
+
"cell_type": "markdown",
|
| 133 |
+
"metadata": {},
|
| 134 |
+
"source": [
|
| 135 |
+
"## Creating Toolspecs\n",
|
| 136 |
+
"\n",
|
| 137 |
+
"Let's create a `ToolSpec` from the `GmailToolSpec` from the LlamaHub and convert it to a list of tools. "
|
| 138 |
+
]
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
"cell_type": "code",
|
| 142 |
+
"execution_count": 14,
|
| 143 |
+
"metadata": {},
|
| 144 |
+
"outputs": [
|
| 145 |
+
{
|
| 146 |
+
"data": {
|
| 147 |
+
"text/plain": [
|
| 148 |
+
"[<llama_index.core.tools.function_tool.FunctionTool at 0x15d638410>,\n",
|
| 149 |
+
" <llama_index.core.tools.function_tool.FunctionTool at 0x15d64a190>,\n",
|
| 150 |
+
" <llama_index.core.tools.function_tool.FunctionTool at 0x159cf8050>,\n",
|
| 151 |
+
" <llama_index.core.tools.function_tool.FunctionTool at 0x15d65b150>,\n",
|
| 152 |
+
" <llama_index.core.tools.function_tool.FunctionTool at 0x15cef6990>,\n",
|
| 153 |
+
" <llama_index.core.tools.function_tool.FunctionTool at 0x15d642b10>]"
|
| 154 |
+
]
|
| 155 |
+
},
|
| 156 |
+
"execution_count": 14,
|
| 157 |
+
"metadata": {},
|
| 158 |
+
"output_type": "execute_result"
|
| 159 |
+
}
|
| 160 |
+
],
|
| 161 |
+
"source": [
|
| 162 |
+
"from llama_index.tools.google import GmailToolSpec\n",
|
| 163 |
+
"\n",
|
| 164 |
+
"tool_spec = GmailToolSpec()\n",
|
| 165 |
+
"tool_spec_list = tool_spec.to_tool_list()\n",
|
| 166 |
+
"tool_spec_list"
|
| 167 |
+
]
|
| 168 |
+
},
|
| 169 |
+
{
|
| 170 |
+
"cell_type": "markdown",
|
| 171 |
+
"metadata": {},
|
| 172 |
+
"source": [
|
| 173 |
+
"To get a more detailed view of the tools, we can take a look at the `metadata` of each tool."
|
| 174 |
+
]
|
| 175 |
+
},
|
| 176 |
+
{
|
| 177 |
+
"cell_type": "code",
|
| 178 |
+
"execution_count": 15,
|
| 179 |
+
"metadata": {},
|
| 180 |
+
"outputs": [
|
| 181 |
+
{
|
| 182 |
+
"data": {
|
| 183 |
+
"text/plain": [
|
| 184 |
+
"[('load_data',\n",
|
| 185 |
+
" \"load_data() -> List[llama_index.core.schema.Document]\\nLoad emails from the user's account.\"),\n",
|
| 186 |
+
" ('search_messages',\n",
|
| 187 |
+
" \"search_messages(query: str, max_results: Optional[int] = None)\\nSearches email messages given a query string and the maximum number\\n of results requested by the user\\n Returns: List of relevant message objects up to the maximum number of results.\\n\\n Args:\\n query[str]: The user's query\\n max_results (Optional[int]): The maximum number of search results\\n to return.\\n \"),\n",
|
| 188 |
+
" ('create_draft',\n",
|
| 189 |
+
" \"create_draft(to: Optional[List[str]] = None, subject: Optional[str] = None, message: Optional[str] = None) -> str\\nCreate and insert a draft email.\\n Print the returned draft's message and id.\\n Returns: Draft object, including draft id and message meta data.\\n\\n Args:\\n to (Optional[str]): The email addresses to send the message to\\n subject (Optional[str]): The subject for the event\\n message (Optional[str]): The message for the event\\n \"),\n",
|
| 190 |
+
" ('update_draft',\n",
|
| 191 |
+
" \"update_draft(to: Optional[List[str]] = None, subject: Optional[str] = None, message: Optional[str] = None, draft_id: str = None) -> str\\nUpdate a draft email.\\n Print the returned draft's message and id.\\n This function is required to be passed a draft_id that is obtained when creating messages\\n Returns: Draft object, including draft id and message meta data.\\n\\n Args:\\n to (Optional[str]): The email addresses to send the message to\\n subject (Optional[str]): The subject for the event\\n message (Optional[str]): The message for the event\\n draft_id (str): the id of the draft to be updated\\n \"),\n",
|
| 192 |
+
" ('get_draft',\n",
|
| 193 |
+
" \"get_draft(draft_id: str = None) -> str\\nGet a draft email.\\n Print the returned draft's message and id.\\n Returns: Draft object, including draft id and message meta data.\\n\\n Args:\\n draft_id (str): the id of the draft to be updated\\n \"),\n",
|
| 194 |
+
" ('send_draft',\n",
|
| 195 |
+
" \"send_draft(draft_id: str = None) -> str\\nSends a draft email.\\n Print the returned draft's message and id.\\n Returns: Draft object, including draft id and message meta data.\\n\\n Args:\\n draft_id (str): the id of the draft to be updated\\n \")]"
|
| 196 |
+
]
|
| 197 |
+
},
|
| 198 |
+
"execution_count": 15,
|
| 199 |
+
"metadata": {},
|
| 200 |
+
"output_type": "execute_result"
|
| 201 |
+
}
|
| 202 |
+
],
|
| 203 |
+
"source": [
|
| 204 |
+
"[(tool.metadata.name, tool.metadata.description) for tool in tool_spec_list]"
|
| 205 |
+
]
|
| 206 |
+
}
|
| 207 |
+
],
|
| 208 |
+
"metadata": {
|
| 209 |
+
"kernelspec": {
|
| 210 |
+
"display_name": ".venv",
|
| 211 |
+
"language": "python",
|
| 212 |
+
"name": "python3"
|
| 213 |
+
},
|
| 214 |
+
"language_info": {
|
| 215 |
+
"codemirror_mode": {
|
| 216 |
+
"name": "ipython",
|
| 217 |
+
"version": 3
|
| 218 |
+
},
|
| 219 |
+
"file_extension": ".py",
|
| 220 |
+
"mimetype": "text/x-python",
|
| 221 |
+
"name": "python",
|
| 222 |
+
"nbconvert_exporter": "python",
|
| 223 |
+
"pygments_lexer": "ipython3",
|
| 224 |
+
"version": "3.11.11"
|
| 225 |
+
}
|
| 226 |
+
},
|
| 227 |
+
"nbformat": 4,
|
| 228 |
+
"nbformat_minor": 2
|
| 229 |
+
}
|
unit2/llama-index/workflows.ipynb
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# Workflows in LlamaIndex\n",
|
| 8 |
+
"\n",
|
| 9 |
+
"\n",
|
| 10 |
+
"This notebook is part of the [Hugging Face Agents Course](https://www.hf.co/learn/agents-course), a free Course from beginner to expert, where you learn to build Agents.\n",
|
| 11 |
+
"\n",
|
| 12 |
+
"\n",
|
| 13 |
+
"\n",
|
| 14 |
+
"## Let's install the dependencies\n",
|
| 15 |
+
"\n",
|
| 16 |
+
"We will install the dependencies for this unit."
|
| 17 |
+
]
|
| 18 |
+
},
|
| 19 |
+
{
|
| 20 |
+
"cell_type": "code",
|
| 21 |
+
"execution_count": 11,
|
| 22 |
+
"metadata": {},
|
| 23 |
+
"outputs": [],
|
| 24 |
+
"source": [
|
| 25 |
+
"!pip install llama-index datasets llama-index-callbacks-arize-phoenix llama-index-vector-stores-chroma llama-index-utils-workflow llama-index-llms-huggingface-api pyvis -U -q"
|
| 26 |
+
]
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"cell_type": "markdown",
|
| 30 |
+
"metadata": {},
|
| 31 |
+
"source": [
|
| 32 |
+
"And, let's log in to Hugging Face to use serverless Inference APIs."
|
| 33 |
+
]
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"cell_type": "code",
|
| 37 |
+
"execution_count": null,
|
| 38 |
+
"metadata": {},
|
| 39 |
+
"outputs": [],
|
| 40 |
+
"source": [
|
| 41 |
+
"from huggingface_hub import login\n",
|
| 42 |
+
"\n",
|
| 43 |
+
"login()"
|
| 44 |
+
]
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"cell_type": "markdown",
|
| 48 |
+
"metadata": {},
|
| 49 |
+
"source": [
|
| 50 |
+
"## Basic Workflow Creation\n",
|
| 51 |
+
"\n",
|
| 52 |
+
"We can start by creating a simple workflow. We use the `StartEvent` and `StopEvent` classes to define the start and stop of the workflow."
|
| 53 |
+
]
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"cell_type": "code",
|
| 57 |
+
"execution_count": 3,
|
| 58 |
+
"metadata": {},
|
| 59 |
+
"outputs": [
|
| 60 |
+
{
|
| 61 |
+
"data": {
|
| 62 |
+
"text/plain": [
|
| 63 |
+
"'Hello, world!'"
|
| 64 |
+
]
|
| 65 |
+
},
|
| 66 |
+
"execution_count": 3,
|
| 67 |
+
"metadata": {},
|
| 68 |
+
"output_type": "execute_result"
|
| 69 |
+
}
|
| 70 |
+
],
|
| 71 |
+
"source": [
|
| 72 |
+
"from llama_index.core.workflow import StartEvent, StopEvent, Workflow, step\n",
|
| 73 |
+
"\n",
|
| 74 |
+
"\n",
|
| 75 |
+
"class MyWorkflow(Workflow):\n",
|
| 76 |
+
" @step\n",
|
| 77 |
+
" async def my_step(self, ev: StartEvent) -> StopEvent:\n",
|
| 78 |
+
" # do something here\n",
|
| 79 |
+
" return StopEvent(result=\"Hello, world!\")\n",
|
| 80 |
+
"\n",
|
| 81 |
+
"\n",
|
| 82 |
+
"w = MyWorkflow(timeout=10, verbose=False)\n",
|
| 83 |
+
"result = await w.run()\n",
|
| 84 |
+
"result"
|
| 85 |
+
]
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
"cell_type": "markdown",
|
| 89 |
+
"metadata": {},
|
| 90 |
+
"source": [
|
| 91 |
+
"## Connecting Multiple Steps\n",
|
| 92 |
+
"\n",
|
| 93 |
+
"We can also create multi-step workflows. Here we pass the event information between steps. Note that we can use type hinting to specify the event type and the flow of the workflow."
|
| 94 |
+
]
|
| 95 |
+
},
|
| 96 |
+
{
|
| 97 |
+
"cell_type": "code",
|
| 98 |
+
"execution_count": 4,
|
| 99 |
+
"metadata": {},
|
| 100 |
+
"outputs": [
|
| 101 |
+
{
|
| 102 |
+
"data": {
|
| 103 |
+
"text/plain": [
|
| 104 |
+
"'Finished processing: Step 1 complete'"
|
| 105 |
+
]
|
| 106 |
+
},
|
| 107 |
+
"execution_count": 4,
|
| 108 |
+
"metadata": {},
|
| 109 |
+
"output_type": "execute_result"
|
| 110 |
+
}
|
| 111 |
+
],
|
| 112 |
+
"source": [
|
| 113 |
+
"from llama_index.core.workflow import Event\n",
|
| 114 |
+
"\n",
|
| 115 |
+
"\n",
|
| 116 |
+
"class ProcessingEvent(Event):\n",
|
| 117 |
+
" intermediate_result: str\n",
|
| 118 |
+
"\n",
|
| 119 |
+
"\n",
|
| 120 |
+
"class MultiStepWorkflow(Workflow):\n",
|
| 121 |
+
" @step\n",
|
| 122 |
+
" async def step_one(self, ev: StartEvent) -> ProcessingEvent:\n",
|
| 123 |
+
" # Process initial data\n",
|
| 124 |
+
" return ProcessingEvent(intermediate_result=\"Step 1 complete\")\n",
|
| 125 |
+
"\n",
|
| 126 |
+
" @step\n",
|
| 127 |
+
" async def step_two(self, ev: ProcessingEvent) -> StopEvent:\n",
|
| 128 |
+
" # Use the intermediate result\n",
|
| 129 |
+
" final_result = f\"Finished processing: {ev.intermediate_result}\"\n",
|
| 130 |
+
" return StopEvent(result=final_result)\n",
|
| 131 |
+
"\n",
|
| 132 |
+
"\n",
|
| 133 |
+
"w = MultiStepWorkflow(timeout=10, verbose=False)\n",
|
| 134 |
+
"result = await w.run()\n",
|
| 135 |
+
"result"
|
| 136 |
+
]
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
"cell_type": "markdown",
|
| 140 |
+
"metadata": {},
|
| 141 |
+
"source": [
|
| 142 |
+
"## Loops and Branches\n",
|
| 143 |
+
"\n",
|
| 144 |
+
"We can also use type hinting to create branches and loops. Note that we can use the `|` operator to specify that the step can return multiple types."
|
| 145 |
+
]
|
| 146 |
+
},
|
| 147 |
+
{
|
| 148 |
+
"cell_type": "code",
|
| 149 |
+
"execution_count": 28,
|
| 150 |
+
"metadata": {},
|
| 151 |
+
"outputs": [
|
| 152 |
+
{
|
| 153 |
+
"name": "stdout",
|
| 154 |
+
"output_type": "stream",
|
| 155 |
+
"text": [
|
| 156 |
+
"Good thing happened\n"
|
| 157 |
+
]
|
| 158 |
+
},
|
| 159 |
+
{
|
| 160 |
+
"data": {
|
| 161 |
+
"text/plain": [
|
| 162 |
+
"'Finished processing: First step complete.'"
|
| 163 |
+
]
|
| 164 |
+
},
|
| 165 |
+
"execution_count": 28,
|
| 166 |
+
"metadata": {},
|
| 167 |
+
"output_type": "execute_result"
|
| 168 |
+
}
|
| 169 |
+
],
|
| 170 |
+
"source": [
|
| 171 |
+
"from llama_index.core.workflow import Event\n",
|
| 172 |
+
"import random\n",
|
| 173 |
+
"\n",
|
| 174 |
+
"\n",
|
| 175 |
+
"class ProcessingEvent(Event):\n",
|
| 176 |
+
" intermediate_result: str\n",
|
| 177 |
+
"\n",
|
| 178 |
+
"\n",
|
| 179 |
+
"class LoopEvent(Event):\n",
|
| 180 |
+
" loop_output: str\n",
|
| 181 |
+
"\n",
|
| 182 |
+
"\n",
|
| 183 |
+
"class MultiStepWorkflow(Workflow):\n",
|
| 184 |
+
" @step\n",
|
| 185 |
+
" async def step_one(self, ev: StartEvent) -> ProcessingEvent | LoopEvent:\n",
|
| 186 |
+
" if random.randint(0, 1) == 0:\n",
|
| 187 |
+
" print(\"Bad thing happened\")\n",
|
| 188 |
+
" return LoopEvent(loop_output=\"Back to step one.\")\n",
|
| 189 |
+
" else:\n",
|
| 190 |
+
" print(\"Good thing happened\")\n",
|
| 191 |
+
" return ProcessingEvent(intermediate_result=\"First step complete.\")\n",
|
| 192 |
+
"\n",
|
| 193 |
+
" @step\n",
|
| 194 |
+
" async def step_two(self, ev: ProcessingEvent | LoopEvent) -> StopEvent:\n",
|
| 195 |
+
" # Use the intermediate result\n",
|
| 196 |
+
" final_result = f\"Finished processing: {ev.intermediate_result}\"\n",
|
| 197 |
+
" return StopEvent(result=final_result)\n",
|
| 198 |
+
"\n",
|
| 199 |
+
"\n",
|
| 200 |
+
"w = MultiStepWorkflow(verbose=False)\n",
|
| 201 |
+
"result = await w.run()\n",
|
| 202 |
+
"result"
|
| 203 |
+
]
|
| 204 |
+
},
|
| 205 |
+
{
|
| 206 |
+
"cell_type": "markdown",
|
| 207 |
+
"metadata": {},
|
| 208 |
+
"source": [
|
| 209 |
+
"## Drawing Workflows\n",
|
| 210 |
+
"\n",
|
| 211 |
+
"We can also draw workflows using the `draw_all_possible_flows` function.\n"
|
| 212 |
+
]
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"cell_type": "code",
|
| 216 |
+
"execution_count": 24,
|
| 217 |
+
"metadata": {},
|
| 218 |
+
"outputs": [
|
| 219 |
+
{
|
| 220 |
+
"name": "stdout",
|
| 221 |
+
"output_type": "stream",
|
| 222 |
+
"text": [
|
| 223 |
+
"<class 'NoneType'>\n",
|
| 224 |
+
"<class '__main__.ProcessingEvent'>\n",
|
| 225 |
+
"<class '__main__.LoopEvent'>\n",
|
| 226 |
+
"<class 'llama_index.core.workflow.events.StopEvent'>\n",
|
| 227 |
+
"workflow_all_flows.html\n"
|
| 228 |
+
]
|
| 229 |
+
}
|
| 230 |
+
],
|
| 231 |
+
"source": [
|
| 232 |
+
"from llama_index.utils.workflow import draw_all_possible_flows\n",
|
| 233 |
+
"\n",
|
| 234 |
+
"draw_all_possible_flows(w)"
|
| 235 |
+
]
|
| 236 |
+
},
|
| 237 |
+
{
|
| 238 |
+
"cell_type": "markdown",
|
| 239 |
+
"metadata": {},
|
| 240 |
+
"source": [
|
| 241 |
+
""
|
| 242 |
+
]
|
| 243 |
+
},
|
| 244 |
+
{
|
| 245 |
+
"cell_type": "markdown",
|
| 246 |
+
"metadata": {},
|
| 247 |
+
"source": [
|
| 248 |
+
"### State Management\n",
|
| 249 |
+
"\n",
|
| 250 |
+
"Instead of passing the event information between steps, we can use the `Context` type hint to pass information between steps. \n",
|
| 251 |
+
"This might be useful for long running workflows, where you want to store information between steps."
|
| 252 |
+
]
|
| 253 |
+
},
|
| 254 |
+
{
|
| 255 |
+
"cell_type": "code",
|
| 256 |
+
"execution_count": 25,
|
| 257 |
+
"metadata": {},
|
| 258 |
+
"outputs": [
|
| 259 |
+
{
|
| 260 |
+
"name": "stdout",
|
| 261 |
+
"output_type": "stream",
|
| 262 |
+
"text": [
|
| 263 |
+
"Query: What is the capital of France?\n"
|
| 264 |
+
]
|
| 265 |
+
},
|
| 266 |
+
{
|
| 267 |
+
"data": {
|
| 268 |
+
"text/plain": [
|
| 269 |
+
"'Finished processing: Step 1 complete'"
|
| 270 |
+
]
|
| 271 |
+
},
|
| 272 |
+
"execution_count": 25,
|
| 273 |
+
"metadata": {},
|
| 274 |
+
"output_type": "execute_result"
|
| 275 |
+
}
|
| 276 |
+
],
|
| 277 |
+
"source": [
|
| 278 |
+
"from llama_index.core.workflow import Event, Context\n",
|
| 279 |
+
"from llama_index.core.agent.workflow import ReActAgent\n",
|
| 280 |
+
"\n",
|
| 281 |
+
"\n",
|
| 282 |
+
"class ProcessingEvent(Event):\n",
|
| 283 |
+
" intermediate_result: str\n",
|
| 284 |
+
"\n",
|
| 285 |
+
"\n",
|
| 286 |
+
"class MultiStepWorkflow(Workflow):\n",
|
| 287 |
+
" @step\n",
|
| 288 |
+
" async def step_one(self, ev: StartEvent, ctx: Context) -> ProcessingEvent:\n",
|
| 289 |
+
" # Process initial data\n",
|
| 290 |
+
" await ctx.set(\"query\", \"What is the capital of France?\")\n",
|
| 291 |
+
" return ProcessingEvent(intermediate_result=\"Step 1 complete\")\n",
|
| 292 |
+
"\n",
|
| 293 |
+
" @step\n",
|
| 294 |
+
" async def step_two(self, ev: ProcessingEvent, ctx: Context) -> StopEvent:\n",
|
| 295 |
+
" # Use the intermediate result\n",
|
| 296 |
+
" query = await ctx.get(\"query\")\n",
|
| 297 |
+
" print(f\"Query: {query}\")\n",
|
| 298 |
+
" final_result = f\"Finished processing: {ev.intermediate_result}\"\n",
|
| 299 |
+
" return StopEvent(result=final_result)\n",
|
| 300 |
+
"\n",
|
| 301 |
+
"\n",
|
| 302 |
+
"w = MultiStepWorkflow(timeout=10, verbose=False)\n",
|
| 303 |
+
"result = await w.run()\n",
|
| 304 |
+
"result"
|
| 305 |
+
]
|
| 306 |
+
},
|
| 307 |
+
{
|
| 308 |
+
"cell_type": "markdown",
|
| 309 |
+
"metadata": {},
|
| 310 |
+
"source": [
|
| 311 |
+
"## Multi-Agent Workflows\n",
|
| 312 |
+
"\n",
|
| 313 |
+
"We can also create multi-agent workflows. Here we define two agents, one that multiplies two integers and one that adds two integers."
|
| 314 |
+
]
|
| 315 |
+
},
|
| 316 |
+
{
|
| 317 |
+
"cell_type": "code",
|
| 318 |
+
"execution_count": null,
|
| 319 |
+
"metadata": {},
|
| 320 |
+
"outputs": [
|
| 321 |
+
{
|
| 322 |
+
"data": {
|
| 323 |
+
"text/plain": [
|
| 324 |
+
"AgentOutput(response=ChatMessage(role=<MessageRole.ASSISTANT: 'assistant'>, additional_kwargs={}, blocks=[TextBlock(block_type='text', text='I have handed off the request to an agent who can help you with adding 5 and 3. Please wait for their response.')]), tool_calls=[ToolCallResult(tool_name='handoff', tool_kwargs={'to_agent': 'addition_agent', 'reason': 'Add 5 and 3'}, tool_id='call_F97vcIcsvZjfAAOBzzIifW3y', tool_output=ToolOutput(content='Agent addition_agent is now handling the request due to the following reason: Add 5 and 3.\\nPlease continue with the current request.', tool_name='handoff', raw_input={'args': (), 'kwargs': {'to_agent': 'addition_agent', 'reason': 'Add 5 and 3'}}, raw_output='Agent addition_agent is now handling the request due to the following reason: Add 5 and 3.\\nPlease continue with the current request.', is_error=False), return_direct=True), ToolCallResult(tool_name='handoff', tool_kwargs={'to_agent': 'addition_agent', 'reason': 'Add 5 and 3'}, tool_id='call_jf49ktFRs09xYdOsnApAk2zz', tool_output=ToolOutput(content='Agent addition_agent is now handling the request due to the following reason: Add 5 and 3.\\nPlease continue with the current request.', tool_name='handoff', raw_input={'args': (), 'kwargs': {'to_agent': 'addition_agent', 'reason': 'Add 5 and 3'}}, raw_output='Agent addition_agent is now handling the request due to the following reason: Add 5 and 3.\\nPlease continue with the current request.', is_error=False), return_direct=True)], raw={'id': 'chatcmpl-B6Cy54VQkvlG3VOrmdzCzgwcJmVOc', 'choices': [{'delta': {'content': None, 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': 'stop', 'index': 0, 'logprobs': None}], 'created': 1740819517, 'model': 'gpt-3.5-turbo-0125', 'object': 'chat.completion.chunk', 'service_tier': 'default', 'system_fingerprint': None, 'usage': None}, current_agent_name='addition_agent')"
|
| 325 |
+
]
|
| 326 |
+
},
|
| 327 |
+
"execution_count": 33,
|
| 328 |
+
"metadata": {},
|
| 329 |
+
"output_type": "execute_result"
|
| 330 |
+
}
|
| 331 |
+
],
|
| 332 |
+
"source": [
|
| 333 |
+
"from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI\n",
|
| 334 |
+
"\n",
|
| 335 |
+
"# Define some tools\n",
|
| 336 |
+
"def add(a: int, b: int) -> int:\n",
|
| 337 |
+
" \"\"\"Add two numbers.\"\"\"\n",
|
| 338 |
+
" return a + b\n",
|
| 339 |
+
"\n",
|
| 340 |
+
"def multiply(a: int, b: int) -> int:\n",
|
| 341 |
+
" \"\"\"Multiply two numbers.\"\"\"\n",
|
| 342 |
+
" return a * b\n",
|
| 343 |
+
"\n",
|
| 344 |
+
"llm = HuggingFaceInferenceAPI(model_name=\"Qwen/Qwen2.5-Coder-32B-Instruct\")\n",
|
| 345 |
+
"\n",
|
| 346 |
+
"# we can pass functions directly without FunctionTool -- the fn/docstring are parsed for the name/description\n",
|
| 347 |
+
"multiply_agent = ReActAgent(\n",
|
| 348 |
+
" name=\"multiply_agent\",\n",
|
| 349 |
+
" description=\"Is able to multiply two integers\",\n",
|
| 350 |
+
" system_prompt=\"A helpful assistant that can use a tool to multiply numbers.\",\n",
|
| 351 |
+
" tools=[multiply], \n",
|
| 352 |
+
" llm=llm,\n",
|
| 353 |
+
")\n",
|
| 354 |
+
"\n",
|
| 355 |
+
"addition_agent = ReActAgent(\n",
|
| 356 |
+
" name=\"add_agent\",\n",
|
| 357 |
+
" description=\"Is able to add two integers\",\n",
|
| 358 |
+
" system_prompt=\"A helpful assistant that can use a tool to add numbers.\",\n",
|
| 359 |
+
" tools=[add], \n",
|
| 360 |
+
" llm=llm,\n",
|
| 361 |
+
")\n",
|
| 362 |
+
"\n",
|
| 363 |
+
"# Create the workflow\n",
|
| 364 |
+
"workflow = AgentWorkflow(\n",
|
| 365 |
+
" agents=[multiply_agent, addition_agent],\n",
|
| 366 |
+
" root_agent=\"multiply_agent\"\n",
|
| 367 |
+
")\n",
|
| 368 |
+
"\n",
|
| 369 |
+
"# Run the system\n",
|
| 370 |
+
"response = await workflow.run(user_msg=\"Can you add 5 and 3?\")"
|
| 371 |
+
]
|
| 372 |
+
}
|
| 373 |
+
],
|
| 374 |
+
"metadata": {
|
| 375 |
+
"kernelspec": {
|
| 376 |
+
"display_name": ".venv",
|
| 377 |
+
"language": "python",
|
| 378 |
+
"name": "python3"
|
| 379 |
+
},
|
| 380 |
+
"language_info": {
|
| 381 |
+
"codemirror_mode": {
|
| 382 |
+
"name": "ipython",
|
| 383 |
+
"version": 3
|
| 384 |
+
},
|
| 385 |
+
"file_extension": ".py",
|
| 386 |
+
"mimetype": "text/x-python",
|
| 387 |
+
"name": "python",
|
| 388 |
+
"nbconvert_exporter": "python",
|
| 389 |
+
"pygments_lexer": "ipython3",
|
| 390 |
+
"version": "3.11.11"
|
| 391 |
+
}
|
| 392 |
+
},
|
| 393 |
+
"nbformat": 4,
|
| 394 |
+
"nbformat_minor": 2
|
| 395 |
+
}
|
unit2/smolagents/code_agents.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
unit2/smolagents/multiagent_notebook.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
unit2/smolagents/retrieval_agents.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
unit2/smolagents/tool_calling_agents.ipynb
ADDED
|
@@ -0,0 +1,596 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {
|
| 6 |
+
"id": "Pi9CF0391ARI"
|
| 7 |
+
},
|
| 8 |
+
"source": [
|
| 9 |
+
"# Integrating Agents With Tools\n",
|
| 10 |
+
"\n",
|
| 11 |
+
"This notebook is part of the [Hugging Face Agents Course](https://www.hf.co/learn/agents-course), a free Course from beginner to expert, where you learn to build Agents.\n",
|
| 12 |
+
"\n",
|
| 13 |
+
""
|
| 14 |
+
]
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"cell_type": "markdown",
|
| 18 |
+
"metadata": {
|
| 19 |
+
"id": "9gsYky7F1GzT"
|
| 20 |
+
},
|
| 21 |
+
"source": [
|
| 22 |
+
"## Let's install the dependencies and login to our HF account to access the Inference API\n",
|
| 23 |
+
"\n",
|
| 24 |
+
"If you haven't installed `smolagents` yet, you can do so by running the following command:"
|
| 25 |
+
]
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"cell_type": "code",
|
| 29 |
+
"execution_count": null,
|
| 30 |
+
"metadata": {
|
| 31 |
+
"id": "MoFopncp0pnJ"
|
| 32 |
+
},
|
| 33 |
+
"outputs": [],
|
| 34 |
+
"source": [
|
| 35 |
+
"!pip install smolagents -U"
|
| 36 |
+
]
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"cell_type": "markdown",
|
| 40 |
+
"source": [
|
| 41 |
+
"Let's also login to the Hugging Face Hub to have access to the Inference API."
|
| 42 |
+
],
|
| 43 |
+
"metadata": {
|
| 44 |
+
"id": "cH-4W1GhYL4T"
|
| 45 |
+
}
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"cell_type": "code",
|
| 49 |
+
"execution_count": null,
|
| 50 |
+
"metadata": {
|
| 51 |
+
"id": "TFTc-ry70y1f"
|
| 52 |
+
},
|
| 53 |
+
"outputs": [],
|
| 54 |
+
"source": [
|
| 55 |
+
"from huggingface_hub import notebook_login\n",
|
| 56 |
+
"\n",
|
| 57 |
+
"notebook_login()"
|
| 58 |
+
]
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"cell_type": "markdown",
|
| 62 |
+
"metadata": {
|
| 63 |
+
"id": "ekKxaZrd1HlB"
|
| 64 |
+
},
|
| 65 |
+
"source": [
|
| 66 |
+
"## Selecting a Playlist for the Party Using `smolagents` and a `ToolCallingAgent`\n",
|
| 67 |
+
"\n",
|
| 68 |
+
"Let's revisit the previous example where Alfred started party preparations, but this time we'll use a `ToolCallingAgent` to highlight the difference. We'll build an agent that can search the web using DuckDuckGo, just like in our Code Agent example. The only difference is the agent type - the framework handles everything else:"
|
| 69 |
+
]
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"cell_type": "code",
|
| 73 |
+
"execution_count": null,
|
| 74 |
+
"metadata": {
|
| 75 |
+
"colab": {
|
| 76 |
+
"base_uri": "https://localhost:8080/",
|
| 77 |
+
"height": 1000
|
| 78 |
+
},
|
| 79 |
+
"id": "6IInDOUN01sP",
|
| 80 |
+
"outputId": "e49f2360-d377-4ed8-b7ae-8da4a3e3757b"
|
| 81 |
+
},
|
| 82 |
+
"outputs": [
|
| 83 |
+
{
|
| 84 |
+
"data": {
|
| 85 |
+
"text/html": [
|
| 86 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d4b702; text-decoration-color: #d4b702\">╭──────────────────────────────────────────────────── </span><span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">New run</span><span style=\"color: #d4b702; text-decoration-color: #d4b702\"> ────────────────────────────────────────────────────╮</span>\n",
|
| 87 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span> <span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span>\n",
|
| 88 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span> <span style=\"font-weight: bold\">Search for the best music recommendations for a party at the Wayne's mansion.</span> <span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span>\n",
|
| 89 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span> <span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span>\n",
|
| 90 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702\">╰─ HfApiModel - Qwen/Qwen2.5-Coder-32B-Instruct ──────────────────────────────────────────────────────────────────╯</span>\n",
|
| 91 |
+
"</pre>\n"
|
| 92 |
+
],
|
| 93 |
+
"text/plain": [
|
| 94 |
+
"\u001b[38;2;212;183;2m╭─\u001b[0m\u001b[38;2;212;183;2m───────────────────────────────────────────────────\u001b[0m\u001b[38;2;212;183;2m \u001b[0m\u001b[1;38;2;212;183;2mNew run\u001b[0m\u001b[38;2;212;183;2m \u001b[0m\u001b[38;2;212;183;2m───────────────────────────────────────────────────\u001b[0m\u001b[38;2;212;183;2m─╮\u001b[0m\n",
|
| 95 |
+
"\u001b[38;2;212;183;2m│\u001b[0m \u001b[38;2;212;183;2m│\u001b[0m\n",
|
| 96 |
+
"\u001b[38;2;212;183;2m│\u001b[0m \u001b[1mSearch for the best music recommendations for a party at the Wayne's mansion.\u001b[0m \u001b[38;2;212;183;2m│\u001b[0m\n",
|
| 97 |
+
"\u001b[38;2;212;183;2m│\u001b[0m \u001b[38;2;212;183;2m│\u001b[0m\n",
|
| 98 |
+
"\u001b[38;2;212;183;2m╰─\u001b[0m\u001b[38;2;212;183;2m HfApiModel - Qwen/Qwen2.5-Coder-32B-Instruct \u001b[0m\u001b[38;2;212;183;2m─────────────────────────────────────────────────────────────────\u001b[0m\u001b[38;2;212;183;2m─╯\u001b[0m\n"
|
| 99 |
+
]
|
| 100 |
+
},
|
| 101 |
+
"metadata": {},
|
| 102 |
+
"output_type": "display_data"
|
| 103 |
+
},
|
| 104 |
+
{
|
| 105 |
+
"data": {
|
| 106 |
+
"text/html": [
|
| 107 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d4b702; text-decoration-color: #d4b702\">━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ </span><span style=\"font-weight: bold\">Step </span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"color: #d4b702; text-decoration-color: #d4b702\"> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</span>\n",
|
| 108 |
+
"</pre>\n"
|
| 109 |
+
],
|
| 110 |
+
"text/plain": [
|
| 111 |
+
"\u001b[38;2;212;183;2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[0m\u001b[1mStep \u001b[0m\u001b[1;36m1\u001b[0m\u001b[38;2;212;183;2m ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\n"
|
| 112 |
+
]
|
| 113 |
+
},
|
| 114 |
+
"metadata": {},
|
| 115 |
+
"output_type": "display_data"
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"name": "stderr",
|
| 119 |
+
"output_type": "stream",
|
| 120 |
+
"text": [
|
| 121 |
+
"/usr/local/lib/python3.11/dist-packages/huggingface_hub/utils/_auth.py:94: UserWarning: \n",
|
| 122 |
+
"The secret `HF_TOKEN` does not exist in your Colab secrets.\n",
|
| 123 |
+
"To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.\n",
|
| 124 |
+
"You will be able to reuse this secret in all of your notebooks.\n",
|
| 125 |
+
"Please note that authentication is recommended but still optional to access public models or datasets.\n",
|
| 126 |
+
" warnings.warn(\n"
|
| 127 |
+
]
|
| 128 |
+
},
|
| 129 |
+
{
|
| 130 |
+
"data": {
|
| 131 |
+
"text/html": [
|
| 132 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
|
| 133 |
+
"│ Calling tool: 'web_search' with arguments: {'query': \"best music recommendations for a party at Wayne's │\n",
|
| 134 |
+
"│ mansion\"} │\n",
|
| 135 |
+
"╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
|
| 136 |
+
"</pre>\n"
|
| 137 |
+
],
|
| 138 |
+
"text/plain": [
|
| 139 |
+
"╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
|
| 140 |
+
"│ Calling tool: 'web_search' with arguments: {'query': \"best music recommendations for a party at Wayne's │\n",
|
| 141 |
+
"│ mansion\"} │\n",
|
| 142 |
+
"╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n"
|
| 143 |
+
]
|
| 144 |
+
},
|
| 145 |
+
"metadata": {},
|
| 146 |
+
"output_type": "display_data"
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"data": {
|
| 150 |
+
"text/html": [
|
| 151 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Observations: ## Search Results\n",
|
| 152 |
+
"\n",
|
| 153 |
+
"|The <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">75</span> Best Party Songs That Will Get Everyone Dancing - \n",
|
| 154 |
+
"Gear4music<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.gear4music.com/blog/best-party-songs/)</span>\n",
|
| 155 |
+
"The best party songs <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>. <span style=\"color: #008000; text-decoration-color: #008000\">\"September\"</span> - Earth, Wind & Fire <span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1978</span><span style=\"font-weight: bold\">)</span> Quite possibly the best party song. An infectious \n",
|
| 156 |
+
"mix of funk and soul, <span style=\"color: #008000; text-decoration-color: #008000\">\"September\"</span> is celebrated for its upbeat melody and <span style=\"color: #008000; text-decoration-color: #008000\">\"ba-dee-ya\"</span> chorus, making it a timeless \n",
|
| 157 |
+
"dance favorite.\n",
|
| 158 |
+
"\n",
|
| 159 |
+
"|Wedding Party Entrance Songs to Get the Party Started - The Mansion \n",
|
| 160 |
+
"<span style=\"color: #808000; text-decoration-color: #808000\">...</span><span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://mansiononmainstreet.com/wedding-party-entrance-songs-to-get-the-party-started/)</span>\n",
|
| 161 |
+
"Best Wedding Party Entrance Songs. No matter what vibe you're going for, there are some wedding party entrance \n",
|
| 162 |
+
"songs that are guaranteed to be a hit with people. From the latest music from Justin Timberlake to oldies but \n",
|
| 163 |
+
"goodies, most of your guests will be familiar with the popular wedding party entrance songs listed below.\n",
|
| 164 |
+
"\n",
|
| 165 |
+
"|<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">50</span> Songs on Every Event Planner's Playlist - \n",
|
| 166 |
+
"Eventbrite<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.eventbrite.com/blog/event-planning-playlist-ds00/)</span>\n",
|
| 167 |
+
"Music sets the mood and provides the soundtrack <span style=\"font-weight: bold\">(</span>literally<span style=\"font-weight: bold\">)</span> for a memorable and exciting time. While the right \n",
|
| 168 |
+
"songs can enhance the experience, the wrong event music can throw off the vibe. For example, fast-paced songs \n",
|
| 169 |
+
"probably aren't the best fit for a formal gala. And smooth jazz is likely to lull your guests at a motivational \n",
|
| 170 |
+
"conference.\n",
|
| 171 |
+
"\n",
|
| 172 |
+
"|<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">200</span> Classic House Party Songs Everyone Knows | The Best <span style=\"color: #808000; text-decoration-color: #808000\">...</span> - \n",
|
| 173 |
+
"iSpyTunes<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.ispytunes.com/post/house-party-songs)</span>\n",
|
| 174 |
+
"\" Branded merchandise adds flair to any occasion, just like the perfect playlist. <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">200</span> classic house party songs \n",
|
| 175 |
+
"everyone knows set the mood, bringing energy to every celebration. The best popular party hits keep guests dancing,\n",
|
| 176 |
+
"creating unforgettable moments. From throwback anthems to modern beats, a great selection ensures nonstop fun.\n",
|
| 177 |
+
"\n",
|
| 178 |
+
"|The Best Songs For Parties - The Ambient Mixer \n",
|
| 179 |
+
"Blog<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://blog.ambient-mixer.com/usage/parties-2/the-best-songs-for-parties/)</span>\n",
|
| 180 |
+
"The <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">100</span> best party songs ever made. Top <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">100</span> Best Party Songs Of All Time. Of course, these are just <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span> of the many \n",
|
| 181 |
+
"available playlists to choose from. However, these two contain some of the most popular ones most people usually \n",
|
| 182 |
+
"end up using. If these are not the type of songs you or your guests might enjoy then simply follow the steps in the\n",
|
| 183 |
+
"<span style=\"color: #808000; text-decoration-color: #808000\">...</span>\n",
|
| 184 |
+
"\n",
|
| 185 |
+
"|Passaic County Parks & Recreation: Music at the \n",
|
| 186 |
+
"Mansion<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://passaiccountynj.myrec.com/info/activities/program_details.aspx?ProgramID=29909)</span>\n",
|
| 187 |
+
"Thursdays from <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">7</span> to <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">9</span> PM the finest local bands will be playing music while In the Drink restaurant sells food and \n",
|
| 188 |
+
"drinks on site. September 3rd: Norton Smull Band; Parking is limited at the Dey Mansion <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">209</span> Totowa Rd. Wayne, NJ. \n",
|
| 189 |
+
"Overflow parking will be at the Preakness Valley Golf Course. You may drop off your guests at the Mansion first.\n",
|
| 190 |
+
"\n",
|
| 191 |
+
"|Grand Entrance Songs | SOUNDfonix<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://soundfonixent.com/resources/reception-song-ideas/grand-entrance-songs/)</span>\n",
|
| 192 |
+
"The entrance song sets the tone for the rest of the dance and the evening. Choose your entrance song wisely.\n",
|
| 193 |
+
"\n",
|
| 194 |
+
"|Party Music Guide: Ultimate Tips for the Perfect \n",
|
| 195 |
+
"Playlist<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://thebackstage-deezer.com/music/perfect-party-music-playlist/)</span>\n",
|
| 196 |
+
"Check out the best party playlists and top party songs to ensure your next party is packed! The most popular party \n",
|
| 197 |
+
"songs are here, just hit play. <span style=\"color: #808000; text-decoration-color: #808000\">...</span> to decor. But, most of all, you need to have fantastic music. We recommend you \n",
|
| 198 |
+
"get at least three hours' worth of party music queued and ready — that's about <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">75</span> songs. Lucky for you, we've <span style=\"color: #808000; text-decoration-color: #808000\">...</span>\n",
|
| 199 |
+
"\n",
|
| 200 |
+
"|The Top <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">100</span> Best Party Songs of All Time - \n",
|
| 201 |
+
"LiveAbout<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.liveabout.com/top-best-party-songs-of-all-time-3248355)</span>\n",
|
| 202 |
+
"<span style=\"color: #008000; text-decoration-color: #008000\">\"Macarena\"</span> then spent <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">14</span> weeks at No. <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span> on the U.S. pop singles chart. For more than a year this was one of the \n",
|
| 203 |
+
"most popular special event songs in the United States. It still works well as a charming party song encouraging \n",
|
| 204 |
+
"everyone to join in on the simple dance.\n",
|
| 205 |
+
"\n",
|
| 206 |
+
"|<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">70</span> Best Piano Bar Songs You Should Request<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.pianoarea.com/best-piano-bar-songs/)</span>\n",
|
| 207 |
+
"Best Piano Bar Songs You Should Request <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>. <span style=\"color: #008000; text-decoration-color: #008000\">\"Piano Man\"</span> by Billy Joel. One of the top recommendations for piano bar \n",
|
| 208 |
+
"songs is <span style=\"color: #008000; text-decoration-color: #008000\">\"Piano Man\"</span> by Billy Joel.. This iconic track was released by Columbia Records in <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1973</span>.. As part of the \n",
|
| 209 |
+
"album titled <span style=\"color: #008000; text-decoration-color: #008000\">'Piano Man,'</span> it's one of Billy Joel's most recognizable works.. The song spins a captivating narrative\n",
|
| 210 |
+
"and showcases Joe's compelling <span style=\"color: #808000; text-decoration-color: #808000\">...</span>\n",
|
| 211 |
+
"</pre>\n"
|
| 212 |
+
],
|
| 213 |
+
"text/plain": [
|
| 214 |
+
"Observations: ## Search Results\n",
|
| 215 |
+
"\n",
|
| 216 |
+
"|The \u001b[1;36m75\u001b[0m Best Party Songs That Will Get Everyone Dancing - \n",
|
| 217 |
+
"Gear4music\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://www.gear4music.com/blog/best-party-songs/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 218 |
+
"The best party songs \u001b[1;36m1\u001b[0m. \u001b[32m\"September\"\u001b[0m - Earth, Wind & Fire \u001b[1m(\u001b[0m\u001b[1;36m1978\u001b[0m\u001b[1m)\u001b[0m Quite possibly the best party song. An infectious \n",
|
| 219 |
+
"mix of funk and soul, \u001b[32m\"September\"\u001b[0m is celebrated for its upbeat melody and \u001b[32m\"ba-dee-ya\"\u001b[0m chorus, making it a timeless \n",
|
| 220 |
+
"dance favorite.\n",
|
| 221 |
+
"\n",
|
| 222 |
+
"|Wedding Party Entrance Songs to Get the Party Started - The Mansion \n",
|
| 223 |
+
"\u001b[33m...\u001b[0m\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://mansiononmainstreet.com/wedding-party-entrance-songs-to-get-the-party-started/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 224 |
+
"Best Wedding Party Entrance Songs. No matter what vibe you're going for, there are some wedding party entrance \n",
|
| 225 |
+
"songs that are guaranteed to be a hit with people. From the latest music from Justin Timberlake to oldies but \n",
|
| 226 |
+
"goodies, most of your guests will be familiar with the popular wedding party entrance songs listed below.\n",
|
| 227 |
+
"\n",
|
| 228 |
+
"|\u001b[1;36m50\u001b[0m Songs on Every Event Planner's Playlist - \n",
|
| 229 |
+
"Eventbrite\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://www.eventbrite.com/blog/event-planning-playlist-ds00/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 230 |
+
"Music sets the mood and provides the soundtrack \u001b[1m(\u001b[0mliterally\u001b[1m)\u001b[0m for a memorable and exciting time. While the right \n",
|
| 231 |
+
"songs can enhance the experience, the wrong event music can throw off the vibe. For example, fast-paced songs \n",
|
| 232 |
+
"probably aren't the best fit for a formal gala. And smooth jazz is likely to lull your guests at a motivational \n",
|
| 233 |
+
"conference.\n",
|
| 234 |
+
"\n",
|
| 235 |
+
"|\u001b[1;36m200\u001b[0m Classic House Party Songs Everyone Knows | The Best \u001b[33m...\u001b[0m - \n",
|
| 236 |
+
"iSpyTunes\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://www.ispytunes.com/post/house-party-songs\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 237 |
+
"\" Branded merchandise adds flair to any occasion, just like the perfect playlist. \u001b[1;36m200\u001b[0m classic house party songs \n",
|
| 238 |
+
"everyone knows set the mood, bringing energy to every celebration. The best popular party hits keep guests dancing,\n",
|
| 239 |
+
"creating unforgettable moments. From throwback anthems to modern beats, a great selection ensures nonstop fun.\n",
|
| 240 |
+
"\n",
|
| 241 |
+
"|The Best Songs For Parties - The Ambient Mixer \n",
|
| 242 |
+
"Blog\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://blog.ambient-mixer.com/usage/parties-2/the-best-songs-for-parties/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 243 |
+
"The \u001b[1;36m100\u001b[0m best party songs ever made. Top \u001b[1;36m100\u001b[0m Best Party Songs Of All Time. Of course, these are just \u001b[1;36m2\u001b[0m of the many \n",
|
| 244 |
+
"available playlists to choose from. However, these two contain some of the most popular ones most people usually \n",
|
| 245 |
+
"end up using. If these are not the type of songs you or your guests might enjoy then simply follow the steps in the\n",
|
| 246 |
+
"\u001b[33m...\u001b[0m\n",
|
| 247 |
+
"\n",
|
| 248 |
+
"|Passaic County Parks & Recreation: Music at the \n",
|
| 249 |
+
"Mansion\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://passaiccountynj.myrec.com/info/activities/program_details.aspx?\u001b[0m\u001b[4;94mProgramID\u001b[0m\u001b[4;94m=\u001b[0m\u001b[4;94m29909\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 250 |
+
"Thursdays from \u001b[1;36m7\u001b[0m to \u001b[1;36m9\u001b[0m PM the finest local bands will be playing music while In the Drink restaurant sells food and \n",
|
| 251 |
+
"drinks on site. September 3rd: Norton Smull Band; Parking is limited at the Dey Mansion \u001b[1;36m209\u001b[0m Totowa Rd. Wayne, NJ. \n",
|
| 252 |
+
"Overflow parking will be at the Preakness Valley Golf Course. You may drop off your guests at the Mansion first.\n",
|
| 253 |
+
"\n",
|
| 254 |
+
"|Grand Entrance Songs | SOUNDfonix\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://soundfonixent.com/resources/reception-song-ideas/grand-entrance-songs/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 255 |
+
"The entrance song sets the tone for the rest of the dance and the evening. Choose your entrance song wisely.\n",
|
| 256 |
+
"\n",
|
| 257 |
+
"|Party Music Guide: Ultimate Tips for the Perfect \n",
|
| 258 |
+
"Playlist\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://thebackstage-deezer.com/music/perfect-party-music-playlist/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 259 |
+
"Check out the best party playlists and top party songs to ensure your next party is packed! The most popular party \n",
|
| 260 |
+
"songs are here, just hit play. \u001b[33m...\u001b[0m to decor. But, most of all, you need to have fantastic music. We recommend you \n",
|
| 261 |
+
"get at least three hours' worth of party music queued and ready — that's about \u001b[1;36m75\u001b[0m songs. Lucky for you, we've \u001b[33m...\u001b[0m\n",
|
| 262 |
+
"\n",
|
| 263 |
+
"|The Top \u001b[1;36m100\u001b[0m Best Party Songs of All Time - \n",
|
| 264 |
+
"LiveAbout\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://www.liveabout.com/top-best-party-songs-of-all-time-3248355\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 265 |
+
"\u001b[32m\"Macarena\"\u001b[0m then spent \u001b[1;36m14\u001b[0m weeks at No. \u001b[1;36m1\u001b[0m on the U.S. pop singles chart. For more than a year this was one of the \n",
|
| 266 |
+
"most popular special event songs in the United States. It still works well as a charming party song encouraging \n",
|
| 267 |
+
"everyone to join in on the simple dance.\n",
|
| 268 |
+
"\n",
|
| 269 |
+
"|\u001b[1;36m70\u001b[0m Best Piano Bar Songs You Should Request\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://www.pianoarea.com/best-piano-bar-songs/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 270 |
+
"Best Piano Bar Songs You Should Request \u001b[1;36m1\u001b[0m. \u001b[32m\"Piano Man\"\u001b[0m by Billy Joel. One of the top recommendations for piano bar \n",
|
| 271 |
+
"songs is \u001b[32m\"Piano Man\"\u001b[0m by Billy Joel.. This iconic track was released by Columbia Records in \u001b[1;36m1973\u001b[0m.. As part of the \n",
|
| 272 |
+
"album titled \u001b[32m'Piano Man,'\u001b[0m it's one of Billy Joel's most recognizable works.. The song spins a captivating narrative\n",
|
| 273 |
+
"and showcases Joe's compelling \u001b[33m...\u001b[0m\n"
|
| 274 |
+
]
|
| 275 |
+
},
|
| 276 |
+
"metadata": {},
|
| 277 |
+
"output_type": "display_data"
|
| 278 |
+
},
|
| 279 |
+
{
|
| 280 |
+
"data": {
|
| 281 |
+
"text/html": [
|
| 282 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">[Step 0: Duration 4.70 seconds| Input tokens: 1,174 | Output tokens: 26]</span>\n",
|
| 283 |
+
"</pre>\n"
|
| 284 |
+
],
|
| 285 |
+
"text/plain": [
|
| 286 |
+
"\u001b[2m[Step 0: Duration 4.70 seconds| Input tokens: 1,174 | Output tokens: 26]\u001b[0m\n"
|
| 287 |
+
]
|
| 288 |
+
},
|
| 289 |
+
"metadata": {},
|
| 290 |
+
"output_type": "display_data"
|
| 291 |
+
},
|
| 292 |
+
{
|
| 293 |
+
"data": {
|
| 294 |
+
"text/html": [
|
| 295 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d4b702; text-decoration-color: #d4b702\">━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ </span><span style=\"font-weight: bold\">Step </span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span><span style=\"color: #d4b702; text-decoration-color: #d4b702\"> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</span>\n",
|
| 296 |
+
"</pre>\n"
|
| 297 |
+
],
|
| 298 |
+
"text/plain": [
|
| 299 |
+
"\u001b[38;2;212;183;2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[0m\u001b[1mStep \u001b[0m\u001b[1;36m2\u001b[0m\u001b[38;2;212;183;2m ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\n"
|
| 300 |
+
]
|
| 301 |
+
},
|
| 302 |
+
"metadata": {},
|
| 303 |
+
"output_type": "display_data"
|
| 304 |
+
},
|
| 305 |
+
{
|
| 306 |
+
"data": {
|
| 307 |
+
"text/html": [
|
| 308 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
|
| 309 |
+
"│ Calling tool: 'web_search' with arguments: {'query': 'best party songs for a mansion late-night event'} │\n",
|
| 310 |
+
"╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
|
| 311 |
+
"</pre>\n"
|
| 312 |
+
],
|
| 313 |
+
"text/plain": [
|
| 314 |
+
"╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
|
| 315 |
+
"│ Calling tool: 'web_search' with arguments: {'query': 'best party songs for a mansion late-night event'} │\n",
|
| 316 |
+
"╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n"
|
| 317 |
+
]
|
| 318 |
+
},
|
| 319 |
+
"metadata": {},
|
| 320 |
+
"output_type": "display_data"
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"data": {
|
| 324 |
+
"text/html": [
|
| 325 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Observations: ## Search Results\n",
|
| 326 |
+
"\n",
|
| 327 |
+
"|The <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">75</span> Best Party Songs That Will Get Everyone Dancing - \n",
|
| 328 |
+
"Gear4music<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.gear4music.com/blog/best-party-songs/)</span>\n",
|
| 329 |
+
"The best party songs <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>. <span style=\"color: #008000; text-decoration-color: #008000\">\"September\"</span> - Earth, Wind & Fire <span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1978</span><span style=\"font-weight: bold\">)</span> Quite possibly the best party song. An infectious \n",
|
| 330 |
+
"mix of funk and soul, <span style=\"color: #008000; text-decoration-color: #008000\">\"September\"</span> is celebrated for its upbeat melody and <span style=\"color: #008000; text-decoration-color: #008000\">\"ba-dee-ya\"</span> chorus, making it a timeless \n",
|
| 331 |
+
"dance favorite.\n",
|
| 332 |
+
"\n",
|
| 333 |
+
"|<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">45</span> Songs That Get Your Event Guests on the Dance Floor Every \n",
|
| 334 |
+
"Time<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://hub.theeventplannerexpo.com/entertainment/35-songs-that-get-your-event-guests-on-the-dance-floor-ever</span>\n",
|
| 335 |
+
"<span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">y-time)</span>\n",
|
| 336 |
+
"You'll know your client's event best, including music genre preferences and styles. But these songs are wildly \n",
|
| 337 |
+
"popular among many generations and are always great to have on standby should your dance guests need a boost. Party\n",
|
| 338 |
+
"Songs <span style=\"color: #008000; text-decoration-color: #008000\">\"Flowers\"</span> by Miley Cyrus <span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2023</span><span style=\"font-weight: bold\">)</span> <span style=\"color: #008000; text-decoration-color: #008000\">\"TQG\"</span> by KAROL G & Shakira <span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2023</span><span style=\"font-weight: bold\">)</span> <span style=\"color: #008000; text-decoration-color: #008000\">\"TRUSTFALL\"</span> by P!nk <span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2023</span><span style=\"font-weight: bold\">)</span>\n",
|
| 339 |
+
"\n",
|
| 340 |
+
"|Top <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">200</span> Most Requested Songs - DJ Event Planner<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://djeventplanner.com/mostrequested.htm)</span>\n",
|
| 341 |
+
"Based on over <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span> million requests using the DJ Event Planner song request system, this is a list of the most \n",
|
| 342 |
+
"requested songs of the past year. <span style=\"color: #808000; text-decoration-color: #808000\">...</span> December <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1963</span> <span style=\"font-weight: bold\">(</span>Oh, What A Night<span style=\"font-weight: bold\">)</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">24</span>: Commodores: Brick House: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">25</span>: Earth, Wind\n",
|
| 343 |
+
"and Fire: Boogie Wonderland: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">26</span>: Elton John: Your Song: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">27</span>: Stevie Wonder: Isn't She Lovely: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">28</span>: <span style=\"color: #808000; text-decoration-color: #808000\">...</span> Grove St. \n",
|
| 344 |
+
"Party: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">30</span> <span style=\"color: #808000; text-decoration-color: #808000\">...</span>\n",
|
| 345 |
+
"\n",
|
| 346 |
+
"|<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">50</span> Songs on Every Event Planner's Playlist - \n",
|
| 347 |
+
"Eventbrite<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.eventbrite.com/blog/event-planning-playlist-ds00/)</span>\n",
|
| 348 |
+
"For example, fast-paced songs probably aren't the best fit for a formal gala. And smooth jazz is likely to lull \n",
|
| 349 |
+
"your guests at a motivational conference. That's why it's crucial to think about the tone you want to set and \n",
|
| 350 |
+
"choose a playlist that embodies it. We've compiled a list of possible tunes to help you pick the best event songs.\n",
|
| 351 |
+
"\n",
|
| 352 |
+
"|The Best Party Songs of All Time <span style=\"font-weight: bold\">(</span>Our Playlists<span style=\"font-weight: bold\">)](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.ispytunes.com/post/best-party-songs)</span>\n",
|
| 353 |
+
"Discover the best party songs to make your event unforgettable! Our playlists feature the top party songs, from \n",
|
| 354 |
+
"timeless classics to the latest hits. <span style=\"color: #808000; text-decoration-color: #808000\">...</span> Last Friday Night by Katy Perry. Sweet Child O' Mine by Guns N' Roses. I \n",
|
| 355 |
+
"Gotta Feeling by the Black Eyed Peas. <span style=\"color: #808000; text-decoration-color: #808000\">...</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">200</span> Classic House Party Songs Everyone Knows | The Best Popular Party \n",
|
| 356 |
+
"Songs <span style=\"color: #808000; text-decoration-color: #808000\">...</span>\n",
|
| 357 |
+
"\n",
|
| 358 |
+
"|<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">15</span> Best Party Songs of All Time - Singersroom.com<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://singersroom.com/w75/best-party-songs-of-all-time/)</span>\n",
|
| 359 |
+
"Whether it's a wild club night, a backyard BBQ, or a house party with friends, the best party songs bring people \n",
|
| 360 |
+
"together, get them moving, and keep the good vibes flowing all night long.\n",
|
| 361 |
+
"\n",
|
| 362 |
+
"|Best Songs To Party: DJ's Ultimate Party Songs Playlist - \n",
|
| 363 |
+
"Top40Weekly.com<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://top40weekly.com/best-songs-to-party/)</span>\n",
|
| 364 |
+
"<span style=\"color: #008000; text-decoration-color: #008000\">\"Jump Around\"</span> by House of Pain is a classic party anthem that has stood the test of time, remaining a staple at \n",
|
| 365 |
+
"parties and sporting events for over two decades. The song's energetic rap verses, pulsating rhythm, and catchy \n",
|
| 366 |
+
"chorus create an atmosphere of pure excitement and exhilaration that never fails to ignite the dance floor.\n",
|
| 367 |
+
"\n",
|
| 368 |
+
"|<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">50</span>+ Best Songs For Your Next Party in <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2025</span> - Aleka's \n",
|
| 369 |
+
"Get-Together<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://alekasgettogether.com/top-songs-for-any-party/)</span>\n",
|
| 370 |
+
"A perfect, high-energy track to keep the party vibe strong all night. Last Friday Night <span style=\"font-weight: bold\">(</span>T.G.I.F.<span style=\"font-weight: bold\">)</span> - Katy Perry \n",
|
| 371 |
+
"This upbeat pop anthem is a must-play to keep the energy light and fun. Bleeding Love - Leona Lewis A heartfelt \n",
|
| 372 |
+
"ballad that balances out the upbeat tracks with an emotional sing-along. Crank That <span style=\"font-weight: bold\">(</span>Soulja Boy<span style=\"font-weight: bold\">)</span> - Soulja Boy Tell \n",
|
| 373 |
+
"'Em\n",
|
| 374 |
+
"\n",
|
| 375 |
+
"|<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">27</span> Most Influential Songs About Parties & Celebrations <span style=\"font-weight: bold\">(</span>Must Hear<span style=\"font-weight: bold\">)](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.pdmusic.org/songs-about-parties/)</span>\n",
|
| 376 |
+
"Contents. <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">27</span> Most Famous Songs About Parties, Partying & Drinking With Friend <span style=\"font-weight: bold\">(</span>Ultimate Playlist<span style=\"font-weight: bold\">)</span>; <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span> #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span> <span style=\"color: #008000; text-decoration-color: #008000\">\"Party in</span>\n",
|
| 377 |
+
"<span style=\"color: #008000; text-decoration-color: #008000\">the U.S.A.\"</span> by Miley Cyrus; <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span> #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span> <span style=\"color: #008000; text-decoration-color: #008000\">\"I Gotta Feeling\"</span> by The Black Eyed Peas; <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">4</span> #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span> <span style=\"color: #008000; text-decoration-color: #008000\">\"Party Rock Anthem\"</span> by LMFAO; <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">5</span> #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">4</span> \n",
|
| 378 |
+
"<span style=\"color: #008000; text-decoration-color: #008000\">\"Last Friday Night (T.G.I.F.)\"</span> by Katy Perry; <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">6</span> #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">5</span> <span style=\"color: #008000; text-decoration-color: #008000\">\"Dancing Queen\"</span> by ABBA; <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">7</span> #<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">6</span> <span style=\"color: #008000; text-decoration-color: #008000\">\"Turn Down for What\"</span> by DJ Snake &\n",
|
| 379 |
+
"Lil Jon\n",
|
| 380 |
+
"\n",
|
| 381 |
+
"|<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">40</span> Best Party Songs | Songs To Dance To, Ranked By Our Editors - Time \n",
|
| 382 |
+
"Out<span style=\"font-weight: bold\">](</span><span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.timeout.com/music/best-party-songs)</span>\n",
|
| 383 |
+
"The best is when you go for the extended version, and find yourself in the midst of the intro for about <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">11</span> minutes.\n",
|
| 384 |
+
"But whichever version you go for, this is the party song, in every way. She <span style=\"color: #808000; text-decoration-color: #808000\">...</span>\n",
|
| 385 |
+
"</pre>\n"
|
| 386 |
+
],
|
| 387 |
+
"text/plain": [
|
| 388 |
+
"Observations: ## Search Results\n",
|
| 389 |
+
"\n",
|
| 390 |
+
"|The \u001b[1;36m75\u001b[0m Best Party Songs That Will Get Everyone Dancing - \n",
|
| 391 |
+
"Gear4music\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://www.gear4music.com/blog/best-party-songs/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 392 |
+
"The best party songs \u001b[1;36m1\u001b[0m. \u001b[32m\"September\"\u001b[0m - Earth, Wind & Fire \u001b[1m(\u001b[0m\u001b[1;36m1978\u001b[0m\u001b[1m)\u001b[0m Quite possibly the best party song. An infectious \n",
|
| 393 |
+
"mix of funk and soul, \u001b[32m\"September\"\u001b[0m is celebrated for its upbeat melody and \u001b[32m\"ba-dee-ya\"\u001b[0m chorus, making it a timeless \n",
|
| 394 |
+
"dance favorite.\n",
|
| 395 |
+
"\n",
|
| 396 |
+
"|\u001b[1;36m45\u001b[0m Songs That Get Your Event Guests on the Dance Floor Every \n",
|
| 397 |
+
"Time\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://hub.theeventplannerexpo.com/entertainment/35-songs-that-get-your-event-guests-on-the-dance-floor-ever\u001b[0m\n",
|
| 398 |
+
"\u001b[4;94my-time\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 399 |
+
"You'll know your client's event best, including music genre preferences and styles. But these songs are wildly \n",
|
| 400 |
+
"popular among many generations and are always great to have on standby should your dance guests need a boost. Party\n",
|
| 401 |
+
"Songs \u001b[32m\"Flowers\"\u001b[0m by Miley Cyrus \u001b[1m(\u001b[0m\u001b[1;36m2023\u001b[0m\u001b[1m)\u001b[0m \u001b[32m\"TQG\"\u001b[0m by KAROL G & Shakira \u001b[1m(\u001b[0m\u001b[1;36m2023\u001b[0m\u001b[1m)\u001b[0m \u001b[32m\"TRUSTFALL\"\u001b[0m by P!nk \u001b[1m(\u001b[0m\u001b[1;36m2023\u001b[0m\u001b[1m)\u001b[0m\n",
|
| 402 |
+
"\n",
|
| 403 |
+
"|Top \u001b[1;36m200\u001b[0m Most Requested Songs - DJ Event Planner\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://djeventplanner.com/mostrequested.htm\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 404 |
+
"Based on over \u001b[1;36m2\u001b[0m million requests using the DJ Event Planner song request system, this is a list of the most \n",
|
| 405 |
+
"requested songs of the past year. \u001b[33m...\u001b[0m December \u001b[1;36m1963\u001b[0m \u001b[1m(\u001b[0mOh, What A Night\u001b[1m)\u001b[0m \u001b[1;36m24\u001b[0m: Commodores: Brick House: \u001b[1;36m25\u001b[0m: Earth, Wind\n",
|
| 406 |
+
"and Fire: Boogie Wonderland: \u001b[1;36m26\u001b[0m: Elton John: Your Song: \u001b[1;36m27\u001b[0m: Stevie Wonder: Isn't She Lovely: \u001b[1;36m28\u001b[0m: \u001b[33m...\u001b[0m Grove St. \n",
|
| 407 |
+
"Party: \u001b[1;36m30\u001b[0m \u001b[33m...\u001b[0m\n",
|
| 408 |
+
"\n",
|
| 409 |
+
"|\u001b[1;36m50\u001b[0m Songs on Every Event Planner's Playlist - \n",
|
| 410 |
+
"Eventbrite\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://www.eventbrite.com/blog/event-planning-playlist-ds00/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 411 |
+
"For example, fast-paced songs probably aren't the best fit for a formal gala. And smooth jazz is likely to lull \n",
|
| 412 |
+
"your guests at a motivational conference. That's why it's crucial to think about the tone you want to set and \n",
|
| 413 |
+
"choose a playlist that embodies it. We've compiled a list of possible tunes to help you pick the best event songs.\n",
|
| 414 |
+
"\n",
|
| 415 |
+
"|The Best Party Songs of All Time \u001b[1m(\u001b[0mOur Playlists\u001b[1m)\u001b[0m\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://www.ispytunes.com/post/best-party-songs\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 416 |
+
"Discover the best party songs to make your event unforgettable! Our playlists feature the top party songs, from \n",
|
| 417 |
+
"timeless classics to the latest hits. \u001b[33m...\u001b[0m Last Friday Night by Katy Perry. Sweet Child O' Mine by Guns N' Roses. I \n",
|
| 418 |
+
"Gotta Feeling by the Black Eyed Peas. \u001b[33m...\u001b[0m \u001b[1;36m200\u001b[0m Classic House Party Songs Everyone Knows | The Best Popular Party \n",
|
| 419 |
+
"Songs \u001b[33m...\u001b[0m\n",
|
| 420 |
+
"\n",
|
| 421 |
+
"|\u001b[1;36m15\u001b[0m Best Party Songs of All Time - Singersroom.com\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://singersroom.com/w75/best-party-songs-of-all-time/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 422 |
+
"Whether it's a wild club night, a backyard BBQ, or a house party with friends, the best party songs bring people \n",
|
| 423 |
+
"together, get them moving, and keep the good vibes flowing all night long.\n",
|
| 424 |
+
"\n",
|
| 425 |
+
"|Best Songs To Party: DJ's Ultimate Party Songs Playlist - \n",
|
| 426 |
+
"Top40Weekly.com\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://top40weekly.com/best-songs-to-party/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 427 |
+
"\u001b[32m\"Jump Around\"\u001b[0m by House of Pain is a classic party anthem that has stood the test of time, remaining a staple at \n",
|
| 428 |
+
"parties and sporting events for over two decades. The song's energetic rap verses, pulsating rhythm, and catchy \n",
|
| 429 |
+
"chorus create an atmosphere of pure excitement and exhilaration that never fails to ignite the dance floor.\n",
|
| 430 |
+
"\n",
|
| 431 |
+
"|\u001b[1;36m50\u001b[0m+ Best Songs For Your Next Party in \u001b[1;36m2025\u001b[0m - Aleka's \n",
|
| 432 |
+
"Get-Together\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://alekasgettogether.com/top-songs-for-any-party/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 433 |
+
"A perfect, high-energy track to keep the party vibe strong all night. Last Friday Night \u001b[1m(\u001b[0mT.G.I.F.\u001b[1m)\u001b[0m - Katy Perry \n",
|
| 434 |
+
"This upbeat pop anthem is a must-play to keep the energy light and fun. Bleeding Love - Leona Lewis A heartfelt \n",
|
| 435 |
+
"ballad that balances out the upbeat tracks with an emotional sing-along. Crank That \u001b[1m(\u001b[0mSoulja Boy\u001b[1m)\u001b[0m - Soulja Boy Tell \n",
|
| 436 |
+
"'Em\n",
|
| 437 |
+
"\n",
|
| 438 |
+
"|\u001b[1;36m27\u001b[0m Most Influential Songs About Parties & Celebrations \u001b[1m(\u001b[0mMust Hear\u001b[1m)\u001b[0m\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://www.pdmusic.org/songs-about-parties/\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 439 |
+
"Contents. \u001b[1;36m1\u001b[0m \u001b[1;36m27\u001b[0m Most Famous Songs About Parties, Partying & Drinking With Friend \u001b[1m(\u001b[0mUltimate Playlist\u001b[1m)\u001b[0m; \u001b[1;36m2\u001b[0m #\u001b[1;36m1\u001b[0m \u001b[32m\"Party in\u001b[0m\n",
|
| 440 |
+
"\u001b[32mthe U.S.A.\"\u001b[0m by Miley Cyrus; \u001b[1;36m3\u001b[0m #\u001b[1;36m2\u001b[0m \u001b[32m\"I Gotta Feeling\"\u001b[0m by The Black Eyed Peas; \u001b[1;36m4\u001b[0m #\u001b[1;36m3\u001b[0m \u001b[32m\"Party Rock Anthem\"\u001b[0m by LMFAO; \u001b[1;36m5\u001b[0m #\u001b[1;36m4\u001b[0m \n",
|
| 441 |
+
"\u001b[32m\"Last Friday Night \u001b[0m\u001b[32m(\u001b[0m\u001b[32mT.G.I.F.\u001b[0m\u001b[32m)\u001b[0m\u001b[32m\"\u001b[0m by Katy Perry; \u001b[1;36m6\u001b[0m #\u001b[1;36m5\u001b[0m \u001b[32m\"Dancing Queen\"\u001b[0m by ABBA; \u001b[1;36m7\u001b[0m #\u001b[1;36m6\u001b[0m \u001b[32m\"Turn Down for What\"\u001b[0m by DJ Snake &\n",
|
| 442 |
+
"Lil Jon\n",
|
| 443 |
+
"\n",
|
| 444 |
+
"|\u001b[1;36m40\u001b[0m Best Party Songs | Songs To Dance To, Ranked By Our Editors - Time \n",
|
| 445 |
+
"Out\u001b[1m]\u001b[0m\u001b[1m(\u001b[0m\u001b[4;94mhttps://www.timeout.com/music/best-party-songs\u001b[0m\u001b[4;94m)\u001b[0m\n",
|
| 446 |
+
"The best is when you go for the extended version, and find yourself in the midst of the intro for about \u001b[1;36m11\u001b[0m minutes.\n",
|
| 447 |
+
"But whichever version you go for, this is the party song, in every way. She \u001b[33m...\u001b[0m\n"
|
| 448 |
+
]
|
| 449 |
+
},
|
| 450 |
+
"metadata": {},
|
| 451 |
+
"output_type": "display_data"
|
| 452 |
+
},
|
| 453 |
+
{
|
| 454 |
+
"data": {
|
| 455 |
+
"text/html": [
|
| 456 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">[Step 1: Duration 6.66 seconds| Input tokens: 3,435 | Output tokens: 55]</span>\n",
|
| 457 |
+
"</pre>\n"
|
| 458 |
+
],
|
| 459 |
+
"text/plain": [
|
| 460 |
+
"\u001b[2m[Step 1: Duration 6.66 seconds| Input tokens: 3,435 | Output tokens: 55]\u001b[0m\n"
|
| 461 |
+
]
|
| 462 |
+
},
|
| 463 |
+
"metadata": {},
|
| 464 |
+
"output_type": "display_data"
|
| 465 |
+
},
|
| 466 |
+
{
|
| 467 |
+
"data": {
|
| 468 |
+
"text/html": [
|
| 469 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d4b702; text-decoration-color: #d4b702\">━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ </span><span style=\"font-weight: bold\">Step </span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span><span style=\"color: #d4b702; text-decoration-color: #d4b702\"> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</span>\n",
|
| 470 |
+
"</pre>\n"
|
| 471 |
+
],
|
| 472 |
+
"text/plain": [
|
| 473 |
+
"\u001b[38;2;212;183;2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[0m\u001b[1mStep \u001b[0m\u001b[1;36m3\u001b[0m\u001b[38;2;212;183;2m ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\n"
|
| 474 |
+
]
|
| 475 |
+
},
|
| 476 |
+
"metadata": {},
|
| 477 |
+
"output_type": "display_data"
|
| 478 |
+
},
|
| 479 |
+
{
|
| 480 |
+
"data": {
|
| 481 |
+
"text/html": [
|
| 482 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
|
| 483 |
+
"│ Calling tool: 'final_answer' with arguments: {'answer': \"For a party at Wayne's mansion, consider playing a mix │\n",
|
| 484 |
+
"│ of classic party hits and modern anthems to cater to various age groups. A recommended playlist might include │\n",
|
| 485 |
+
"│ songs like 'September' by Earth, Wind & Fire, 'I Gotta Feeling' by The Black Eyed Peas, 'Last Friday Night │\n",
|
| 486 |
+
"│ (T.G.I.F.)' by Katy Perry, 'Dancing Queen' by ABBA, 'Turn Down for What' by DJ Snake & Lil Jon, and 'Crank That │\n",
|
| 487 |
+
"│ (Soulja Boy)' by Soulja Boy Tell 'Em. These songs are known to get everyone dancing and celebrating!\"} │\n",
|
| 488 |
+
"╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
|
| 489 |
+
"</pre>\n"
|
| 490 |
+
],
|
| 491 |
+
"text/plain": [
|
| 492 |
+
"╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
|
| 493 |
+
"│ Calling tool: 'final_answer' with arguments: {'answer': \"For a party at Wayne's mansion, consider playing a mix │\n",
|
| 494 |
+
"│ of classic party hits and modern anthems to cater to various age groups. A recommended playlist might include │\n",
|
| 495 |
+
"│ songs like 'September' by Earth, Wind & Fire, 'I Gotta Feeling' by The Black Eyed Peas, 'Last Friday Night │\n",
|
| 496 |
+
"│ (T.G.I.F.)' by Katy Perry, 'Dancing Queen' by ABBA, 'Turn Down for What' by DJ Snake & Lil Jon, and 'Crank That │\n",
|
| 497 |
+
"│ (Soulja Boy)' by Soulja Boy Tell 'Em. These songs are known to get everyone dancing and celebrating!\"} │\n",
|
| 498 |
+
"╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n"
|
| 499 |
+
]
|
| 500 |
+
},
|
| 501 |
+
"metadata": {},
|
| 502 |
+
"output_type": "display_data"
|
| 503 |
+
},
|
| 504 |
+
{
|
| 505 |
+
"data": {
|
| 506 |
+
"text/html": [
|
| 507 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">Final answer: For a party at Wayne's mansion, consider playing a mix of classic party hits and modern anthems to </span>\n",
|
| 508 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">cater to various age groups. A recommended playlist might include songs like 'September' by Earth, Wind & Fire, 'I </span>\n",
|
| 509 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">Gotta Feeling' by The Black Eyed Peas, 'Last Friday Night (T.G.I.F.)' by Katy Perry, 'Dancing Queen' by ABBA, 'Turn</span>\n",
|
| 510 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">Down for What' by DJ Snake & Lil Jon, and 'Crank That (Soulja Boy)' by Soulja Boy Tell 'Em. These songs are known </span>\n",
|
| 511 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">to get everyone dancing and celebrating!</span>\n",
|
| 512 |
+
"</pre>\n"
|
| 513 |
+
],
|
| 514 |
+
"text/plain": [
|
| 515 |
+
"\u001b[1;38;2;212;183;2mFinal answer: For a party at Wayne's mansion, consider playing a mix of classic party hits and modern anthems to \u001b[0m\n",
|
| 516 |
+
"\u001b[1;38;2;212;183;2mcater to various age groups. A recommended playlist might include songs like 'September' by Earth, Wind & Fire, 'I \u001b[0m\n",
|
| 517 |
+
"\u001b[1;38;2;212;183;2mGotta Feeling' by The Black Eyed Peas, 'Last Friday Night (T.G.I.F.)' by Katy Perry, 'Dancing Queen' by ABBA, 'Turn\u001b[0m\n",
|
| 518 |
+
"\u001b[1;38;2;212;183;2mDown for What' by DJ Snake & Lil Jon, and 'Crank That (Soulja Boy)' by Soulja Boy Tell 'Em. These songs are known \u001b[0m\n",
|
| 519 |
+
"\u001b[1;38;2;212;183;2mto get everyone dancing and celebrating!\u001b[0m\n"
|
| 520 |
+
]
|
| 521 |
+
},
|
| 522 |
+
"metadata": {},
|
| 523 |
+
"output_type": "display_data"
|
| 524 |
+
},
|
| 525 |
+
{
|
| 526 |
+
"data": {
|
| 527 |
+
"text/html": [
|
| 528 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">[Step 2: Duration 10.69 seconds| Input tokens: 6,869 | Output tokens: 199]</span>\n",
|
| 529 |
+
"</pre>\n"
|
| 530 |
+
],
|
| 531 |
+
"text/plain": [
|
| 532 |
+
"\u001b[2m[Step 2: Duration 10.69 seconds| Input tokens: 6,869 | Output tokens: 199]\u001b[0m\n"
|
| 533 |
+
]
|
| 534 |
+
},
|
| 535 |
+
"metadata": {},
|
| 536 |
+
"output_type": "display_data"
|
| 537 |
+
},
|
| 538 |
+
{
|
| 539 |
+
"data": {
|
| 540 |
+
"application/vnd.google.colaboratory.intrinsic+json": {
|
| 541 |
+
"type": "string"
|
| 542 |
+
},
|
| 543 |
+
"text/plain": [
|
| 544 |
+
"\"For a party at Wayne's mansion, consider playing a mix of classic party hits and modern anthems to cater to various age groups. A recommended playlist might include songs like 'September' by Earth, Wind & Fire, 'I Gotta Feeling' by The Black Eyed Peas, 'Last Friday Night (T.G.I.F.)' by Katy Perry, 'Dancing Queen' by ABBA, 'Turn Down for What' by DJ Snake & Lil Jon, and 'Crank That (Soulja Boy)' by Soulja Boy Tell 'Em. These songs are known to get everyone dancing and celebrating!\""
|
| 545 |
+
]
|
| 546 |
+
},
|
| 547 |
+
"execution_count": 3,
|
| 548 |
+
"metadata": {},
|
| 549 |
+
"output_type": "execute_result"
|
| 550 |
+
}
|
| 551 |
+
],
|
| 552 |
+
"source": [
|
| 553 |
+
"from smolagents import ToolCallingAgent, DuckDuckGoSearchTool, HfApiModel\n",
|
| 554 |
+
"\n",
|
| 555 |
+
"agent = ToolCallingAgent(tools=[DuckDuckGoSearchTool()], model=HfApiModel())\n",
|
| 556 |
+
"\n",
|
| 557 |
+
"agent.run(\"Search for the best music recommendations for a party at the Wayne's mansion.\")"
|
| 558 |
+
]
|
| 559 |
+
},
|
| 560 |
+
{
|
| 561 |
+
"cell_type": "markdown",
|
| 562 |
+
"source": [
|
| 563 |
+
"\n",
|
| 564 |
+
"When you examine the agent's trace, instead of seeing `Executing parsed code:`, you'll see something like:\n",
|
| 565 |
+
"\n",
|
| 566 |
+
"```text\n",
|
| 567 |
+
"╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
|
| 568 |
+
"│ Calling tool: 'web_search' with arguments: {'query': \"best music recommendations for a party at Wayne's │\n",
|
| 569 |
+
"│ mansion\"} │\n",
|
| 570 |
+
"╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
|
| 571 |
+
"``` \n",
|
| 572 |
+
"\n",
|
| 573 |
+
"The agent generates a structured tool call that the system processes to produce the output, rather than directly executing code like a `CodeAgent`.\n",
|
| 574 |
+
"\n",
|
| 575 |
+
"Now that we understand both agent types, we can choose the right one for our needs. Let's continue exploring `smolagents` to make Alfred's party a success! 🎉"
|
| 576 |
+
],
|
| 577 |
+
"metadata": {
|
| 578 |
+
"id": "Cl19VWGRYXrr"
|
| 579 |
+
}
|
| 580 |
+
}
|
| 581 |
+
],
|
| 582 |
+
"metadata": {
|
| 583 |
+
"colab": {
|
| 584 |
+
"provenance": []
|
| 585 |
+
},
|
| 586 |
+
"kernelspec": {
|
| 587 |
+
"display_name": "Python 3",
|
| 588 |
+
"name": "python3"
|
| 589 |
+
},
|
| 590 |
+
"language_info": {
|
| 591 |
+
"name": "python"
|
| 592 |
+
}
|
| 593 |
+
},
|
| 594 |
+
"nbformat": 4,
|
| 595 |
+
"nbformat_minor": 0
|
| 596 |
+
}
|
unit2/smolagents/tools.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
unit2/smolagents/vision_agents.ipynb
ADDED
|
@@ -0,0 +1,535 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {
|
| 6 |
+
"id": "O7wvDb5Xq0ZH"
|
| 7 |
+
},
|
| 8 |
+
"source": [
|
| 9 |
+
"# Vision Agents with smolagents\n",
|
| 10 |
+
"\n",
|
| 11 |
+
"\n",
|
| 12 |
+
"This notebook is part of the [Hugging Face Agents Course](https://www.hf.co/learn/agents-course), a free Course from beginner to expert, where you learn to build Agents.\n",
|
| 13 |
+
"\n",
|
| 14 |
+
""
|
| 15 |
+
]
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"cell_type": "markdown",
|
| 19 |
+
"metadata": {
|
| 20 |
+
"id": "fqKoOdz8q6fF"
|
| 21 |
+
},
|
| 22 |
+
"source": [
|
| 23 |
+
"## Let's install the dependencies and login to our HF account to access the Inference API\n",
|
| 24 |
+
"\n",
|
| 25 |
+
"If you haven't installed `smolagents` yet, you can do so by running the following command:"
|
| 26 |
+
]
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"cell_type": "code",
|
| 30 |
+
"execution_count": null,
|
| 31 |
+
"metadata": {
|
| 32 |
+
"id": "m_muGXjDRhTD"
|
| 33 |
+
},
|
| 34 |
+
"outputs": [],
|
| 35 |
+
"source": [
|
| 36 |
+
"!pip install smolagents"
|
| 37 |
+
]
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"cell_type": "markdown",
|
| 41 |
+
"source": [
|
| 42 |
+
"Let's also login to the Hugging Face Hub to have access to the Inference API."
|
| 43 |
+
],
|
| 44 |
+
"metadata": {
|
| 45 |
+
"id": "WJGFjRbZbL50"
|
| 46 |
+
}
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
"cell_type": "code",
|
| 50 |
+
"execution_count": null,
|
| 51 |
+
"metadata": {
|
| 52 |
+
"id": "MnLNhxDzRiKh"
|
| 53 |
+
},
|
| 54 |
+
"outputs": [],
|
| 55 |
+
"source": [
|
| 56 |
+
"from huggingface_hub import notebook_login\n",
|
| 57 |
+
"\n",
|
| 58 |
+
"notebook_login()"
|
| 59 |
+
]
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"cell_type": "markdown",
|
| 63 |
+
"metadata": {
|
| 64 |
+
"id": "qOp72sO9q-TD"
|
| 65 |
+
},
|
| 66 |
+
"source": [
|
| 67 |
+
"## Providing Images at the Start of the Agent's Execution\n",
|
| 68 |
+
"\n",
|
| 69 |
+
"In this approach, images are passed to the agent at the start and stored as `task_images` alongside the task prompt. The agent then processes these images throughout its execution. \n",
|
| 70 |
+
"\n",
|
| 71 |
+
"Consider the case where Alfred wants to verify the identities of the superheroes attending the party. He already has a dataset of images from previous parties with the names of the guests. Given a new visitor's image, the agent can compare it with the existing dataset and make a decision about letting them in. \n",
|
| 72 |
+
"\n",
|
| 73 |
+
"In this case, a guest is trying to enter, and Alfred suspects that this visitor might be The Joker impersonating Wonder Woman. Alfred needs to verify their identity to prevent anyone unwanted from entering. \n",
|
| 74 |
+
"\n",
|
| 75 |
+
"Let’s build the example. First, the images are loaded. In this case, we use images from Wikipedia to keep the example minimal, but image the possible use-case!"
|
| 76 |
+
]
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"cell_type": "code",
|
| 80 |
+
"execution_count": null,
|
| 81 |
+
"metadata": {
|
| 82 |
+
"id": "BI9E3okPR5wc"
|
| 83 |
+
},
|
| 84 |
+
"outputs": [],
|
| 85 |
+
"source": [
|
| 86 |
+
"from PIL import Image\n",
|
| 87 |
+
"import requests\n",
|
| 88 |
+
"from io import BytesIO\n",
|
| 89 |
+
"\n",
|
| 90 |
+
"image_urls = [\n",
|
| 91 |
+
" \"https://upload.wikimedia.org/wikipedia/commons/e/e8/The_Joker_at_Wax_Museum_Plus.jpg\",\n",
|
| 92 |
+
" \"https://upload.wikimedia.org/wikipedia/en/9/98/Joker_%28DC_Comics_character%29.jpg\"\n",
|
| 93 |
+
"]\n",
|
| 94 |
+
"\n",
|
| 95 |
+
"images = []\n",
|
| 96 |
+
"for url in image_urls:\n",
|
| 97 |
+
" response = requests.get(url)\n",
|
| 98 |
+
" image = Image.open(BytesIO(response.content)).convert(\"RGB\")\n",
|
| 99 |
+
" images.append(image)"
|
| 100 |
+
]
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"cell_type": "markdown",
|
| 104 |
+
"source": [
|
| 105 |
+
"Now that we have the images, the agent will tell us wether the guests is actually a superhero (Wonder Woman) or a villian (The Joker)."
|
| 106 |
+
],
|
| 107 |
+
"metadata": {
|
| 108 |
+
"id": "vUBQjETkbRU6"
|
| 109 |
+
}
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"cell_type": "code",
|
| 113 |
+
"execution_count": null,
|
| 114 |
+
"metadata": {
|
| 115 |
+
"id": "6HroQ3eIT-3m"
|
| 116 |
+
},
|
| 117 |
+
"outputs": [],
|
| 118 |
+
"source": [
|
| 119 |
+
"from google.colab import userdata\n",
|
| 120 |
+
"import os\n",
|
| 121 |
+
"os.environ[\"OPENAI_API_KEY\"] = userdata.get('OPENAI_API_KEY')"
|
| 122 |
+
]
|
| 123 |
+
},
|
| 124 |
+
{
|
| 125 |
+
"cell_type": "code",
|
| 126 |
+
"execution_count": null,
|
| 127 |
+
"metadata": {
|
| 128 |
+
"colab": {
|
| 129 |
+
"base_uri": "https://localhost:8080/",
|
| 130 |
+
"height": 1000
|
| 131 |
+
},
|
| 132 |
+
"id": "A8qra0deRkUY",
|
| 133 |
+
"outputId": "2867daa1-e84e-4d02-ef10-eeeaf3ea863d"
|
| 134 |
+
},
|
| 135 |
+
"outputs": [
|
| 136 |
+
{
|
| 137 |
+
"data": {
|
| 138 |
+
"text/html": [
|
| 139 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d4b702; text-decoration-color: #d4b702\">╭──────────────────────────────────────────────────── </span><span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">New run</span><span style=\"color: #d4b702; text-decoration-color: #d4b702\"> ────────────────────────────────────────────────────╮</span>\n",
|
| 140 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span> <span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span>\n",
|
| 141 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span> <span style=\"font-weight: bold\">Describe the costume and makeup that the comic character in these photos is wearing and return the description.</span> <span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span>\n",
|
| 142 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span> <span style=\"font-weight: bold\"> Tell me if the guest is The Joker or Wonder Woman.</span> <span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span>\n",
|
| 143 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span> <span style=\"color: #d4b702; text-decoration-color: #d4b702\">│</span>\n",
|
| 144 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702\">╰─ OpenAIServerModel - gpt-4o ────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
| 145 |
+
"</pre>\n"
|
| 146 |
+
],
|
| 147 |
+
"text/plain": [
|
| 148 |
+
"\u001b[38;2;212;183;2m╭─\u001b[0m\u001b[38;2;212;183;2m───────────────────────────────────────────────────\u001b[0m\u001b[38;2;212;183;2m \u001b[0m\u001b[1;38;2;212;183;2mNew run\u001b[0m\u001b[38;2;212;183;2m \u001b[0m\u001b[38;2;212;183;2m───────────────────────────────────────────────────\u001b[0m\u001b[38;2;212;183;2m─╮\u001b[0m\n",
|
| 149 |
+
"\u001b[38;2;212;183;2m│\u001b[0m \u001b[38;2;212;183;2m│\u001b[0m\n",
|
| 150 |
+
"\u001b[38;2;212;183;2m│\u001b[0m \u001b[1mDescribe the costume and makeup that the comic character in these photos is wearing and return the description.\u001b[0m \u001b[38;2;212;183;2m│\u001b[0m\n",
|
| 151 |
+
"\u001b[38;2;212;183;2m│\u001b[0m \u001b[1m Tell me if the guest is The Joker or Wonder Woman.\u001b[0m \u001b[38;2;212;183;2m│\u001b[0m\n",
|
| 152 |
+
"\u001b[38;2;212;183;2m│\u001b[0m \u001b[38;2;212;183;2m│\u001b[0m\n",
|
| 153 |
+
"\u001b[38;2;212;183;2m╰─\u001b[0m\u001b[38;2;212;183;2m OpenAIServerModel - gpt-4o \u001b[0m\u001b[38;2;212;183;2m───────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b[38;2;212;183;2m─╯\u001b[0m\n"
|
| 154 |
+
]
|
| 155 |
+
},
|
| 156 |
+
"metadata": {},
|
| 157 |
+
"output_type": "display_data"
|
| 158 |
+
},
|
| 159 |
+
{
|
| 160 |
+
"data": {
|
| 161 |
+
"text/html": [
|
| 162 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d4b702; text-decoration-color: #d4b702\">━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ </span><span style=\"font-weight: bold\">Step </span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"color: #d4b702; text-decoration-color: #d4b702\"> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</span>\n",
|
| 163 |
+
"</pre>\n"
|
| 164 |
+
],
|
| 165 |
+
"text/plain": [
|
| 166 |
+
"\u001b[38;2;212;183;2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[0m\u001b[1mStep \u001b[0m\u001b[1;36m1\u001b[0m\u001b[38;2;212;183;2m ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━��━━━━━━━━━━━━━━━━━━━\u001b[0m\n"
|
| 167 |
+
]
|
| 168 |
+
},
|
| 169 |
+
"metadata": {},
|
| 170 |
+
"output_type": "display_data"
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"data": {
|
| 174 |
+
"text/html": [
|
| 175 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold; font-style: italic\">Output message of the LLM:</span> <span style=\"color: #d4b702; text-decoration-color: #d4b702\">────────────────────────────────────────────────────────────────────────────────────────</span>\n",
|
| 176 |
+
"<span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">I don't have the capability to identify or recognize people in images, but I can describe what I see.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 177 |
+
"<span style=\"background-color: #0d1117\"> </span>\n",
|
| 178 |
+
"<span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">The character in the photos you provided is wearing:</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 179 |
+
"<span style=\"background-color: #0d1117\"> </span>\n",
|
| 180 |
+
"<span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117\">1.</span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\"> </span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117; font-weight: bold\">**Costume:**</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 181 |
+
"<span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117\">-</span><span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">A purple suit with a large bow tie in one image.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 182 |
+
"<span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117\">-</span><span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">A white flower lapel and card in another image.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 183 |
+
"<span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117\">-</span><span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">The style is flamboyant and colorful, typical of a comic villain.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 184 |
+
"<span style=\"background-color: #0d1117\"> </span>\n",
|
| 185 |
+
"<span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117\">2.</span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\"> </span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117; font-weight: bold\">**Makeup:**</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 186 |
+
"<span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117\">-</span><span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">White face makeup covering the entire face.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 187 |
+
"<span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117\">-</span><span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">Red lips forming a wide, exaggerated smile.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 188 |
+
"<span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117\">-</span><span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">Dark makeup around the eyes.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 189 |
+
"<span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117\">-</span><span style=\"color: #6e7681; text-decoration-color: #6e7681; background-color: #0d1117\"> </span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">Green hair.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 190 |
+
"<span style=\"background-color: #0d1117\"> </span>\n",
|
| 191 |
+
"<span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">From the description, this character resembles The Joker, a well-known comic book villain.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 192 |
+
"</pre>\n"
|
| 193 |
+
],
|
| 194 |
+
"text/plain": [
|
| 195 |
+
"\u001b[1;3mOutput message of the LLM:\u001b[0m \u001b[38;2;212;183;2m────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\n",
|
| 196 |
+
"\u001b[38;2;230;237;243;48;2;13;17;23mI\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mdon't\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mhave\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mthe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcapability\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mto\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23midentify\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mor\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mrecognize\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mpeople\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23min\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mimages,\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mbut\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mI\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcan\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mdescribe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mwhat\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mI\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23msee.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 197 |
+
"\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 198 |
+
"\u001b[38;2;230;237;243;48;2;13;17;23mThe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcharacter\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23min\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mthe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mphotos\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23myou\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mprovided\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mis\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mwearing:\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 199 |
+
"\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 200 |
+
"\u001b[38;2;255;123;114;48;2;13;17;23m1.\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[1;38;2;230;237;243;48;2;13;17;23m**Costume:**\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 201 |
+
"\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;255;123;114;48;2;13;17;23m-\u001b[0m\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mA\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mpurple\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23msuit\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mwith\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23ma\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mlarge\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mbow\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mtie\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23min\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mone\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mimage.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 202 |
+
"\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;255;123;114;48;2;13;17;23m-\u001b[0m\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mA\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mwhite\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mflower\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mlapel\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mand\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcard\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23min\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23manother\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mimage.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 203 |
+
"\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;255;123;114;48;2;13;17;23m-\u001b[0m\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mThe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mstyle\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mis\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mflamboyant\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mand\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcolorful,\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mtypical\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mof\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23ma\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcomic\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mvillain.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 204 |
+
"\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 205 |
+
"\u001b[38;2;255;123;114;48;2;13;17;23m2.\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[1;38;2;230;237;243;48;2;13;17;23m**Makeup:**\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 206 |
+
"\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;255;123;114;48;2;13;17;23m-\u001b[0m\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mWhite\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mface\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mmakeup\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcovering\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mthe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mentire\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mface.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 207 |
+
"\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;255;123;114;48;2;13;17;23m-\u001b[0m\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mRed\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mlips\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mforming\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23ma\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mwide,\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mexaggerated\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23msmile.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 208 |
+
"\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;255;123;114;48;2;13;17;23m-\u001b[0m\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mDark\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mmakeup\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23maround\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mthe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23meyes.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 209 |
+
"\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;255;123;114;48;2;13;17;23m-\u001b[0m\u001b[38;2;110;118;129;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mGreen\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mhair.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 210 |
+
"\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 211 |
+
"\u001b[38;2;230;237;243;48;2;13;17;23mFrom\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mthe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mdescription,\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mthis\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcharacter\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mresembles\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mThe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mJoker,\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23ma\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mwell-known\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcomic\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mbook\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mvillain.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n"
|
| 212 |
+
]
|
| 213 |
+
},
|
| 214 |
+
"metadata": {},
|
| 215 |
+
"output_type": "display_data"
|
| 216 |
+
},
|
| 217 |
+
{
|
| 218 |
+
"data": {
|
| 219 |
+
"text/html": [
|
| 220 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">Error in code parsing:</span>\n",
|
| 221 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">Your code snippet is invalid, because the regex pattern ```(?:py|python)?\\n(.*?)\\n``` was not found in it.</span>\n",
|
| 222 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">Here is your code snippet:</span>\n",
|
| 223 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">I don't have the capability to identify or recognize people in images, but I can describe what I see.</span>\n",
|
| 224 |
+
"\n",
|
| 225 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">The character in the photos you provided is wearing:</span>\n",
|
| 226 |
+
"\n",
|
| 227 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">1</span><span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">. **Costume:**</span>\n",
|
| 228 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\"> - A purple suit with a large bow tie in one image.</span>\n",
|
| 229 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\"> - A white flower lapel and card in another image.</span>\n",
|
| 230 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\"> - The style is flamboyant and colorful, typical of a comic villain.</span>\n",
|
| 231 |
+
"\n",
|
| 232 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">2</span><span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">. **Makeup:**</span>\n",
|
| 233 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\"> - White face makeup covering the entire face.</span>\n",
|
| 234 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\"> - Red lips forming a wide, exaggerated smile.</span>\n",
|
| 235 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\"> - Dark makeup around the eyes.</span>\n",
|
| 236 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\"> - Green hair.</span>\n",
|
| 237 |
+
"\n",
|
| 238 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">From the description, this character resembles The Joker, a well-known comic book villain.</span>\n",
|
| 239 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">Make sure to include code with the correct pattern, for instance:</span>\n",
|
| 240 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">Thoughts: Your thoughts</span>\n",
|
| 241 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">Code:</span>\n",
|
| 242 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">```py</span>\n",
|
| 243 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\"># Your python code here</span>\n",
|
| 244 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">```<end_code></span>\n",
|
| 245 |
+
"<span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">Make sure to provide correct code blobs.</span>\n",
|
| 246 |
+
"</pre>\n"
|
| 247 |
+
],
|
| 248 |
+
"text/plain": [
|
| 249 |
+
"\u001b[1;31mError in code parsing:\u001b[0m\n",
|
| 250 |
+
"\u001b[1;31mYour code snippet is invalid, because the regex pattern ```\u001b[0m\u001b[1;31m(\u001b[0m\u001b[1;31m?:py|python\u001b[0m\u001b[1;31m)\u001b[0m\u001b[1;31m?\\\u001b[0m\u001b[1;31mn\u001b[0m\u001b[1;31m(\u001b[0m\u001b[1;31m.*?\u001b[0m\u001b[1;31m)\u001b[0m\u001b[1;31m\\n``` was not found in it.\u001b[0m\n",
|
| 251 |
+
"\u001b[1;31mHere is your code snippet:\u001b[0m\n",
|
| 252 |
+
"\u001b[1;31mI don't have the capability to identify or recognize people in images, but I can describe what I see.\u001b[0m\n",
|
| 253 |
+
"\n",
|
| 254 |
+
"\u001b[1;31mThe character in the photos you provided is wearing:\u001b[0m\n",
|
| 255 |
+
"\n",
|
| 256 |
+
"\u001b[1;31m1\u001b[0m\u001b[1;31m. **Costume:**\u001b[0m\n",
|
| 257 |
+
"\u001b[1;31m - A purple suit with a large bow tie in one image.\u001b[0m\n",
|
| 258 |
+
"\u001b[1;31m - A white flower lapel and card in another image.\u001b[0m\n",
|
| 259 |
+
"\u001b[1;31m - The style is flamboyant and colorful, typical of a comic villain.\u001b[0m\n",
|
| 260 |
+
"\n",
|
| 261 |
+
"\u001b[1;31m2\u001b[0m\u001b[1;31m. **Makeup:**\u001b[0m\n",
|
| 262 |
+
"\u001b[1;31m - White face makeup covering the entire face.\u001b[0m\n",
|
| 263 |
+
"\u001b[1;31m - Red lips forming a wide, exaggerated smile.\u001b[0m\n",
|
| 264 |
+
"\u001b[1;31m - Dark makeup around the eyes.\u001b[0m\n",
|
| 265 |
+
"\u001b[1;31m - Green hair.\u001b[0m\n",
|
| 266 |
+
"\n",
|
| 267 |
+
"\u001b[1;31mFrom the description, this character resembles The Joker, a well-known comic book villain.\u001b[0m\n",
|
| 268 |
+
"\u001b[1;31mMake sure to include code with the correct pattern, for instance:\u001b[0m\n",
|
| 269 |
+
"\u001b[1;31mThoughts: Your thoughts\u001b[0m\n",
|
| 270 |
+
"\u001b[1;31mCode:\u001b[0m\n",
|
| 271 |
+
"\u001b[1;31m```py\u001b[0m\n",
|
| 272 |
+
"\u001b[1;31m# Your python code here\u001b[0m\n",
|
| 273 |
+
"\u001b[1;31m```\u001b[0m\u001b[1;31m<\u001b[0m\u001b[1;31mend_code\u001b[0m\u001b[1;31m>\u001b[0m\n",
|
| 274 |
+
"\u001b[1;31mMake sure to provide correct code blobs.\u001b[0m\n"
|
| 275 |
+
]
|
| 276 |
+
},
|
| 277 |
+
"metadata": {},
|
| 278 |
+
"output_type": "display_data"
|
| 279 |
+
},
|
| 280 |
+
{
|
| 281 |
+
"data": {
|
| 282 |
+
"text/html": [
|
| 283 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">[Step 0: Duration 4.30 seconds| Input tokens: 3,004 | Output tokens: 139]</span>\n",
|
| 284 |
+
"</pre>\n"
|
| 285 |
+
],
|
| 286 |
+
"text/plain": [
|
| 287 |
+
"\u001b[2m[Step 0: Duration 4.30 seconds| Input tokens: 3,004 | Output tokens: 139]\u001b[0m\n"
|
| 288 |
+
]
|
| 289 |
+
},
|
| 290 |
+
"metadata": {},
|
| 291 |
+
"output_type": "display_data"
|
| 292 |
+
},
|
| 293 |
+
{
|
| 294 |
+
"data": {
|
| 295 |
+
"text/html": [
|
| 296 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d4b702; text-decoration-color: #d4b702\">━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ </span><span style=\"font-weight: bold\">Step </span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span><span style=\"color: #d4b702; text-decoration-color: #d4b702\"> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</span>\n",
|
| 297 |
+
"</pre>\n"
|
| 298 |
+
],
|
| 299 |
+
"text/plain": [
|
| 300 |
+
"\u001b[38;2;212;183;2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[0m\u001b[1mStep \u001b[0m\u001b[1;36m2\u001b[0m\u001b[38;2;212;183;2m ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\n"
|
| 301 |
+
]
|
| 302 |
+
},
|
| 303 |
+
"metadata": {},
|
| 304 |
+
"output_type": "display_data"
|
| 305 |
+
},
|
| 306 |
+
{
|
| 307 |
+
"data": {
|
| 308 |
+
"text/html": [
|
| 309 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold; font-style: italic\">Output message of the LLM:</span> <span style=\"color: #d4b702; text-decoration-color: #d4b702\">────────────────────────────────────────────────────────────────────────────────────────</span>\n",
|
| 310 |
+
"<span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">I'm unable to identify characters in images, but I can offer a description.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 311 |
+
"<span style=\"background-color: #0d1117\"> </span>\n",
|
| 312 |
+
"<span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">Thought: From the images, I will describe the costume and makeup.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 313 |
+
"<span style=\"background-color: #0d1117\"> </span>\n",
|
| 314 |
+
"<span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">Code:</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 315 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\">```py</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 316 |
+
"<span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">description </span><span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117; font-weight: bold\">=</span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\"> </span><span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\">\"\"\"</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 317 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\">1. Costume:</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 318 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\"> - A purple suit with a yellow shirt and a large purple bow tie.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 319 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\"> - Features a white flower lapel and a playing card in the second image.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 320 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\"> - The style is flamboyant, consistent with a comic villain.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 321 |
+
"<span style=\"background-color: #0d1117\"> </span>\n",
|
| 322 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\">2. Makeup:</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 323 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\"> - White face makeup covering the entire face.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 324 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\"> - Red lips forming a wide, exaggerated smile.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 325 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\"> - Blue eyeshadow with dark eye accents.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 326 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\"> - Slicked-back green hair.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 327 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\">\"\"\"</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 328 |
+
"<span style=\"background-color: #0d1117\"> </span>\n",
|
| 329 |
+
"<span style=\"color: #8b949e; text-decoration-color: #8b949e; background-color: #0d1117; font-style: italic\"># Based on the description, this character resembles The Joker.</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 330 |
+
"<span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">character </span><span style=\"color: #ff7b72; text-decoration-color: #ff7b72; background-color: #0d1117; font-weight: bold\">=</span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\"> </span><span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\">\"The Joker\"</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 331 |
+
"<span style=\"background-color: #0d1117\"> </span>\n",
|
| 332 |
+
"<span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">final_answer({</span><span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\">\"description\"</span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">: description, </span><span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\">\"character\"</span><span style=\"color: #e6edf3; text-decoration-color: #e6edf3; background-color: #0d1117\">: character})</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 333 |
+
"<span style=\"color: #a5d6ff; text-decoration-color: #a5d6ff; background-color: #0d1117\">```</span><span style=\"background-color: #0d1117\"> </span>\n",
|
| 334 |
+
"</pre>\n"
|
| 335 |
+
],
|
| 336 |
+
"text/plain": [
|
| 337 |
+
"\u001b[1;3mOutput message of the LLM:\u001b[0m \u001b[38;2;212;183;2m────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\n",
|
| 338 |
+
"\u001b[38;2;230;237;243;48;2;13;17;23mI'm\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23munable\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mto\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23midentify\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcharacters\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23min\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mimages,\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mbut\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mI\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcan\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23moffer\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23ma\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mdescription.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 339 |
+
"\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 340 |
+
"\u001b[38;2;230;237;243;48;2;13;17;23mThought:\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mFrom\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mthe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mimages,\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mI\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mwill\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mdescribe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mthe\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcostume\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mand\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mmakeup.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 341 |
+
"\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 342 |
+
"\u001b[38;2;230;237;243;48;2;13;17;23mCode:\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 343 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m```\u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23mpy\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 344 |
+
"\u001b[38;2;230;237;243;48;2;13;17;23mdescription\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[1;38;2;255;123;114;48;2;13;17;23m=\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23m\"\"\"\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 345 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m1. Costume:\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 346 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m - A purple suit with a yellow shirt and a large purple bow tie.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 347 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m - Features a white flower lapel and a playing card in the second image.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 348 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m - The style is flamboyant, consistent with a comic villain.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 349 |
+
"\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 350 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m2. Makeup:\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 351 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m - White face makeup covering the entire face.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 352 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m - Red lips forming a wide, exaggerated smile.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 353 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m - Blue eyeshadow with dark eye accents.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 354 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m - Slicked-back green hair.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 355 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m\"\"\"\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 356 |
+
"\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 357 |
+
"\u001b[3;38;2;139;148;158;48;2;13;17;23m# Based on the description, this character resembles The Joker.\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 358 |
+
"\u001b[38;2;230;237;243;48;2;13;17;23mcharacter\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[1;38;2;255;123;114;48;2;13;17;23m=\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23m\"\u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23mThe Joker\u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23m\"\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 359 |
+
"\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 360 |
+
"\u001b[38;2;230;237;243;48;2;13;17;23mfinal_answer\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m(\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m{\u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23m\"\u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23mdescription\u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23m\"\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m:\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mdescription\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m,\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23m\"\u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23mcharacter\u001b[0m\u001b[38;2;165;214;255;48;2;13;17;23m\"\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m:\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m \u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23mcharacter\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m}\u001b[0m\u001b[38;2;230;237;243;48;2;13;17;23m)\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n",
|
| 361 |
+
"\u001b[38;2;165;214;255;48;2;13;17;23m```\u001b[0m\u001b[48;2;13;17;23m \u001b[0m\n"
|
| 362 |
+
]
|
| 363 |
+
},
|
| 364 |
+
"metadata": {},
|
| 365 |
+
"output_type": "display_data"
|
| 366 |
+
},
|
| 367 |
+
{
|
| 368 |
+
"data": {
|
| 369 |
+
"text/html": [
|
| 370 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"> ─ <span style=\"font-weight: bold\">Executing parsed code:</span> ──────────────────────────────────────────────────────────────────────────────────────── \n",
|
| 371 |
+
" <span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">description </span><span style=\"color: #ff4689; text-decoration-color: #ff4689; background-color: #272822\">=</span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\"> </span><span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\">\"\"\"</span><span style=\"background-color: #272822\"> </span> \n",
|
| 372 |
+
" <span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\">1. Costume:</span><span style=\"background-color: #272822\"> </span> \n",
|
| 373 |
+
" <span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\"> - A purple suit with a yellow shirt and a large purple bow tie.</span><span style=\"background-color: #272822\"> </span> \n",
|
| 374 |
+
" <span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\"> - Features a white flower lapel and a playing card in the second image.</span><span style=\"background-color: #272822\"> </span> \n",
|
| 375 |
+
" <span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\"> - The style is flamboyant, consistent with a comic villain.</span><span style=\"background-color: #272822\"> </span> \n",
|
| 376 |
+
" <span style=\"background-color: #272822\"> </span> \n",
|
| 377 |
+
" <span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\">2. Makeup:</span><span style=\"background-color: #272822\"> </span> \n",
|
| 378 |
+
" <span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\"> - White face makeup covering the entire face.</span><span style=\"background-color: #272822\"> </span> \n",
|
| 379 |
+
" <span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\"> - Red lips forming a wide, exaggerated smile.</span><span style=\"background-color: #272822\"> </span> \n",
|
| 380 |
+
" <span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\"> - Blue eyeshadow with dark eye accents.</span><span style=\"background-color: #272822\"> </span> \n",
|
| 381 |
+
" <span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\"> - Slicked-back green hair.</span><span style=\"background-color: #272822\"> </span> \n",
|
| 382 |
+
" <span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\">\"\"\"</span><span style=\"background-color: #272822\"> </span> \n",
|
| 383 |
+
" <span style=\"background-color: #272822\"> </span> \n",
|
| 384 |
+
" <span style=\"color: #959077; text-decoration-color: #959077; background-color: #272822\"># Based on the description, this character resembles The Joker.</span><span style=\"background-color: #272822\"> </span> \n",
|
| 385 |
+
" <span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">character </span><span style=\"color: #ff4689; text-decoration-color: #ff4689; background-color: #272822\">=</span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\"> </span><span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\">\"The Joker\"</span><span style=\"background-color: #272822\"> </span> \n",
|
| 386 |
+
" <span style=\"background-color: #272822\"> </span> \n",
|
| 387 |
+
" <span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">final_answer({</span><span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\">\"description\"</span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">: description, </span><span style=\"color: #e6db74; text-decoration-color: #e6db74; background-color: #272822\">\"character\"</span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">: character})</span><span style=\"background-color: #272822\"> </span> \n",
|
| 388 |
+
" ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── \n",
|
| 389 |
+
"</pre>\n"
|
| 390 |
+
],
|
| 391 |
+
"text/plain": [
|
| 392 |
+
" ─ \u001b[1mExecuting parsed code:\u001b[0m ──────────────────────────────────────────────────────────────────────────────────────── \n",
|
| 393 |
+
" \u001b[38;2;248;248;242;48;2;39;40;34mdescription\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m=\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"\"\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 394 |
+
" \u001b[38;2;230;219;116;48;2;39;40;34m1. Costume:\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 395 |
+
" \u001b[38;2;230;219;116;48;2;39;40;34m - A purple suit with a yellow shirt and a large purple bow tie.\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 396 |
+
" \u001b[38;2;230;219;116;48;2;39;40;34m - Features a white flower lapel and a playing card in the second image.\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 397 |
+
" \u001b[38;2;230;219;116;48;2;39;40;34m - The style is flamboyant, consistent with a comic villain.\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 398 |
+
" \u001b[48;2;39;40;34m \u001b[0m \n",
|
| 399 |
+
" \u001b[38;2;230;219;116;48;2;39;40;34m2. Makeup:\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 400 |
+
" \u001b[38;2;230;219;116;48;2;39;40;34m - White face makeup covering the entire face.\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 401 |
+
" \u001b[38;2;230;219;116;48;2;39;40;34m - Red lips forming a wide, exaggerated smile.\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 402 |
+
" \u001b[38;2;230;219;116;48;2;39;40;34m - Blue eyeshadow with dark eye accents.\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 403 |
+
" \u001b[38;2;230;219;116;48;2;39;40;34m - Slicked-back green hair.\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 404 |
+
" \u001b[38;2;230;219;116;48;2;39;40;34m\"\"\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 405 |
+
" \u001b[48;2;39;40;34m \u001b[0m \n",
|
| 406 |
+
" \u001b[38;2;149;144;119;48;2;39;40;34m# Based on the description, this character resembles The Joker.\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 407 |
+
" \u001b[38;2;248;248;242;48;2;39;40;34mcharacter\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m=\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"\u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mThe Joker\u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 408 |
+
" \u001b[48;2;39;40;34m \u001b[0m \n",
|
| 409 |
+
" \u001b[38;2;248;248;242;48;2;39;40;34mfinal_answer\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m(\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"\u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mdescription\u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mdescription\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"\u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mcharacter\u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mcharacter\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m)\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n",
|
| 410 |
+
" ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── \n"
|
| 411 |
+
]
|
| 412 |
+
},
|
| 413 |
+
"metadata": {},
|
| 414 |
+
"output_type": "display_data"
|
| 415 |
+
},
|
| 416 |
+
{
|
| 417 |
+
"data": {
|
| 418 |
+
"text/html": [
|
| 419 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">Out - Final answer: {'description': '\\n1. Costume:\\n - A purple suit with a yellow shirt and a large purple bow </span>\n",
|
| 420 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">tie.\\n - Features a white flower lapel and a playing card in the second image.\\n - The style is flamboyant, </span>\n",
|
| 421 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">consistent with a comic villain.\\n\\n2. Makeup:\\n - White face makeup covering the entire face.\\n - Red lips </span>\n",
|
| 422 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">forming a wide, exaggerated smile.\\n - Blue eyeshadow with dark eye accents.\\n - Slicked-back green hair.\\n', </span>\n",
|
| 423 |
+
"<span style=\"color: #d4b702; text-decoration-color: #d4b702; font-weight: bold\">'character': 'The Joker'}</span>\n",
|
| 424 |
+
"</pre>\n"
|
| 425 |
+
],
|
| 426 |
+
"text/plain": [
|
| 427 |
+
"\u001b[1;38;2;212;183;2mOut - Final answer: {'description': '\\n1. Costume:\\n - A purple suit with a yellow shirt and a large purple bow \u001b[0m\n",
|
| 428 |
+
"\u001b[1;38;2;212;183;2mtie.\\n - Features a white flower lapel and a playing card in the second image.\\n - The style is flamboyant, \u001b[0m\n",
|
| 429 |
+
"\u001b[1;38;2;212;183;2mconsistent with a comic villain.\\n\\n2. Makeup:\\n - White face makeup covering the entire face.\\n - Red lips \u001b[0m\n",
|
| 430 |
+
"\u001b[1;38;2;212;183;2mforming a wide, exaggerated smile.\\n - Blue eyeshadow with dark eye accents.\\n - Slicked-back green hair.\\n', \u001b[0m\n",
|
| 431 |
+
"\u001b[1;38;2;212;183;2m'character': 'The Joker'}\u001b[0m\n"
|
| 432 |
+
]
|
| 433 |
+
},
|
| 434 |
+
"metadata": {},
|
| 435 |
+
"output_type": "display_data"
|
| 436 |
+
},
|
| 437 |
+
{
|
| 438 |
+
"data": {
|
| 439 |
+
"text/html": [
|
| 440 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">[Step 1: Duration 7.36 seconds| Input tokens: 7,431 | Output tokens: 302]</span>\n",
|
| 441 |
+
"</pre>\n"
|
| 442 |
+
],
|
| 443 |
+
"text/plain": [
|
| 444 |
+
"\u001b[2m[Step 1: Duration 7.36 seconds| Input tokens: 7,431 | Output tokens: 302]\u001b[0m\n"
|
| 445 |
+
]
|
| 446 |
+
},
|
| 447 |
+
"metadata": {},
|
| 448 |
+
"output_type": "display_data"
|
| 449 |
+
}
|
| 450 |
+
],
|
| 451 |
+
"source": [
|
| 452 |
+
"from smolagents import CodeAgent, OpenAIServerModel\n",
|
| 453 |
+
"\n",
|
| 454 |
+
"model = OpenAIServerModel(model_id=\"gpt-4o\")\n",
|
| 455 |
+
"\n",
|
| 456 |
+
"# Instantiate the agent\n",
|
| 457 |
+
"agent = CodeAgent(\n",
|
| 458 |
+
" tools=[],\n",
|
| 459 |
+
" model=model,\n",
|
| 460 |
+
" max_steps=20,\n",
|
| 461 |
+
" verbosity_level=2\n",
|
| 462 |
+
")\n",
|
| 463 |
+
"\n",
|
| 464 |
+
"response = agent.run(\n",
|
| 465 |
+
" \"\"\"\n",
|
| 466 |
+
" Describe the costume and makeup that the comic character in these photos is wearing and return the description.\n",
|
| 467 |
+
" Tell me if the guest is The Joker or Wonder Woman.\n",
|
| 468 |
+
" \"\"\",\n",
|
| 469 |
+
" images=images\n",
|
| 470 |
+
")"
|
| 471 |
+
]
|
| 472 |
+
},
|
| 473 |
+
{
|
| 474 |
+
"cell_type": "code",
|
| 475 |
+
"execution_count": null,
|
| 476 |
+
"metadata": {
|
| 477 |
+
"colab": {
|
| 478 |
+
"base_uri": "https://localhost:8080/"
|
| 479 |
+
},
|
| 480 |
+
"id": "uvKj37AmeIu0",
|
| 481 |
+
"outputId": "ed7984d4-f6a2-4062-9939-41cb2e97b3b2"
|
| 482 |
+
},
|
| 483 |
+
"outputs": [
|
| 484 |
+
{
|
| 485 |
+
"data": {
|
| 486 |
+
"text/plain": [
|
| 487 |
+
"{'description': '\\n1. Costume:\\n - A purple suit with a yellow shirt and a large purple bow tie.\\n - Features a white flower lapel and a playing card in the second image.\\n - The style is flamboyant, consistent with a comic villain.\\n\\n2. Makeup:\\n - White face makeup covering the entire face.\\n - Red lips forming a wide, exaggerated smile.\\n - Blue eyeshadow with dark eye accents.\\n - Slicked-back green hair.\\n',\n",
|
| 488 |
+
" 'character': 'The Joker'}"
|
| 489 |
+
]
|
| 490 |
+
},
|
| 491 |
+
"execution_count": 40,
|
| 492 |
+
"metadata": {},
|
| 493 |
+
"output_type": "execute_result"
|
| 494 |
+
}
|
| 495 |
+
],
|
| 496 |
+
"source": [
|
| 497 |
+
"response"
|
| 498 |
+
]
|
| 499 |
+
},
|
| 500 |
+
{
|
| 501 |
+
"cell_type": "markdown",
|
| 502 |
+
"source": [
|
| 503 |
+
"In this case, the output reveals that the person is impersonating someone else, so we can prevent The Joker from entering the party!"
|
| 504 |
+
],
|
| 505 |
+
"metadata": {
|
| 506 |
+
"id": "NrV-yK5zbT9r"
|
| 507 |
+
}
|
| 508 |
+
},
|
| 509 |
+
{
|
| 510 |
+
"cell_type": "markdown",
|
| 511 |
+
"metadata": {
|
| 512 |
+
"id": "ziyfk-3ZrHw5"
|
| 513 |
+
},
|
| 514 |
+
"source": [
|
| 515 |
+
"## Providing Images with Dynamic Retrieval\n",
|
| 516 |
+
"\n",
|
| 517 |
+
"This examples is provided as a `.py` file since it needs to be run locally since it'll browse the web. Go to the [Hugging Face Agents Course](https://www.hf.co/learn/agents-course) for more details."
|
| 518 |
+
]
|
| 519 |
+
}
|
| 520 |
+
],
|
| 521 |
+
"metadata": {
|
| 522 |
+
"colab": {
|
| 523 |
+
"provenance": []
|
| 524 |
+
},
|
| 525 |
+
"kernelspec": {
|
| 526 |
+
"display_name": "Python 3",
|
| 527 |
+
"name": "python3"
|
| 528 |
+
},
|
| 529 |
+
"language_info": {
|
| 530 |
+
"name": "python"
|
| 531 |
+
}
|
| 532 |
+
},
|
| 533 |
+
"nbformat": 4,
|
| 534 |
+
"nbformat_minor": 0
|
| 535 |
+
}
|
unit2/smolagents/vision_web_browser.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
from io import BytesIO
|
| 3 |
+
from time import sleep
|
| 4 |
+
|
| 5 |
+
import helium
|
| 6 |
+
from dotenv import load_dotenv
|
| 7 |
+
from PIL import Image
|
| 8 |
+
from selenium import webdriver
|
| 9 |
+
from selenium.webdriver.common.by import By
|
| 10 |
+
from selenium.webdriver.common.keys import Keys
|
| 11 |
+
|
| 12 |
+
from smolagents import CodeAgent, DuckDuckGoSearchTool, tool
|
| 13 |
+
from smolagents.agents import ActionStep
|
| 14 |
+
from smolagents.cli import load_model
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
alfred_guest_list_request = """
|
| 18 |
+
I am Alfred, the butler of Wayne Manor, responsible for verifying the identity of guests at party. A superhero has arrived at the entrance claiming to be Wonder Woman, but I need to confirm if she is who she says she is.
|
| 19 |
+
|
| 20 |
+
Please search for images of Wonder Woman and generate a detailed visual description based on those images. Additionally, navigate to Wikipedia to gather key details about her appearance. With this information, I can determine whether to grant her access to the event.
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def parse_arguments():
|
| 25 |
+
parser = argparse.ArgumentParser(description="Run a web browser automation script with a specified model.")
|
| 26 |
+
parser.add_argument(
|
| 27 |
+
"prompt",
|
| 28 |
+
type=str,
|
| 29 |
+
nargs="?", # Makes it optional
|
| 30 |
+
default=alfred_guest_list_request,
|
| 31 |
+
help="The prompt to run with the agent",
|
| 32 |
+
)
|
| 33 |
+
parser.add_argument(
|
| 34 |
+
"--model-type",
|
| 35 |
+
type=str,
|
| 36 |
+
default="LiteLLMModel",
|
| 37 |
+
help="The model type to use (e.g., OpenAIServerModel, LiteLLMModel, TransformersModel, HfApiModel)",
|
| 38 |
+
)
|
| 39 |
+
parser.add_argument(
|
| 40 |
+
"--model-id",
|
| 41 |
+
type=str,
|
| 42 |
+
default="gpt-4o",
|
| 43 |
+
help="The model ID to use for the specified model type",
|
| 44 |
+
)
|
| 45 |
+
return parser.parse_args()
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def save_screenshot(memory_step: ActionStep, agent: CodeAgent) -> None:
|
| 49 |
+
sleep(1.0) # Let JavaScript animations happen before taking the screenshot
|
| 50 |
+
driver = helium.get_driver()
|
| 51 |
+
current_step = memory_step.step_number
|
| 52 |
+
if driver is not None:
|
| 53 |
+
for previous_memory_step in agent.memory.steps: # Remove previous screenshots from logs for lean processing
|
| 54 |
+
if isinstance(previous_memory_step, ActionStep) and previous_memory_step.step_number <= current_step - 2:
|
| 55 |
+
previous_memory_step.observations_images = None
|
| 56 |
+
png_bytes = driver.get_screenshot_as_png()
|
| 57 |
+
image = Image.open(BytesIO(png_bytes))
|
| 58 |
+
print(f"Captured a browser screenshot: {image.size} pixels")
|
| 59 |
+
memory_step.observations_images = [image.copy()] # Create a copy to ensure it persists, important!
|
| 60 |
+
|
| 61 |
+
# Update observations with current URL
|
| 62 |
+
url_info = f"Current url: {driver.current_url}"
|
| 63 |
+
memory_step.observations = (
|
| 64 |
+
url_info if memory_step.observations is None else memory_step.observations + "\n" + url_info
|
| 65 |
+
)
|
| 66 |
+
return
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
@tool
|
| 70 |
+
def search_item_ctrl_f(text: str, nth_result: int = 1) -> str:
|
| 71 |
+
"""
|
| 72 |
+
Searches for text on the current page via Ctrl + F and jumps to the nth occurrence.
|
| 73 |
+
Args:
|
| 74 |
+
text: The text to search for
|
| 75 |
+
nth_result: Which occurrence to jump to (default: 1)
|
| 76 |
+
"""
|
| 77 |
+
elements = driver.find_elements(By.XPATH, f"//*[contains(text(), '{text}')]")
|
| 78 |
+
if nth_result > len(elements):
|
| 79 |
+
raise Exception(f"Match n°{nth_result} not found (only {len(elements)} matches found)")
|
| 80 |
+
result = f"Found {len(elements)} matches for '{text}'."
|
| 81 |
+
elem = elements[nth_result - 1]
|
| 82 |
+
driver.execute_script("arguments[0].scrollIntoView(true);", elem)
|
| 83 |
+
result += f"Focused on element {nth_result} of {len(elements)}"
|
| 84 |
+
return result
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
@tool
|
| 88 |
+
def go_back() -> None:
|
| 89 |
+
"""Goes back to previous page."""
|
| 90 |
+
driver.back()
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
@tool
|
| 94 |
+
def close_popups() -> str:
|
| 95 |
+
"""
|
| 96 |
+
Closes any visible modal or pop-up on the page. Use this to dismiss pop-up windows! This does not work on cookie consent banners.
|
| 97 |
+
"""
|
| 98 |
+
webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform()
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def initialize_driver():
|
| 102 |
+
"""Initialize the Selenium WebDriver."""
|
| 103 |
+
chrome_options = webdriver.ChromeOptions()
|
| 104 |
+
chrome_options.add_argument("--force-device-scale-factor=1")
|
| 105 |
+
chrome_options.add_argument("--window-size=1000,1350")
|
| 106 |
+
chrome_options.add_argument("--disable-pdf-viewer")
|
| 107 |
+
chrome_options.add_argument("--window-position=0,0")
|
| 108 |
+
return helium.start_chrome(headless=False, options=chrome_options)
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def initialize_agent(model):
|
| 112 |
+
"""Initialize the CodeAgent with the specified model."""
|
| 113 |
+
return CodeAgent(
|
| 114 |
+
tools=[DuckDuckGoSearchTool(), go_back, close_popups, search_item_ctrl_f],
|
| 115 |
+
model=model,
|
| 116 |
+
additional_authorized_imports=["helium"],
|
| 117 |
+
step_callbacks=[save_screenshot],
|
| 118 |
+
max_steps=20,
|
| 119 |
+
verbosity_level=2,
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
helium_instructions = """
|
| 124 |
+
Use your web_search tool when you want to get Google search results.
|
| 125 |
+
Then you can use helium to access websites. Don't use helium for Google search, only for navigating websites!
|
| 126 |
+
Don't bother about the helium driver, it's already managed.
|
| 127 |
+
We've already ran "from helium import *"
|
| 128 |
+
Then you can go to pages!
|
| 129 |
+
Code:
|
| 130 |
+
```py
|
| 131 |
+
go_to('github.com/trending')
|
| 132 |
+
```<end_code>
|
| 133 |
+
|
| 134 |
+
You can directly click clickable elements by inputting the text that appears on them.
|
| 135 |
+
Code:
|
| 136 |
+
```py
|
| 137 |
+
click("Top products")
|
| 138 |
+
```<end_code>
|
| 139 |
+
|
| 140 |
+
If it's a link:
|
| 141 |
+
Code:
|
| 142 |
+
```py
|
| 143 |
+
click(Link("Top products"))
|
| 144 |
+
```<end_code>
|
| 145 |
+
|
| 146 |
+
If you try to interact with an element and it's not found, you'll get a LookupError.
|
| 147 |
+
In general stop your action after each button click to see what happens on your screenshot.
|
| 148 |
+
Never try to login in a page.
|
| 149 |
+
|
| 150 |
+
To scroll up or down, use scroll_down or scroll_up with as an argument the number of pixels to scroll from.
|
| 151 |
+
Code:
|
| 152 |
+
```py
|
| 153 |
+
scroll_down(num_pixels=1200) # This will scroll one viewport down
|
| 154 |
+
```<end_code>
|
| 155 |
+
|
| 156 |
+
When you have pop-ups with a cross icon to close, don't try to click the close icon by finding its element or targeting an 'X' element (this most often fails).
|
| 157 |
+
Just use your built-in tool `close_popups` to close them:
|
| 158 |
+
Code:
|
| 159 |
+
```py
|
| 160 |
+
close_popups()
|
| 161 |
+
```<end_code>
|
| 162 |
+
|
| 163 |
+
You can use .exists() to check for the existence of an element. For example:
|
| 164 |
+
Code:
|
| 165 |
+
```py
|
| 166 |
+
if Text('Accept cookies?').exists():
|
| 167 |
+
click('I accept')
|
| 168 |
+
```<end_code>
|
| 169 |
+
|
| 170 |
+
Proceed in several steps rather than trying to solve the task in one shot.
|
| 171 |
+
And at the end, only when you have your answer, return your final answer.
|
| 172 |
+
Code:
|
| 173 |
+
```py
|
| 174 |
+
final_answer("YOUR_ANSWER_HERE")
|
| 175 |
+
```<end_code>
|
| 176 |
+
|
| 177 |
+
If pages seem stuck on loading, you might have to wait, for instance `import time` and run `time.sleep(5.0)`. But don't overuse this!
|
| 178 |
+
To list elements on page, DO NOT try code-based element searches like 'contributors = find_all(S("ol > li"))': just look at the latest screenshot you have and read it visually, or use your tool search_item_ctrl_f.
|
| 179 |
+
Of course, you can act on buttons like a user would do when navigating.
|
| 180 |
+
After each code blob you write, you will be automatically provided with an updated screenshot of the browser and the current browser url.
|
| 181 |
+
But beware that the screenshot will only be taken at the end of the whole action, it won't see intermediate states.
|
| 182 |
+
Don't kill the browser.
|
| 183 |
+
When you have modals or cookie banners on screen, you should get rid of them before you can click anything else.
|
| 184 |
+
"""
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
def main():
|
| 188 |
+
# Load environment variables
|
| 189 |
+
load_dotenv()
|
| 190 |
+
|
| 191 |
+
# Parse command line arguments
|
| 192 |
+
args = parse_arguments()
|
| 193 |
+
|
| 194 |
+
# Initialize the model based on the provided arguments
|
| 195 |
+
model = load_model(args.model_type, args.model_id)
|
| 196 |
+
|
| 197 |
+
global driver
|
| 198 |
+
driver = initialize_driver()
|
| 199 |
+
agent = initialize_agent(model)
|
| 200 |
+
|
| 201 |
+
# Run the agent with the provided prompt
|
| 202 |
+
agent.python_executor("from helium import *", agent.state)
|
| 203 |
+
agent.run(args.prompt + helium_instructions)
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
if __name__ == "__main__":
|
| 207 |
+
main()
|