From 11a2027e68507cf5ed7004d05c0bf065959577e3 Mon Sep 17 00:00:00 2001 From: fm1320 Date: Tue, 17 Dec 2024 15:14:34 +0000 Subject: [PATCH 1/2] fix: TypeError: Client.__init__() got an unexpected keyword argument 'proxies' [Google Colab] #294 --- notebooks/adalflow_colab_template.ipynb | 3 + ...lflow_object_count_auto_optimization.ipynb | 4 +- ...adalflow_classification_optimization.ipynb | 159 +++---- notebooks/tutorials/adalflow_component.ipynb | 4 +- .../tutorials/adalflow_dataclasses.ipynb | 4 +- .../tutorials/adalflow_function_calls.ipynb | 420 +++++++++--------- notebooks/tutorials/adalflow_logger.ipynb | 186 ++++---- .../tutorials/adalflow_modelclient.ipynb | 4 +- .../tutorials/adalflow_rag_optimization.ipynb | 187 ++++---- .../tutorials/adalflow_rag_playbook.ipynb | 239 +++++----- .../tutorials/adalflow_rag_vanilla.ipynb | 4 +- .../tutorials/adalflow_text_splitter.ipynb | 5 +- notebooks/tutorials/adalflow_tracing.ipynb | 121 ++--- 13 files changed, 686 insertions(+), 654 deletions(-) diff --git a/notebooks/adalflow_colab_template.ipynb b/notebooks/adalflow_colab_template.ipynb index 191bbf08..f132053c 100644 --- a/notebooks/adalflow_colab_template.ipynb +++ b/notebooks/adalflow_colab_template.ipynb @@ -54,6 +54,9 @@ "from IPython.display import clear_output\n", "\n", "!pip install -U adalflow[openai,groq,faiss-cpu]\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "\n", "clear_output()" ] diff --git a/notebooks/qas/adalflow_object_count_auto_optimization.ipynb b/notebooks/qas/adalflow_object_count_auto_optimization.ipynb index ac7e3cbf..9c64a8b0 100644 --- a/notebooks/qas/adalflow_object_count_auto_optimization.ipynb +++ b/notebooks/qas/adalflow_object_count_auto_optimization.ipynb @@ -58,7 +58,9 @@ "from IPython.display import clear_output\n", "\n", "!pip install -U adalflow[openai,groq,datasets]\n", - "\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "clear_output()" ] }, diff --git a/notebooks/tutorials/adalflow_classification_optimization.ipynb b/notebooks/tutorials/adalflow_classification_optimization.ipynb index 0afb97df..e914003e 100644 --- a/notebooks/tutorials/adalflow_classification_optimization.ipynb +++ b/notebooks/tutorials/adalflow_classification_optimization.ipynb @@ -1,21 +1,10 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, "cells": [ { "cell_type": "markdown", + "metadata": { + "id": "xHF95Kr4CzGq" + }, "source": [ "# 馃 Welcome to AdalFlow!\n", "## The PyTorch library to auto-optimize any LLM task pipelines\n", @@ -36,13 +25,13 @@ "## 馃摉 Outline\n", "\n", "This is the code for a classification optimization tutorial ![image.png](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+gAAAJYCAIAAAB+fFtyAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAD6KADAAQAAAABAAACWAAAAADDsFQWAABAAElEQVR4AeydB5gURRqGe5clLJJUMnqIiCiKYBbBnOMZThEDYMCcc1bMeurpKYZTDHcqYsSM2RMFwawcZhEUliRZ4rJ772xJ0fSEnZ2Znunu+ebhWaqrq6v+eqt75qu//64uqa6udvQRAREQAREQAREQAREQAREINoHSYJsn60RABERABERABERABERABGIEJNx1HoiACIiACIiACIiACIhACAhIuIdgkGSiCIiACIiACIiACIiACEi46xwQAREQAREQAREQAREQgRAQkHAPwSDJRBEQAREQAREQAREQARGQcNc5IAIiIAIiIAIiIAIiIAIhICDhHoJBkokiIAIiIAIiIAIiIAIiIOGuc0AEREAEREAEREAEREAEQkBAwj0EgyQTRUAEREAEREAEREAEREDCXeeACIiACIiACIiACIiACISAgIR7CAZJJoqACIiACIiACIiACIiAhLvOAREQAREQAREQAREQAREIAQEJ9xAMkkwUAREQAREQAREQAREQAQl3nQMiIAIiIAIiIAIiIAIiEAICEu4hGCSZKAIiIAIiIAIiIAIiIAIS7joHREAEREAEREAEREAERCAEBCTcQzBIMlEEREAEREAEREAEREAEJNx1DoiACIiACIiACIiACIhACAhIuIdgkGSiCIiACIiACIiACIiACEi46xwQAREQAREQAREQAREQgRAQkHAPwSDJRBEQAREQAREQAREQARGQcNc5IAIiIAIiIAIiIAIiIAIhICDhHoJBkokiIAIiIAIiIAIiIAIiIOGuc0AEREAEREAEREAEREAEQkBAwj0EgyQTRUAEREAEREAEREAEREDCXeeACIiACIiACIiACIiACISAgIR7CAZJJoqACIiACIiACIiACIiAhLvOAREQAREQAREQAREQAREIAQEJ9xAMkkwUAREQAREQAREQAREQAQl3nQMiIAIiIAIiIAIiIAIiEAICEu4hGCSZKAIiIAIiIAIiIAIiIAIS7joHREAEREAEREAEREAERCAEBCTcQzBIMlEEREAEREAEREAEREAEJNx1DoiACIiACIiACIiACIhACAhIuIdgkGSiCIiACIiACIiACIiACEi46xwQAREQAREQAREQAREQgRAQkHAPwSDJRBEQAREQAREQAREQARGQcNc5IAIiIAIiIAIiIAIiIAIhICDhHoJBkokiIAIiIAIiIAIiIAIiIOGuc0AEREAEREAEREAEREAEQkBAwj0EgyQTRUAEREAEREAEREAEREDCXeeACIiACIiACIiACIiACISAgIR7CAZJJoqACIiACIiACIiACIiAhLvOAREQAREQAREQAREQAREIAQEJ9xAMkkwUAREQAREQAREQAREQAQl3nQMiIAIiIAIiIAIiIAIiEAICEu4hGCSZKAIiIAIiIAIiIAIiIAIS7joHREAEREAEREAEREAERCAEBCTcQzBIMlEEREAEREAEREAEREAEJNx1DoiACOSYwC+//FJSUvLII4/kuN5wVrdzzSdN2+F29dVXp1k4V8WyHK/33nsPs/mbK3tsPf7VbJtQok4E/D4/PRfL9OnT//a3v6299tq0e8cdd/h6Pqy33noDBw6sEw0VFoGCEJBwLwh2NZohAb6+U3wykA6LFi1CJ6V54Kuvvkrr7du3r6qqyrADITnM/EA+88wzHntPP/10CHgy87+J0Dz22GM7d+7cqFGjtm3b7rjjjldddVX+zYhvccKECZxOmBe/K1c5v//++wUXXNC1a1f6vtZaa+21114vv/xynSp/4okn0EB1OiQ/he+5554wTvYY8RRfSihR6KEIbZmGDRtuuOGGV1555ZIlS9xgbQF34uSTT3aX4cI85JBDOOcbNGjQunXrAw444LnnnnMXiE//9NNPRx55JIXLy8u7dOly2WWXxZdx53zxxRdHH330uuuui52cYLvvvvvDDz+8YsUKd5m8pc8555zXX3/9kksu+c9//rP33nvnqt3Ro0czanPnzs1VhapHBPJJoCyfjaktEciSAF/ftoZ///vfb775pjtn4403tnvTTCDcBw8eTGHz+5r6qMcffxyvDLLsnXfe4fcsdeFi3tuxY8fFixfXr1/fDwg//vjj1ltvjQo57rjjGI6KiorPPvvs5ptvNuPoR4vp14lwxwzOJQyzR73xxhs2nWXiu+++22233WbOnMm8ZauttkJ5cE6i3s4///y///3vaVaOcB8/fvzZZ59t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aOHKSCuJC3bEiBFpFU2v0I477vjEE0+kVzbQpTLjmU6XJkyYsM466/zxxx/pFFaZ/BBAuL9Q8yGRnxbVigiIgAiIQJYEJNyzBFjgw1dUVY/56fcXvpjCX9I5sWbnnXc+++yzs6kq+xqStb7eeuvdcccddm/fvn2///57u5lmgjVG9tlnnzQL11rsxRdfnD59+hFHHPHee+/htlxzzTX5y9zA/WFXrfXYAumoZx6B/fvf/77FFlusscYazZs379Gjx+WXX84jmLaS3CZ++eWX448/nkUVy8vLO3fufNVVV2FAwiZYw/60007jAWuW1jn00EMhY4p169Ztu+22u/322xMepUwREAEREAEREIF0CChUJh1KAS0zcnzF4JcmVMxbYuxr17zRVQd023vTdgE11wez0JF86loxS63X9ZD48jyTgJ+S5Tj++c9/HnvssTznt/3220+ZMmXBggVNmzY955xz5s+f//DDD5sD11prrfgaMs5ZunTpnnvu+dVXXw0ePLh3796smjJx4sRhw4bdddddN954o6daFHb2S5h/++23LJhz//33b7DBBuPHjx80aBC+81tvvdXTFpt0/JVXXnn66aeZTpx++umHHHLIhx9+aIpBiQMvueQSrWESz005IiACIiACIpAOAXnc06EUxDKo9lMe+8yqdkycNm8JOeRnY+7AgQP/+9//3nnnncZhjKuV2tBquKjxobZp0+aYY46ZNWsWmXiRUYSjRo0yzd1yyy2sZYmHNWENpoznLw1ts802DRs2bNeu3cUXX2zW1aEMDns0Hx/EX8uWLa+44grz5C75kyZNQhoa2yjpdk5fffXVPXv2fOihh1ixG1NPPfVUhDVWIdMx7Prrr7etc7gJleEQt1+cNBVSDJGKAjYOZpzZzzzzjDmWLlPmtdde23LLLTH7gw8+mDlz5jvvvHPAAQdQABq0BSL+Mp2gAAk++OAvvfTSDh064B3fdtttjfcdz/Qmm2xy4oknmpp/+ukn5D7GsxeBO2/ePGMYFpoC7r//+Mc/aJp2zzzzTCyhvzvttNN99913ww03mGIGILdNoLfXXnuRiaubOGYMWHfddSHDYvO2QrpMDSxndPDBB//+++82353Ye++9mYQwW1h//fUPPPDA888//7nnnnMXMGnMHjp0KG3tuuuuGMYho0eP/uijj8zePfbYY/bs2Qx6/IHK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IAJFRUDCvaiGW50VAREQARFIg4BevZQGJBURARHIPwEJ9/wzV4siIAIiIALBJqAA92CPj6wTgaIlIOFetEOvjouACIiACCQhIOGeBIyyRUAECktA67gXlr9aFwEREIHCECgtLd1qq61om0RhLAhsqwumOwsqHKck9vYlfURABEQgSAQk3IM0GrJFBERABPJFoKysbL/99stXa6FqxwS4t+ziNGwSKrtlrAiIQPQJyNES/TFWD0VABERABOpAQHEydYCloiIgAnklII97XnGrMREQAREICIHq6upFixZhTOPGjUtKSgJiVSDMkHAPxDDICBEQgQQE5HFPAEVZIiACIhB5AsuXL7+15kMi8p2tWweNcG+7Wd2OUmkREAER8J+AhLv/jNWCCIiACIhAWAgsnuPMnRQztp2Ee1jGTHaKQBERkHAvosFWV0VABERABGohUPFVrECLjk75mrWU1G4REAERyDsBCfe8I1eDIiACIiACgSWgd6YGdmhkmAiIAAv4CoIIiIAIiIAIiMCfBPRkqk4FERCBABOQcA/w4Mg0ERABERCBPBOQcM8zcDUnAiJQFwIS7nWhpbIiIAIiIAIRJrB0oTPrh1j/2vWIcC/VNREQgfAS0Dru4R07WS4CIiACmRMoLS3t0SMmT0lkXkvEjpw+3nGqnabtnCatI9YzdUcERCAaBCTcozGO6oUIiIAI1I1AWVnZQQcdVLdjIl/aLCkjd3vkB1odFIHQEpCjJbRDJ8NFQAREQARyS0AB7rnlqdpEQARyTUAe91wTVX0iIAIiEAYC1dXV5p2p9evXLykpCYPJ/tuod6b6z1gtiIAIZENAHvds6OlYERABEQgrAVT7jTUfI9/D2o0c2l251Jn5Taw+hcrkkKqqEgERyCkBCfec4lRlIiACIiACISUwY4JTVemUr+U0XyekPZDZIiACkScg4R75IVYHRUAEREAE0iBgA9wVOJQGLRURAREoCAEJ94JgV6MiIAIiIAIBI/CncN8sYGbJHBEQARFYRUDCfRULpURABERABIqXgPW4Fy8C9VwERCDoBCTcgz5Csk8EREAERMB3Aisqnen/i7XSrqfvbakBERABEciUgIR7jNyQIUPWW2+9Ro0abbvttuPGjUsI84477ujatWt5efm66657zjnnLFmyxBTjQFZSc39OO+20hDUoUwREQAREIKAEZn3vVC5xGjR11uwUUAtllgiIgAg4jtZxd4YPH37uuefed999qHbU+V577fXdd9+1br3a+66feOKJiy+++KGHHtp+++2///77gQMHotRvv/12TqGPP/54xYoV5lwaP378Hnvscdhhh+nUEgEREIGAEygtLe3WrRtGkgi4qfkwzwa4i0Y+cKsNERCBDAlIuDvo70GDBh177LEgRL6/8sorCHRkupvo6NGje/fufeSRR5KJi71fv35jx441BVq1amVL3nTTTZ07d95pp51sjhIiIAIiEEwCZWVl8jKsGhoj3NvqydRVSJQSAREIIIFiF+7Lli379NNPL7nkEjM2eJ523333MWPGeIYKR/tjjz1GFM0222zz888/v/rqq8ccc4ynDFVRBuc9znjPLjaX1nxM/vz580nw0hPz3hP33/gDlRMiAhrKEA1WalM1lKn5hGhvmkNZb+rn3HeobL0pr5MNUe+KytQ0h7KomIS0s56hNJsh7Uv+zS524T5r1iwCXdq0aWPRk/7222/tpknga6dknz59eEl4ZWXlySeffOmll3rKjBgxYu7cuUTRePLNJi8oHDx4sHvXG2+80bhxY5vz5ptv2rQSoSagoQz18LmN11C6aYQ6XctQVlftN+ULhPv7P8xb8Nuroe5p5I2vZSgj3/8IddAO5aJFiyLULd+7UuzCPU3A77333g033HDPPfcQB//jjz+eddZZ11577RVXXOE+fOjQofvss0/79u3dmTaNUx9nvNnE484TrnvuuWezZs3IYa7J6UtwfP369W15JcJIQEMZxlFLaHMxDCU3CW+99Va6f/755zdo0CAhhwhkpjWUs38q+2JJdVmjHQ4+zinVz2JAhz2toQyo7TJrNQKeoTRhCKuV0EZyAsX+DdWyZct69epNnz7dIiLdtm1bu2kSaHRiY0444QQ2u3fv/scff5x44omXXXaZfahr0qRJb7311nPPPec50G42rPnYTRLIdLdS92y6SyodLgIaynCNVwproz2U3D80fY92N9Pq48zYQpAlbTat37A8xfmgXUEgUAynaxA458EGO5Qk8tBcZJoo9sUE8DNtueWWb7/9thnRqqoq0r169fIMMPdxrEZnF1qfv/Znj/TDDz/MQjT77bef50BtioAIiIAIBJ2AXVIm6IbKPhEQgWInUOwed8afCJYBAwZstdVWPHjKcpB4080KM/37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BxfHOIa1l1rEPawjJ7tFQAREQAREQATyTiA6wn3KlCmPPPIIr2GaO3funDlznnjiicMPP5xXA+YdqRqsA4GVMe4KlakDNBUVgZwQqF+//imnnEJVJHJSoSoRAREQARHwm0AUVpV59tln9913365duxLdftttt02dOrW0tJQYd6l2v8+eLOtfsnzFrIXLqKRDC60qkyVLHS4CdSbANySr6PLRV2Wd2ekAERABESgQgSh43Pv27XvRRRfxZGrTpk0LhFHNZkKgYt4SDmvcoF7zcjn8MgGoY0RABERABERABIqKQBQ87scff/yQIUP23nvv++67jyCZohq/UHd2ZZxMuRx+oR5HGR9SArzv4r2aD4mQdkFmi4AIiECxEYiCcL///vsrKipOPPHEYcOGtWvX7q9//Wt1dTXruBfbWIauvyvXglScTOiGTgZHgQB6/b81Hwn3KAyn+iACIlAcBKIg3BkpFm4fMGAAv0Fff/31Jpts0qZNm969ex955JGsLVMc4xjKXhqPe4cWejI1lMMno0VABERABERABPJMICLC3VJjGfcbbrjh119/feyxxxYtWtSvXz+7S4mgETCLuLdrLo970EZG9oiACIiACIiACASRQBQeTo3nyqoyB9R8ZsyYEb9XOQEhYBZxb68lZQIyHjJDBERABERABEQg2ASi5nH30GalM0+ONoNDYGWMu0JlgjMmskQEREAEREAERCC4BCIu3IMLvugt4wHilTHuCpUp+rNBAERABERABERABNIgIOGeBiQV8YHAnEXLlyyPrfzTtrk87j7wVZUiIAIiIAIiIAKRIxDNGPfIDVMEO2Tc7a2aNmxYVi+C3VOXRCDwBMrKyk444QTMJBF4Y2WgCIiACIhAjEB0PO7rr7/+77//7h7VuXPnkunOUTo4BFYGuCtOJjhjIkuKiwAP8Xeo+ZAorp6rtyIgAiIQWgLR+b7+5ZdfPK8RWbp06ZQpU0I7NBE3vGLuYnqoRdwjPszqngiIgAiIgAiIQO4IROEO6YsvvmiAvP76682bNzdpRPzbb7+93nrr5Y6VasolganzllCdFnHPJVPVJQJ1IcCX5EcffcQR2223Xb16ilirCzuVFQEREIECEYiCcD/ooIOgV1JSwstTLcb69euj2m+77Tabo0SgCChUJlDDIWOKkADC/a233qLjW2+9tYR7EZ4A6rIIiEAY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AAIIIIAAAggcW4DC/dhGHFEbga17c3U6d6bWxpBzEUAAAQQQQAABCVC48zaIrkDWvkO6gOa4R/cytI4AAggggAACCLguQOHueobj3T9vqkzzzLR4B8L1EUAAAQQQQAABuwUo3O3On+HRFxcXb/3vkRF3psoYninCQwABBBBAAAHzBSjczc+RxRHuzy3IzitUB1pkMFXG4jwSOgIIIIAAAgiYIMA67iZkwdkYvHkyx9VPTU/lO9WdzTIds1RA35x68cUXK3htWNoFwkYAAQSCJkDhHrSMx7S/LOIeU24uhkB1BFSvX3LJJdU5g2MRQAABBOIswFSZOCfA7cuziLvb+aV3CCCAAAIIIBBLAUbcY6kduGuxiHvgUk6H7RHQveO7du1SvE2aNElISLAncCJFAAEEgivAiHtwcx+DnrOIewyQuQQCNRPIz89/uuShjZq1wFkIIIAAAjEWoHA/Av7UU0+1bds2LS2te/fuq1evLjcHjz766Jlnnpment66des777wzN/fIF4KGPu6//36NWo0bNy50Z8C3WcQ94G8Auo8AAggggAACERSgcK+zePHi8ePHT5s2be3atR07duzXr9/OnTvDiF966aWJEyfqmA0bNsyfP1+nTJ48OfSYjz766JlnnunQoUPoTra37T3y6w2LuPNOQAABBBBAAAEEai9A4eHP9oEAACUdSURBVF5nzpw5I0aMuPnmm9u1azdv3rx69eo999xzYbIrVqzo2bPnkCFDNDDft2/fG264IXRg/uDBg0OHDn322WcbN24cdmKQnxYUFm3ff6Rwb5nJIu5BfiPQdwQQQAABBBCIjEDQb07Ny8tbs2bNpEmTPM7ExMTevXuvXLkyTPfCCy9cuHChivVu3bp99dVXb7311o033ugfc/vtt19xxRU68b777vN3hm0cLnl4O/fv368NzSv1ppaG/jfsLKufZu3LLSwqTklKyKyb6PXR6u5UJXhXU1mVvjt2TBBS6X8qteHwzalBSKVjn76KukMqK5Kxbn9YKr2n1vUiXgEHvXDfvXt3YWFh06ZN/QRoe+PGjf5Tb0Nj7TqyV69eWoehoKBg1KhR/lSZRYsWaY6NpsqEnRL2dPbs2dOnTw/duXTpUo3u+3uWLVvmb7ux8dWRX0+SGyUXvfPO2270qIq9cC+VVey4e4e5nUr96PNS9u677zr/HUxup9K9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RoDC3ZlUxq0jpRPcWVImbingwgjUQCAlJWXEiBE1OJFTEEAAAQTiJcBUmXjJu3NdFnF3J5f0BAEEEEAAAQQMFqBwP5Kcp556qm3btmlpad27d1+9enW5+Xr00UfPPPPM9PT01q1b33nnnbm5R27H1OPpp5/u0KFDo5JHjx493n77bW9/cP7LWpDByTU9RQABBBBAAIE4ClC411m8ePH48eOnTZu2du3ajh079uvXb+fOnWEpeemllyZOnKhjNmzYMH/+fJ0yefJk75hWrVrdf//9a9as+fjjj3/2s58NHDjws88+Czvd7acU7m7nl965KpCfn6/xCD204Wof6RcCCCDgmACFe505c+ZooufNN9/crl27efPm1atX77nnngtL84oVK3r27DlkyBANzPft2/eGG27wB+YHDBhw+eWXn3766WecccbMmTMbNGiwatWqsNPdfrpt3yF1sAWLuLudZnrnnEBxcfG+koc2nOscHUIAAQTcFAh64Z6Xl6fB8t69e3vpTUxM1PbKlSvDsn3hhRfqMK9Y/+qrr9566y0V62HHFBYWLlq0KDs7WxNmwl5y+6k3x51F3N3OMr1DAAEEEEAAgbgLBH1Vmd27d6vgbtq0qZ8JbW/cuNF/6m1orF1H9urVS0NTBQUFo0aN8qfK6ID169erWNesdw23v/baaxq5DztdTw+XPLz9+/fv14b+PO39hTr0v2VPNHxPUVFxVsmI+4n1k72OGB5wVMOzOpVRlbGu8SCk0v/AasPhFSGDkErrPl81C5hU1szNwLPCUuk9NTBOM0MKeuFexawsX7581qxZc+fO1d2rmzdvHjt27IwZM6ZMmeKdrptW161bp785v/rqqzfddNP7779ftnafPXv29OnTQy+3dOlSTcvx9yxbtszftmhjX16d/MLkhDrFa/7593UsBl2SOUtTadG7Lmahup1KjVl4ku+++25SUlLMVONyIbdTGRfSeF2UVMZLPuLX9VOZk5MT8cYdbjAh4LMbNVVG1bMK7kGDBnlpVuW9d+/eN954IzTrF1100QUXXPDggw96OxcuXDhy5MiDBw9qak3oYdrWTJtTTz31mWeeCdsfNuKupWk0hK+laHSYftfU27dPnz5aVjnsLPOfrvtu77X/d7W+M/WDCT8xP9poR2h1KqONY1f7QUilfvo99NBDysuECRNSU1PtSlDVow1C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AAEEEIiLACPucWHnoggggECEBTRSrvpbQ+OXXXbZ8uXLVXNrNL3sNTSafu+993oj9Pqvan0Nxufk5HhH9ujRwz9F296I+/Dhw9etW3fmmWeqgl+6dKl/ABsIIIAAAjEWoHCPMTiXQwABBKIloDnoffr00XSXFStWqNqeNm1a2SsdPHhQ89pViHuP9evXb9q0SSeWPdLfo98Bvv766xkzZmg4/7rrrrvmmmv8l9hAAAEEEIilAIV7LLW5FgIIIBAjgXbt2mVnZ+tiKSkphYWF/lVVhWuq+mk/fiQmHv23YNWqVf6R2j777LO9p40aNRo8ePCzzz67ePFizcnZs2ePfxgbCCCAAAIxE2A5yJhRcyEEEEAgWgJa+fHaa6/95S9/qXntDRs2/Pjjjx944IGBAwfqerqXVEtD9uzZU+u7N27ceOrUqT//+c+13LsGzlWva+bMp59+et9993mRvfLKK127du3Vq5duQl29evX8+fO1f86cOVpSpnPnzjpeB2iR+MzMzGj1hHYRQAABBCoWoHCv2IZXEEAAAUsENFu9e/fujzzyyJdffpmfn9+6dWtNXp88ebLCf/jhh8ePH6/B8pYtW37zzTf6YqY333xT09y1dqQG488666xbb73V76Vm0SxatGj06NGq1F9++WUN2+sl/SagXwM0oyYpKen8889/6623/BF6/0Q2EEAAAQRiIMCqMjFA5hIIIICABQJh689YEDEhIoAAAgETYI57wBJOdxFAAAEEEEAAAQTsFKBwtzNvRI0AAggggAACCCAQMAGmygQs4XQXAQQQQAABBBBAwE4BRtztzBtRI4AAAggggAACCARMgMI9YAmnuwgggAACCCCAAAJ2ClC425k3okYAAQQQQAABBBAImACFe8ASTncRQAABBBBAAAEE7BSgcLczb0SNAAIIIIAAAgggEDABCveAJZzuIoAAAggggAACCNgpQOFuZ96IGgEEEEAAAQQQQCBgAhTuAUs43UUAAQQQQAABBBCwU4DC3c68ETUCCCCAAAIIIIBAwAQo3AOWcLqLAAIIIIAAAgggYKcAhbudeSNqBBBAAAEEEEAAgYAJULgHLOF0FwEEEEAAAQQQQMBOAQp3O/NG1AgggAACCCCAAAIBE6BwD1jC6S4CCCCAAAIIIICAnQIU7nbmjagRQAABBBBAAAEEAiZA4R6whNNdBBBAAAEEEEAAATsFKNztzBtRI4AAAggggAACCARMgMI9YAmnuwgggAACCCCAAAJ2ClC425k3okYAAQQQQAABBBAImACFe8ASTncRQAABBBBAAAEE7BSgcLczb0SNAAIIIIAAAgggEDABCveAJZzuIoAAAggggAACCNgp8P8BhKg2I1BqsPcAAAAASUVORK5CYII=)\n" - ], - "metadata": { - "id": "xHF95Kr4CzGq" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "Kof5M6DRaKhh" + }, "source": [ "\n", "# Installation\n", @@ -55,10 +44,7 @@ "2. Setup `openai` and `groq` API key in the environment variables\n", "\n", "You can choose to use different client. You can import the model client you prefer. We support `Anthropic`, `Cohere`, `Google`, `GROQ`, `OpenAI`, `Transformer` and more in development. We will use OpenAI here as an example.Please refer to our [full installation guide](https://adalflow.sylph.ai/get_started/installation.html)" - ], - "metadata": { - "id": "Kof5M6DRaKhh" - } + ] }, { "cell_type": "code", @@ -72,11 +58,17 @@ "\n", "!pip install -U adalflow[openai] # also install the package for the model client you'll use\n", "!pip install datasets\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "clear_output()" ] }, { "cell_type": "markdown", + "metadata": { + "id": "KapUyHMM07pJ" + }, "source": [ "## Set Environment Variables\n", "\n", @@ -85,27 +77,11 @@ "Note: for normal `.py` projects, follow our [official installation guide](https://lightrag.sylph.ai/get_started/installation.html).\n", "\n", "*Go to [OpenAI](https://platform.openai.com/docs/introduction) to get API keys if you don't already have.*" - ], - "metadata": { - "id": "KapUyHMM07pJ" - } + ] }, { "cell_type": "code", - "source": [ - "import os\n", - "\n", - "from getpass import getpass\n", - "\n", - "# Prompt user to enter their API keys securely\n", - "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", - "\n", - "\n", - "# Set environment variables\n", - "os.environ['OPENAI_API_KEY'] = openai_api_key\n", - "\n", - "print(\"API keys have been set.\")" - ], + "execution_count": 43, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -113,20 +89,38 @@ "id": "ONfzF9Puzdd_", "outputId": "e5c3cfc5-69cb-448a-c248-a8cebda5ba71" }, - "execution_count": 43, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Please enter your OpenAI API key: 路路路路路路路路路路\n", "API keys have been set.\n" ] } + ], + "source": [ + "import os\n", + "\n", + "from getpass import getpass\n", + "\n", + "# Prompt user to enter their API keys securely\n", + "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", + "\n", + "\n", + "# Set environment variables\n", + "os.environ['OPENAI_API_KEY'] = openai_api_key\n", + "\n", + "print(\"API keys have been set.\")" ] }, { "cell_type": "code", + "execution_count": 49, + "metadata": { + "id": "ZZIEtZYHNVjo" + }, + "outputs": [], "source": [ "from dataclasses import dataclass, field\n", "from typing import List, Dict, Union, Optional, Tuple, Any, Callable\n", @@ -192,15 +186,15 @@ " )\n", " __input_fields__ = [\"question\"]\n", " __output_fields__ = [\"rationale\", \"class_name\"] # it is important to have the rationale before the class_name" - ], - "metadata": { - "id": "ZZIEtZYHNVjo" - }, - "execution_count": 49, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": 50, + "metadata": { + "id": "3Q3H9XC4Ncfi" + }, + "outputs": [], "source": [ "class TRECClassifierStructuredOutput(adal.Component):\n", "\n", @@ -269,15 +263,15 @@ " prompt_kwargs = self._prepare_input(question)\n", " output = self.llm(prompt_kwargs=prompt_kwargs, id=id)\n", " return output" - ], - "metadata": { - "id": "3Q3H9XC4Ncfi" - }, - "execution_count": 50, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": 51, + "metadata": { + "id": "HpkQYsh2NevT" + }, + "outputs": [], "source": [ "class TrecClassifierAdal(adal.AdalComponent):\n", " def __init__(\n", @@ -334,15 +328,15 @@ " requires_opt=False,\n", " )\n", " return self.loss_fn, {\"kwargs\": {\"y\": y_pred, \"y_gt\": y_gt}}" - ], - "metadata": { - "id": "HpkQYsh2NevT" - }, - "execution_count": 51, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": 52, + "metadata": { + "id": "PEj6xiZ5dVaj" + }, + "outputs": [], "source": [ "def train(\n", " model_client: adal.ModelClient,\n", @@ -411,15 +405,16 @@ " except Exception as e:\n", " print(f\"Error occurred: {str(e)}\")\n", " raise" - ], - "metadata": { - "id": "PEj6xiZ5dVaj" - }, - "execution_count": 52, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "id": "GnlZBQOMEj6E" + }, + "outputs": [], "source": [ "from adalflow.components.model_client.openai_client import OpenAIClient\n", "\n", @@ -438,26 +433,34 @@ " model_client=OpenAIClient(),\n", " model_kwargs=gpt_4o_model,\n", " )" - ], - "metadata": { - "id": "GnlZBQOMEj6E", - "collapsed": true - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "AmkbyxmuruUu" + }, "source": [ "# Issues and feedback\n", "\n", "If you encounter any issues, please report them here: [GitHub Issues](https://github.com/SylphAI-Inc/LightRAG/issues).\n", "\n", "For feedback, you can use either the [GitHub discussions](https://github.com/SylphAI-Inc/LightRAG/discussions) or [Discord](https://discord.gg/ezzszrRZvT)." - ], - "metadata": { - "id": "AmkbyxmuruUu" - } + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" } - ] + }, + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/notebooks/tutorials/adalflow_component.ipynb b/notebooks/tutorials/adalflow_component.ipynb index 2da8aa78..b81cbc16 100644 --- a/notebooks/tutorials/adalflow_component.ipynb +++ b/notebooks/tutorials/adalflow_component.ipynb @@ -55,7 +55,9 @@ "from IPython.display import clear_output\n", "\n", "!pip install -U adalflow[openai,groq,datasets]\n", - "\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "clear_output()" ] }, diff --git a/notebooks/tutorials/adalflow_dataclasses.ipynb b/notebooks/tutorials/adalflow_dataclasses.ipynb index 3c96ffe5..d7163d2f 100644 --- a/notebooks/tutorials/adalflow_dataclasses.ipynb +++ b/notebooks/tutorials/adalflow_dataclasses.ipynb @@ -78,7 +78,9 @@ "from IPython.display import clear_output\n", "\n", "!pip install -U adalflow[openai,groq]\n", - "\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "clear_output()" ] }, diff --git a/notebooks/tutorials/adalflow_function_calls.ipynb b/notebooks/tutorials/adalflow_function_calls.ipynb index 622448c9..33471645 100644 --- a/notebooks/tutorials/adalflow_function_calls.ipynb +++ b/notebooks/tutorials/adalflow_function_calls.ipynb @@ -1,21 +1,10 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, "cells": [ { "cell_type": "markdown", + "metadata": { + "id": "lLGpv1fLLIjF" + }, "source": [ "# Function calls\n", "\n", @@ -30,10 +19,7 @@ "- Function call in action\n", "\n", "It follows the tutorial here: https://adalflow.sylph.ai/tutorials/tool_helper.html#" - ], - "metadata": { - "id": "lLGpv1fLLIjF" - } + ] }, { "cell_type": "code", @@ -46,26 +32,15 @@ "from IPython.display import clear_output\n", "\n", "!pip install -U adalflow[openai,groq,faiss-cpu]\n", - "\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "clear_output()\n" ] }, { "cell_type": "code", - "source": [ - "import os\n", - "from getpass import getpass\n", - "\n", - "# Prompt user to enter their API keys securely\n", - "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", - "groq_api_key = getpass(\"Please enter your GROQ API key: \")\n", - "\n", - "# Set environment variables\n", - "os.environ['OPENAI_API_KEY'] = openai_api_key\n", - "os.environ['GROQ_API_KEY'] = groq_api_key\n", - "\n", - "print(\"API keys have been set.\")\n" - ], + "execution_count": 2, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -73,21 +48,39 @@ "id": "-4c_AGBt3PlR", "outputId": "21a26437-9f95-4478-84e9-ba4369956b6f" }, - "execution_count": 2, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Please enter your OpenAI API key: 路路路路路路路路路路\n", "Please enter your GROQ API key: 路路路路路路路路路路\n", "API keys have been set.\n" ] } + ], + "source": [ + "import os\n", + "from getpass import getpass\n", + "\n", + "# Prompt user to enter their API keys securely\n", + "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", + "groq_api_key = getpass(\"Please enter your GROQ API key: \")\n", + "\n", + "# Set environment variables\n", + "os.environ['OPENAI_API_KEY'] = openai_api_key\n", + "os.environ['GROQ_API_KEY'] = groq_api_key\n", + "\n", + "print(\"API keys have been set.\")\n" ] }, { "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "GMKuuP7xR9Nt" + }, + "outputs": [], "source": [ "from dataclasses import dataclass\n", "from typing import List\n", @@ -136,34 +129,20 @@ "\n", "def add_points(p1: Point, p2: Point) -> Point:\n", " return Point(p1.x + p2.x, p1.y + p2.y)" - ], - "metadata": { - "id": "GMKuuP7xR9Nt" - }, - "execution_count": 4, - "outputs": [] + ] }, { "cell_type": "markdown", - "source": [ - "##聽Function Tool" - ], "metadata": { "id": "jCA7HMjtT16P" - } + }, + "source": [ + "##聽Function Tool" + ] }, { "cell_type": "code", - "source": [ - "from adalflow.core.func_tool import FunctionTool\n", - "\n", - "functions =[multiply, add, divide, search, numpy_sum, add_points]\n", - "tools = [\n", - " FunctionTool(fn=fn) for fn in functions\n", - "]\n", - "for tool in tools:\n", - " print(tool)" - ], + "execution_count": 5, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -171,11 +150,10 @@ "id": "fgOEoLoDSBqh", "outputId": "7e636e2c-9a5d-44f1-f0fe-fe8a6bea474d" }, - "execution_count": 5, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='multiply', func_desc='multiply(a: int, b: int) -> int\\nMultiply two numbers.', func_parameters={'type': 'object', 'properties': {'a': {'type': 'int'}, 'b': {'type': 'int'}}, 'required': ['a', 'b']}))\n", "FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='add', func_desc='add(a: int, b: int) -> int\\nAdd two numbers.', func_parameters={'type': 'object', 'properties': {'a': {'type': 'int'}, 'b': {'type': 'int'}}, 'required': ['a', 'b']}))\n", @@ -185,13 +163,21 @@ "FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='add_points', func_desc='add_points(p1: __main__.Point, p2: __main__.Point) -> __main__.Point\\nNone', func_parameters={'type': 'object', 'properties': {'p1': {'type': \"{'type': 'Point', 'properties': {'x': {'type': 'int'}, 'y': {'type': 'int'}}, 'required': ['x', 'y']}\"}, 'p2': {'type': \"{'type': 'Point', 'properties': {'x': {'type': 'int'}, 'y': {'type': 'int'}}, 'required': ['x', 'y']}\"}}, 'required': ['p1', 'p2']}))\n" ] } + ], + "source": [ + "from adalflow.core.func_tool import FunctionTool\n", + "\n", + "functions =[multiply, add, divide, search, numpy_sum, add_points]\n", + "tools = [\n", + " FunctionTool(fn=fn) for fn in functions\n", + "]\n", + "for tool in tools:\n", + " print(tool)" ] }, { "cell_type": "code", - "source": [ - "print(tools[-2].definition.to_dict())" - ], + "execution_count": 6, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -199,50 +185,47 @@ "id": "CYJaHFhGSEzH", "outputId": "9ab36c6c-7509-4e7f-ce85-11dae889c8c2" }, - "execution_count": 6, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "{'func_name': 'numpy_sum', 'func_desc': 'numpy_sum(arr: numpy.ndarray) -> float\\nSum the elements of an array.', 'func_parameters': {'type': 'object', 'properties': {'arr': {'type': 'ndarray'}}, 'required': ['arr']}}\n" ] } + ], + "source": [ + "print(tools[-2].definition.to_dict())" ] }, { "cell_type": "code", - "source": [ - "context_map = {tool.definition.func_name: tool for tool in tools}" - ], + "execution_count": 7, "metadata": { "id": "_O4bQgXrSKb6" }, - "execution_count": 7, - "outputs": [] + "outputs": [], + "source": [ + "context_map = {tool.definition.func_name: tool for tool in tools}" + ] }, { "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "-RgWWMdISL1u" + }, + "outputs": [], "source": [ "function_name = \"add\"\n", "function_to_call = context_map[function_name]\n", "function_args = {\"a\": 1, \"b\": 2}\n", "function_response = function_to_call.call(**function_args)" - ], - "metadata": { - "id": "-RgWWMdISL1u" - }, - "execution_count": 8, - "outputs": [] + ] }, { "cell_type": "code", - "source": [ - "from adalflow.core.tool_manager import ToolManager\n", - "\n", - "tool_manager = ToolManager(tools=functions)\n", - "print(tool_manager)" - ], + "execution_count": 9, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -250,34 +233,34 @@ "id": "6CT7Tez1SOai", "outputId": "e486d882-9179-4db3-f077-6adfc9fc6579" }, - "execution_count": 9, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "ToolManager(Tools: [FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='multiply', func_desc='multiply(a: int, b: int) -> int\\nMultiply two numbers.', func_parameters={'type': 'object', 'properties': {'a': {'type': 'int'}, 'b': {'type': 'int'}}, 'required': ['a', 'b']})), FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='add', func_desc='add(a: int, b: int) -> int\\nAdd two numbers.', func_parameters={'type': 'object', 'properties': {'a': {'type': 'int'}, 'b': {'type': 'int'}}, 'required': ['a', 'b']})), FunctionTool(fn: , async: True, definition: FunctionDefinition(func_name='divide', func_desc='divide(a: float, b: float) -> float\\nDivide two numbers.', func_parameters={'type': 'object', 'properties': {'a': {'type': 'float'}, 'b': {'type': 'float'}}, 'required': ['a', 'b']})), FunctionTool(fn: , async: True, definition: FunctionDefinition(func_name='search', func_desc='search(query: str) -> List[str]\\nSearch for query and return a list of results.', func_parameters={'type': 'object', 'properties': {'query': {'type': 'str'}}, 'required': ['query']})), FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='numpy_sum', func_desc='numpy_sum(arr: numpy.ndarray) -> float\\nSum the elements of an array.', func_parameters={'type': 'object', 'properties': {'arr': {'type': 'ndarray'}}, 'required': ['arr']})), FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='add_points', func_desc='add_points(p1: __main__.Point, p2: __main__.Point) -> __main__.Point\\nNone', func_parameters={'type': 'object', 'properties': {'p1': {'type': \"{'type': 'Point', 'properties': {'x': {'type': 'int'}, 'y': {'type': 'int'}}, 'required': ['x', 'y']}\"}, 'p2': {'type': \"{'type': 'Point', 'properties': {'x': {'type': 'int'}, 'y': {'type': 'int'}}, 'required': ['x', 'y']}\"}}, 'required': ['p1', 'p2']}))], Additional Context: {})\n" ] } + ], + "source": [ + "from adalflow.core.tool_manager import ToolManager\n", + "\n", + "tool_manager = ToolManager(tools=functions)\n", + "print(tool_manager)" ] }, { "cell_type": "markdown", - "source": [ - "## ToolManager" - ], "metadata": { "id": "jzFqNnN_T-cu" - } + }, + "source": [ + "## ToolManager" + ] }, { "cell_type": "code", - "source": [ - "from adalflow.core.tool_manager import ToolManager\n", - "\n", - "tool_manager = ToolManager(tools=functions)\n", - "print(tool_manager)" - ], + "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -285,28 +268,38 @@ "id": "JX7MibWiUF3U", "outputId": "20707186-5ec3-49a4-d553-c3160c3daa84" }, - "execution_count": 10, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "ToolManager(Tools: [FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='multiply', func_desc='multiply(a: int, b: int) -> int\\nMultiply two numbers.', func_parameters={'type': 'object', 'properties': {'a': {'type': 'int'}, 'b': {'type': 'int'}}, 'required': ['a', 'b']})), FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='add', func_desc='add(a: int, b: int) -> int\\nAdd two numbers.', func_parameters={'type': 'object', 'properties': {'a': {'type': 'int'}, 'b': {'type': 'int'}}, 'required': ['a', 'b']})), FunctionTool(fn: , async: True, definition: FunctionDefinition(func_name='divide', func_desc='divide(a: float, b: float) -> float\\nDivide two numbers.', func_parameters={'type': 'object', 'properties': {'a': {'type': 'float'}, 'b': {'type': 'float'}}, 'required': ['a', 'b']})), FunctionTool(fn: , async: True, definition: FunctionDefinition(func_name='search', func_desc='search(query: str) -> List[str]\\nSearch for query and return a list of results.', func_parameters={'type': 'object', 'properties': {'query': {'type': 'str'}}, 'required': ['query']})), FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='numpy_sum', func_desc='numpy_sum(arr: numpy.ndarray) -> float\\nSum the elements of an array.', func_parameters={'type': 'object', 'properties': {'arr': {'type': 'ndarray'}}, 'required': ['arr']})), FunctionTool(fn: , async: False, definition: FunctionDefinition(func_name='add_points', func_desc='add_points(p1: __main__.Point, p2: __main__.Point) -> __main__.Point\\nNone', func_parameters={'type': 'object', 'properties': {'p1': {'type': \"{'type': 'Point', 'properties': {'x': {'type': 'int'}, 'y': {'type': 'int'}}, 'required': ['x', 'y']}\"}, 'p2': {'type': \"{'type': 'Point', 'properties': {'x': {'type': 'int'}, 'y': {'type': 'int'}}, 'required': ['x', 'y']}\"}}, 'required': ['p1', 'p2']}))], Additional Context: {})\n" ] } + ], + "source": [ + "from adalflow.core.tool_manager import ToolManager\n", + "\n", + "tool_manager = ToolManager(tools=functions)\n", + "print(tool_manager)" ] }, { "cell_type": "markdown", - "source": [ - "## Function Call end-to-end" - ], "metadata": { "id": "9Bw2fs--UKX7" - } + }, + "source": [ + "## Function Call end-to-end" + ] }, { "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "TywPQMIVUOqh" + }, + "outputs": [], "source": [ "template = r\"\"\"You have these tools available:\n", "{% if tools %}\n", @@ -325,24 +318,11 @@ "User: {{input_str}}\n", "You:\n", "\"\"\"" - ], - "metadata": { - "id": "TywPQMIVUOqh" - }, - "execution_count": 11, - "outputs": [] + ] }, { "cell_type": "code", - "source": [ - "from adalflow.core.prompt_builder import Prompt\n", - "\n", - "prompt = Prompt(template=template)\n", - "small_tool_manager = ToolManager(tools=tools[:2])\n", - "\n", - "renered_prompt = prompt(tools=small_tool_manager.yaml_definitions)\n", - "print(renered_prompt)" - ], + "execution_count": 12, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -350,11 +330,10 @@ "id": "-vMajeXoUQ5A", "outputId": "ca68601b-e9c8-41c3-a6fa-777f225e68e3" }, - "execution_count": 12, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "You have these tools available:\n", "\n", @@ -400,19 +379,20 @@ "\n" ] } - ] - }, - { - "cell_type": "code", + ], "source": [ - "from adalflow.core.types import Function\n", + "from adalflow.core.prompt_builder import Prompt\n", "\n", - "output_data_class = Function\n", - "output_format_str = output_data_class.to_json_signature(exclude=[\"thought\", \"args\"])\n", + "prompt = Prompt(template=template)\n", + "small_tool_manager = ToolManager(tools=tools[:2])\n", "\n", - "renered_prompt= prompt(output_format_str=output_format_str)\n", + "renered_prompt = prompt(tools=small_tool_manager.yaml_definitions)\n", "print(renered_prompt)" - ], + ] + }, + { + "cell_type": "code", + "execution_count": 13, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -420,11 +400,10 @@ "id": "V9-90IFRUUNT", "outputId": "ed2f829e-c656-43c6-a454-8a7c32d5dafe" }, - "execution_count": 13, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "You have these tools available:\n", "\n", @@ -439,17 +418,20 @@ "\n" ] } + ], + "source": [ + "from adalflow.core.types import Function\n", + "\n", + "output_data_class = Function\n", + "output_format_str = output_data_class.to_json_signature(exclude=[\"thought\", \"args\"])\n", + "\n", + "renered_prompt= prompt(output_format_str=output_format_str)\n", + "print(renered_prompt)" ] }, { "cell_type": "code", - "source": [ - "from adalflow.core.types import FunctionExpression\n", - "\n", - "output_data_class = FunctionExpression\n", - "output_format_str = output_data_class.to_json_signature(exclude=[\"thought\"])\n", - "print(prompt(output_format_str=output_format_str))" - ], + "execution_count": 14, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -457,11 +439,10 @@ "id": "p3kPMhWaUYT1", "outputId": "a3de7117-c3eb-404e-e2e7-8a5187b32f6b" }, - "execution_count": 14, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "You have these tools available:\n", "\n", @@ -475,17 +456,18 @@ "\n" ] } + ], + "source": [ + "from adalflow.core.types import FunctionExpression\n", + "\n", + "output_data_class = FunctionExpression\n", + "output_format_str = output_data_class.to_json_signature(exclude=[\"thought\"])\n", + "print(prompt(output_format_str=output_format_str))" ] }, { "cell_type": "code", - "source": [ - "from adalflow.components.output_parsers import JsonOutputParser\n", - "\n", - "func_parser = JsonOutputParser(data_class=Function, exclude_fields=[\"thought\", \"args\"])\n", - "instructions = func_parser.format_instructions()\n", - "print(instructions)" - ], + "execution_count": 17, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -493,11 +475,10 @@ "id": "MvGyoUmMUatR", "outputId": "e819866b-f6e3-4c88-f9f1-22d725a28865" }, - "execution_count": 17, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Your output should be formatted as a standard JSON instance with the following schema:\n", "```\n", @@ -512,19 +493,31 @@ "-Follow the JSON formatting conventions.\n" ] } + ], + "source": [ + "from adalflow.components.output_parsers import JsonOutputParser\n", + "\n", + "func_parser = JsonOutputParser(data_class=Function, exclude_fields=[\"thought\", \"args\"])\n", + "instructions = func_parser.format_instructions()\n", + "print(instructions)" ] }, { "cell_type": "markdown", - "source": [ - "## Function Output Format" - ], "metadata": { "id": "9W7DiGcpUme5" - } + }, + "source": [ + "## Function Output Format" + ] }, { "cell_type": "code", + "execution_count": 20, + "metadata": { + "id": "z5tNhoruUp6o" + }, + "outputs": [], "source": [ "from adalflow.core.generator import Generator\n", "from adalflow.core.types import ModelClientType\n", @@ -541,42 +534,11 @@ " prompt_kwargs=prompt_kwargs,\n", " output_processors=func_parser,\n", ")" - ], - "metadata": { - "id": "z5tNhoruUp6o" - }, - "execution_count": 20, - "outputs": [] + ] }, { "cell_type": "code", - "source": [ - "queries = [\n", - " \"add 2 and 3\",\n", - " \"search for something\",\n", - " \"add points (1, 2) and (3, 4)\",\n", - " \"sum numpy array with arr = np.array([[1, 2], [3, 4]])\",\n", - " \"multiply 2 with local variable x\",\n", - " \"divide 2 by 3\",\n", - " \"Add 5 to variable y\",\n", - "]\n", - "\n", - "for idx, query in enumerate(queries):\n", - " prompt_kwargs = {\"input_str\": query}\n", - " print(f\"\\n{idx} Query: {query}\")\n", - " print(f\"{'-'*50}\")\n", - " try:\n", - " result = generator(prompt_kwargs=prompt_kwargs)\n", - " # print(f\"LLM raw output: {result.raw_response}\")\n", - " func = Function.from_dict(result.data)\n", - " print(f\"Function: {func}\")\n", - " func_output = tool_manager.execute_func(func)\n", - " print(f\"Function output: {func_output}\")\n", - " except Exception as e:\n", - " print(\n", - " f\"Failed to execute the function for query: {query}, func: {result.data}, error: {e}\"\n", - " )" - ], + "execution_count": 21, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -584,11 +546,10 @@ "id": "9DCukn1SUs_x", "outputId": "dcfd952c-0699-4d79-ee6d-a59373e3c75d" }, - "execution_count": 21, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "\n", "0 Query: add 2 and 3\n", @@ -606,15 +567,15 @@ ] }, { - "output_type": "stream", "name": "stderr", + "output_type": "stream", "text": [ "ERROR:adalflow.core.func_tool:Error at calling : 'dict' object has no attribute 'x'\n" ] }, { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Function: Function(thought=None, name='add_points', args=[], kwargs={'p1': {'x': 1, 'y': 2}, 'p2': {'x': 3, 'y': 4}})\n", "Function output: FunctionOutput(name='add_points', input=Function(thought=None, name='add_points', args=(), kwargs={'p1': {'x': 1, 'y': 2}, 'p2': {'x': 3, 'y': 4}}), parsed_input=None, output=None, error=\"'dict' object has no attribute 'x'\")\n", @@ -640,62 +601,94 @@ ] }, { - "output_type": "stream", "name": "stderr", + "output_type": "stream", "text": [ "ERROR:adalflow.core.func_tool:Error at calling : unsupported operand type(s) for +: 'int' and 'str'\n" ] }, { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Function output: FunctionOutput(name='add', input=Function(thought=None, name='add', args=(), kwargs={'a': 5, 'b': 'y'}), parsed_input=None, output=None, error=\"unsupported operand type(s) for +: 'int' and 'str'\")\n" ] } + ], + "source": [ + "queries = [\n", + " \"add 2 and 3\",\n", + " \"search for something\",\n", + " \"add points (1, 2) and (3, 4)\",\n", + " \"sum numpy array with arr = np.array([[1, 2], [3, 4]])\",\n", + " \"multiply 2 with local variable x\",\n", + " \"divide 2 by 3\",\n", + " \"Add 5 to variable y\",\n", + "]\n", + "\n", + "for idx, query in enumerate(queries):\n", + " prompt_kwargs = {\"input_str\": query}\n", + " print(f\"\\n{idx} Query: {query}\")\n", + " print(f\"{'-'*50}\")\n", + " try:\n", + " result = generator(prompt_kwargs=prompt_kwargs)\n", + " # print(f\"LLM raw output: {result.raw_response}\")\n", + " func = Function.from_dict(result.data)\n", + " print(f\"Function: {func}\")\n", + " func_output = tool_manager.execute_func(func)\n", + " print(f\"Function output: {func_output}\")\n", + " except Exception as e:\n", + " print(\n", + " f\"Failed to execute the function for query: {query}, func: {result.data}, error: {e}\"\n", + " )" ] }, { "cell_type": "markdown", - "source": [ - "## FunctionExpression Output Format" - ], "metadata": { "id": "O-sBTPATUwsD" - } + }, + "source": [ + "## FunctionExpression Output Format" + ] }, { "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "TVRZ44N1UyWg" + }, + "outputs": [], "source": [ "tool_manager = ToolManager(\n", " tools=functions,\n", " additional_context={\"x\": x, \"y\": 0, \"np.array\": np.array, \"np\": np},\n", ")\n", "func_parser = JsonOutputParser(data_class=FunctionExpression)" - ], - "metadata": { - "id": "TVRZ44N1UyWg" - }, - "execution_count": 22, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": 23, + "metadata": { + "id": "9h47p4XpU2BC" + }, + "outputs": [], "source": [ "context = r\"\"\"\n", "Your function expression also have access to these context:\n", "{{context_str}}\n", "\n", "\"\"\"" - ], - "metadata": { - "id": "9h47p4XpU2BC" - }, - "execution_count": 23, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": 24, + "metadata": { + "id": "n9Qq7wcOU4X9" + }, + "outputs": [], "source": [ "async def run_async_function_call(self, generator, tool_manager):\n", " answers = []\n", @@ -726,12 +719,21 @@ " f\"Failed to execute the function for query: {query}, func: {result.data}, error: {e}\"\n", " )\n", " return None" - ], - "metadata": { - "id": "n9Qq7wcOU4X9" - }, - "execution_count": 24, - "outputs": [] + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" } - ] + }, + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/notebooks/tutorials/adalflow_logger.ipynb b/notebooks/tutorials/adalflow_logger.ipynb index 135d6450..6693f011 100644 --- a/notebooks/tutorials/adalflow_logger.ipynb +++ b/notebooks/tutorials/adalflow_logger.ipynb @@ -1,21 +1,10 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, "cells": [ { "cell_type": "markdown", + "metadata": { + "id": "lLGpv1fLLIjF" + }, "source": [ "# Adalflow RAG Playbook example\n", "\n", @@ -26,10 +15,7 @@ "- RAG with dynamic data access and caching the embedding dynamically in a local storage.\n", "\n", "Here we will have have a look at an example with a local DB using FAISS" - ], - "metadata": { - "id": "lLGpv1fLLIjF" - } + ] }, { "cell_type": "code", @@ -42,26 +28,15 @@ "from IPython.display import clear_output\n", "\n", "!pip install -U adalflow[openai,groq,faiss-cpu]\n", - "\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "clear_output()\n" ] }, { "cell_type": "code", - "source": [ - "import os\n", - "from getpass import getpass\n", - "\n", - "# Prompt user to enter their API keys securely\n", - "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", - "groq_api_key = getpass(\"Please enter your GROQ API key: \")\n", - "\n", - "# Set environment variables\n", - "os.environ['OPENAI_API_KEY'] = openai_api_key\n", - "os.environ['GROQ_API_KEY'] = groq_api_key\n", - "\n", - "print(\"API keys have been set.\")\n" - ], + "execution_count": 2, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -69,21 +44,37 @@ "id": "-4c_AGBt3PlR", "outputId": "275b050a-ce64-4b40-a5f9-4ccc12d92add" }, - "execution_count": 2, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Please enter your OpenAI API key: 路路路路路路路路路路\n", "Please enter your GROQ API key: 路路路路路路路路路路\n", "API keys have been set.\n" ] } + ], + "source": [ + "import os\n", + "from getpass import getpass\n", + "\n", + "# Prompt user to enter their API keys securely\n", + "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", + "groq_api_key = getpass(\"Please enter your GROQ API key: \")\n", + "\n", + "# Set environment variables\n", + "os.environ['OPENAI_API_KEY'] = openai_api_key\n", + "os.environ['GROQ_API_KEY'] = groq_api_key\n", + "\n", + "print(\"API keys have been set.\")\n" ] }, { "cell_type": "markdown", + "metadata": { + "id": "4NztjiLR_EQE" + }, "source": [ "## Design\n", "\n", @@ -96,45 +87,38 @@ "2. Additionally, as we can鈥檛 always control the outputs of generators, we will provide customized logger and tracers(drop-in decorators) for them, for which we will explain in Tracing. This will not break the first objective.\n", "\n", "In the future, when we have more complex requirements from users, we will consider adding hooks/callbacks but we will do it in a way to keep the functional and user-facing APIs clean." - ], - "metadata": { - "id": "4NztjiLR_EQE" - } + ] }, { "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "d2H1vYoC_F-g" + }, + "outputs": [], "source": [ "import logging\n", "\n", "log = logging.getLogger(__name__)" - ], - "metadata": { - "id": "d2H1vYoC_F-g" - }, - "execution_count": 3, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "e2GxAapG_TJH" + }, + "outputs": [], "source": [ "from adalflow.utils.logger import get_logger\n", "\n", "\n", "root_logger = get_logger()" - ], - "metadata": { - "id": "e2GxAapG_TJH" - }, - "execution_count": 4, - "outputs": [] + ] }, { "cell_type": "code", - "source": [ - "from adalflow.utils.logger import printc\n", - "\n", - "printc(\"All logging examples are done. Feeling green!\", color=\"green\")" - ], + "execution_count": 5, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -142,30 +126,39 @@ "id": "Yk4oiBFE_asG", "outputId": "470e30dc-1b31-40c1-9e48-30754ae54b45" }, - "execution_count": 5, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "\u001b[32m2024-11-28 13:39:41 - [:3:] - All logging examples are done. Feeling green!\u001b[0m\n" ] } + ], + "source": [ + "from adalflow.utils.logger import printc\n", + "\n", + "printc(\"All logging examples are done. Feeling green!\", color=\"green\")" ] }, { "cell_type": "markdown", + "metadata": { + "id": "B8lmlT_9_nVP" + }, "source": [ "Set up all logs in one file\n", "\n", "Assume your source code is at src/task.py. You can log simply by:" - ], - "metadata": { - "id": "B8lmlT_9_nVP" - } + ] }, { "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "o_Ru1myM_c-J" + }, + "outputs": [], "source": [ "import logging\n", "\n", @@ -174,26 +167,11 @@ "class Task:\n", " def __init__(self):\n", " log.info(\"This is a user program child logger\")" - ], - "metadata": { - "id": "o_Ru1myM_c-J" - }, - "execution_count": 6, - "outputs": [] + ] }, { "cell_type": "code", - "source": [ - "import logging\n", - "from adalflow.utils.logger import get_logger\n", - "\n", - "root_logger = get_logger(level=\"DEBUG\", save_dir=\"./logs\") # log to ./logs/lib.log\n", - "\n", - "# run code from the library components such as generator\n", - "# ....\n", - "\n", - "root_logger.info(\"This is the log in the main file\")" - ], + "execution_count": 7, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -201,28 +179,43 @@ "id": "o7YPjEZk_ehg", "outputId": "ad0f58e9-6f5c-4d00-e737-2fa1ad5ebd85" }, - "execution_count": 7, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "2024-11-28 13:39:46 - - INFO - [:9:] - This is the log in the main file\n" ] } + ], + "source": [ + "import logging\n", + "from adalflow.utils.logger import get_logger\n", + "\n", + "root_logger = get_logger(level=\"DEBUG\", save_dir=\"./logs\") # log to ./logs/lib.log\n", + "\n", + "# run code from the library components such as generator\n", + "# ....\n", + "\n", + "root_logger.info(\"This is the log in the main file\")" ] }, { "cell_type": "markdown", - "source": [ - "Separate library and application logs" - ], "metadata": { "id": "Db1_Ob3X_gpe" - } + }, + "source": [ + "Separate library and application logs" + ] }, { "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "rQWuFnUc_gNm" + }, + "outputs": [], "source": [ "from adalflow.utils.logger import get_logger\n", "\n", @@ -231,12 +224,21 @@ "class Task:\n", " def __init__(self):\n", " app_logger.info(\"This is a user program child logger\")" - ], - "metadata": { - "id": "rQWuFnUc_gNm" - }, - "execution_count": 8, - "outputs": [] + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" } - ] + }, + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/notebooks/tutorials/adalflow_modelclient.ipynb b/notebooks/tutorials/adalflow_modelclient.ipynb index 1674c69a..884086db 100644 --- a/notebooks/tutorials/adalflow_modelclient.ipynb +++ b/notebooks/tutorials/adalflow_modelclient.ipynb @@ -83,7 +83,9 @@ "from IPython.display import clear_output\n", "\n", "!pip install -U adalflow[openai,groq,faiss-cpu]\n", - "\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "clear_output()" ] }, diff --git a/notebooks/tutorials/adalflow_rag_optimization.ipynb b/notebooks/tutorials/adalflow_rag_optimization.ipynb index 7ae0b152..79fff86d 100644 --- a/notebooks/tutorials/adalflow_rag_optimization.ipynb +++ b/notebooks/tutorials/adalflow_rag_optimization.ipynb @@ -1,21 +1,10 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, "cells": [ { "cell_type": "markdown", + "metadata": { + "id": "xHF95Kr4CzGq" + }, "source": [ "# 馃 Welcome to AdalFlow!\n", "## The PyTorch library to auto-optimize any LLM task pipelines\n", @@ -44,13 +33,13 @@ "- Build the standard RAG with Retriever and Generator components.\n", "\n", "- Learn how to connect the output-input between components to enable auto-text-grad optimization." - ], - "metadata": { - "id": "xHF95Kr4CzGq" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "Kof5M6DRaKhh" + }, "source": [ "\n", "# Installation\n", @@ -63,10 +52,7 @@ "2. Setup `openai` and `groq` API key in the environment variables\n", "\n", "You can choose to use different client. You can import the model client you prefer. We support `Anthropic`, `Cohere`, `Google`, `GROQ`, `OpenAI`, `Transformer` and more in development. We will use OpenAI here as an example.Please refer to our [full installation guide](https://adalflow.sylph.ai/get_started/installation.html)" - ], - "metadata": { - "id": "Kof5M6DRaKhh" - } + ] }, { "cell_type": "code", @@ -81,11 +67,17 @@ "!pip install -U adalflow[openai] # also install the package for the model client you'll use\n", "!pip install dspy\n", "!pip install datasets\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "clear_output()" ] }, { "cell_type": "markdown", + "metadata": { + "id": "KapUyHMM07pJ" + }, "source": [ "## Set Environment Variables\n", "\n", @@ -94,27 +86,11 @@ "Note: for normal `.py` projects, follow our [official installation guide](https://lightrag.sylph.ai/get_started/installation.html).\n", "\n", "*Go to [OpenAI](https://platform.openai.com/docs/introduction) to get API keys if you don't already have.*" - ], - "metadata": { - "id": "KapUyHMM07pJ" - } + ] }, { "cell_type": "code", - "source": [ - "import os\n", - "\n", - "from getpass import getpass\n", - "\n", - "# Prompt user to enter their API keys securely\n", - "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", - "\n", - "\n", - "# Set environment variables\n", - "os.environ['OPENAI_API_KEY'] = openai_api_key\n", - "\n", - "print(\"API keys have been set.\")" - ], + "execution_count": 3, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -122,20 +98,38 @@ "id": "ONfzF9Puzdd_", "outputId": "5fc0cd30-9ae7-443a-c06c-31e9edeafd69" }, - "execution_count": 3, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Please enter your OpenAI API key: 路路路路路路路路路路\n", "API keys have been set.\n" ] } + ], + "source": [ + "import os\n", + "\n", + "from getpass import getpass\n", + "\n", + "# Prompt user to enter their API keys securely\n", + "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", + "\n", + "\n", + "# Set environment variables\n", + "os.environ['OPENAI_API_KEY'] = openai_api_key\n", + "\n", + "print(\"API keys have been set.\")" ] }, { "cell_type": "code", + "execution_count": 20, + "metadata": { + "id": "aE3I05BqOmd7" + }, + "outputs": [], "source": [ "import dspy\n", "import re\n", @@ -150,15 +144,15 @@ "from adalflow.core.retriever import Retriever\n", "from adalflow.core.component import fun_to_component\n", "from adalflow.components.model_client.openai_client import OpenAIClient" - ], - "metadata": { - "id": "aE3I05BqOmd7" - }, - "execution_count": 20, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cqUUoua9fUxQ" + }, + "outputs": [], "source": [ "\n", "gpt_4o_model = {\n", @@ -176,15 +170,37 @@ " \"max_tokens\": 2000,\n", " },\n", "}" - ], - "metadata": { - "id": "cqUUoua9fUxQ" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": 22, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "0irHeHUkOmL8", + "outputId": "61f778a2-9ec1-4fda-daa2-bcc7f31baa78" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "HotPotQAData(id='5a8b57f25542995d1e6f1371', question='Were Scott Derrickson and Ed Wood of the same nationality?', answer='yes', gold_titles=\"{'Scott Derrickson', 'Ed Wood'}\") \n" + ] + }, + { + "data": { + "text/plain": [ + "HotPotQAData(id='5a8b57f25542995d1e6f1371', question='Were Scott Derrickson and Ed Wood of the same nationality?', answer='yes', gold_titles=\"{'Scott Derrickson', 'Ed Wood'}\")" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "def load_datasets():\n", "\n", @@ -211,37 +227,15 @@ "print(dataset[0], type(dataset[0]))\n", "\n", "HotPotQAData(id='5a8b57f25542995d1e6f1371', question='Were Scott Derrickson and Ed Wood of the same nationality?', answer='yes', gold_titles=\"{'Scott Derrickson', 'Ed Wood'}\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "0irHeHUkOmL8", - "outputId": "61f778a2-9ec1-4fda-daa2-bcc7f31baa78" - }, - "execution_count": 22, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "HotPotQAData(id='5a8b57f25542995d1e6f1371', question='Were Scott Derrickson and Ed Wood of the same nationality?', answer='yes', gold_titles=\"{'Scott Derrickson', 'Ed Wood'}\") \n" - ] - }, - { - "output_type": "execute_result", - "data": { - "text/plain": [ - "HotPotQAData(id='5a8b57f25542995d1e6f1371', question='Were Scott Derrickson and Ed Wood of the same nationality?', answer='yes', gold_titles=\"{'Scott Derrickson', 'Ed Wood'}\")" - ] - }, - "metadata": {}, - "execution_count": 22 - } ] }, { "cell_type": "code", + "execution_count": 23, + "metadata": { + "id": "ZZIEtZYHNVjo" + }, + "outputs": [], "source": [ "class DspyRetriever(adal.Retriever):\n", " def __init__(self, top_k: int = 3):\n", @@ -471,25 +465,34 @@ " trainer.diagnose(dataset=trainset, split=\"train\")\n", " # trainer.diagnose(dataset=valset, split=\"val\")\n", " # trainer.diagnose(dataset=testset, split=\"test\")\n" - ], - "metadata": { - "id": "ZZIEtZYHNVjo" - }, - "execution_count": 23, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "AmkbyxmuruUu" + }, "source": [ "# Issues and feedback\n", "\n", "If you encounter any issues, please report them here: [GitHub Issues](https://github.com/SylphAI-Inc/LightRAG/issues).\n", "\n", "For feedback, you can use either the [GitHub discussions](https://github.com/SylphAI-Inc/LightRAG/discussions) or [Discord](https://discord.gg/ezzszrRZvT)." - ], - "metadata": { - "id": "AmkbyxmuruUu" - } + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" } - ] + }, + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/notebooks/tutorials/adalflow_rag_playbook.ipynb b/notebooks/tutorials/adalflow_rag_playbook.ipynb index 27c6bda0..e869f06a 100644 --- a/notebooks/tutorials/adalflow_rag_playbook.ipynb +++ b/notebooks/tutorials/adalflow_rag_playbook.ipynb @@ -1,21 +1,10 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, "cells": [ { "cell_type": "markdown", + "metadata": { + "id": "lLGpv1fLLIjF" + }, "source": [ "# Adalflow RAG Playbook example\n", "\n", @@ -26,10 +15,7 @@ "- RAG with dynamic data access and caching the embedding dynamically in a local storage.\n", "\n", "Here we will have have a look at an example with a local DB using FAISS" - ], - "metadata": { - "id": "lLGpv1fLLIjF" - } + ] }, { "cell_type": "code", @@ -42,26 +28,16 @@ "from IPython.display import clear_output\n", "\n", "!pip install -U adalflow[openai,groq,faiss-cpu]\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "\n", "clear_output()\n" ] }, { "cell_type": "code", - "source": [ - "import os\n", - "from getpass import getpass\n", - "\n", - "# Prompt user to enter their API keys securely\n", - "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", - "groq_api_key = getpass(\"Please enter your GROQ API key: \")\n", - "\n", - "# Set environment variables\n", - "os.environ['OPENAI_API_KEY'] = openai_api_key\n", - "os.environ['GROQ_API_KEY'] = groq_api_key\n", - "\n", - "print(\"API keys have been set.\")\n" - ], + "execution_count": 2, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -69,21 +45,39 @@ "id": "-4c_AGBt3PlR", "outputId": "a36f157b-0b18-4f3d-d5a8-09aa94743922" }, - "execution_count": 2, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Please enter your OpenAI API key: 路路路路路路路路路路\n", "Please enter your GROQ API key: 路路路路路路路路路路\n", "API keys have been set.\n" ] } + ], + "source": [ + "import os\n", + "from getpass import getpass\n", + "\n", + "# Prompt user to enter their API keys securely\n", + "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", + "groq_api_key = getpass(\"Please enter your GROQ API key: \")\n", + "\n", + "# Set environment variables\n", + "os.environ['OPENAI_API_KEY'] = openai_api_key\n", + "os.environ['GROQ_API_KEY'] = groq_api_key\n", + "\n", + "print(\"API keys have been set.\")\n" ] }, { "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "V9LsGDnm3RbV" + }, + "outputs": [], "source": [ "from typing import Any, List, Optional\n", "import os\n", @@ -99,15 +93,15 @@ " TextSplitter,\n", ")\n", "from adalflow.utils.global_config import get_adalflow_default_root_path\n" - ], - "metadata": { - "id": "V9LsGDnm3RbV" - }, - "execution_count": 4, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "kWGTZxrw3Tli" + }, + "outputs": [], "source": [ "configs = {\n", " \"embedder\": {\n", @@ -135,15 +129,15 @@ " \"chunk_overlap\": 200,\n", " },\n", "}\n" - ], - "metadata": { - "id": "kWGTZxrw3Tli" - }, - "execution_count": 5, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "1QE0PCKs4BLz" + }, + "outputs": [], "source": [ "def prepare_data_pipeline():\n", " splitter = TextSplitter(**configs[\"text_splitter\"])\n", @@ -171,15 +165,15 @@ " data_transformer = prepare_data_pipeline()\n", " db.transform(data_transformer, key=\"data_transformer\")\n", " db.save_state(index_path)\n" - ], - "metadata": { - "id": "1QE0PCKs4BLz" - }, - "execution_count": 6, - "outputs": [] + ] }, { "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "6Mu1HXhy4DIG" + }, + "outputs": [], "source": [ "RAG_PROMPT_TEMPLATE = r\"\"\"\n", "{{task_desc}}\n", @@ -282,42 +276,11 @@ " print(f\"context_str: \\n {context_str}\")\n", "\n", " return self.generate(query, context=context_str)\n" - ], - "metadata": { - "id": "6Mu1HXhy4DIG" - }, - "execution_count": 7, - "outputs": [] + ] }, { "cell_type": "code", - "source": [ - "# Prepare initial documents\n", - "doc1 = Document(\n", - " meta_data={\"title\": \"Li Yin's profile\"},\n", - " text=\"My name is Li Yin, I love rock climbing\" + \"lots of nonsense text\" * 500,\n", - " id=\"doc1\",\n", - ")\n", - "doc2 = Document(\n", - " meta_data={\"title\": \"Interviewing Li Yin\"},\n", - " text=\"lots of more nonsense text\" * 250\n", - " + \"Li Yin is an AI researcher and a software engineer\"\n", - " + \"lots of more nonsense text\" * 250,\n", - " id=\"doc2\",\n", - ")\n", - "\n", - "# Prepare the database (only runs once)\n", - "prepare_database_with_index([doc1, doc2], index_file=\"index.faiss\")\n", - "\n", - "# Initialize RAG\n", - "rag = RAG(index_file=\"index.faiss\")\n", - "print(rag)\n", - "\n", - "# Query the RAG system\n", - "query = \"What is Li Yin's hobby and profession?\"\n", - "response = rag.call(query)\n", - "print(f\"Response: {response}\")\n" - ], + "execution_count": 8, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -325,11 +288,10 @@ "id": "sPnx4PY34D1j", "outputId": "f66d6f1a-70bf-40e9-a160-591fcfdcbed3" }, - "execution_count": 8, "outputs": [ { - "output_type": "stream", "name": "stderr", + "output_type": "stream", "text": [ "Splitting Documents in Batches: 100%|鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 1/1 [00:00<00:00, 109.58it/s]\n", "Batch embedding documents: 100%|鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 1/1 [00:01<00:00, 1.33s/it]\n", @@ -337,8 +299,8 @@ ] }, { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Saved the state of the DB to /root/.adalflow/index.faiss\n", "RAG(\n", @@ -433,33 +395,38 @@ "Response: (GeneratorOutput(id=None, data={'answer': \"Li Yin's hobby is rock climbing and profession is an AI researcher and a software engineer.\"}, error=None, usage=CompletionUsage(completion_tokens=25, prompt_tokens=2713, total_tokens=2738), raw_response='{\\n \"answer\": \"Li Yin\\'s hobby is rock climbing and profession is an AI researcher and a software engineer.\"\\n}', metadata=None), ' My name is Li Yin, I love rock climbinglots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textLi Yin is an AI researcher and a software engineerlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more textLi Yin is an AI researcher and a software engineerlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense ')\n" ] } - ] - }, - { - "cell_type": "code", + ], "source": [ - "# Add more documents at runtime\n", - "doc3 = Document(\n", - " meta_data={\"title\": \"Apple's profile\"},\n", - " text=\"Apple is a cute dog with black and tan fur\" + \"lots of nonsense text\" * 500,\n", - " id=\"doc3\",\n", + "# Prepare initial documents\n", + "doc1 = Document(\n", + " meta_data={\"title\": \"Li Yin's profile\"},\n", + " text=\"My name is Li Yin, I love rock climbing\" + \"lots of nonsense text\" * 500,\n", + " id=\"doc1\",\n", ")\n", - "doc4 = Document(\n", - " meta_data={\"title\": \"Apple's characteristics\"},\n", + "doc2 = Document(\n", + " meta_data={\"title\": \"Interviewing Li Yin\"},\n", " text=\"lots of more nonsense text\" * 250\n", - " + \"Apple is energetic, loves to play with her monkey toy\"\n", + " + \"Li Yin is an AI researcher and a software engineer\"\n", " + \"lots of more nonsense text\" * 250,\n", - " id=\"doc4\",\n", + " id=\"doc2\",\n", ")\n", "\n", - "rag.add_documents([doc3, doc4])\n", - "rag.prepare_retriever()\n", + "# Prepare the database (only runs once)\n", + "prepare_database_with_index([doc1, doc2], index_file=\"index.faiss\")\n", "\n", - "# Test a new query\n", - "query = \"What is Apple's favorite toy?\"\n", + "# Initialize RAG\n", + "rag = RAG(index_file=\"index.faiss\")\n", + "print(rag)\n", + "\n", + "# Query the RAG system\n", + "query = \"What is Li Yin's hobby and profession?\"\n", "response = rag.call(query)\n", "print(f\"Response: {response}\")\n" - ], + ] + }, + { + "cell_type": "code", + "execution_count": 9, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -467,11 +434,10 @@ "id": "bcC1-dCheVEC", "outputId": "133bab3f-ff2e-40db-99dc-71d64af6283f" }, - "execution_count": 9, "outputs": [ { - "output_type": "stream", "name": "stderr", + "output_type": "stream", "text": [ "Splitting Documents in Batches: 100%|鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 1/1 [00:00<00:00, 114.76it/s]\n", "Batch embedding documents: 100%|鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 1/1 [00:00<00:00, 1.35it/s]\n", @@ -479,23 +445,41 @@ ] }, { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Saved the state of the DB to /root/.adalflow/index.faiss\n", "Response: (GeneratorOutput(id=None, data={'answer': \"Apple's favorite toy is her monkey toy.\"}, error=None, usage=CompletionUsage(completion_tokens=16, prompt_tokens=2647, total_tokens=2663), raw_response='{\\n \"answer\": \"Apple\\'s favorite toy is her monkey toy.\"\\n}', metadata=None), ' Apple is a cute dog with black and tan furlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots of nonsense textlots textApple is energetic, loves to play with her monkey toylots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textApple is energetic, loves to play with her monkey toylots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textLi Yin is an AI researcher and a software engineerlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more textLi Yin is an AI researcher and a software engineerlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more ')\n" ] } + ], + "source": [ + "# Add more documents at runtime\n", + "doc3 = Document(\n", + " meta_data={\"title\": \"Apple's profile\"},\n", + " text=\"Apple is a cute dog with black and tan fur\" + \"lots of nonsense text\" * 500,\n", + " id=\"doc3\",\n", + ")\n", + "doc4 = Document(\n", + " meta_data={\"title\": \"Apple's characteristics\"},\n", + " text=\"lots of more nonsense text\" * 250\n", + " + \"Apple is energetic, loves to play with her monkey toy\"\n", + " + \"lots of more nonsense text\" * 250,\n", + " id=\"doc4\",\n", + ")\n", + "\n", + "rag.add_documents([doc3, doc4])\n", + "rag.prepare_retriever()\n", + "\n", + "# Test a new query\n", + "query = \"What is Apple's favorite toy?\"\n", + "response = rag.call(query)\n", + "print(f\"Response: {response}\")\n" ] }, { "cell_type": "code", - "source": [ - "# View all documents in the database\n", - "print(\"All documents in the database:\")\n", - "for item in rag.db.items:\n", - " print(f\"ID: {item.id}, Title: {item.meta_data['title']}, Text: {item.text[:100]}...\")\n" - ], + "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -503,11 +487,10 @@ "id": "o9TzVv5GeZZ2", "outputId": "bde56355-186c-4013-d702-b4530f82881b" }, - "execution_count": 10, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "All documents in the database:\n", "ID: doc1, Title: Li Yin's profile, Text: My name is Li Yin, I love rock climbinglots of nonsense textlots of nonsense textlots of nonsense te...\n", @@ -516,7 +499,27 @@ "ID: doc4, Title: Apple's characteristics, Text: lots of more nonsense textlots of more nonsense textlots of more nonsense textlots of more nonsense ...\n" ] } + ], + "source": [ + "# View all documents in the database\n", + "print(\"All documents in the database:\")\n", + "for item in rag.db.items:\n", + " print(f\"ID: {item.id}, Title: {item.meta_data['title']}, Text: {item.text[:100]}...\")\n" ] } - ] + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/notebooks/tutorials/adalflow_rag_vanilla.ipynb b/notebooks/tutorials/adalflow_rag_vanilla.ipynb index 34a53174..7fdb1738 100644 --- a/notebooks/tutorials/adalflow_rag_vanilla.ipynb +++ b/notebooks/tutorials/adalflow_rag_vanilla.ipynb @@ -98,7 +98,9 @@ "outputs": [], "source": [ "from adalflow.utils import setup_env\n", - "\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "# Load environment variables - Make sure to have OPENAI_API_KEY in .env file and .env is present in current folder\n", "setup_env(\".env\")" ] diff --git a/notebooks/tutorials/adalflow_text_splitter.ipynb b/notebooks/tutorials/adalflow_text_splitter.ipynb index 66fb81c7..26831f3d 100644 --- a/notebooks/tutorials/adalflow_text_splitter.ipynb +++ b/notebooks/tutorials/adalflow_text_splitter.ipynb @@ -8,7 +8,10 @@ }, "outputs": [], "source": [ - "!pip install adalflow[openai,groq,faiss-cpu]" + "!pip install adalflow[openai,groq,faiss-cpu]\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1" ] }, { diff --git a/notebooks/tutorials/adalflow_tracing.ipynb b/notebooks/tutorials/adalflow_tracing.ipynb index 014c1b5e..25e39455 100644 --- a/notebooks/tutorials/adalflow_tracing.ipynb +++ b/notebooks/tutorials/adalflow_tracing.ipynb @@ -1,31 +1,17 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, "cells": [ { "cell_type": "markdown", + "metadata": { + "id": "lLGpv1fLLIjF" + }, "source": [ "# Tracing\n", "\n", "In particular, we provide two tracing methods to help you develop and improve the Generator:\n", "\n", "1. Trace the history change(states) on prompt during your development process. Developers typically go through a long process of prompt optimization and it is frustrating to lose track of the prompt changes when your current change actually makes the performance much worse.\n" - ], - "metadata": { - "id": "lLGpv1fLLIjF" - } + ] }, { "cell_type": "code", @@ -38,26 +24,16 @@ "from IPython.display import clear_output\n", "\n", "!pip install -U adalflow[openai,groq,faiss-cpu]\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "\n", "clear_output()\n" ] }, { "cell_type": "code", - "source": [ - "import os\n", - "from getpass import getpass\n", - "\n", - "# Prompt user to enter their API keys securely\n", - "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", - "groq_api_key = getpass(\"Please enter your GROQ API key: \")\n", - "\n", - "# Set environment variables\n", - "os.environ['OPENAI_API_KEY'] = openai_api_key\n", - "os.environ['GROQ_API_KEY'] = groq_api_key\n", - "\n", - "print(\"API keys have been set.\")\n" - ], + "execution_count": 2, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -65,30 +41,48 @@ "id": "-4c_AGBt3PlR", "outputId": "85aba038-ee9c-463d-bdbd-027cbfff0094" }, - "execution_count": 2, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Please enter your OpenAI API key: 路路路路路路路路路路\n", "Please enter your GROQ API key: 路路路路路路路路路路\n", "API keys have been set.\n" ] } + ], + "source": [ + "import os\n", + "from getpass import getpass\n", + "\n", + "# Prompt user to enter their API keys securely\n", + "openai_api_key = getpass(\"Please enter your OpenAI API key: \")\n", + "groq_api_key = getpass(\"Please enter your GROQ API key: \")\n", + "\n", + "# Set environment variables\n", + "os.environ['OPENAI_API_KEY'] = openai_api_key\n", + "os.environ['GROQ_API_KEY'] = groq_api_key\n", + "\n", + "print(\"API keys have been set.\")\n" ] }, { "cell_type": "markdown", - "source": [ - "We created a GeneratorStateLogger to handle the logging and saving into json files. To further simplify developers鈥檚 process, we provides a class decorator trace_generator_states where a single line of code can be added to any of your task component. It will automatically track any attributes of type Generator." - ], "metadata": { "id": "yWi2uEiE6UIf" - } + }, + "source": [ + "We created a GeneratorStateLogger to handle the logging and saving into json files. To further simplify developers鈥檚 process, we provides a class decorator trace_generator_states where a single line of code can be added to any of your task component. It will automatically track any attributes of type Generator." + ] }, { "cell_type": "code", + "execution_count": 13, + "metadata": { + "id": "qk9pkcCVzdek" + }, + "outputs": [], "source": [ "from adalflow.tracing import trace_generator_states\n", "from adalflow.core import Component, Generator\n", @@ -109,33 +103,33 @@ "\n", " def call(self, query: str) -> str:\n", " return self.doc(prompt_kwargs={\"input_str\": query}).data\n" - ], - "metadata": { - "id": "qk9pkcCVzdek" - }, - "execution_count": 13, - "outputs": [] + ] }, { "cell_type": "markdown", - "source": [ - "Here is the folder structer of where the trace is generated as a .json file and also an example output below" - ], "metadata": { "id": "LAZUSnYn-lnI" - } + }, + "source": [ + "Here is the folder structer of where the trace is generated as a .json file and also an example output below" + ] }, { "cell_type": "markdown", - "source": [ - "![image.png](data:image/png;base64,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zbq6aOkpV/TYnUL89O7d2za1FAEREAEREAERyDiBmhU+uLfSMImfNCiqDBEQAREQARFoGgI16+oqNaan0O1A/Jjrq1C6QsemTZvmJk6c6MaMGeOmTp1aKKmOiYAIiIAIiIAIlEmgZlt8yuTVaNkQYt26dfNxR8QfyURABERABERABNInIOGTPtOKSiTuiPgjmQiIgAiIgAiIQPoEatbVlT7K9EqsJP6oZ8+erl+/fr4yjz7yiBs5alR6FVNJIiACIiACIlDlBCR8MngDK4k/WmKJJdwCCyzgr6rLcstl8OpUJREQAREQARFoPgJydTUfe51ZBERABERABESgiQmoxaeJgTfW6ZZeemk322yzuY4dO0anaN++vVtmmWX89qeffup+++03v77kkku6Nm3auF9++cVNnjzZtWvXzm2wwQZu8cUXd4899ph7//33ozJYIe1qq63mVl55Zffdd9+5Dz74wL355pvu999/r5MuaWPOOed0a621lltqqaV8/d5++233xhtvuJ9++ikpeZ191GudddbxeadMmeJefvllN2nSpDppkjaIk6KuXbp08eekvpzz+++/T0qufSIgAiIgAjVEQMKnhdzsc845p96V8OIfMmSI33/VVVe5+++/36+fe+65fvnzzz+7xx9/3G2++eZR3k6dOkV5FllkEXfKKadErrMoUW5lxowZbsSIEe7uu+8Od9dZP/TQQ92GG27oxUd4YObMmV5gDRs2LK94Ovroo93aa6/tWrVqFWb14o1rffHFF+vsZwOBdsghh3gRhwiM24QJE9yFF14oARQHo20REAERqCECFQsfRi6udAwb4635r4xE0yznmmuuOqInPCtB0oiI1q1bh7ujdUTG3nvv7RAx99xzT7TfVvr37+8oI8kQMxtvvLHrutJK7pBcurgde+yxvpUovp/t2Wef3Q0ePNiLrttvv71OkjPPPDNq4apzYNYGrVbnDh3qDvrHP9wff/yRlET7REAEREAEWjiB1rlg2JMrucYPP/zQ/yo3l0q5ZTW16Mn6VBPwKMVef/1134qCmCHAGWNAxAsuuMCNHz/et5DQSoPttttufmn/cHlxH1977TX31FNPeXfSGWec4UUGab7++msvbq688kpHK9Fiiy3mcGFhq666qrvtttu8API7cv923HFHt+2229qmL/Paa6919957r2+Vodca4gdXFq65559/PkqLmOrVq5ffRpzceeedjvPSwrPssstGk8l27drVtzaZu41Wq8022ywqhzJHjhzp880///yRCxA+Cy64oHvuueeitFoRAREQARGoHQIVt/iAyibqLLflp6lFT0u8vcSwYAgRM0aARswUsi+++MIPmhimIa7GhA0jStN6Yy0kw4cPd/fdd5+7/PLLfRZcSoiQ8Dx9+/aNigtdbOy85JJL3HvvvecOPPBAn4bYoksvvdSvI2xCwXTCCSe4d955xx/76KOP3AsvvOAuvvhit9BCC/mWqP3339/hLsPWXXddv+QfIu7ss8+OthF+++23n9tqq638vlVWWSU6phUREAEREIHaIlA/EKLM60f8lNpKwakkesoEnkI2xMwxxxxTr6RPPvnEt5bQYnL++edHoscSfvvtt+7zzz+3TbdSzmVltuKKK0ZxOQQTW1yRHWc5duxY9+OPP/pdtMBY9/0ddtghSvbqq69GoifamVu54ooros1QwORzyVni0aNHu7feesv/0TomEwEREAERqE0CqbT4GLpSW34keoxc8ywRPj/88EO9kyNqcF+ZEc9DTzB6Zs0777x+dxg83CaIA1pzzTUtm2+hiTZiK7jg6EWGmQgKBRTCh0DruIWCy+pCGlx0JoRwu5544onujjvucK+88oovAhFGC5JMBERABESgtgmkKnxAWaz4kejJ/oPXo0cPPwo0vbuKtVC80FU+nxGzE++ZNffcc0fJ99xzT8dfITN3HGkeyY1SzVQfCDSMec/4IwaIetDKNG7cuLy9yHwm/RMBERABEWjxBFJzdYWkGnJ7SfSEtLK5TlzPkUce6ULRQw8uAqQJhmY9ycIJVr/66qukJHn30bJUioVd3anXEUcc4cWNBXFTFi4wxNABBxzgiE9ab731SjmF0oqACIiACLQwAqW9aUq4+HwtPxI9JUBspqS4jKxnFVWghxSigUEQzXAbhYHUtp8BDhdddFG/SRByKcYAixarM2bMGEdgdSGzHl1hGoKu+aO1aqONNnLEHJlLjLIRR/GA6zC/1kVABERABFo2gUYTPmCLix+Jnup4mHbeeeeoooiesIdUdCDPCuLI3F0Ww5Mnab3diCZrYaI31xNPPFEvTbE7nn76accfRvf+k086yXWYbz6/Tc+xpKBrf1D/REAEREAEWjSBRhU+kDPxE19v0VSr/OIY58aMHl5Jxtg4ScbYQWbdu3e31XpLemfNN0uI0C2d1p3PPvssEj477bRTXuGDS2yOOeaIgqKJDbrmmmv8OQiUprzQEGP/vegid/zxx/vdSUHTYXqti4AIiIAItFwCjRLjE8eF+AkFUPy4ttMjQPyNWbkveFpezDbdZBNbjZaHH354FETMztlzIsSMVj2bEwxBkhSgvEmuTBM9nMtcWrfeeqsV48tnIMS44bZi7B7cVauvvro/zLxfv/76q3eT0TU+aTyp6dOnR0Xli0+KEmhFBERABESgxRJo9BafFksuoxf28ccfRzUj1uawww7zA/q99NJLdWJ0okQJK6QlNgbDPXT11Vf7AQppaWG/jbtjWS2Ghm0Cixn/hxGYMcQLrq8nn3zSj/pM7A2Tlpo9+OCDturH7WGQQjuOaCI9E6cSz0MvLaadsN5c/fr18xOXUgATmFrg8sEHH+y2335798wzz3hRRR7r6k5aBkOUiYAIiIAI1CYBCZ8Wdt8RLYgPRAq9ngjw5Y/pIUaNGlXU1TKGD1N6WHAyQsdEhRVAq4n1qmJm+NCYuJTWGAt+RiyZkArT0Qp40003hbv8gInEFDEtBsZozvzFDfHCnF5mTD5KfZmYlXqRP6nFCDY2Savl1VIEREAERKB2CDSJq6t2cDb/lfJivygXz5LU46mU2g0aNMj35oq7hSiX8XCYOsLMenHZNsvTTjvN965ibq+4MZUGriqbqiI8TvqBAwe6m2++OXKZhceJ4WGwQuoXXiPXjRB64IEHHK6vuHEdDGY4YMCAOqNOx9NpWwREQAREoGUTaJVzJSQPyNKyr9sxCWeW7bjjjquoesxizhxa7du39wP40UJi822VUjBdwJdffnk/sSeBy2GX9mLLwTWFmwrxMWHCBN8iVWxe4oRwU1F3hIvFDzWUnxYvWpyYEmPSpEmOIO1yrr+h8+i4CIiACIhAdRGQq6u67lfRtUUgIDIqNVpVmOOqEiPgOpyBvZSyaL0pZyZ1WoDiI0OXcl6lFQEREAERaJkEatbVZT2Jsnhbs1y3LPJSnURABERABESgWAI1K3zC8WaKhdVU6bJct6ZioPOIgAiIgAiIQGMQqFnhw5QINit4Y4Att0zqRN1kIiACIiACIiAC6RNonRvO/+T0i81+icSdECzLGDRt27aNxoZprprj3mKahhEjRjh6PclEQAREQAREQATSJ1CzvbrSR6kSRUAEREAEREAEsk6gZl1dWb8xqp8IiIAIiIAIiED6BCR80meqEkVABERABERABDJKQMInozdG1RIBERABERABEUifgIRP+kxVogiIgAiIgAiIQEYJSPhk9MaoWiIgAiIgAiIgAukTkPBJn6lKFAEREAEREAERyCgBCZ+M3hhVSwREQAREQAREIH0CEj7pM1WJIiACIiACIiACGSUg4ZPRG6NqiYAIiIAIiIAIpE9Awid9pipRBERABERABEQgowQkfDJ6Y1QtERABERABERCB9AlI+KTPVCWKgAiIgAiIgAhklICET0ZvjKolAiIgAiIgAiKQPgEJn/SZqkQREAEREAEREIGMEpDwyeiNUbVEQAREQAREQATSJyDhkz5TlSgCIiACIiACIpBRAhI+Gb0xqpYIiIAIiIAIiED6BCR80meqEkVABERABERABDJKQMInozdG1RIBERABERABEUifgIRP+kxVogiIgAiIgAiIQEYJSPhk9MaoWiIgAiIgAiIgAukTkPBJn6lKFAEREAEREAERyCgBCZ+M3hhVSwREQAREQAREIH0CEj7pM1WJIiACIiACIiACGSUg4ZPRG6NqiYAIiIAIiIAIpE9Awid9pipRBERABERABEQgowQkfDJ6Y1QtERABERABERCB9AlI+KTPVCWKgAiIgAiIgAhklICET0ZvjKolAiIgAiIgAiKQPgEJn/SZqkQREAEREAEREIGMEpDwyeiNUbVEQAREQAREQATSJ9Am/SJVYloEOnTo4Pr06eM6d+7s5plnnpKKffjhh91DDz1UUh4lFgEREAEREIGWTkDCJ6N3GNEzYMAA17Zt27JquOmmm/p8Ej9l4VMmERABERCBFkpArq6M3lhaesoVPXZJiJ/evXvbppYiIAIiIAIiUPMEJHwy+gjg3krDJH7SoKgyREAEREAEWgoBuboyeidLjekpdBmIH3N9FUpX6Ni0adPcxIkT3ZgxY9zUqVMLJdUxERABERABEcgsAQmfzN6abFUMIdatWzfXpUsXd9FFF5UtftZaay3Xvn37ehdnwuqbb76pdyzrO+aaay7Xs2dPt/TSS7uOHTu6KVOmuE8++cSNHz/e/fTTT2VVf8MNN3StW7d23333nZswYUJZZSiTCIiACIhAfQISPvWZaE8BAsQdEX80atSoAqnyHxo0aJBr0yb/Y/fHH3+49957zw0fPty98cYb+QvKwJE555zTHX744W7NNdd0s81W32u83377uVdffdUNHTq0JAG03nrruYEDB/ornDlzptt3333djz/+mIErVhVEQAREoPoJ1P+2rv5r0hU0MoG04o+SqomAWGGFFdwpp5wSvfyT0jX3vvnnn99dcsklbu21104UPdSPa1lttdXcsGHDXKdOnYqu8g477BClbdWqldt5552jba2IgAiIgAhURiD/T+/KylXuFkwgrfij0aNHu6+//trxcl9yySXdcsst5xBVs88+u6eHu2ehhRZyxx13XOZoDhkyxM0777xRvT788EP37LPPunfffddfBy695Zdf3h9v166dI/0BBxzgaNEqZHPPPbdbZpll6iTp1auXu+GGG+rs04YIiIAIiEB5BCR8yuOmXCkQeOKJJ9ynn35apyTcYAidVVZZxe+n9Wfbbbd1d999d510zbnRd4893HzzzRdV4bacgBsZuP6IyUHUbbfddm6vvfbywo64JlxWV199dZQvaWWnnXby6cNjCCxiq95///1wt9ZFQAREQATKICBXVxnQlKXxCMyYMcO7uZ577rnoJP369cvrTiIRLiVcTrvssosjLe6lQnFEUcGzVojVWX/99d0eOUGz5557OlpraHnJZ1tvs0106IUXXqgjeqIDuZW77rrLIe7MNt98c1vNu9xkk02iY88//3y03rdv32hdKyIgAiIgAuUTUItP+eyUsxEJ0HPsmmuu8aKG3k30mnr00UfrnXHXXXd1tJKEQsdiZAiSPvXUUwsGFh966KEOl1o8OJmg4scee8zH5/z+++/ReWmBQihhpLniiiuiY0kr1157rS8fdx51pCXrtddeS0rqll12WceI3dj06dN97zkYkJd81LEhV1liwdopAiIgAiIQEWjxwoeRiysdw8Zoaf4rI9H4S3ox0Zqyzjrr+JPRWhIXPrjAdtttt7yVIWYIYXLSSScluon69+/vBVVSAYiNjTfe2HVdaSV3SC6dWTgS9meffea7rtuxpOX333/vu7YvtdRS/jBl5hM+tDiZPfXUU+6HH35wkydNcosvsYTv2r7FFlu4+++/35JoKQIiIAIiUAaBFu/qYq4qBEulJtFTKcHS8xMobLbgggvaql/S5XvvvfeO9r3zzju+2/ixxx7rbr/9dmetNLTOsC9uO+64oyNo2Ayhcdppp7mjjz7aPfLII741h2OdcsHVBx98sCWr0zvryy+/jPYXWvnqq6+iw/HrsAO05qy66qq26WOE2LgvN2Ck2VZbbWWrWoqACIiACJRJoMULH7hUKn4kesp8uirMRk8ps3DeMkSCjXPD8ccff9wHRD/99NO+ZWfEiBHuqKOOisQPgci0DoUWxsxcddVV7rzzznOvvPKK45x0U7/yyiuj5BtssEG0bq4odkzKtcYUY1988UWULAyKjnbmVjbbbDPfqsM+BJUN5Pjggw9G17Hooou6BRZYIMymdREQAREQgRIJ1ITwgUm54keip8QnKsXkH3/8cVSadXFnB+4m4n4wgqEvvvhivx7+Y+TksKUvFD4rrrhi1HMKV1SS+2js2LHRoIGMzGxd+OfOrZuFLTm2L2kZtgxZfFA83dZbbx3t4lk1I6bnzTfftE23++67R+taEQEREAERKJ1AzQgf0JQqfiR6Sn+g0syB4DAjkNjM4n7Yfvnll6MWETtuy+uuu85WI+HCDkZaNiOOKJ9dcMEF7vrrr/d/NnLyn7Vw0XhD+fLbfuKFIguuw/YxGOJiiy3mN7nOeNf9O+64w5L63mfRhlZEQAREQARKJtDig5vjROzXdEMBzxI9cXJNvx0O5Pfbb79FFUAomNGyk89++eUX3yJEbyr+aG1h30q5gGWzyZMn22q95Ysvvuj4Cy2cewvXUzEWpvsxYe6usBUHV1t4rZTPuEA///yzQwjyh3CL16uYeiiNCIiACIiAczUnfLjpDYkfiZ5sfDTo3m1G926zsCWooZniERHW1R0BMjE3w3wYp1Osu8rOzaShTEaKFTsNxSKLLGLZHa61uDGGkBkjWBNjFLc55pgj2sUUFhI+EQ6tiIAIiEBJBGrK1RWSyef2kugJKTXv+sorrxxVgK7jZhb4y3bSTO+WjmUoGCwf4sWMKTFKsTCgefHFFy8qayh8wusgM4MthoMlEsuEoIr/heMM0U0/X6xQURVSIhEQARGoYQI1K3y453HxI9GTnU8C81wxTYPZnXfeaat+XBzb6Ny5s63WWzLVgwVBEztjrS3hNBnFihcrfEzQvZweVgRKF7IlcmPwhOKKoOnQGG3ajC74uLTy/dnghYggpsOQiYAIiIAIlE6gJl1dISZze7EvXA/TaL1pCdDqMWjQoOikxNXQ1dyMMXu23HJLv7nGGmv4ION4XAwHmRTUbMqUKbbq3V220b17d1utt2TwQ+t+vv/++7tp06a5zz//3Asom6D0wAMPdEceeWS9vLbjoIMOslU/gvRHH30UbXOdjARtxhxlhebjYjoOG5WaAR1vueUWy6qlCIiACIhAkQRqusXHGCF4JHqMRvMuGcSPiTzD8WqGDh1ap1JMJcGoxhgtOoMHD65znI2uXbu6Hj16RPvHjRsXrdOyZ0IJNxPzc8WNObNM9OAaQ/SYMe6PGSMyn3HGGfWmvOA4gyGGgdQ33nijZfNLWm3MhcX1FBI9ZKB3l/VuI8Cb1iSZCIiACIhAaQRqvsWnNFxKnSYBWmToJo54scH5wsBlznXPPff4Xk3x8w4bNixqFerWrZsfywfxijsL0cP8W9aN/PXXX3e33XZbVARj/4wcOTIa+ZlRnBEoTz75pHczIZiYqNSMQQRDY5TnPn36RG4uWm3oOo9woZfYwgsv7N107dq1i7IxJlHczcUUFGaU2ZAhjogxMsGDYBsyZEhD2XRcBERABEQgICDhE8DQatMSYOLNfEa8CxOVhrObh2mfeeYZ98ADD0QuL+JowtGYLS1ChIlK48ZYOauvvno0TQSxOknxOoipm266KZ7dz/91/PHHO0QXhmAjGDsMyLZMU3MtRowkHRqxRWGr1ujRo8PDedeJMcK9huHmk4mACIiACJRGQK6u0ngpdYUEzFUTL4b9jLHD9A60xhDPkk/0WF6mlTj99NPruKHsGIHADG6Iu8mCgu2YLZmb6/LLL/etPLbPlnSTx6V16aWX2q46S8pEUF122WXR9BJ1EgQbHXJTZuyzzz7BHlcnOJku9WEMUp2EsY1wCgu66YeDOcaSalMEREAERCCBQKtcs344GG1CEu1qDgLEjWTZCMTNkuEuw11FXA7iiYEAcWkVa3QPp/UGAcaAgaXk5RzMJca4Qx07dnSIJkTJEUccUWd0Z+p0wgkneIFXbL2UTgREQAREIF0CEj7p8kytNAmf1FA2W0H0/DrrrLPqdGdnAMW426vZKqgTi4AIiEANEpCrK6M3PexFlLUqZrluWWJFoHX//v0ds8ZjjM9zzjnnZKmKqosIiIAI1BwBBTdn9JbTMmCBs1mrInWTFU+A7vhMS0Hvsoam2Ci+VKUUAREQAREoh4BafMqh1gR56L1jM4I3wemKPgV1CkcvLjpjjSeku7pET40/BLp8ERCBTBBonRsT5ORM1ESVqEOAHk6MVkycCIGzzT03E+4tRkweMWKEXuB17pQ2REAEREAEqomAgpur6W6priIgAiIgAiIgAhURkKurInzKLAIiIAIiIAIiUE0EJHyq6W6priIgAiIgAiIgAhURkPCpCJ8yi4AIiIAIiIAIVBMBCZ9quluqqwiIgAiIgAiIQEUEJHwqwqfMIiACIiACIiAC1URAwqea7pbqKgIiIAIiIAIiUBEBCZ+K8CmzCIiACIiACIhANRGQ8Kmmu6W6ioAIiIAIiIAIVERAwqcifMosAiIgAiIgAiJQTQQkfKrpbqmuIiACIiACIiACFRGQ8KkInzKLgAiIgAiIgAhUEwEJn2q6W6qrCIiACIiACIhARQQkfCrCp8wiIAIiIAIiIALVREDCp5ruluoqAiIgAiIgAiJQEQEJn4rwKbMIiIAIiIAIiEA1EZDwqaa7pbqKgAiIgAiIgAhUREDCpyJ8yiwCIiACIiACIlBNBCR8quluqa4iIAIiIAIiIAIVEZDwqQifMouACIiACIiACFQTAQmfarpbqqsIiIAIiIAIiEBFBCR8KsKnzCIgAiIgAiIgAtVEQMKnmu6W6ioCIiACIiACIlARAQmfivApswiIgAiIgAiIQDURkPCppruluoqACIiACIiACFREQMKnInzKLAIiIAIiIAIiUE0EJHyq6W6priIgAiIgAiIgAhURkPCpCJ8yi4AIiIAIiIAIVBOBNtVUWdU12wQ6dOjg+vTp4zp37uzmmWeeiir78MMPu4ceeqiiMpRZBERABERABOIEJHziRLRdFgFEz4ABA1zbtm3Lyh/PtOmmm/pdEj9xMtoWAREQARGohIBcXZXQU96IAC09aYkeKxTx07t3b9vUUgREQAREQAQqJiDhUzFCFQAB3FuNYRI/jUFVZYqACIhA7RKQ8Knde5/qlVca02OVIbYnbhI/cSLaFgEREAERKJeAhE+55JSvUQgQ0yPx0yhoVagIiIAIiECOgISPHoPMEZD4ydwtUYVEQAREoMUQkPBpMbeyZV2IxE/Lup+6GhEQARHICgEJn6zcCdWjHgGJn3pItEMEREAERKBCAhI+FQJU9sYlIPHTuHxVugiIQOMSWGKJJdzAgQPdX//618Y9kUovmoAGMCwalRI2FwHED0bvrtBs246Hx7QuAiIgAlkgcNppp7n27du7DTfc0E2dOtX973//y0K1aroOEj41ffur5+JN3JjYsZrbth23/Vpmh0DPnj1dv379fIUefeQRN3LUqOxUrpFqwkjmQ4YM8aV/+umnjpdf2nbQQQe5tdZayxd78cUXu1deeSXtU5RUXlNcc0kVykjiNm3+fM0usMACGalVbVdDrq7avv9VdfWIm3xd3avqQmqssjT184XPX5fllquJq+cXvl3zsssu2yjXvFyOpZ1jkUUWaZRzlFJoU1xzKfXJStprrrnGff755+6FF15wDzzwQFaqVdP1+FOK1jQGXXy1ELCWHWvpqZZ6q54iIAK1SYAfa0k/2GqTRjauWsInG/dBtZhF4IwzzsgMi06dOrl1113XzTvvvO7ll192b731lvvjjz/cQgst5Nq1a+d+++03hxsjn/ErfPXVV3csP/zwQ/fSSy+577//PjE55+IX88yZM93EiRN9Gs679tprO1pM2DdhwgQfI5BYQLCTuq2zzjpuqaWWclOmTPF1nzRpUpDiz1VG3F5wwQX9Dn6V/vTTT26FFVbw1/3DDz+422677c/Es9bIg4uFaUomT57s3n33XX998YRLL720m2222VzHjh2jQ1zjMsss47dhB8O4wRduiy66qPviiy/ciy++6L788st4smi7nGuIMhe5wnV07drV0cqCS+ejjz7yzwPMQrNng7qb4eqwa+Z+5HsGFl54YX/faMXhfr/55pvuq6++smL8cvbZZ/fPAxtzzz13dIy8nGPGjBnuk08+ifaHK6U8F2G+htZLuWZ7zikThq1atfLPOGzffvtt99RTT9U7XTFc6mWatQMmlE0dP/vsM/faa68V/MxaOdxvnvHlunRxM37/3b366qvunXfe8Z9/S1PskuefzzLGNfMdkmR8nlZcccXouedzxZ8sfQKtevToMTP9YlVirRFobsFy3HHHpYYcocL12JeVFYwoGTFihNtqq63c/PPP73fvuuuudjha8mI8+eSToxdUdCC38vXXX7sTTzyx3gvt6quvdjbtB7EbnJ+XRGic/5FcjMywYcPC3XXWjz76aP8i4YUSGgLjnHPO8SIi3P+vf/3LrbHGGn7XmDFj3CabbOLmmmuuKEl4fbnvCte/f/86xy3hd9995/773/9GcSZMWHvdddfZ4cTlVVdd5e6///7oGC982Cy++OLRPlvhhc51P/bYY7YrWpZyDVGm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)" - ], "metadata": { "id": "cVofNXVW-EMo" - } + }, + "source": [ + "![image.png](data:image/png;base64,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zbq6aOkpV/TYnUL89O7d2za1FAEREAEREAERyDiBmhU+uLfSMImfNCiqDBEQAREQARFoGgI16+oqNaan0O1A/Jjrq1C6QsemTZvmJk6c6MaMGeOmTp1aKKmOiYAIiIAIiIAIlEmgZlt8yuTVaNkQYt26dfNxR8QfyURABERABERABNInIOGTPtOKSiTuiPgjmQiIgAiIgAiIQPoEatbVlT7K9EqsJP6oZ8+erl+/fr4yjz7yiBs5alR6FVNJIiACIiACIlDlBCR8MngDK4k/WmKJJdwCCyzgr6rLcstl8OpUJREQAREQARFoPgJydTUfe51ZBERABERABESgiQmoxaeJgTfW6ZZeemk322yzuY4dO0anaN++vVtmmWX89qeffup+++03v77kkku6Nm3auF9++cVNnjzZtWvXzm2wwQZu8cUXd4899ph7//33ozJYIe1qq63mVl55Zffdd9+5Dz74wL355pvu999/r5MuaWPOOed0a621lltqqaV8/d5++233xhtvuJ9++ikpeZ191GudddbxeadMmeJefvllN2nSpDppkjaIk6KuXbp08eekvpzz+++/T0qufSIgAiIgAjVEQMKnhdzsc845p96V8OIfMmSI33/VVVe5+++/36+fe+65fvnzzz+7xx9/3G2++eZR3k6dOkV5FllkEXfKKadErrMoUW5lxowZbsSIEe7uu+8Od9dZP/TQQ92GG27oxUd4YObMmV5gDRs2LK94Ovroo93aa6/tWrVqFWb14o1rffHFF+vsZwOBdsghh3gRhwiM24QJE9yFF14oARQHo20REAERqCECFQsfRi6udAwb4635r4xE0yznmmuuOqInPCtB0oiI1q1bh7ujdUTG3nvv7RAx99xzT7TfVvr37+8oI8kQMxtvvLHrutJK7pBcurgde+yxvpUovp/t2Wef3Q0ePNiLrttvv71OkjPPPDNq4apzYNYGrVbnDh3qDvrHP9wff/yRlET7REAEREAEWjiB1rlg2JMrucYPP/zQ/yo3l0q5ZTW16Mn6VBPwKMVef/1134qCmCHAGWNAxAsuuMCNHz/et5DQSoPttttufmn/cHlxH1977TX31FNPeXfSGWec4UUGab7++msvbq688kpHK9Fiiy3mcGFhq666qrvtttu8API7cv923HFHt+2229qmL/Paa6919957r2+Vodca4gdXFq65559/PkqLmOrVq5ffRpzceeedjvPSwrPssstGk8l27drVtzaZu41Wq8022ywqhzJHjhzp880///yRCxA+Cy64oHvuueeitFoRAREQARGoHQIVt/iAyibqLLflp6lFT0u8vcSwYAgRM0aARswUsi+++MIPmhimIa7GhA0jStN6Yy0kw4cPd/fdd5+7/PLLfRZcSoiQ8Dx9+/aNigtdbOy85JJL3HvvvecOPPBAn4bYoksvvdSvI2xCwXTCCSe4d955xx/76KOP3AsvvOAuvvhit9BCC/mWqP3339/hLsPWXXddv+QfIu7ss8+OthF+++23n9tqq638vlVWWSU6phUREAEREIHaIlA/EKLM60f8lNpKwakkesoEnkI2xMwxxxxTr6RPPvnEt5bQYnL++edHoscSfvvtt+7zzz+3TbdSzmVltuKKK0ZxOQQTW1yRHWc5duxY9+OPP/pdtMBY9/0ddtghSvbqq69GoifamVu54ooros1QwORzyVni0aNHu7feesv/0TomEwEREAERqE0CqbT4GLpSW34keoxc8ywRPj/88EO9kyNqcF+ZEc9DTzB6Zs0777x+dxg83CaIA1pzzTUtm2+hiTZiK7jg6EWGmQgKBRTCh0DruIWCy+pCGlx0JoRwu5544onujjvucK+88oovAhFGC5JMBERABESgtgmkKnxAWaz4kejJ/oPXo0cPPwo0vbuKtVC80FU+nxGzE++ZNffcc0fJ99xzT8dfITN3HGkeyY1SzVQfCDSMec/4IwaIetDKNG7cuLy9yHwm/RMBERABEWjxBFJzdYWkGnJ7SfSEtLK5TlzPkUce6ULRQw8uAqQJhmY9ycIJVr/66qukJHn30bJUioVd3anXEUcc4cWNBXFTFi4wxNABBxzgiE9ab731SjmF0oqACIiACLQwAqW9aUq4+HwtPxI9JUBspqS4jKxnFVWghxSigUEQzXAbhYHUtp8BDhdddFG/SRByKcYAixarM2bMGEdgdSGzHl1hGoKu+aO1aqONNnLEHJlLjLIRR/GA6zC/1kVABERABFo2gUYTPmCLix+Jnup4mHbeeeeoooiesIdUdCDPCuLI3F0Ww5Mnab3diCZrYaI31xNPPFEvTbE7nn76accfRvf+k086yXWYbz6/Tc+xpKBrf1D/REAEREAEWjSBRhU+kDPxE19v0VSr/OIY58aMHl5Jxtg4ScbYQWbdu3e31XpLemfNN0uI0C2d1p3PPvssEj477bRTXuGDS2yOOeaIgqKJDbrmmmv8OQiUprzQEGP/vegid/zxx/vdSUHTYXqti4AIiIAItFwCjRLjE8eF+AkFUPy4ttMjQPyNWbkveFpezDbdZBNbjZaHH354FETMztlzIsSMVj2bEwxBkhSgvEmuTBM9nMtcWrfeeqsV48tnIMS44bZi7B7cVauvvro/zLxfv/76q3eT0TU+aTyp6dOnR0Xli0+KEmhFBERABESgxRJo9BafFksuoxf28ccfRzUj1uawww7zA/q99NJLdWJ0okQJK6QlNgbDPXT11Vf7AQppaWG/jbtjWS2Ghm0Cixn/hxGYMcQLrq8nn3zSj/pM7A2Tlpo9+OCDturH7WGQQjuOaCI9E6cSz0MvLaadsN5c/fr18xOXUgATmFrg8sEHH+y2335798wzz3hRRR7r6k5aBkOUiYAIiIAI1CYBCZ8Wdt8RLYgPRAq9ngjw5Y/pIUaNGlXU1TKGD1N6WHAyQsdEhRVAq4n1qmJm+NCYuJTWGAt+RiyZkArT0Qp40003hbv8gInEFDEtBsZozvzFDfHCnF5mTD5KfZmYlXqRP6nFCDY2Savl1VIEREAERKB2CDSJq6t2cDb/lfJivygXz5LU46mU2g0aNMj35oq7hSiX8XCYOsLMenHZNsvTTjvN965ibq+4MZUGriqbqiI8TvqBAwe6m2++OXKZhceJ4WGwQuoXXiPXjRB64IEHHK6vuHEdDGY4YMCAOqNOx9NpWwREQAREoGUTaJVzJSQPyNKyr9sxCWeW7bjjjquoesxizhxa7du39wP40UJi822VUjBdwJdffnk/sSeBy2GX9mLLwTWFmwrxMWHCBN8iVWxe4oRwU1F3hIvFDzWUnxYvWpyYEmPSpEmOIO1yrr+h8+i4CIiACIhAdRGQq6u67lfRtUUgIDIqNVpVmOOqEiPgOpyBvZSyaL0pZyZ1WoDiI0OXcl6lFQEREAERaJkEatbVZT2Jsnhbs1y3LPJSnURABERABESgWAI1K3zC8WaKhdVU6bJct6ZioPOIgAiIgAiIQGMQqFnhw5QINit4Y4Att0zqRN1kIiACIiACIiAC6RNonRvO/+T0i81+icSdECzLGDRt27aNxoZprprj3mKahhEjRjh6PclEQAREQAREQATSJ1CzvbrSR6kSRUAEREAEREAEsk6gZl1dWb8xqp8IiIAIiIAIiED6BCR80meqEkVABERABERABDJKQMInozdG1RIBERABERABEUifgIRP+kxVogiIgAiIgAiIQEYJSPhk9MaoWiIgAiIgAiIgAukTkPBJn6lKFAEREAEREAERyCgBCZ+M3hhVSwREQAREQAREIH0CEj7pM1WJIiACIiACIiACGSUg4ZPRG6NqiYAIiIAIiIAIpE9Awid9pipRBERABERABEQgowQkfDJ6Y1QtERABERABERCB9AlI+KTPVCWKgAiIgAiIgAhklICET0ZvjKolAiIgAiIgAiKQPgEJn/SZqkQREAEREAEREIGMEpDwyeiNUbVEQAREQAREQATSJyDhkz5TlSgCIiACIiACIpBRAhI+Gb0xqpYIiIAIiIAIiED6BCR80meqEkVABERABERABDJKQMInozdG1RIBERABERABEUifgIRP+kxVogiIgAiIgAiIQEYJSPhk9MaoWiIgAiIgAiIgAukTkPBJn6lKFAEREAEREAERyCgBCZ+M3hhVSwREQAREQAREIH0CEj7pM1WJIiACIiACIiACGSUg4ZPRG6NqiYAIiIAIiIAIpE9Awid9pipRBERABERABEQgowQkfDJ6Y1QtERABERABERCB9AlI+KTPVCWKgAiIgAiIgAhklICET0ZvjKolAiIgAiIgAiKQPgEJn/SZqkQREAEREAEREIGMEpDwyeiNUbVEQAREQAREQATSJ9Am/SJVYloEOnTo4Pr06eM6d+7s5plnnpKKffjhh91DDz1UUh4lFgEREAEREIGWTkDCJ6N3GNEzYMAA17Zt27JquOmmm/p8Ej9l4VMmERABERCBFkpArq6M3lhaesoVPXZJiJ/evXvbppYiIAIiIAIiUPMEJHwy+gjg3krDJH7SoKgyREAEREAEWgoBuboyeidLjekpdBmIH3N9FUpX6Ni0adPcxIkT3ZgxY9zUqVMLJdUxERABERABEcgsAQmfzN6abFUMIdatWzfXpUsXd9FFF5UtftZaay3Xvn37ehdnwuqbb76pdyzrO+aaay7Xs2dPt/TSS7uOHTu6KVOmuE8++cSNHz/e/fTTT2VVf8MNN3StW7d23333nZswYUJZZSiTCIiACIhAfQISPvWZaE8BAsQdEX80atSoAqnyHxo0aJBr0yb/Y/fHH3+49957zw0fPty98cYb+QvKwJE555zTHX744W7NNdd0s81W32u83377uVdffdUNHTq0JAG03nrruYEDB/ornDlzptt3333djz/+mIErVhVEQAREoPoJ1P+2rv5r0hU0MoG04o+SqomAWGGFFdwpp5wSvfyT0jX3vvnnn99dcsklbu21104UPdSPa1lttdXcsGHDXKdOnYqu8g477BClbdWqldt5552jba2IgAiIgAhURiD/T+/KylXuFkwgrfij0aNHu6+//trxcl9yySXdcsst5xBVs88+u6eHu2ehhRZyxx13XOZoDhkyxM0777xRvT788EP37LPPunfffddfBy695Zdf3h9v166dI/0BBxzgaNEqZHPPPbdbZpll6iTp1auXu+GGG+rs04YIiIAIiEB5BCR8yuOmXCkQeOKJJ9ynn35apyTcYAidVVZZxe+n9Wfbbbd1d999d510zbnRd4893HzzzRdV4bacgBsZuP6IyUHUbbfddm6vvfbywo64JlxWV199dZQvaWWnnXby6cNjCCxiq95///1wt9ZFQAREQATKICBXVxnQlKXxCMyYMcO7uZ577rnoJP369cvrTiIRLiVcTrvssosjLe6lQnFEUcGzVojVWX/99d0eOUGz5557OlpraHnJZ1tvs0106IUXXqgjeqIDuZW77rrLIe7MNt98c1vNu9xkk02iY88//3y03rdv32hdKyIgAiIgAuUTUItP+eyUsxEJ0HPsmmuu8aKG3k30mnr00UfrnXHXXXd1tJKEQsdiZAiSPvXUUwsGFh966KEOl1o8OJmg4scee8zH5/z+++/ReWmBQihhpLniiiuiY0kr1157rS8fdx51pCXrtddeS0rqll12WceI3dj06dN97zkYkJd81LEhV1liwdopAiIgAiIQEWjxwoeRiysdw8Zoaf4rI9H4S3ox0Zqyzjrr+JPRWhIXPrjAdtttt7yVIWYIYXLSSScluon69+/vBVVSAYiNjTfe2HVdaSV3SC6dWTgS9meffea7rtuxpOX333/vu7YvtdRS/jBl5hM+tDiZPfXUU+6HH35wkydNcosvsYTv2r7FFlu4+++/35JoKQIiIAIiUAaBFu/qYq4qBEulJtFTKcHS8xMobLbgggvaql/S5XvvvfeO9r3zzju+2/ixxx7rbr/9dmetNLTOsC9uO+64oyNo2Ayh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DTfc0E2dOtX973//y0K1aroOEj41ffur5+JN3JjYsZrbth23/Vpmh0DPnj1dv379fIUefeQRN3LUqOxUrpFqwkjmQ4YM8aV/+umnjpdf2nbQQQe5tdZayxd78cUXu1deeSXtU5RUXlNcc0kVykjiNm3+fM0usMACGalVbVdDrq7avv9VdfWIm3xd3avqQmqssjT184XPX5fllquJq+cXvl3zsssu2yjXvFyOpZ1jkUUWaZRzlFJoU1xzKfXJStprrrnGff755+6FF15wDzzwQFaqVdP1+FOK1jQGXXy1ELCWHWvpqZZ6q54iIAK1SYAfa0k/2GqTRjauWsInG/dBtZhF4IwzzsgMi06dOrl1113XzTvvvO7ll192b731lvvjjz/cQgst5Nq1a+d+++03hxsjn/ErfPXVV3csP/zwQ/fSSy+577//PjE55+IX88yZM93EiRN9Gs679tprO1pM2DdhwgQfI5BYQLCTuq2zzjpuqaWWclOmTPF1nzRpUpDiz1VG3F5wwQX9Dn6V/vTTT26FFVbw1/3DDz+422677c/Es9bIg4uFaUomT57s3n33XX998YRLL720m2222VzHjh2jQ1zjMsss47dhB8O4wRduiy66qPviiy/ciy++6L788st4smi7nGuIMhe5wnV07drV0cqCS+ejjz7yzwPMQrNng7qb4eqwa+Z+5HsGFl54YX/faMXhfr/55pvuq6++smL8cvbZZ/fPAxtzzz13dIy8nGPGjBnuk08+ifaHK6U8F2G+htZLuWZ7zikThq1atfLPOGzffvtt99RTT9U7XTFc6mWatQMmlE0dP/vsM/faa68V/MxaOdxvnvHlunRxM37/3b366qvunXfe8Z9/S1PskuefzzLGNfMdkmR8nlZcccXouedzxZ8sfQKtevToMTP9YlVirRFobsFy3HHHpYYcocL12JeVFYwoGTFihNtqq63c/PPP73fvuuuudjha8mI8+eSToxdUdCC38vXXX7sTTzyx3gvt6quvdjbtB7EbnJ+XRGic/5FcjMywYcPC3XXWjz76aP8i4YUSGgLjnHPO8SIi3P+vf/3LrbHGGn7XmDFj3CabbOLmmmuuKEl4fbnvCte/f/86xy3hd9995/773/9GcSZMWHvdddfZ4cTlVVdd5e6///7oGC982Cy++OLRPlvhhc51P/bYY7YrWpZyDVGm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)" + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "dPd9i6_t7ERJ" + }, + "outputs": [], "source": [ "'''\n", " {\n", @@ -172,12 +166,21 @@ " ]\n", "}\n", "'''" - ], - "metadata": { - "id": "dPd9i6_t7ERJ" - }, - "execution_count": null, - "outputs": [] + ] } - ] + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 } From e78448b57f057d9a4ba2b2ebd936b91081ae8ec3 Mon Sep 17 00:00:00 2001 From: fm1320 Date: Tue, 17 Dec 2024 15:14:34 +0000 Subject: [PATCH 2/2] fix: TypeError: Client.__init__() got an unexpected keyword argument 'proxies' [Google Colab] #294 --- .../tutorials/adalflow_rag_optimization.ipynb | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/notebooks/tutorials/adalflow_rag_optimization.ipynb b/notebooks/tutorials/adalflow_rag_optimization.ipynb index a0f00d6e..b9365680 100644 --- a/notebooks/tutorials/adalflow_rag_optimization.ipynb +++ b/notebooks/tutorials/adalflow_rag_optimization.ipynb @@ -5,6 +5,9 @@ "metadata": { "id": "xHF95Kr4CzGq" }, + "metadata": { + "id": "xHF95Kr4CzGq" + }, "source": [ "# 馃 Welcome to AdalFlow!\n", "## The PyTorch library to auto-optimize any LLM task pipelines\n", @@ -34,6 +37,7 @@ "\n", "- Learn how to connect the output-input between components to enable auto-text-grad optimization." ] + ] }, "id": "ONfzF9Puzdd_", "outputId": "5fc0cd30-9ae7-443a-c06c-31e9edeafd69" @@ -46,6 +50,9 @@ "metadata": { "id": "Kof5M6DRaKhh" }, + "metadata": { + "id": "Kof5M6DRaKhh" + }, "source": [ "\n", "# Installation\n", @@ -59,6 +66,7 @@ "\n", "You can choose to use different client. You can import the model client you prefer. We support `Anthropic`, `Cohere`, `Google`, `GROQ`, `OpenAI`, `Transformer` and more in development. We will use OpenAI here as an example.Please refer to our [full installation guide](https://adalflow.sylph.ai/get_started/installation.html)" ] + ] }, { "cell_type": "code", @@ -76,6 +84,9 @@ "!pip uninstall httpx anyio -y\n", "!pip install \"anyio>=3.1.0,<4.0\"\n", "!pip install httpx==0.24.1\n", + "!pip uninstall httpx anyio -y\n", + "!pip install \"anyio>=3.1.0,<4.0\"\n", + "!pip install httpx==0.24.1\n", "clear_output()" ] }, @@ -84,6 +95,9 @@ "metadata": { "id": "KapUyHMM07pJ" }, + "metadata": { + "id": "KapUyHMM07pJ" + }, "source": [ "## Set Environment Variables\n", "\n", @@ -93,6 +107,7 @@ "\n", "*Go to [OpenAI](https://platform.openai.com/docs/introduction) to get API keys if you don't already have.*" ] + ] }, { "cell_type": "code", @@ -114,6 +129,24 @@ ] } ], + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ONfzF9Puzdd_", + "outputId": "5fc0cd30-9ae7-443a-c06c-31e9edeafd69" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Please enter your OpenAI API key: 路路路路路路路路路路\n", + "API keys have been set.\n" + ] + } + ], "source": [ "import os\n", "\n", @@ -136,6 +169,11 @@ "id": "aE3I05BqOmd7" }, "outputs": [], + "execution_count": 20, + "metadata": { + "id": "aE3I05BqOmd7" + }, + "outputs": [], "source": [ "import dspy\n", "import re\n", @@ -151,6 +189,7 @@ "from adalflow.core.component import fun_to_component\n", "from adalflow.components.model_client.openai_client import OpenAIClient" ] + ] }, { "cell_type": "code", @@ -159,6 +198,11 @@ "id": "cqUUoua9fUxQ" }, "outputs": [], + "execution_count": null, + "metadata": { + "id": "cqUUoua9fUxQ" + }, + "outputs": [], "source": [ "\n", "gpt_4o_model = {\n", @@ -177,6 +221,7 @@ " },\n", "}" ] + ] }, { "cell_type": "code", @@ -207,6 +252,33 @@ "output_type": "execute_result" } ], + "execution_count": 22, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "0irHeHUkOmL8", + "outputId": "61f778a2-9ec1-4fda-daa2-bcc7f31baa78" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "HotPotQAData(id='5a8b57f25542995d1e6f1371', question='Were Scott Derrickson and Ed Wood of the same nationality?', answer='yes', gold_titles=\"{'Scott Derrickson', 'Ed Wood'}\") \n" + ] + }, + { + "data": { + "text/plain": [ + "HotPotQAData(id='5a8b57f25542995d1e6f1371', question='Were Scott Derrickson and Ed Wood of the same nationality?', answer='yes', gold_titles=\"{'Scott Derrickson', 'Ed Wood'}\")" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "def load_datasets():\n", "\n", @@ -242,6 +314,11 @@ "id": "ZZIEtZYHNVjo" }, "outputs": [], + "execution_count": 23, + "metadata": { + "id": "ZZIEtZYHNVjo" + }, + "outputs": [], "source": [ "class DspyRetriever(adal.Retriever):\n", " def __init__(self, top_k: int = 3):\n",