From 98176ac982b92fd0811c6a7abba3921a16f23e97 Mon Sep 17 00:00:00 2001 From: Aditya <31382824+Adi8885@users.noreply.github.com> Date: Fri, 9 Feb 2024 01:00:42 +0530 Subject: [PATCH 01/35] langchain_google_vertexai : added logic to override get_num_tokens_from_messages() for ChatVertexAI (#16784) - **Description: changes to you.com files** - general cleanup - adds community/utilities/you.py, moving bulk of code from retriever -> utility - removes `snippet` as endpoint - adds `news` as endpoint - adds more tests **Description: update community MAKE file** - adds `integration_tests` - adds `coverage` - **Issue:** the issue # it fixes if applicable, - [For New Contributors: Update Integration Documentation](https://github.com/langchain-ai/langchain/issues/15664#issuecomment-1920099868) - **Dependencies:** n/a - **Twitter handle:** @scottnath - **Mastodon handle:** scottnath@mastodon.social --------- Co-authored-by: Bagatur --- .../retrievers/you-retriever.ipynb | 385 +++++++++++++++++- .../retrievers/__init__.py | 4 +- .../langchain_community/retrievers/you.py | 65 +-- .../langchain_community/utilities/__init__.py | 9 + .../langchain_community/utilities/you.py | 230 +++++++++++ .../unit_tests/retrievers/test_imports.py | 1 + .../tests/unit_tests/retrievers/test_you.py | 86 +++- .../unit_tests/utilities/test_imports.py | 1 + .../tests/unit_tests/utilities/test_you.py | 190 +++++++++ 9 files changed, 883 insertions(+), 88 deletions(-) create mode 100644 libs/community/langchain_community/utilities/you.py create mode 100644 libs/community/tests/unit_tests/utilities/test_you.py diff --git a/docs/docs/integrations/retrievers/you-retriever.ipynb b/docs/docs/integrations/retrievers/you-retriever.ipynb index 447111de5a560c1..950c592cda75c2b 100644 --- a/docs/docs/integrations/retrievers/you-retriever.ipynb +++ b/docs/docs/integrations/retrievers/you-retriever.ipynb @@ -2,39 +2,396 @@ "cells": [ { "cell_type": "markdown", - "id": "47828a7a", + "id": "818fc023", "metadata": {}, "source": [ - "## Using the You.com Retriever\n", - "The retriever from You.com is good for retrieving lots of text. We return multiple of the best text snippets per URL we find to be relevant.\n", + "# You.com Retriever\n", "\n", - "First you just need to initialize the retriever" + "The [you.com API](https://api.you.com) is a suite of tools designed to help developers ground the output of LLMs in the most recent, most accurate, most relevant information that may not have been included in their training dataset." + ] + }, + { + "cell_type": "markdown", + "id": "02335552", + "metadata": {}, + "source": [ + "## Setup" + ] + }, + { + "cell_type": "markdown", + "id": "c5c53f28", + "metadata": {}, + "source": [ + "The retriever lives in the `langchain-community` package.\n", + "\n", + "You also need to set your you.com API key." ] }, { "cell_type": "code", "execution_count": null, - "id": "a90d61d4", + "id": "6d091ccb", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --upgrade --quiet langchain-community" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f43dd867", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "os.environ[\"YDC_API_KEY\"] = \"\"\n", + "\n", + "# For use in Chaining section\n", + "os.environ[\"OPENAI_API_KEY\"] = \"\"\n", + "\n", + "## ALTERNATIVE: load YDC_API_KEY from a .env file\n", + "\n", + "# !pip install --quiet -U python-dotenv\n", + "# import dotenv\n", + "# dotenv.load_dotenv()" + ] + }, + { + "cell_type": "markdown", + "id": "17e70216", + "metadata": {}, + "source": [ + "It's also helpful (but not needed) to set up [LangSmith](https://smith.langchain.com/) for best-in-class observability" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ce49fa4c", + "metadata": {}, + "outputs": [], + "source": [ + "# os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n", + "# os.environ[\"LANGCHAIN_API_KEY\"] = getpass.getpass()\n", + "# os.environ[\"LANGCHAIN_PROJECT\"] = 'Experimentz'" + ] + }, + { + "cell_type": "markdown", + "id": "2278de15", + "metadata": {}, + "source": [ + "## Utility Usage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab11b2e0", "metadata": {}, "outputs": [], "source": [ - "from langchain.chains import RetrievalQA\n", - "from langchain.retrievers.you_retriever import YouRetriever\n", - "from langchain_openai import OpenAI\n", + "from langchain_community.utilities.you import YouSearchAPIWrapper\n", + "\n", + "utility = YouSearchAPIWrapper(num_web_results=1)\n", + "\n", + "utility" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "2656a45d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "[\n", + " {\n", + " \"description\": \"Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com\",\n", + " \"snippets\": [\n", + " \"10 Day Weather-Manhattan, NY\\nToday43\\u00b0/39\\u00b01%\\nToday\\nSun 31 | Day\\nGenerally cloudy. High 43F. Winds W at 10 to 15 mph.\\n- Humidity54%\\n- UV Index0 of 11\\n- Sunrise7:19 am\\n- Sunset4:38 pm\\nSun 31 | Night\\nCloudy. Low 39F. Winds light and variable.\\n- Humidity70%\\n- UV Index0 of 11\\n- Moonrise9:13 pmWaning Gibbous\\n- Moonset10:28 am\\nMon 0145\\u00b0/33\\u00b07%\\nMon 01\\nMon 01 | Day\\nConsiderable cloudiness. High around 45F. Winds light and variable.\\n- Humidity71%\\n- UV Index1 of 11\\n- Sunrise7:19 am\\n- Sunset4:39 pm\\nMon 01 | Night\\nA few clouds. Low 33F. Winds NNW at 5 to 10 mph.\\n- Humidity64%\\n- UV Index0 of 11\\n- Moonrise10:14 pmWaning Gibbous\\n- Moonset10:49 am\\nTue 0246\\u00b0/35\\u00b04%\\nTue 02\\nTue 02 | Day\\nMainly sunny. High 46F. Winds NW at 5 to 10 mph.\\n- Humidity52%\\n- UV Index2 of 11\\n- Sunrise7:19 am\\n- Sunset4:40 pm\\nTue 02 | Night\\nA few clouds overnight. Low around 35F. Winds W at 5 to 10 mph.\\n- Humidity64%\\n- UV Index0 of 11\\n- Moonrise11:13 pmWaning Gibbous\\n- Moonset11:08 am\\nWed 0346\\u00b0/38\\u00b04%\\nWed 03\\nWed 03 | Day\",\n", + " \"Radar\\nLatest News\\nOur Changing World\\nYour Privacy\\nTo personalize your product experience, we collect data from your device. We also may use or disclose to specific data vendors your precise geolocation data to provide the Services. To learn more please refer to our Privacy Policy.\\nChoose how my information is shared\",\n", + " \"- Humidity82%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:34 pm\\nTue 26 | Night\\nCloudy with light rain developing after midnight. Low 47F. Winds light and variable. Chance of rain 80%.\\n- Humidity90%\\n- UV Index0 of 11\\n- Moonrise4:00 pmFull Moon\\n- Moonset7:17 am\\nWed 2754\\u00b0/49\\u00b093%\\nWed 27\\nWed 27 | Day\\nRain. High 54F. Winds E at 5 to 10 mph. Chance of rain 90%. Rainfall near a half an inch.\\n- Humidity93%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:35 pm\\nWed 27 | Night\\nSteady light rain in the evening. Showers continuing late. Low 49F. Winds light and variable. Chance of rain 70%.\\n- Humidity91%\\n- UV Index0 of 11\\n- Moonrise4:59 pmFull Moon\\n- Moonset8:12 am\\nThu 2853\\u00b0/42\\u00b019%\\nThu 28\\nThu 28 | Day\\nCloudy skies early will become partly cloudy later in the day. Slight chance of a rain shower. High 53F. Winds WSW at 5 to 10 mph.\\n- Humidity77%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:36 pm\\nThu 28 | Night\\nPartly cloudy skies. Low 42F. Winds W at 5 to 10 mph.\\n- Humidity71%\\n- UV Index0 of 11\",\n", + " \"- Moonrise2:20 amWaning Crescent\\n- Moonset12:33 pm\\nSun 0740\\u00b0/29\\u00b019%\\nSun 07\\nSun 07 | Day\\nIntervals of clouds and sunshine. High around 40F. Winds NW at 5 to 10 mph.\\n- Humidity57%\\n- UV Index2 of 11\\n- Sunrise7:19 am\\n- Sunset4:44 pm\\nSun 07 | Night\\nA few clouds from time to time. Low 29F. Winds NNW at 5 to 10 mph.\\n- Humidity60%\\n- UV Index0 of 11\\n- Moonrise3:28 amWaning Crescent\\n- Moonset1:04 pm\\nMon 0840\\u00b0/32\\u00b035%\\nMon 08\\nMon 08 | Day\\nPartly cloudy early followed mostly cloudy skies and a few snow showers later in the day. High near 40F. Winds N at 5 to 10 mph. Chance of snow 40%.\\n- UV Index1 of 11\\n- Sunrise7:19 am\\n- Sunset4:45 pm\\nMon 08 | Night\\nVariable clouds with snow showers or flurries. Low 32F. Winds NNE at 5 to 10 mph. Chance of snow 60%. Snow accumulations less than one inch.\\n- UV Index0 of 11\\n- Moonrise4:40 amWaning Crescent\\n- Moonset1:43 pm\\nLatest News\\nOur Changing World\\nYour Privacy\",\n", + " \"- Humidity91%\\n- UV Index0 of 11\\n- Moonrise5:50 amWaning Crescent\\n- Moonset2:35 pm\\nWed 1056\\u00b0/39\\u00b034%\\nWed 10\\nWed 10 | Day\\nA shower or two possible early with partly cloudy skies in the afternoon. Morning high of 56F with temps falling to near 45. Winds SW at 15 to 25 mph. Chance of rain 30%.\\n- Humidity66%\\n- UV Index1 of 11\\n- Sunrise7:19 am\\n- Sunset4:47 pm\\nWed 10 | Night\\nA few clouds from time to time. Low 39F. Winds WSW at 10 to 20 mph.\\n- Humidity64%\\n- UV Index0 of 11\\n- Moonrise6:56 amWaning Crescent\\n- Moonset3:38 pm\\nThu 1147\\u00b0/38\\u00b05%\\nThu 11\\nThu 11 | Day\\nPartly cloudy. High 47F. Winds WSW at 5 to 10 mph.\\n- Humidity62%\\n- UV Index2 of 11\\n- Sunrise7:19 am\\n- Sunset4:48 pm\\nThu 11 | Night\\nMostly clear skies. Low 38F. Winds W at 5 to 10 mph.\\n- Humidity66%\\n- UV Index0 of 11\\n- Moonrise7:52 amNew Moon\\n- Moonset4:53 pm\\nFri 1248\\u00b0/42\\u00b019%\\nFri 12\\nFri 12 | Day\\nIntervals of clouds and sunshine. High 48F. Winds WSW at 5 to 10 mph.\\n- Humidity62%\\n- UV Index2 of 11\\n- Sunrise7:18 am\\n- Sunset4:49 pm\",\n", + " \"Sat 1346\\u00b0/36\\u00b053%\\nSat 13\\nSat 13 | Day\\nCloudy with showers. High 46F. Winds WSW at 10 to 15 mph. Chance of rain 50%.\\n- Humidity73%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:50 pm\\nSat 13 | Night\\nRain showers early transitioning to snow showers late. Low 36F. Winds W at 10 to 15 mph. Chance of precip 50%.\\n- Humidity70%\\n- UV Index0 of 11\\n- Moonrise9:14 amWaxing Crescent\\n- Moonset7:33 pm\\nSun 1442\\u00b0/34\\u00b037%\\nSun 14\\nSun 14 | Day\\nSnow showers early will transition to a few showers later. High 42F. Winds WSW at 10 to 15 mph. Chance of rain 40%.\\n- Humidity63%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:51 pm\\nSun 14 | Night\\nVariable clouds with snow showers. Low 34F. Winds W at 10 to 15 mph. Chance of snow 60%. Snow accumulations less than one inch.\\n- UV Index0 of 11\\n- Moonrise9:44 amWaxing Crescent\\n- Moonset8:52 pm\\nMon 1540\\u00b0/31\\u00b051%\\nMon 15\\nMon 15 | Day\",\n", + " \"- Humidity70%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:34 pm\\nMon 25 | Night\\nOvercast with showers at times. Low 43F. Winds light and variable. Chance of rain 40%.\\n- Humidity80%\\n- UV Index0 of 11\\n- Moonrise3:08 pmWaxing Gibbous\\n- Moonset6:14 am\\nTue 2653\\u00b0/45\\u00b058%\\nTue 26\\nTue 26 | Day\\nOvercast with rain showers at times. High 53F. Winds E at 5 to 10 mph. Chance of rain 60%.\\n- Humidity79%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:34 pm\\nTue 26 | Night\\nShowers early then scattered thunderstorms developing late. Low near 45F. Winds ESE at 5 to 10 mph. Chance of rain 60%.\\n- Humidity93%\\n- UV Index0 of 11\\n- Moonrise4:00 pmFull Moon\\n- Moonset7:17 am\\nWed 2751\\u00b0/41\\u00b058%\\nWed 27\\nWed 27 | Day\\nCloudy with showers. High 51F. Winds WSW at 5 to 10 mph. Chance of rain 60%.\\n- Humidity79%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:35 pm\\nWed 27 | Night\\nCloudy with showers. Low 41F. Winds NW at 5 to 10 mph. Chance of rain 60%.\\n- Humidity72%\\n- UV Index0 of 11\\n- Moonrise4:59 pmFull Moon\\n- Moonset8:13 am\"\n", + " ],\n", + " \"thumbnail_url\": \"https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw\",\n", + " \"title\": \"10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...\",\n", + " \"url\": \"https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US\"\n", + " }\n", + "]\n" + ] + } + ], + "source": [ + "import json\n", "\n", - "yr = YouRetriever()\n", - "qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type=\"map_reduce\", retriever=yr)" + "# .raw_results returns the unaltered response from the API\n", + "response = utility.raw_results(query=\"What is the weather in NY\")\n", + "# API returns an object with a `hits` key containing a list of hits\n", + "hits = response[\"hits\"]\n", + "\n", + "# with `num_web_results=1`, `hits` should be len of 1\n", + "print(len(hits))\n", + "\n", + "print(json.dumps(hits, indent=2))" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "c8f5689f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n", + "[Document(page_content='10 Day Weather-Manhattan, NY\\nToday43°/39°1%\\nToday\\nSun 31 | Day\\nGenerally cloudy. High 43F. Winds W at 10 to 15 mph.\\n- Humidity54%\\n- UV Index0 of 11\\n- Sunrise7:19 am\\n- Sunset4:38 pm\\nSun 31 | Night\\nCloudy. Low 39F. Winds light and variable.\\n- Humidity70%\\n- UV Index0 of 11\\n- Moonrise9:13 pmWaning Gibbous\\n- Moonset10:28 am\\nMon 0145°/33°7%\\nMon 01\\nMon 01 | Day\\nConsiderable cloudiness. High around 45F. Winds light and variable.\\n- Humidity71%\\n- UV Index1 of 11\\n- Sunrise7:19 am\\n- Sunset4:39 pm\\nMon 01 | Night\\nA few clouds. Low 33F. Winds NNW at 5 to 10 mph.\\n- Humidity64%\\n- UV Index0 of 11\\n- Moonrise10:14 pmWaning Gibbous\\n- Moonset10:49 am\\nTue 0246°/35°4%\\nTue 02\\nTue 02 | Day\\nMainly sunny. High 46F. Winds NW at 5 to 10 mph.\\n- Humidity52%\\n- UV Index2 of 11\\n- Sunrise7:19 am\\n- Sunset4:40 pm\\nTue 02 | Night\\nA few clouds overnight. Low around 35F. Winds W at 5 to 10 mph.\\n- Humidity64%\\n- UV Index0 of 11\\n- Moonrise11:13 pmWaning Gibbous\\n- Moonset11:08 am\\nWed 0346°/38°4%\\nWed 03\\nWed 03 | Day', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='Radar\\nLatest News\\nOur Changing World\\nYour Privacy\\nTo personalize your product experience, we collect data from your device. We also may use or disclose to specific data vendors your precise geolocation data to provide the Services. To learn more please refer to our Privacy Policy.\\nChoose how my information is shared', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='- Humidity82%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:34 pm\\nTue 26 | Night\\nCloudy with light rain developing after midnight. Low 47F. Winds light and variable. Chance of rain 80%.\\n- Humidity90%\\n- UV Index0 of 11\\n- Moonrise4:00 pmFull Moon\\n- Moonset7:17 am\\nWed 2754°/49°93%\\nWed 27\\nWed 27 | Day\\nRain. High 54F. Winds E at 5 to 10 mph. Chance of rain 90%. Rainfall near a half an inch.\\n- Humidity93%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:35 pm\\nWed 27 | Night\\nSteady light rain in the evening. Showers continuing late. Low 49F. Winds light and variable. Chance of rain 70%.\\n- Humidity91%\\n- UV Index0 of 11\\n- Moonrise4:59 pmFull Moon\\n- Moonset8:12 am\\nThu 2853°/42°19%\\nThu 28\\nThu 28 | Day\\nCloudy skies early will become partly cloudy later in the day. Slight chance of a rain shower. High 53F. Winds WSW at 5 to 10 mph.\\n- Humidity77%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:36 pm\\nThu 28 | Night\\nPartly cloudy skies. Low 42F. Winds W at 5 to 10 mph.\\n- Humidity71%\\n- UV Index0 of 11', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='- Moonrise2:20 amWaning Crescent\\n- Moonset12:33 pm\\nSun 0740°/29°19%\\nSun 07\\nSun 07 | Day\\nIntervals of clouds and sunshine. High around 40F. Winds NW at 5 to 10 mph.\\n- Humidity57%\\n- UV Index2 of 11\\n- Sunrise7:19 am\\n- Sunset4:44 pm\\nSun 07 | Night\\nA few clouds from time to time. Low 29F. Winds NNW at 5 to 10 mph.\\n- Humidity60%\\n- UV Index0 of 11\\n- Moonrise3:28 amWaning Crescent\\n- Moonset1:04 pm\\nMon 0840°/32°35%\\nMon 08\\nMon 08 | Day\\nPartly cloudy early followed mostly cloudy skies and a few snow showers later in the day. High near 40F. Winds N at 5 to 10 mph. Chance of snow 40%.\\n- UV Index1 of 11\\n- Sunrise7:19 am\\n- Sunset4:45 pm\\nMon 08 | Night\\nVariable clouds with snow showers or flurries. Low 32F. Winds NNE at 5 to 10 mph. Chance of snow 60%. Snow accumulations less than one inch.\\n- UV Index0 of 11\\n- Moonrise4:40 amWaning Crescent\\n- Moonset1:43 pm\\nLatest News\\nOur Changing World\\nYour Privacy', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='- Humidity91%\\n- UV Index0 of 11\\n- Moonrise5:50 amWaning Crescent\\n- Moonset2:35 pm\\nWed 1056°/39°34%\\nWed 10\\nWed 10 | Day\\nA shower or two possible early with partly cloudy skies in the afternoon. Morning high of 56F with temps falling to near 45. Winds SW at 15 to 25 mph. Chance of rain 30%.\\n- Humidity66%\\n- UV Index1 of 11\\n- Sunrise7:19 am\\n- Sunset4:47 pm\\nWed 10 | Night\\nA few clouds from time to time. Low 39F. Winds WSW at 10 to 20 mph.\\n- Humidity64%\\n- UV Index0 of 11\\n- Moonrise6:56 amWaning Crescent\\n- Moonset3:38 pm\\nThu 1147°/38°5%\\nThu 11\\nThu 11 | Day\\nPartly cloudy. High 47F. Winds WSW at 5 to 10 mph.\\n- Humidity62%\\n- UV Index2 of 11\\n- Sunrise7:19 am\\n- Sunset4:48 pm\\nThu 11 | Night\\nMostly clear skies. Low 38F. Winds W at 5 to 10 mph.\\n- Humidity66%\\n- UV Index0 of 11\\n- Moonrise7:52 amNew Moon\\n- Moonset4:53 pm\\nFri 1248°/42°19%\\nFri 12\\nFri 12 | Day\\nIntervals of clouds and sunshine. High 48F. Winds WSW at 5 to 10 mph.\\n- Humidity62%\\n- UV Index2 of 11\\n- Sunrise7:18 am\\n- Sunset4:49 pm', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='Sat 1346°/36°53%\\nSat 13\\nSat 13 | Day\\nCloudy with showers. High 46F. Winds WSW at 10 to 15 mph. Chance of rain 50%.\\n- Humidity73%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:50 pm\\nSat 13 | Night\\nRain showers early transitioning to snow showers late. Low 36F. Winds W at 10 to 15 mph. Chance of precip 50%.\\n- Humidity70%\\n- UV Index0 of 11\\n- Moonrise9:14 amWaxing Crescent\\n- Moonset7:33 pm\\nSun 1442°/34°37%\\nSun 14\\nSun 14 | Day\\nSnow showers early will transition to a few showers later. High 42F. Winds WSW at 10 to 15 mph. Chance of rain 40%.\\n- Humidity63%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:51 pm\\nSun 14 | Night\\nVariable clouds with snow showers. Low 34F. Winds W at 10 to 15 mph. Chance of snow 60%. Snow accumulations less than one inch.\\n- UV Index0 of 11\\n- Moonrise9:44 amWaxing Crescent\\n- Moonset8:52 pm\\nMon 1540°/31°51%\\nMon 15\\nMon 15 | Day', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='- Humidity70%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:34 pm\\nMon 25 | Night\\nOvercast with showers at times. Low 43F. Winds light and variable. Chance of rain 40%.\\n- Humidity80%\\n- UV Index0 of 11\\n- Moonrise3:08 pmWaxing Gibbous\\n- Moonset6:14 am\\nTue 2653°/45°58%\\nTue 26\\nTue 26 | Day\\nOvercast with rain showers at times. High 53F. Winds E at 5 to 10 mph. Chance of rain 60%.\\n- Humidity79%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:34 pm\\nTue 26 | Night\\nShowers early then scattered thunderstorms developing late. Low near 45F. Winds ESE at 5 to 10 mph. Chance of rain 60%.\\n- Humidity93%\\n- UV Index0 of 11\\n- Moonrise4:00 pmFull Moon\\n- Moonset7:17 am\\nWed 2751°/41°58%\\nWed 27\\nWed 27 | Day\\nCloudy with showers. High 51F. Winds WSW at 5 to 10 mph. Chance of rain 60%.\\n- Humidity79%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:35 pm\\nWed 27 | Night\\nCloudy with showers. Low 41F. Winds NW at 5 to 10 mph. Chance of rain 60%.\\n- Humidity72%\\n- UV Index0 of 11\\n- Moonrise4:59 pmFull Moon\\n- Moonset8:13 am', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'})]\n" + ] + } + ], + "source": [ + "# .results returns parsed results with each snippet in a Document\n", + "response = utility.results(query=\"What is the weather in NY\")\n", + "\n", + "# .results should have a Document for each `snippet`\n", + "print(len(response))\n", + "\n", + "print(response)" + ] + }, + { + "cell_type": "markdown", + "id": "190ed085", + "metadata": {}, + "source": [ + "## Retriever Usage" ] }, { "cell_type": "code", "execution_count": null, - "id": "4a223f2f", + "id": "1367af5c", "metadata": {}, "outputs": [], "source": [ - "query = \"what starting ohio state quarterback most recently went their entire college career without beating Michigan?\"\n", - "qa.run(query)" + "from langchain_community.retrievers.you import YouRetriever\n", + "\n", + "retriever = YouRetriever(num_web_results=1)\n", + "\n", + "retriever" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "id": "a90d61d4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n", + "[Document(page_content='10 Day Weather-Manhattan, NY\\nToday43°/39°1%\\nToday\\nSun 31 | Day\\nGenerally cloudy. High 43F. Winds W at 10 to 15 mph.\\n- Humidity54%\\n- UV Index0 of 11\\n- Sunrise7:19 am\\n- Sunset4:38 pm\\nSun 31 | Night\\nCloudy. Low 39F. Winds light and variable.\\n- Humidity70%\\n- UV Index0 of 11\\n- Moonrise9:13 pmWaning Gibbous\\n- Moonset10:28 am\\nMon 0145°/33°7%\\nMon 01\\nMon 01 | Day\\nConsiderable cloudiness. High around 45F. Winds light and variable.\\n- Humidity71%\\n- UV Index1 of 11\\n- Sunrise7:19 am\\n- Sunset4:39 pm\\nMon 01 | Night\\nA few clouds. Low 33F. Winds NNW at 5 to 10 mph.\\n- Humidity64%\\n- UV Index0 of 11\\n- Moonrise10:14 pmWaning Gibbous\\n- Moonset10:49 am\\nTue 0246°/35°4%\\nTue 02\\nTue 02 | Day\\nMainly sunny. High 46F. Winds NW at 5 to 10 mph.\\n- Humidity52%\\n- UV Index2 of 11\\n- Sunrise7:19 am\\n- Sunset4:40 pm\\nTue 02 | Night\\nA few clouds overnight. Low around 35F. Winds W at 5 to 10 mph.\\n- Humidity64%\\n- UV Index0 of 11\\n- Moonrise11:13 pmWaning Gibbous\\n- Moonset11:08 am\\nWed 0346°/38°4%\\nWed 03\\nWed 03 | Day', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='Radar\\nLatest News\\nOur Changing World\\nYour Privacy\\nTo personalize your product experience, we collect data from your device. We also may use or disclose to specific data vendors your precise geolocation data to provide the Services. To learn more please refer to our Privacy Policy.\\nChoose how my information is shared', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='- Humidity82%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:34 pm\\nTue 26 | Night\\nCloudy with light rain developing after midnight. Low 47F. Winds light and variable. Chance of rain 80%.\\n- Humidity90%\\n- UV Index0 of 11\\n- Moonrise4:00 pmFull Moon\\n- Moonset7:17 am\\nWed 2754°/49°93%\\nWed 27\\nWed 27 | Day\\nRain. High 54F. Winds E at 5 to 10 mph. Chance of rain 90%. Rainfall near a half an inch.\\n- Humidity93%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:35 pm\\nWed 27 | Night\\nSteady light rain in the evening. Showers continuing late. Low 49F. Winds light and variable. Chance of rain 70%.\\n- Humidity91%\\n- UV Index0 of 11\\n- Moonrise4:59 pmFull Moon\\n- Moonset8:12 am\\nThu 2853°/42°19%\\nThu 28\\nThu 28 | Day\\nCloudy skies early will become partly cloudy later in the day. Slight chance of a rain shower. High 53F. Winds WSW at 5 to 10 mph.\\n- Humidity77%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:36 pm\\nThu 28 | Night\\nPartly cloudy skies. Low 42F. Winds W at 5 to 10 mph.\\n- Humidity71%\\n- UV Index0 of 11', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='- Moonrise2:20 amWaning Crescent\\n- Moonset12:33 pm\\nSun 0740°/29°19%\\nSun 07\\nSun 07 | Day\\nIntervals of clouds and sunshine. High around 40F. Winds NW at 5 to 10 mph.\\n- Humidity57%\\n- UV Index2 of 11\\n- Sunrise7:19 am\\n- Sunset4:44 pm\\nSun 07 | Night\\nA few clouds from time to time. Low 29F. Winds NNW at 5 to 10 mph.\\n- Humidity60%\\n- UV Index0 of 11\\n- Moonrise3:28 amWaning Crescent\\n- Moonset1:04 pm\\nMon 0840°/32°35%\\nMon 08\\nMon 08 | Day\\nPartly cloudy early followed mostly cloudy skies and a few snow showers later in the day. High near 40F. Winds N at 5 to 10 mph. Chance of snow 40%.\\n- UV Index1 of 11\\n- Sunrise7:19 am\\n- Sunset4:45 pm\\nMon 08 | Night\\nVariable clouds with snow showers or flurries. Low 32F. Winds NNE at 5 to 10 mph. Chance of snow 60%. Snow accumulations less than one inch.\\n- UV Index0 of 11\\n- Moonrise4:40 amWaning Crescent\\n- Moonset1:43 pm\\nLatest News\\nOur Changing World\\nYour Privacy', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='- Humidity91%\\n- UV Index0 of 11\\n- Moonrise5:50 amWaning Crescent\\n- Moonset2:35 pm\\nWed 1056°/39°34%\\nWed 10\\nWed 10 | Day\\nA shower or two possible early with partly cloudy skies in the afternoon. Morning high of 56F with temps falling to near 45. Winds SW at 15 to 25 mph. Chance of rain 30%.\\n- Humidity66%\\n- UV Index1 of 11\\n- Sunrise7:19 am\\n- Sunset4:47 pm\\nWed 10 | Night\\nA few clouds from time to time. Low 39F. Winds WSW at 10 to 20 mph.\\n- Humidity64%\\n- UV Index0 of 11\\n- Moonrise6:56 amWaning Crescent\\n- Moonset3:38 pm\\nThu 1147°/38°5%\\nThu 11\\nThu 11 | Day\\nPartly cloudy. High 47F. Winds WSW at 5 to 10 mph.\\n- Humidity62%\\n- UV Index2 of 11\\n- Sunrise7:19 am\\n- Sunset4:48 pm\\nThu 11 | Night\\nMostly clear skies. Low 38F. Winds W at 5 to 10 mph.\\n- Humidity66%\\n- UV Index0 of 11\\n- Moonrise7:52 amNew Moon\\n- Moonset4:53 pm\\nFri 1248°/42°19%\\nFri 12\\nFri 12 | Day\\nIntervals of clouds and sunshine. High 48F. Winds WSW at 5 to 10 mph.\\n- Humidity62%\\n- UV Index2 of 11\\n- Sunrise7:18 am\\n- Sunset4:49 pm', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='Sat 1346°/36°53%\\nSat 13\\nSat 13 | Day\\nCloudy with showers. High 46F. Winds WSW at 10 to 15 mph. Chance of rain 50%.\\n- Humidity73%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:50 pm\\nSat 13 | Night\\nRain showers early transitioning to snow showers late. Low 36F. Winds W at 10 to 15 mph. Chance of precip 50%.\\n- Humidity70%\\n- UV Index0 of 11\\n- Moonrise9:14 amWaxing Crescent\\n- Moonset7:33 pm\\nSun 1442°/34°37%\\nSun 14\\nSun 14 | Day\\nSnow showers early will transition to a few showers later. High 42F. Winds WSW at 10 to 15 mph. Chance of rain 40%.\\n- Humidity63%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:51 pm\\nSun 14 | Night\\nVariable clouds with snow showers. Low 34F. Winds W at 10 to 15 mph. Chance of snow 60%. Snow accumulations less than one inch.\\n- UV Index0 of 11\\n- Moonrise9:44 amWaxing Crescent\\n- Moonset8:52 pm\\nMon 1540°/31°51%\\nMon 15\\nMon 15 | Day', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'}), Document(page_content='- Humidity70%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:34 pm\\nMon 25 | Night\\nOvercast with showers at times. Low 43F. Winds light and variable. Chance of rain 40%.\\n- Humidity80%\\n- UV Index0 of 11\\n- Moonrise3:08 pmWaxing Gibbous\\n- Moonset6:14 am\\nTue 2653°/45°58%\\nTue 26\\nTue 26 | Day\\nOvercast with rain showers at times. High 53F. Winds E at 5 to 10 mph. Chance of rain 60%.\\n- Humidity79%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:34 pm\\nTue 26 | Night\\nShowers early then scattered thunderstorms developing late. Low near 45F. Winds ESE at 5 to 10 mph. Chance of rain 60%.\\n- Humidity93%\\n- UV Index0 of 11\\n- Moonrise4:00 pmFull Moon\\n- Moonset7:17 am\\nWed 2751°/41°58%\\nWed 27\\nWed 27 | Day\\nCloudy with showers. High 51F. Winds WSW at 5 to 10 mph. Chance of rain 60%.\\n- Humidity79%\\n- UV Index1 of 11\\n- Sunrise7:18 am\\n- Sunset4:35 pm\\nWed 27 | Night\\nCloudy with showers. Low 41F. Winds NW at 5 to 10 mph. Chance of rain 60%.\\n- Humidity72%\\n- UV Index0 of 11\\n- Moonrise4:59 pmFull Moon\\n- Moonset8:13 am', metadata={'url': 'https://weather.com/weather/tenday/l/New+York+NY+USNY0996:1:US', 'thumbnail_url': 'https://imgs.search.brave.com/9xHc5-Bh2lvLyRJwQqeegm3gzoF6hawlpF8LZEjFLo8/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9zLnct/eC5jby8yNDB4MTgw/X3R3Y19kZWZhdWx0/LnBuZw', 'title': '10-Day Weather Forecast for Manhattan, NY - The Weather Channel ...', 'description': 'Be prepared with the most accurate 10-day forecast for Manhattan, NY with highs, lows, chance of precipitation from The Weather Channel and Weather.com'})]\n" + ] + } + ], + "source": [ + "# .invoke wraps utility.results\n", + "response = retriever.invoke(\"What is the weather in NY\")\n", + "\n", + "# .invoke should have a Document for each `snippet`\n", + "print(len(response))\n", + "\n", + "print(response)" + ] + }, + { + "cell_type": "markdown", + "id": "aac4a1f9", + "metadata": {}, + "source": [ + "## Chaining" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21559e10", + "metadata": {}, + "outputs": [], + "source": [ + "# you need a model to use in the chain\n", + "!pip install --upgrade --quiet langchain-openai" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "id": "655e0fec-c831-4efe-a47b-d3bb5c5a81ce", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_community.retrievers.you import YouRetriever\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langchain_core.runnables import RunnablePassthrough\n", + "from langchain_openai import ChatOpenAI\n", + "\n", + "# set up runnable\n", + "runnable = RunnablePassthrough\n", + "\n", + "# set up retriever, limit sources to one\n", + "retriever = YouRetriever(num_web_results=1)\n", + "\n", + "# set up model\n", + "model = ChatOpenAI(model=\"gpt-3.5-turbo-16k\")\n", + "\n", + "# set up output parser\n", + "output_parser = StrOutputParser()" + ] + }, + { + "cell_type": "markdown", + "id": "47e1fcca", + "metadata": {}, + "source": [ + "### Invoke" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "id": "6e92557d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The weather in New York City today is 43° with a high/low of --/39°. The wind is 3 mph, humidity is 63%, and the air quality is considered good.\n" + ] + } + ], + "source": [ + "# set up prompt that expects one question\n", + "prompt = ChatPromptTemplate.from_template(\n", + " \"\"\"Answer the question based only on the context provided.\n", + "\n", + "Context: {context}\n", + "\n", + "Question: {question}\"\"\"\n", + ")\n", + "\n", + "# set up chain\n", + "chain = (\n", + " runnable.assign(context=(lambda x: x[\"question\"]) | retriever)\n", + " | prompt\n", + " | model\n", + " | output_parser\n", + ")\n", + "\n", + "output = chain.invoke({\"question\": \"what is the weather in NY today\"})\n", + "\n", + "print(output)" + ] + }, + { + "cell_type": "markdown", + "id": "66b15f94", + "metadata": {}, + "source": [ + "### Stream" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "id": "cfe5af8b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The weather in New York City today is a high of 39°F and a low of 31°F with a feels like temperature of 43°F. The wind speed is 3 mph, humidity is 63%, and the air quality is considered to be good." + ] + } + ], + "source": [ + "# set up prompt that expects one question\n", + "prompt = ChatPromptTemplate.from_template(\n", + " \"\"\"Answer the question based only on the context provided.\n", + "\n", + "Context: {context}\n", + "\n", + "Question: {question}\"\"\"\n", + ")\n", + "\n", + "# set up chain - same as above\n", + "chain = (\n", + " runnable.assign(context=(lambda x: x[\"question\"]) | retriever)\n", + " | prompt\n", + " | model\n", + " | output_parser\n", + ")\n", + "\n", + "for s in chain.stream({\"question\": \"what is the weather in NY today\"}):\n", + " print(s, end=\"\", flush=True)" + ] + }, + { + "cell_type": "markdown", + "id": "28ee9450", + "metadata": {}, + "source": [ + "### Batch" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "id": "a8d8270b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Based on the provided context, the weather in New York City today is 43° with a high/low of --/39°.\n", + "Based on the provided context, the current weather in San Francisco is partly cloudy with a temperature of 61°F and a humidity of 57%.\n" + ] + } + ], + "source": [ + "chain = (\n", + " runnable.assign(context=(lambda x: x[\"question\"]) | retriever)\n", + " | prompt\n", + " | model\n", + " | output_parser\n", + ")\n", + "\n", + "output = chain.batch(\n", + " [\n", + " {\"question\": \"what is the weather in NY today\"},\n", + " {\"question\": \"what is the weather in sf today\"},\n", + " ]\n", + ")\n", + "\n", + "for o in output:\n", + " print(o)" ] } ], @@ -54,7 +411,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.17" + "version": "3.9.6" } }, "nbformat": 4, diff --git a/libs/community/langchain_community/retrievers/__init__.py b/libs/community/langchain_community/retrievers/__init__.py index a28c3ede92e6bc6..e7130931c1a6ebf 100644 --- a/libs/community/langchain_community/retrievers/__init__.py +++ b/libs/community/langchain_community/retrievers/__init__.py @@ -70,6 +70,7 @@ WeaviateHybridSearchRetriever, ) from langchain_community.retrievers.wikipedia import WikipediaRetriever +from langchain_community.retrievers.you import YouRetriever from langchain_community.retrievers.zep import ZepRetriever from langchain_community.retrievers.zilliz import ZillizRetriever @@ -79,6 +80,7 @@ "ArceeRetriever", "ArxivRetriever", "AzureCognitiveSearchRetriever", + "BM25Retriever", "BreebsRetriever", "ChatGPTPluginRetriever", "ChaindeskRetriever", @@ -103,10 +105,10 @@ "SVMRetriever", "TavilySearchAPIRetriever", "TFIDFRetriever", - "BM25Retriever", "VespaRetriever", "WeaviateHybridSearchRetriever", "WikipediaRetriever", + "YouRetriever", "ZepRetriever", "ZillizRetriever", "DocArrayRetriever", diff --git a/libs/community/langchain_community/retrievers/you.py b/libs/community/langchain_community/retrievers/you.py index b65f2aad78f0e7e..9564e7307ea054b 100644 --- a/libs/community/langchain_community/retrievers/you.py +++ b/libs/community/langchain_community/retrievers/you.py @@ -1,64 +1,23 @@ -from typing import Any, Dict, List, Optional +from typing import Any, List from langchain_core.callbacks import CallbackManagerForRetrieverRun from langchain_core.documents import Document -from langchain_core.pydantic_v1 import root_validator from langchain_core.retrievers import BaseRetriever -from langchain_core.utils import get_from_dict_or_env +from langchain_community.utilities import YouSearchAPIWrapper -class YouRetriever(BaseRetriever): - """`You` retriever that uses You.com's search API. - - To connect to the You.com api requires an API key which - you can get by emailing api@you.com. - You can check out our docs at https://documentation.you.com. - You need to set the environment variable `YDC_API_KEY` for retriever to operate. +class YouRetriever(BaseRetriever, YouSearchAPIWrapper): + """`You` retriever that uses You.com's search API. + It wraps results() to get_relevant_documents + It uses all YouSearchAPIWrapper arguments without any change. """ - ydc_api_key: str - k: Optional[int] = None - n_hits: Optional[int] = None - n_snippets_per_hit: Optional[int] = None - endpoint_type: str = "web" - - @root_validator(pre=True) - def validate_client( - cls, - values: Dict[str, Any], - ) -> Dict[str, Any]: - values["ydc_api_key"] = get_from_dict_or_env( - values, "ydc_api_key", "YDC_API_KEY" - ) - return values - def _get_relevant_documents( - self, query: str, *, run_manager: CallbackManagerForRetrieverRun + self, + query: str, + *, + run_manager: CallbackManagerForRetrieverRun, + **kwargs: Any, ) -> List[Document]: - import requests - - headers = {"X-API-Key": self.ydc_api_key} - if self.endpoint_type == "web": - results = requests.get( - f"https://api.ydc-index.io/search?query={query}", - headers=headers, - ).json() - - docs = [] - n_hits = self.n_hits or len(results["hits"]) - for hit in results["hits"][:n_hits]: - n_snippets_per_hit = self.n_snippets_per_hit or len(hit["snippets"]) - for snippet in hit["snippets"][:n_snippets_per_hit]: - docs.append(Document(page_content=snippet)) - if self.k is not None and len(docs) >= self.k: - return docs - return docs - elif self.endpoint_type == "snippet": - results = requests.get( - f"https://api.ydc-index.io/snippet_search?query={query}", - headers=headers, - ).json() - return [Document(page_content=snippet) for snippet in results] - else: - raise RuntimeError(f"Invalid endpoint type provided {self.endpoint_type}") + return self.results(query, run_manager=run_manager.get_child(), **kwargs) diff --git a/libs/community/langchain_community/utilities/__init__.py b/libs/community/langchain_community/utilities/__init__.py index 2af2c51ac6ccfcc..b03fa2585d7e81a 100644 --- a/libs/community/langchain_community/utilities/__init__.py +++ b/libs/community/langchain_community/utilities/__init__.py @@ -248,6 +248,12 @@ def _import_twilio() -> Any: return TwilioAPIWrapper +def _import_you() -> Any: + from langchain_community.utilities.you import YouSearchAPIWrapper + + return YouSearchAPIWrapper + + def _import_wikipedia() -> Any: from langchain_community.utilities.wikipedia import WikipediaAPIWrapper @@ -377,6 +383,8 @@ def __getattr__(name: str) -> Any: return _import_tensorflow_datasets() elif name == "TwilioAPIWrapper": return _import_twilio() + elif name == "YouSearchAPIWrapper": + return _import_you() elif name == "WikipediaAPIWrapper": return _import_wikipedia() elif name == "WolframAlphaAPIWrapper": @@ -434,6 +442,7 @@ def __getattr__(name: str) -> Any: "TensorflowDatasets", "TextRequestsWrapper", "TwilioAPIWrapper", + "YouSearchAPIWrapper", "WikipediaAPIWrapper", "WolframAlphaAPIWrapper", "ZapierNLAWrapper", diff --git a/libs/community/langchain_community/utilities/you.py b/libs/community/langchain_community/utilities/you.py new file mode 100644 index 000000000000000..c01a1ed37a1a176 --- /dev/null +++ b/libs/community/langchain_community/utilities/you.py @@ -0,0 +1,230 @@ +"""Util that calls you.com Search API. + +In order to set this up, follow instructions at: +""" +import json +from typing import Any, Dict, List, Literal, Optional + +import aiohttp +import requests +from langchain_core.documents import Document +from langchain_core.pydantic_v1 import BaseModel, Field, root_validator +from langchain_core.utils import get_from_dict_or_env + +YOU_API_URL = "https://api.ydc-index.io" + + +class YouHitMetadata(BaseModel): + """Metadata on a single hit from you.com""" + + title: str = Field(description="The title of the result") + url: str = Field(description="The url of the result") + thumbnail_url: str = Field(description="Thumbnail associated with the result") + description: str = Field(description="Details about the result") + + +class YouHit(YouHitMetadata): + """A single hit from you.com, which may contain multiple snippets""" + + snippets: List[str] = Field(description="One or snippets of text") + + +class YouAPIOutput(BaseModel): + """The output from you.com api""" + + hits: List[YouHit] = Field( + description="A list of dictionaries containing the results" + ) + + +class YouDocument(BaseModel): + """The output of parsing one snippet""" + + page_content: str = Field(description="One snippet of text") + metadata: YouHitMetadata + + +class YouSearchAPIWrapper(BaseModel): + """Wrapper for you.com Search API. + + To connect to the You.com api requires an API key which + you can get at https://api.you.com. + You can check out the docs at https://documentation.you.com. + + You need to set the environment variable `YDC_API_KEY` for retriever to operate. + + Attributes + ---------- + ydc_api_key: str, optional + you.com api key, if YDC_API_KEY is not set in the environment + num_web_results: int, optional + The max number of web results to return, must be under 20 + safesearch: str, optional + Safesearch settings, one of off, moderate, strict, defaults to moderate + country: str, optional + Country code, ex: 'US' for united states, see api docs for list + k: int, optional + max number of Documents to return using `results()` + n_hits: int, optional, deprecated + Alias for num_web_results + n_snippets_per_hit: int, optional + limit the number of snippets returned per hit + endpoint_type: str, optional + you.com endpoints: search, news, rag; + `web` and `snippet` alias `search` + `rag` returns `{'message': 'Forbidden'}` + @todo `news` endpoint + """ + + ydc_api_key: Optional[str] = None + num_web_results: Optional[int] = None + safesearch: Optional[str] = None + country: Optional[str] = None + k: Optional[int] = None + n_snippets_per_hit: Optional[int] = None + # @todo deprecate `snippet`, not part of API + endpoint_type: Literal["search", "news", "rag", "snippet"] = "search" + # should deprecate n_hits + n_hits: Optional[int] = None + + @root_validator(pre=True) + def validate_environment(cls, values: Dict) -> Dict: + """Validate that api key exists in environment.""" + ydc_api_key = get_from_dict_or_env(values, "ydc_api_key", "YDC_API_KEY") + values["ydc_api_key"] = ydc_api_key + + return values + + def _parse_results(self, raw_search_results: Dict) -> List[Document]: + """ + Extracts snippets from each hit and puts them in a Document + Parameters: + raw_search_results: A dict containing list of hits + Returns: + List[YouDocument]: A dictionary of parsed results + """ + + # return news results + if self.endpoint_type == "news": + return [ + Document(page_content=result["description"], metadata=result) + for result in raw_search_results["news"]["results"] + ] + + docs = [] + for hit in raw_search_results["hits"]: + n_snippets_per_hit = self.n_snippets_per_hit or len(hit["snippets"]) + for snippet in hit["snippets"][:n_snippets_per_hit]: + docs.append( + Document( + page_content=snippet, + metadata={ + "url": hit["url"], + "thumbnail_url": hit["thumbnail_url"], + "title": hit["title"], + "description": hit["description"], + }, + ) + ) + if self.k is not None and len(docs) >= self.k: + return docs + return docs + + def raw_results( + self, + query: str, + **kwargs: Any, + ) -> Dict: + """Run query through you.com Search and return hits. + + Args: + query: The query to search for. + num_web_results: The maximum number of results to return. + safesearch: Safesearch settings, + one of off, moderate, strict, defaults to moderate + country: Country code + Returns: YouAPIOutput + """ + headers = {"X-API-Key": self.ydc_api_key or ""} + params = { + "query": query, + "num_web_results": self.num_web_results, + "safesearch": self.safesearch, + "country": self.country, + **kwargs, + } + + params = {k: v for k, v in params.items() if v is not None} + # news endpoint expects `q` instead of `query` + if self.endpoint_type == "news": + params["q"] = params["query"] + del params["query"] + + # @todo deprecate `snippet`, not part of API + if self.endpoint_type == "snippet": + self.endpoint_type = "search" + response = requests.get( + # type: ignore + f"{YOU_API_URL}/{self.endpoint_type}", + params=params, + headers=headers, + ) + response.raise_for_status() + return response.json() + + def results( + self, + query: str, + **kwargs: Any, + ) -> List[Document]: + """Run query through you.com Search and parses results into Documents.""" + + raw_search_results = self.raw_results( + query, + **{key: value for key, value in kwargs.items() if value is not None}, + ) + return self._parse_results(raw_search_results) + + async def raw_results_async( + self, + query: str, + num_web_results: Optional[int] = 5, + safesearch: Optional[str] = "moderate", + country: Optional[str] = "US", + ) -> Dict: + """Get results from the you.com Search API asynchronously.""" + + # Function to perform the API call + async def fetch() -> str: + params = { + "query": query, + "num_web_results": num_web_results, + "safesearch": safesearch, + "country": country, + } + async with aiohttp.ClientSession() as session: + async with session.post(f"{YOU_API_URL}/search", json=params) as res: + if res.status == 200: + data = await res.text() + return data + else: + raise Exception(f"Error {res.status}: {res.reason}") + + results_json_str = await fetch() + return json.loads(results_json_str) + + async def results_async( + self, + query: str, + num_web_results: Optional[int] = 5, + safesearch: Optional[str] = "moderate", + country: Optional[str] = "US", + ) -> List[Document]: + results_json = await self.raw_results_async( + query=query, + num_web_results=num_web_results, + safesearch=safesearch, + country=country, + ) + + return self._parse_results(results_json["results"]) diff --git a/libs/community/tests/unit_tests/retrievers/test_imports.py b/libs/community/tests/unit_tests/retrievers/test_imports.py index d9acc880387d5b4..d13bfe288103eda 100644 --- a/libs/community/tests/unit_tests/retrievers/test_imports.py +++ b/libs/community/tests/unit_tests/retrievers/test_imports.py @@ -34,6 +34,7 @@ "VespaRetriever", "WeaviateHybridSearchRetriever", "WikipediaRetriever", + "YouRetriever", "ZepRetriever", "ZillizRetriever", "DocArrayRetriever", diff --git a/libs/community/tests/unit_tests/retrievers/test_you.py b/libs/community/tests/unit_tests/retrievers/test_you.py index 0d5acfeb693a988..dbc8cc65091cb7b 100644 --- a/libs/community/tests/unit_tests/retrievers/test_you.py +++ b/libs/community/tests/unit_tests/retrievers/test_you.py @@ -1,26 +1,72 @@ -import json -import os -from unittest import mock - -from langchain_core.documents import Document -from requests import Response +import responses from langchain_community.retrievers.you import YouRetriever +from ..utilities.test_you import ( + LIMITED_PARSED_OUTPUT, + MOCK_PARSED_OUTPUT, + MOCK_RESPONSE_RAW, + NEWS_RESPONSE_PARSED, + NEWS_RESPONSE_RAW, + TEST_ENDPOINT, +) + class TestYouRetriever: + @responses.activate def test_get_relevant_documents(self) -> None: - os.environ["YDC_API_KEY"] = "MOCK KEY!" - retriever = YouRetriever() - - with mock.patch("requests.get") as mock_get: - fixture = {"hits": [{"snippets": ["yo"]}, {"snippets": ["bird up"]}]} - response = Response() - response._content = bytes(json.dumps(fixture).encode("utf-8")) - mock_get.return_value = response - - actual = retriever.get_relevant_documents("test") - assert actual == [ - Document(page_content="yo"), - Document(page_content="bird up"), - ] + responses.add( + responses.GET, f"{TEST_ENDPOINT}/search", json=MOCK_RESPONSE_RAW, status=200 + ) + query = "Test query text" + you_wrapper = YouRetriever(ydc_api_key="test") + results = you_wrapper.get_relevant_documents(query) + expected_result = MOCK_PARSED_OUTPUT + assert results == expected_result + + @responses.activate + def test_invoke(self) -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/search", json=MOCK_RESPONSE_RAW, status=200 + ) + query = "Test query text" + you_wrapper = YouRetriever(ydc_api_key="test") + results = you_wrapper.invoke(query) + expected_result = MOCK_PARSED_OUTPUT + assert results == expected_result + + @responses.activate + def test_invoke_max_docs(self) -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/search", json=MOCK_RESPONSE_RAW, status=200 + ) + query = "Test query text" + you_wrapper = YouRetriever(k=2, ydc_api_key="test") + results = you_wrapper.invoke(query) + expected_result = [MOCK_PARSED_OUTPUT[0], MOCK_PARSED_OUTPUT[1]] + assert results == expected_result + + @responses.activate + def test_invoke_limit_snippets(self) -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/search", json=MOCK_RESPONSE_RAW, status=200 + ) + + query = "Test query text" + you_wrapper = YouRetriever(n_snippets_per_hit=1, ydc_api_key="test") + results = you_wrapper.results(query) + expected_result = LIMITED_PARSED_OUTPUT + assert results == expected_result + + @responses.activate + def test_invoke_news(self) -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/news", json=NEWS_RESPONSE_RAW, status=200 + ) + + query = "Test news text" + # ensure limit on number of docs returned + you_wrapper = YouRetriever(endpoint_type="news", ydc_api_key="test") + results = you_wrapper.results(query) + expected_result = NEWS_RESPONSE_PARSED + assert results == expected_result diff --git a/libs/community/tests/unit_tests/utilities/test_imports.py b/libs/community/tests/unit_tests/utilities/test_imports.py index a7bd210b4f9bdab..91d1712be3c9a2f 100644 --- a/libs/community/tests/unit_tests/utilities/test_imports.py +++ b/libs/community/tests/unit_tests/utilities/test_imports.py @@ -48,6 +48,7 @@ "TwilioAPIWrapper", "WikipediaAPIWrapper", "WolframAlphaAPIWrapper", + "YouSearchAPIWrapper", "ZapierNLAWrapper", "MerriamWebsterAPIWrapper", ] diff --git a/libs/community/tests/unit_tests/utilities/test_you.py b/libs/community/tests/unit_tests/utilities/test_you.py new file mode 100644 index 000000000000000..adc004ad4380705 --- /dev/null +++ b/libs/community/tests/unit_tests/utilities/test_you.py @@ -0,0 +1,190 @@ +from typing import Any, Dict, List, Optional, Union + +import responses +from langchain_core.documents import Document + +from langchain_community.utilities.you import YouSearchAPIWrapper + +TEST_ENDPOINT = "https://api.ydc-index.io" + +# Mock you.com response for testing +MOCK_RESPONSE_RAW: Dict[str, List[Dict[str, Union[str, List[str]]]]] = { + "hits": [ + { + "description": "Test description", + "snippets": ["yo", "bird up"], + "thumbnail_url": "https://example.com/image.gif", + "title": "Test title 1", + "url": "https://example.com/article.html", + }, + { + "description": "Test description 2", + "snippets": ["worst show", "on tv"], + "thumbnail_url": "https://example.com/image2.gif", + "title": "Test title 2", + "url": "https://example.com/article2.html", + }, + ] +} + + +def generate_parsed_metadata(num: Optional[int] = 0) -> Dict[Any, Any]: + """generate metadata for testing""" + if num is None: + num = 0 + hit: Dict[str, Union[str, List[str]]] = MOCK_RESPONSE_RAW["hits"][num] + return { + "url": hit["url"], + "thumbnail_url": hit["thumbnail_url"], + "title": hit["title"], + "description": hit["description"], + } + + +def generate_parsed_output(num: Optional[int] = 0) -> List[Document]: + """generate parsed output for testing""" + if num is None: + num = 0 + hit: Dict[str, Union[str, List[str]]] = MOCK_RESPONSE_RAW["hits"][num] + output = [] + for snippit in hit["snippets"]: + doc = Document(page_content=snippit, metadata=generate_parsed_metadata(num)) + output.append(doc) + return output + + +# Mock results after parsing +MOCK_PARSED_OUTPUT = generate_parsed_output() +MOCK_PARSED_OUTPUT.extend(generate_parsed_output(1)) +# Single-snippet +LIMITED_PARSED_OUTPUT = [] +LIMITED_PARSED_OUTPUT.append(generate_parsed_output()[0]) +LIMITED_PARSED_OUTPUT.append(generate_parsed_output(1)[0]) + +# copied from you api docs +NEWS_RESPONSE_RAW = { + "news": { + "results": [ + { + "age": "18 hours ago", + "breaking": True, + "description": "Search on YDC for the news", + "meta_url": { + "hostname": "www.reuters.com", + "netloc": "reuters.com", + "path": "› 2023 › 10 › 18 › politics › inflation › index.html", + "scheme": "https", + }, + "page_age": "2 days", + "page_fetched": "2023-10-12T23:00:00Z", + "thumbnail": {"original": "https://reuters.com/news.jpg"}, + "title": "Breaking News about the World's Greatest Search Engine!", + "type": "news", + "url": "https://news.you.com", + } + ] + } +} + +NEWS_RESPONSE_PARSED = [ + Document(page_content=str(result["description"]), metadata=result) + for result in NEWS_RESPONSE_RAW["news"]["results"] +] + + +@responses.activate +def test_raw_results() -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/search", json=MOCK_RESPONSE_RAW, status=200 + ) + + query = "Test query text" + # ensure default endpoint_type + you_wrapper = YouSearchAPIWrapper(endpoint_type="snippet", ydc_api_key="test") + raw_results = you_wrapper.raw_results(query) + expected_result = MOCK_RESPONSE_RAW + assert raw_results == expected_result + + +@responses.activate +def test_raw_results_defaults() -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/search", json=MOCK_RESPONSE_RAW, status=200 + ) + + query = "Test query text" + # ensure limit on number of docs returned + you_wrapper = YouSearchAPIWrapper(ydc_api_key="test") + raw_results = you_wrapper.raw_results(query) + expected_result = MOCK_RESPONSE_RAW + assert raw_results == expected_result + + +@responses.activate +def test_raw_results_news() -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/news", json=NEWS_RESPONSE_RAW, status=200 + ) + + query = "Test news text" + # ensure limit on number of docs returned + you_wrapper = YouSearchAPIWrapper(endpoint_type="news", ydc_api_key="test") + raw_results = you_wrapper.raw_results(query) + expected_result = NEWS_RESPONSE_RAW + assert raw_results == expected_result + + +@responses.activate +def test_results() -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/search", json=MOCK_RESPONSE_RAW, status=200 + ) + + query = "Test query text" + you_wrapper = YouSearchAPIWrapper(ydc_api_key="test") + results = you_wrapper.results(query) + expected_result = MOCK_PARSED_OUTPUT + assert results == expected_result + + +@responses.activate +def test_results_max_docs() -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/search", json=MOCK_RESPONSE_RAW, status=200 + ) + + query = "Test query text" + you_wrapper = YouSearchAPIWrapper(k=2, ydc_api_key="test") + results = you_wrapper.results(query) + expected_result = generate_parsed_output() + assert results == expected_result + + +@responses.activate +def test_results_limit_snippets() -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/search", json=MOCK_RESPONSE_RAW, status=200 + ) + + query = "Test query text" + you_wrapper = YouSearchAPIWrapper(n_snippets_per_hit=1, ydc_api_key="test") + results = you_wrapper.results(query) + expected_result = LIMITED_PARSED_OUTPUT + assert results == expected_result + + +@responses.activate +def test_results_news() -> None: + responses.add( + responses.GET, f"{TEST_ENDPOINT}/news", json=NEWS_RESPONSE_RAW, status=200 + ) + + query = "Test news text" + # ensure limit on number of docs returned + you_wrapper = YouSearchAPIWrapper(endpoint_type="news", ydc_api_key="test") + raw_results = you_wrapper.results(query) + expected_result = NEWS_RESPONSE_PARSED + assert raw_results == expected_result + + +# @todo test async methods From 641efcf41c8358655dcf1db2fbe827cfe77feae0 Mon Sep 17 00:00:00 2001 From: Armin Stepanyan Date: Thu, 8 Feb 2024 21:58:31 +0000 Subject: [PATCH 17/35] community: add runtime kwargs to HuggingFacePipeline (#17005) This PR enables changing the behaviour of huggingface pipeline between different calls. For example, before this PR there's no way of changing maximum generation length between different invocations of the chain. This is desirable in cases, such as when we want to scale the maximum output size depending on a dynamic prompt size. Usage example: ```python from langchain_community.llms.huggingface_pipeline import HuggingFacePipeline from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline model_id = "gpt2" tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_pretrained(model_id) pipe = pipeline("text-generation", model=model, tokenizer=tokenizer) hf = HuggingFacePipeline(pipeline=pipe) hf("Say foo:", pipeline_kwargs={"max_new_tokens": 42}) ``` --------- Co-authored-by: Bagatur --- .../langchain_community/llms/huggingface_pipeline.py | 3 ++- .../llms/test_huggingface_pipeline.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/libs/community/langchain_community/llms/huggingface_pipeline.py b/libs/community/langchain_community/llms/huggingface_pipeline.py index 9b2e94db326d599..388ba117c25ecd8 100644 --- a/libs/community/langchain_community/llms/huggingface_pipeline.py +++ b/libs/community/langchain_community/llms/huggingface_pipeline.py @@ -195,12 +195,13 @@ def _generate( ) -> LLMResult: # List to hold all results text_generations: List[str] = [] + pipeline_kwargs = kwargs.get("pipeline_kwargs", {}) for i in range(0, len(prompts), self.batch_size): batch_prompts = prompts[i : i + self.batch_size] # Process batch of prompts - responses = self.pipeline(batch_prompts) + responses = self.pipeline(batch_prompts, **pipeline_kwargs) # Process each response in the batch for j, response in enumerate(responses): diff --git a/libs/community/tests/integration_tests/llms/test_huggingface_pipeline.py b/libs/community/tests/integration_tests/llms/test_huggingface_pipeline.py index 885f3b3eaf3cc01..aa6a0e1defe8d51 100755 --- a/libs/community/tests/integration_tests/llms/test_huggingface_pipeline.py +++ b/libs/community/tests/integration_tests/llms/test_huggingface_pipeline.py @@ -69,3 +69,14 @@ def test_init_with_pipeline() -> None: llm = HuggingFacePipeline(pipeline=pipe) output = llm("Say foo:") assert isinstance(output, str) + + +def test_huggingface_pipeline_runtime_kwargs() -> None: + """Test pipelines specifying the device map parameter.""" + llm = HuggingFacePipeline.from_model_id( + model_id="gpt2", + task="text-generation", + ) + prompt = "Say foo:" + output = llm(prompt, pipeline_kwargs={"max_new_tokens": 2}) + assert len(output) < 10 From e35c7fa3b2af870006108beb778aefe8303ef687 Mon Sep 17 00:00:00 2001 From: Mohammad Mohtashim <45242107+keenborder786@users.noreply.github.com> Date: Fri, 9 Feb 2024 03:05:33 +0500 Subject: [PATCH 18/35] [Langchain_core]: Added Docstring for RunnableConfigurableAlternatives (#17263) I noticed that RunnableConfigurableAlternatives which is an important composition in LCEL has no Docstring. Therefore I added the detailed Docstring for it. @baskaryan, @eyurtsev, @hwchase17 please have a look and let me if the docstring is looking good. --------- Co-authored-by: Bagatur --- .../langchain_core/runnables/configurable.py | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/libs/core/langchain_core/runnables/configurable.py b/libs/core/langchain_core/runnables/configurable.py index 81ab33d8fd445cf..4c795a7b5bda15e 100644 --- a/libs/core/langchain_core/runnables/configurable.py +++ b/libs/core/langchain_core/runnables/configurable.py @@ -313,7 +313,60 @@ class StrEnum(str, enum.Enum): class RunnableConfigurableAlternatives(DynamicRunnable[Input, Output]): - """A Runnable that can be dynamically configured.""" + """A Runnable that can be dynamically configured. + + A RunnableConfigurableAlternatives should be initiated using the + `configurable_alternatives` method of a runnable or can be + initiated directly as well. + + Here is an example of using a RunnableConfigurableAlternatives that uses + alternative prompts to illustrate its functionality: + + .. code-block:: python + + from langchain_core.runnables import ConfigurableField + from langchain_openai import ChatOpenAI + + # This creates a RunnableConfigurableAlternatives for Prompt Runnable + # with two alternatives. + prompt = PromptTemplate.from_template( + "Tell me a joke about {topic}" + ).configurable_alternatives( + ConfigurableField(id="prompt"), + default_key="joke", + poem=PromptTemplate.from_template("Write a short poem about {topic}") + ) + + # When invoking the created RunnableSequence, you can pass in the + # value for your ConfigurableField's id which in this case will either be + # `joke` or `poem`. + chain = prompt | ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0) + + # The `with_config` method brings in the desired Prompt Runnable in your + # Runnable Sequence. + chain.with_config(configurable={"prompt": "poem"}).invoke({"topic": "bears"}) + + + Equivalently, you can initialize RunnableConfigurableAlternatives directly + and use in LCEL in the same way: + + .. code-block:: python + + from langchain_core.runnables import ConfigurableField + from langchain_core.runnables.configurable import RunnableConfigurableAlternatives + from langchain_openai import ChatOpenAI + + prompt = RunnableConfigurableAlternatives( + which=ConfigurableField(id='prompt'), + default=PromptTemplate.from_template("Tell me a joke about {topic}"), + default_key='joke', + prefix_keys=False, + alternatives={"poem":PromptTemplate.from_template("Write a short poem about {topic}")} + ) + chain = prompt | ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0) + chain.with_config(configurable={"prompt": "poem"}).invoke({"topic": "bears"}) + + """ # noqa: E501 which: ConfigurableField From de5e96b5f95531d8a8f5d5e582b07ab774909647 Mon Sep 17 00:00:00 2001 From: Alex <77668803+Sssanek@users.noreply.github.com> Date: Fri, 9 Feb 2024 01:43:44 +0300 Subject: [PATCH 19/35] community[patch]: updated openai prices in mapping (#17009) - **Description:** there are january prices update for chatgpt [blog](https://openai.com/blog/new-embedding-models-and-api-updates), also there are updates on their website on page [pricing](https://openai.com/pricing) - **Issue:** N/A --------- Co-authored-by: Bagatur --- libs/community/langchain_community/callbacks/openai_info.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/community/langchain_community/callbacks/openai_info.py b/libs/community/langchain_community/callbacks/openai_info.py index d18059c119341de..c6f8262285b9916 100644 --- a/libs/community/langchain_community/callbacks/openai_info.py +++ b/libs/community/langchain_community/callbacks/openai_info.py @@ -25,7 +25,10 @@ "gpt-4-vision-preview-completion": 0.03, "gpt-4-1106-preview-completion": 0.03, # GPT-3.5 input + # gpt-3.5-turbo points at gpt-3.5-turbo-0613 until Feb 16, 2024. + # Switches to gpt-3.5-turbo-0125 after. "gpt-3.5-turbo": 0.0015, + "gpt-3.5-turbo-0125": 0.0005, "gpt-3.5-turbo-0301": 0.0015, "gpt-3.5-turbo-0613": 0.0015, "gpt-3.5-turbo-1106": 0.001, @@ -33,7 +36,10 @@ "gpt-3.5-turbo-16k": 0.003, "gpt-3.5-turbo-16k-0613": 0.003, # GPT-3.5 output + # gpt-3.5-turbo points at gpt-3.5-turbo-0613 until Feb 16, 2024. + # Switches to gpt-3.5-turbo-0125 after. "gpt-3.5-turbo-completion": 0.002, + "gpt-3.5-turbo-0125-completion": 0.0015, "gpt-3.5-turbo-0301-completion": 0.002, "gpt-3.5-turbo-0613-completion": 0.002, "gpt-3.5-turbo-1106-completion": 0.002, From 389b055bd69cdee37dc4972e5522d4aba0d1758c Mon Sep 17 00:00:00 2001 From: Leonid Ganeline Date: Thu, 8 Feb 2024 14:52:26 -0800 Subject: [PATCH 20/35] docs: `Toolkits` menu (#16217) The Integrations `Toolkits` menu was named as [`Agents and toolkits`](https://python.langchain.com/docs/integrations/toolkits). This name has a historical reason that is not correct anymore. Now this menu is all about community `Toolkits`. There is a separate menu for [Agents](https://python.langchain.com/docs/modules/agents/). Also Agents are officially not part of Integrations (Community package) but part of LangChain package. --- docs/sidebars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sidebars.js b/docs/sidebars.js index 3918fe92795ff6c..aa28a21dfd96a88 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -107,7 +107,7 @@ module.exports = { { type: "category", label: "Vector stores", collapsed: true, items: [{type: "autogenerated", dirName: "integrations/vectorstores" }], link: {type: "generated-index", slug: "integrations/vectorstores" }}, { type: "category", label: "Retrievers", collapsed: true, items: [{type: "autogenerated", dirName: "integrations/retrievers" }], link: {type: "generated-index", slug: "integrations/retrievers" }}, { type: "category", label: "Tools", collapsed: true, items: [{type: "autogenerated", dirName: "integrations/tools" }], link: {type: "generated-index", slug: "integrations/tools" }}, - { type: "category", label: "Agents and toolkits", collapsed: true, items: [{type: "autogenerated", dirName: "integrations/toolkits" }], link: {type: "generated-index", slug: "integrations/toolkits" }}, + { type: "category", label: "Toolkits", collapsed: true, items: [{type: "autogenerated", dirName: "integrations/toolkits" }], link: {type: "generated-index", slug: "integrations/toolkits" }}, { type: "category", label: "Memory", collapsed: true, items: [{type: "autogenerated", dirName: "integrations/memory" }], link: {type: "generated-index", slug: "integrations/memory" }}, { type: "category", label: "Callbacks", collapsed: true, items: [{type: "autogenerated", dirName: "integrations/callbacks" }], link: {type: "generated-index", slug: "integrations/callbacks" }}, { type: "category", label: "Chat loaders", collapsed: true, items: [{type: "autogenerated", dirName: "integrations/chat_loaders" }], link: {type: "generated-index", slug: "integrations/chat_loaders" }}, From 35c1bf339d1824a3b0970c2520dfcdd6f05db8b3 Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:28:22 -0800 Subject: [PATCH 21/35] infra: rm boto3, gcaip from pyproject (#17270) --- .github/workflows/_integration_test.yml | 5 + .github/workflows/scheduled_test.yml | 5 + libs/community/poetry.lock | 390 ++---------------------- libs/community/pyproject.toml | 2 - 4 files changed, 42 insertions(+), 360 deletions(-) diff --git a/.github/workflows/_integration_test.yml b/.github/workflows/_integration_test.yml index 8f64e2bfd47e6d2..7e4afe70e2bfa00 100644 --- a/.github/workflows/_integration_test.yml +++ b/.github/workflows/_integration_test.yml @@ -38,6 +38,11 @@ jobs: shell: bash run: poetry install --with test,test_integration + - name: Install deps outside pyproject + if: ${{ startsWith(inputs.working-directory, 'libs/community/') }} + shell: bash + run: poetry run pip install "boto3<2" "google-cloud-aiplatform<2" + - name: 'Authenticate to Google Cloud' id: 'auth' uses: google-github-actions/auth@v2 diff --git a/.github/workflows/scheduled_test.yml b/.github/workflows/scheduled_test.yml index 4ae8b755c146c88..a5bae539102a1d9 100644 --- a/.github/workflows/scheduled_test.yml +++ b/.github/workflows/scheduled_test.yml @@ -54,6 +54,11 @@ jobs: echo "Running scheduled tests, installing dependencies with poetry..." poetry install --with=test_integration,test + - name: Install deps outside pyproject + if: ${{ startsWith(inputs.working-directory, 'libs/community/') }} + shell: bash + run: poetry run pip install "boto3<2" "google-cloud-aiplatform<2" + - name: Run tests shell: bash env: diff --git a/libs/community/poetry.lock b/libs/community/poetry.lock index fccdc9749fbc87b..c5ea8eae37ae45a 100644 --- a/libs/community/poetry.lock +++ b/libs/community/poetry.lock @@ -700,52 +700,11 @@ files = [ {file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"}, ] -[[package]] -name = "boto3" -version = "1.34.37" -description = "The AWS SDK for Python" -optional = false -python-versions = ">= 3.8" -files = [ - {file = "boto3-1.34.37-py3-none-any.whl", hash = "sha256:65acfe7f1cf2a9b7df3d4edb87c8022e02685825bd1957e7bb678cc0d09f5e5f"}, - {file = "boto3-1.34.37.tar.gz", hash = "sha256:73f5ec89cb3ddb3ed577317889fd2f2df783f66b6502a9a4239979607e33bf74"}, -] - -[package.dependencies] -botocore = ">=1.34.37,<1.35.0" -jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.10.0,<0.11.0" - -[package.extras] -crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] - -[[package]] -name = "botocore" -version = "1.34.37" -description = "Low-level, data-driven core of boto 3." -optional = false -python-versions = ">= 3.8" -files = [ - {file = "botocore-1.34.37-py3-none-any.whl", hash = "sha256:2a5bf33aacd2d970afd3d492e179e06ea98a5469030d5cfe7a2ad9995f7bb2ef"}, - {file = "botocore-1.34.37.tar.gz", hash = "sha256:3c46ddb1679e6ef45ca78b48665398636bda532a07cd476e4b500697d13d9a99"}, -] - -[package.dependencies] -jmespath = ">=0.7.1,<2.0.0" -python-dateutil = ">=2.1,<3.0.0" -urllib3 = [ - {version = ">=1.25.4,<1.27", markers = "python_version < \"3.10\""}, - {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""}, -] - -[package.extras] -crt = ["awscrt (==0.19.19)"] - [[package]] name = "cachetools" version = "5.3.2" description = "Extensible memoizing collections and decorators" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, @@ -2339,7 +2298,7 @@ test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre name = "google-api-core" version = "2.16.2" description = "Google API client core library" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "google-api-core-2.16.2.tar.gz", hash = "sha256:032d37b45d1d6bdaf68fb11ff621e2593263a239fa9246e2e94325f9c47876d2"}, @@ -2369,7 +2328,7 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] name = "google-auth" version = "2.27.0" description = "Google Authentication Library" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "google-auth-2.27.0.tar.gz", hash = "sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821"}, @@ -2388,94 +2347,6 @@ pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] requests = ["requests (>=2.20.0,<3.0.0.dev0)"] -[[package]] -name = "google-cloud-aiplatform" -version = "1.40.0" -description = "Vertex AI API client library" -optional = false -python-versions = ">=3.8" -files = [ - {file = "google-cloud-aiplatform-1.40.0.tar.gz", hash = "sha256:1ee9aff2fa27c6852558a2abeaf0ffe0537bff90c5dc9f0e967762ac17291001"}, - {file = "google_cloud_aiplatform-1.40.0-py2.py3-none-any.whl", hash = "sha256:9c67a2664e138387ea82d70dec4b54e081b7de6e1089ed23fdaf66900d00320a"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.32.0,<2.0.dev0 || >=2.8.dev0,<3.0.0dev", extras = ["grpc"]} -google-cloud-bigquery = ">=1.15.0,<4.0.0dev" -google-cloud-resource-manager = ">=1.3.3,<3.0.0dev" -google-cloud-storage = ">=1.32.0,<3.0.0dev" -packaging = ">=14.3" -proto-plus = ">=1.22.0,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" -setuptools = {version = "*", markers = "python_version >= \"3.12\""} -shapely = "<3.0.0dev" - -[package.extras] -autologging = ["mlflow (>=1.27.0,<=2.1.1)"] -cloud-profiler = ["tensorboard-plugin-profile (>=2.4.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "werkzeug (>=2.0.0,<2.1.0dev)"] -datasets = ["pyarrow (>=10.0.1)", "pyarrow (>=3.0.0,<8.0dev)"] -endpoint = ["requests (>=2.28.1)"] -full = ["cloudpickle (<3.0)", "docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0)", "fastapi (>=0.71.0,<0.103.1)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-cloud-logging (<4.0)", "google-vizier (>=0.1.6)", "httpx (>=0.23.0,<0.25.0)", "lit-nlp (==0.4.0)", "mlflow (>=1.27.0,<=2.1.1)", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "pyarrow (>=10.0.1)", "pyarrow (>=3.0.0,<8.0dev)", "pyarrow (>=6.0.1)", "pydantic (<2)", "pyyaml (==5.3.1)", "ray[default] (>=2.4,<2.5)", "ray[default] (>=2.5,<2.5.1)", "requests (>=2.28.1)", "starlette (>=0.17.1)", "tensorflow (>=2.3.0,<2.15.0)", "tensorflow (>=2.3.0,<3.0.0dev)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)"] -lit = ["explainable-ai-sdk (>=1.0.0)", "lit-nlp (==0.4.0)", "pandas (>=1.0.0)", "tensorflow (>=2.3.0,<3.0.0dev)"] -metadata = ["numpy (>=1.15.0)", "pandas (>=1.0.0)"] -pipelines = ["pyyaml (==5.3.1)"] -prediction = ["docker (>=5.0.3)", "fastapi (>=0.71.0,<0.103.1)", "httpx (>=0.23.0,<0.25.0)", "starlette (>=0.17.1)", "uvicorn[standard] (>=0.16.0)"] -preview = ["cloudpickle (<3.0)", "google-cloud-logging (<4.0)"] -private-endpoints = ["requests (>=2.28.1)", "urllib3 (>=1.21.1,<1.27)"] -ray = ["google-cloud-bigquery", "google-cloud-bigquery-storage", "pandas (>=1.0.0)", "pyarrow (>=6.0.1)", "pydantic (<2)", "ray[default] (>=2.4,<2.5)", "ray[default] (>=2.5,<2.5.1)"] -tensorboard = ["tensorflow (>=2.3.0,<2.15.0)"] -testing = ["bigframes", "cloudpickle (<3.0)", "docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0)", "fastapi (>=0.71.0,<0.103.1)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-cloud-logging (<4.0)", "google-vizier (>=0.1.6)", "grpcio-testing", "httpx (>=0.23.0,<0.25.0)", "ipython", "kfp (>=2.6.0,<3.0.0)", "lit-nlp (==0.4.0)", "mlflow (>=1.27.0,<=2.1.1)", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "pyarrow (>=10.0.1)", "pyarrow (>=3.0.0,<8.0dev)", "pyarrow (>=6.0.1)", "pydantic (<2)", "pyfakefs", "pytest-asyncio", "pytest-xdist", "pyyaml (==5.3.1)", "ray[default] (>=2.4,<2.5)", "ray[default] (>=2.5,<2.5.1)", "requests (>=2.28.1)", "requests-toolbelt (<1.0.0)", "scikit-learn", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<3.0.0dev)", "tensorflow (>=2.3.0,<2.15.0)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.3.0,<=2.12.0)", "tensorflow (>=2.4.0,<3.0.0dev)", "torch (>=2.0.0,<2.1.0)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<2.1.0dev)", "xgboost", "xgboost-ray"] -vizier = ["google-vizier (>=0.1.6)"] -xai = ["tensorflow (>=2.3.0,<3.0.0dev)"] - -[[package]] -name = "google-cloud-bigquery" -version = "3.17.2" -description = "Google BigQuery API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-bigquery-3.17.2.tar.gz", hash = "sha256:6e1cf669a40e567ab3289c7b5f2056363da9fcb85d9a4736ee90240d4a7d84ea"}, - {file = "google_cloud_bigquery-3.17.2-py2.py3-none-any.whl", hash = "sha256:cdadf5283dca55a1a350bacf8c8a7466169d3cf46c5a0a3abc5e9aa0b0a51dee"}, -] - -[package.dependencies] -google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0dev" -google-cloud-core = ">=1.6.0,<3.0.0dev" -google-resumable-media = ">=0.6.0,<3.0dev" -packaging = ">=20.0.0" -python-dateutil = ">=2.7.2,<3.0dev" -requests = ">=2.21.0,<3.0.0dev" - -[package.extras] -all = ["Shapely (>=1.8.4,<3.0.0dev)", "db-dtypes (>=0.3.0,<2.0.0dev)", "geopandas (>=0.9.0,<1.0dev)", "google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "importlib-metadata (>=1.0.0)", "ipykernel (>=6.0.0)", "ipython (>=7.23.1,!=8.1.0)", "ipywidgets (>=7.7.0)", "opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)", "pandas (>=1.1.0)", "proto-plus (>=1.15.0,<2.0.0dev)", "protobuf (>=3.19.5,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev)", "pyarrow (>=3.0.0)", "tqdm (>=4.7.4,<5.0.0dev)"] -bigquery-v2 = ["proto-plus (>=1.15.0,<2.0.0dev)", "protobuf (>=3.19.5,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev)"] -bqstorage = ["google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "pyarrow (>=3.0.0)"] -geopandas = ["Shapely (>=1.8.4,<3.0.0dev)", "geopandas (>=0.9.0,<1.0dev)"] -ipython = ["ipykernel (>=6.0.0)", "ipython (>=7.23.1,!=8.1.0)"] -ipywidgets = ["ipykernel (>=6.0.0)", "ipywidgets (>=7.7.0)"] -opentelemetry = ["opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)"] -pandas = ["db-dtypes (>=0.3.0,<2.0.0dev)", "importlib-metadata (>=1.0.0)", "pandas (>=1.1.0)", "pyarrow (>=3.0.0)"] -tqdm = ["tqdm (>=4.7.4,<5.0.0dev)"] - -[[package]] -name = "google-cloud-core" -version = "2.4.1" -description = "Google Cloud API client core library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"}, - {file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"}, -] - -[package.dependencies] -google-api-core = ">=1.31.6,<2.0.dev0 || >2.3.0,<3.0.0dev" -google-auth = ">=1.25.0,<3.0dev" - -[package.extras] -grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] - [[package]] name = "google-cloud-documentai" version = "2.23.0" @@ -2493,149 +2364,11 @@ google-auth = ">=2.14.1,<3.0.0dev" proto-plus = ">=1.22.3,<2.0.0dev" protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" -[[package]] -name = "google-cloud-resource-manager" -version = "1.12.1" -description = "Google Cloud Resource Manager API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-resource-manager-1.12.1.tar.gz", hash = "sha256:25b3112c984ef6a2569ca7047160b2341c528c70e1d2e72deb99686aa2e167dd"}, - {file = "google_cloud_resource_manager-1.12.1-py2.py3-none-any.whl", hash = "sha256:6a0b97886998fb076a71a7e9679a1187f6bed97519e0dff13352e7946513d458"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.0,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-storage" -version = "2.14.0" -description = "Google Cloud Storage API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-storage-2.14.0.tar.gz", hash = "sha256:2d23fcf59b55e7b45336729c148bb1c464468c69d5efbaee30f7201dd90eb97e"}, - {file = "google_cloud_storage-2.14.0-py2.py3-none-any.whl", hash = "sha256:8641243bbf2a2042c16a6399551fbb13f062cbc9a2de38d6c0bb5426962e9dbd"}, -] - -[package.dependencies] -google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0dev" -google-auth = ">=2.23.3,<3.0dev" -google-cloud-core = ">=2.3.0,<3.0dev" -google-crc32c = ">=1.0,<2.0dev" -google-resumable-media = ">=2.6.0" -requests = ">=2.18.0,<3.0.0dev" - -[package.extras] -protobuf = ["protobuf (<5.0.0dev)"] - -[[package]] -name = "google-crc32c" -version = "1.5.0" -description = "A python wrapper of the C library 'Google CRC32C'" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-crc32c-1.5.0.tar.gz", hash = "sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7"}, - {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13"}, - {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c"}, - {file = "google_crc32c-1.5.0-cp310-cp310-win32.whl", hash = "sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee"}, - {file = "google_crc32c-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289"}, - {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273"}, - {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c"}, - {file = "google_crc32c-1.5.0-cp311-cp311-win32.whl", hash = "sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709"}, - {file = "google_crc32c-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-win32.whl", hash = "sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740"}, - {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8"}, - {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-win32.whl", hash = "sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4"}, - {file = "google_crc32c-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c"}, - {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7"}, - {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61"}, - {file = "google_crc32c-1.5.0-cp39-cp39-win32.whl", hash = "sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c"}, - {file = "google_crc32c-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93"}, -] - -[package.extras] -testing = ["pytest"] - -[[package]] -name = "google-resumable-media" -version = "2.7.0" -description = "Utilities for Google Media Downloads and Resumable Uploads" -optional = false -python-versions = ">= 3.7" -files = [ - {file = "google-resumable-media-2.7.0.tar.gz", hash = "sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b"}, - {file = "google_resumable_media-2.7.0-py2.py3-none-any.whl", hash = "sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08"}, -] - -[package.dependencies] -google-crc32c = ">=1.0,<2.0dev" - -[package.extras] -aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)", "google-auth (>=1.22.0,<2.0dev)"] -requests = ["requests (>=2.18.0,<3.0.0dev)"] - [[package]] name = "googleapis-common-protos" version = "1.62.0" description = "Common protobufs used in Google APIs" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, @@ -2643,7 +2376,6 @@ files = [ ] [package.dependencies] -grpcio = {version = ">=1.44.0,<2.0.0.dev0", optional = true, markers = "extra == \"grpc\""} protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" [package.extras] @@ -2776,27 +2508,11 @@ files = [ docs = ["Sphinx", "furo"] test = ["objgraph", "psutil"] -[[package]] -name = "grpc-google-iam-v1" -version = "0.13.0" -description = "IAM API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "grpc-google-iam-v1-0.13.0.tar.gz", hash = "sha256:fad318608b9e093258fbf12529180f400d1c44453698a33509cc6ecf005b294e"}, - {file = "grpc_google_iam_v1-0.13.0-py2.py3-none-any.whl", hash = "sha256:53902e2af7de8df8c1bd91373d9be55b0743ec267a7428ea638db3775becae89"}, -] - -[package.dependencies] -googleapis-common-protos = {version = ">=1.56.0,<2.0.0dev", extras = ["grpc"]} -grpcio = ">=1.44.0,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - [[package]] name = "grpcio" version = "1.60.1" description = "HTTP/2-based RPC framework" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "grpcio-1.60.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:14e8f2c84c0832773fb3958240c69def72357bc11392571f87b2d7b91e0bb092"}, @@ -2862,7 +2578,7 @@ protobuf = ["grpcio-tools (>=1.60.1)"] name = "grpcio-status" version = "1.60.1" description = "Status proto mapping for gRPC" -optional = false +optional = true python-versions = ">=3.6" files = [ {file = "grpcio-status-1.60.1.tar.gz", hash = "sha256:61b5aab8989498e8aa142c20b88829ea5d90d18c18c853b9f9e6d407d37bf8b4"}, @@ -3360,7 +3076,7 @@ i18n = ["Babel (>=2.7)"] name = "jmespath" version = "1.0.1" description = "JSON Matching Expressions" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, @@ -5154,9 +4870,9 @@ numpy = [ {version = ">=1.21.0", markers = "python_version <= \"3.9\" and platform_system == \"Darwin\" and platform_machine == \"arm64\" and python_version >= \"3.8\""}, {version = ">=1.19.3", markers = "platform_system == \"Linux\" and platform_machine == \"aarch64\" and python_version >= \"3.8\" and python_version < \"3.10\" or python_version > \"3.9\" and python_version < \"3.10\" or python_version >= \"3.9\" and platform_system != \"Darwin\" and python_version < \"3.10\" or python_version >= \"3.9\" and platform_machine != \"arm64\" and python_version < \"3.10\""}, {version = ">=1.17.3", markers = "(platform_system != \"Darwin\" and platform_system != \"Linux\") and python_version >= \"3.8\" and python_version < \"3.9\" or platform_system != \"Darwin\" and python_version >= \"3.8\" and python_version < \"3.9\" and platform_machine != \"aarch64\" or platform_machine != \"arm64\" and python_version >= \"3.8\" and python_version < \"3.9\" and platform_system != \"Linux\" or (platform_machine != \"arm64\" and platform_machine != \"aarch64\") and python_version >= \"3.8\" and python_version < \"3.9\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, - {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, ] [[package]] @@ -5329,8 +5045,8 @@ files = [ [package.dependencies] numpy = [ {version = ">=1.20.3", markers = "python_version < \"3.10\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -5655,7 +5371,7 @@ wcwidth = "*" name = "proto-plus" version = "1.23.0" description = "Beautiful, Pythonic protocol buffers." -optional = false +optional = true python-versions = ">=3.6" files = [ {file = "proto-plus-1.23.0.tar.gz", hash = "sha256:89075171ef11988b3fa157f5dbd8b9cf09d65fffee97e29ce403cd8defba19d2"}, @@ -5958,7 +5674,7 @@ files = [ name = "pyasn1" version = "0.5.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" -optional = false +optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, @@ -5969,7 +5685,7 @@ files = [ name = "pyasn1-modules" version = "0.3.0" description = "A collection of ASN.1-based protocols modules" -optional = false +optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, @@ -7513,7 +7229,7 @@ files = [ name = "rsa" version = "4.9" description = "Pure-Python RSA implementation" -optional = false +optional = true python-versions = ">=3.6,<4" files = [ {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, @@ -7564,23 +7280,6 @@ files = [ {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, ] -[[package]] -name = "s3transfer" -version = "0.10.0" -description = "An Amazon S3 Transfer Manager" -optional = false -python-versions = ">= 3.8" -files = [ - {file = "s3transfer-0.10.0-py3-none-any.whl", hash = "sha256:3cdb40f5cfa6966e812209d0994f2a4709b561c88e90cf00c2696d2df4e56b2e"}, - {file = "s3transfer-0.10.0.tar.gz", hash = "sha256:d0c8bbf672d5eebbe4e57945e23b972d963f07d82f661cabf678a5c88831595b"}, -] - -[package.dependencies] -botocore = ">=1.33.2,<2.0a.0" - -[package.extras] -crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] - [[package]] name = "scikit-learn" version = "1.3.2" @@ -7712,7 +7411,7 @@ files = [ name = "shapely" version = "2.0.2" description = "Manipulation and analysis of geometric objects" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "shapely-2.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6ca8cffbe84ddde8f52b297b53f8e0687bd31141abb2c373fd8a9f032df415d6"}, @@ -8529,20 +8228,6 @@ files = [ cryptography = ">=35.0.0" types-pyOpenSSL = "*" -[[package]] -name = "types-requests" -version = "2.31.0.6" -description = "Typing stubs for requests" -optional = false -python-versions = ">=3.7" -files = [ - {file = "types-requests-2.31.0.6.tar.gz", hash = "sha256:cd74ce3b53c461f1228a9b783929ac73a666658f223e28ed29753771477b3bd0"}, - {file = "types_requests-2.31.0.6-py3-none-any.whl", hash = "sha256:a2db9cb228a81da8348b49ad6db3f5519452dd20a9c1e1a868c83c5fe88fd1a9"}, -] - -[package.dependencies] -types-urllib3 = "*" - [[package]] name = "types-requests" version = "2.31.0.20240125" @@ -8568,17 +8253,6 @@ files = [ {file = "types_toml-0.10.8.7-py3-none-any.whl", hash = "sha256:61951da6ad410794c97bec035d59376ce1cbf4453dc9b6f90477e81e4442d631"}, ] -[[package]] -name = "types-urllib3" -version = "1.26.25.14" -description = "Typing stubs for urllib3" -optional = false -python-versions = "*" -files = [ - {file = "types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f"}, - {file = "types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e"}, -] - [[package]] name = "typing" version = "3.7.4.3" @@ -8693,22 +8367,6 @@ files = [ [package.extras] dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake8-commas", "flake8-comprehensions", "flake8-continuation", "flake8-datetimez", "flake8-docstrings", "flake8-import-order", "flake8-literal", "flake8-modern-annotations", "flake8-noqa", "flake8-pyproject", "flake8-requirements", "flake8-typechecking-import", "flake8-use-fstring", "mypy", "pep8-naming", "types-PyYAML"] -[[package]] -name = "urllib3" -version = "1.26.18" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" -files = [ - {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, - {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, -] - -[package.extras] -brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - [[package]] name = "urllib3" version = "2.0.7" @@ -8758,6 +8416,23 @@ testing = ["pytest (>=7.4.0)"] tooling = ["black (>=23.7.0)", "pyright (>=1.1.325)", "ruff (>=0.0.287)"] tooling-extras = ["pyaml (>=23.7.0)", "pypandoc-binary (>=1.11)", "pytest (>=7.4.0)"] +[[package]] +name = "vcrpy" +version = "4.3.0" +description = "Automatically mock your HTTP interactions to simplify and speed up testing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "vcrpy-4.3.0-py2.py3-none-any.whl", hash = "sha256:8fbd4be412e8a7f35f623dd61034e6380a1c8dbd0edf6e87277a3289f6e98093"}, + {file = "vcrpy-4.3.0.tar.gz", hash = "sha256:49c270ce67e826dba027d83e20d25b67a5885487697e97bca6dbdf53d750a0ac"}, +] + +[package.dependencies] +PyYAML = "*" +six = ">=1.5" +wrapt = "*" +yarl = "*" + [[package]] name = "vcrpy" version = "6.0.1" @@ -8770,7 +8445,6 @@ files = [ [package.dependencies] PyYAML = "*" -urllib3 = {version = "<2", markers = "platform_python_implementation == \"PyPy\" or python_version < \"3.10\""} wrapt = "*" yarl = "*" @@ -9329,4 +9003,4 @@ extended-testing = ["aiosqlite", "aleph-alpha-client", "anthropic", "arxiv", "as [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "9e795e7b2f95e3bd1daa3d92129172e21c6c0c1b5dc82e4791872f39a33472aa" +content-hash = "fe633ab7d246239420a26bebf8bcf857edcf0778f75b3eb2a4b1314cb13645c8" diff --git a/libs/community/pyproject.toml b/libs/community/pyproject.toml index 926e9a7ee552400..320553a2af576aa 100644 --- a/libs/community/pyproject.toml +++ b/libs/community/pyproject.toml @@ -150,8 +150,6 @@ tiktoken = ">=0.3.2,<0.6.0" anthropic = "^0.3.11" langchain-core = { path = "../core", develop = true } fireworks-ai = "^0.9.0" -boto3 = ">=1.28.57,<2" -google-cloud-aiplatform = ">=1.37.0,<2" [tool.poetry.group.lint] optional = true From 02ef9164b5091ffe2459786cbd8832024f350c82 Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:07:18 -0800 Subject: [PATCH 22/35] langchain[patch]: expose cohere rerank score, add parent doc param (#16887) --- .../vectorstores/elasticsearch.py | 2 +- .../chains/query_constructor/__init__.py | 3 + .../chains/query_constructor/base.py | 3 +- .../document_compressors/cohere_rerank.py | 73 ++++++++++++------- .../retrievers/parent_document_retriever.py | 23 ++++-- .../langchain_openai/chat_models/base.py | 18 ++--- 6 files changed, 76 insertions(+), 46 deletions(-) diff --git a/libs/community/langchain_community/vectorstores/elasticsearch.py b/libs/community/langchain_community/vectorstores/elasticsearch.py index 2f8a9e2469bbb64..7b6eef40feaaaaf 100644 --- a/libs/community/langchain_community/vectorstores/elasticsearch.py +++ b/libs/community/langchain_community/vectorstores/elasticsearch.py @@ -484,8 +484,8 @@ class ElasticsearchStore(VectorStore): from langchain_community.vectorstores.utils import DistanceStrategy vectorstore = ElasticsearchStore( + "langchain-demo", embedding=OpenAIEmbeddings(), - index_name="langchain-demo", es_url="http://localhost:9200", distance_strategy="DOT_PRODUCT" ) diff --git a/libs/langchain/langchain/chains/query_constructor/__init__.py b/libs/langchain/langchain/chains/query_constructor/__init__.py index e69de29bb2d1d64..9d08ca0e080649f 100644 --- a/libs/langchain/langchain/chains/query_constructor/__init__.py +++ b/libs/langchain/langchain/chains/query_constructor/__init__.py @@ -0,0 +1,3 @@ +from langchain.chains.query_constructor.base import load_query_constructor_runnable + +__all__ = ["load_query_constructor_runnable"] diff --git a/libs/langchain/langchain/chains/query_constructor/base.py b/libs/langchain/langchain/chains/query_constructor/base.py index d99c046abfadf3b..c08e74f20da5fff 100644 --- a/libs/langchain/langchain/chains/query_constructor/base.py +++ b/libs/langchain/langchain/chains/query_constructor/base.py @@ -323,7 +323,8 @@ def load_query_constructor_runnable( Args: llm: BaseLanguageModel to use for the chain. - document_contents: The contents of the document to be queried. + document_contents: Description of the page contents of the document to be + queried. attribute_info: Sequence of attributes in the document. examples: Optional list of examples to use for the chain. allowed_comparators: Sequence of allowed comparators. Defaults to all diff --git a/libs/langchain/langchain/retrievers/document_compressors/cohere_rerank.py b/libs/langchain/langchain/retrievers/document_compressors/cohere_rerank.py index c767f86bde60922..b36ea305c789300 100644 --- a/libs/langchain/langchain/retrievers/document_compressors/cohere_rerank.py +++ b/libs/langchain/langchain/retrievers/document_compressors/cohere_rerank.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Dict, Optional, Sequence +from copy import deepcopy +from typing import Any, Dict, List, Optional, Sequence, Union from langchain_core.documents import Document from langchain_core.pydantic_v1 import Extra, root_validator @@ -9,23 +10,13 @@ from langchain.retrievers.document_compressors.base import BaseDocumentCompressor from langchain.utils import get_from_dict_or_env -if TYPE_CHECKING: - from cohere import Client -else: - # We do to avoid pydantic annotation issues when actually instantiating - # while keeping this import optional - try: - from cohere import Client - except ImportError: - pass - class CohereRerank(BaseDocumentCompressor): """Document compressor that uses `Cohere Rerank API`.""" - client: Client + client: Any """Cohere client to use for compressing documents.""" - top_n: int = 3 + top_n: Optional[int] = 3 """Number of documents to return.""" model: str = "rerank-english-v2.0" """Model to use for reranking.""" @@ -57,6 +48,42 @@ def validate_environment(cls, values: Dict) -> Dict: values["client"] = cohere.Client(cohere_api_key, client_name=client_name) return values + def rerank( + self, + documents: Sequence[Union[str, Document, dict]], + query: str, + *, + model: Optional[str] = None, + top_n: Optional[int] = -1, + max_chunks_per_doc: Optional[int] = None, + ) -> List[Dict[str, Any]]: + """Returns an ordered list of documents ordered by their relevance to the provided query. + + Args: + query: The query to use for reranking. + documents: A sequence of documents to rerank. + model: The model to use for re-ranking. Default to self.model. + top_n : The number of results to return. If None returns all results. + Defaults to self.top_n. + max_chunks_per_doc : The maximum number of chunks derived from a document. + """ # noqa: E501 + if len(documents) == 0: # to avoid empty api call + return [] + docs = [ + doc.page_content if isinstance(doc, Document) else doc for doc in documents + ] + model = model or self.model + top_n = top_n if (top_n is None or top_n > 0) else self.top_n + results = self.client.rerank( + query, docs, model, top_n=top_n, max_chunks_per_doc=max_chunks_per_doc + ) + result_dicts = [] + for res in results: + result_dicts.append( + {"index": res.index, "relevance_score": res.relevance_score} + ) + return result_dicts + def compress_documents( self, documents: Sequence[Document], @@ -74,16 +101,10 @@ def compress_documents( Returns: A sequence of compressed documents. """ - if len(documents) == 0: # to avoid empty api call - return [] - doc_list = list(documents) - _docs = [d.page_content for d in doc_list] - results = self.client.rerank( - model=self.model, query=query, documents=_docs, top_n=self.top_n - ) - final_results = [] - for r in results: - doc = doc_list[r.index] - doc.metadata["relevance_score"] = r.relevance_score - final_results.append(doc) - return final_results + compressed = [] + for res in self.rerank(documents, query): + doc = documents[res["index"]] + doc_copy = Document(doc.page_content, metadata=deepcopy(doc.metadata)) + doc_copy.metadata["relevance_score"] = res["relevance_score"] + compressed.append(doc_copy) + return compressed diff --git a/libs/langchain/langchain/retrievers/parent_document_retriever.py b/libs/langchain/langchain/retrievers/parent_document_retriever.py index 86e4cef18685987..5095c13540ee3e6 100644 --- a/libs/langchain/langchain/retrievers/parent_document_retriever.py +++ b/libs/langchain/langchain/retrievers/parent_document_retriever.py @@ -1,5 +1,5 @@ import uuid -from typing import List, Optional +from typing import List, Optional, Sequence from langchain_core.documents import Document @@ -31,17 +31,16 @@ class ParentDocumentRetriever(MultiVectorRetriever): .. code-block:: python - # Imports - from langchain_community.vectorstores import Chroma from langchain_community.embeddings import OpenAIEmbeddings + from langchain_community.vectorstores import Chroma from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.storage import InMemoryStore # This text splitter is used to create the parent documents - parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000) + parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000, add_start_index=True) # This text splitter is used to create the child documents # It should create documents smaller than the parent - child_splitter = RecursiveCharacterTextSplitter(chunk_size=400) + child_splitter = RecursiveCharacterTextSplitter(chunk_size=400, add_start_index=True) # The vectorstore to use to index the child chunks vectorstore = Chroma(embedding_function=OpenAIEmbeddings()) # The storage layer for the parent documents @@ -54,7 +53,7 @@ class ParentDocumentRetriever(MultiVectorRetriever): child_splitter=child_splitter, parent_splitter=parent_splitter, ) - """ + """ # noqa: E501 child_splitter: TextSplitter """The text splitter to use to create child documents.""" @@ -65,6 +64,11 @@ class ParentDocumentRetriever(MultiVectorRetriever): """The text splitter to use to create parent documents. If none, then the parent documents will be the raw documents passed in.""" + child_metadata_fields: Optional[Sequence[str]] = None + """Metadata fields to leave in child documents. If None, leave all parent document + metadata. + """ + def add_documents( self, documents: List[Document], @@ -76,7 +80,7 @@ def add_documents( Args: documents: List of documents to add ids: Optional list of ids for documents. If provided should be the same - length as the list of documents. Can provided if parent documents + length as the list of documents. Can be provided if parent documents are already in the document store and you don't want to re-add to the docstore. If not provided, random UUIDs will be used as ids. @@ -106,6 +110,11 @@ def add_documents( for i, doc in enumerate(documents): _id = doc_ids[i] sub_docs = self.child_splitter.split_documents([doc]) + if self.child_metadata_fields is not None: + for _doc in sub_docs: + _doc.metadata = { + k: _doc.metadata[k] for k in self.child_metadata_fields + } for _doc in sub_docs: _doc.metadata[self.id_key] = _id docs.extend(sub_docs) diff --git a/libs/partners/openai/langchain_openai/chat_models/base.py b/libs/partners/openai/langchain_openai/chat_models/base.py index ed33b919bdd7381..fc1430e24250e3d 100644 --- a/libs/partners/openai/langchain_openai/chat_models/base.py +++ b/libs/partners/openai/langchain_openai/chat_models/base.py @@ -649,7 +649,7 @@ def bind_functions( Must be the name of the single provided function or "auto" to automatically determine which function to call (if any). - kwargs: Any additional parameters to pass to the + **kwargs: Any additional parameters to pass to the :class:`~langchain.runnable.Runnable` constructor. """ @@ -701,22 +701,21 @@ def bind_tools( "auto" to automatically determine which function to call (if any), or a dict of the form: {"type": "function", "function": {"name": <>}}. - kwargs: Any additional parameters to pass to the + **kwargs: Any additional parameters to pass to the :class:`~langchain.runnable.Runnable` constructor. """ formatted_tools = [convert_to_openai_tool(tool) for tool in tools] if tool_choice is not None: - if isinstance(tool_choice, str) and tool_choice not in ("auto", "none"): + if isinstance(tool_choice, str) and (tool_choice not in ("auto", "none")): tool_choice = {"type": "function", "function": {"name": tool_choice}} - if isinstance(tool_choice, dict) and len(formatted_tools) != 1: + if isinstance(tool_choice, dict) and (len(formatted_tools) != 1): raise ValueError( "When specifying `tool_choice`, you must provide exactly one " f"tool. Received {len(formatted_tools)} tools." ) - if ( - isinstance(tool_choice, dict) - and formatted_tools[0]["function"]["name"] + if isinstance(tool_choice, dict) and ( + formatted_tools[0]["function"]["name"] != tool_choice["function"]["name"] ): raise ValueError( @@ -724,7 +723,4 @@ def bind_tools( f"provided tool was {formatted_tools[0]['function']['name']}." ) kwargs["tool_choice"] = tool_choice - return super().bind( - tools=formatted_tools, - **kwargs, - ) + return super().bind(tools=formatted_tools, **kwargs) From 7fa4dc593fd75051596f950e5edd7817f2ad8518 Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:13:33 -0800 Subject: [PATCH 23/35] core[patch]: Release 0.1.22 (#17274) --- libs/core/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/core/pyproject.toml b/libs/core/pyproject.toml index 12b241f5f9e9fd4..6a639b763b8a229 100644 --- a/libs/core/pyproject.toml +++ b/libs/core/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-core" -version = "0.1.21" +version = "0.1.22" description = "Building applications with LLMs through composability" authors = [] license = "MIT" From 8bad4157add8de17b0303a42fd5a6fd667f414bf Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:25:06 -0800 Subject: [PATCH 24/35] langchain[patch]: Release 0.1.6 (#17133) --- libs/langchain/poetry.lock | 21 +++++++++++---------- libs/langchain/pyproject.toml | 6 +++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/libs/langchain/poetry.lock b/libs/langchain/poetry.lock index 51244301a2f17ec..64a0beba1dc5971 100644 --- a/libs/langchain/poetry.lock +++ b/libs/langchain/poetry.lock @@ -3049,7 +3049,6 @@ files = [ {file = "jq-1.6.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:227b178b22a7f91ae88525810441791b1ca1fc71c86f03190911793be15cec3d"}, {file = "jq-1.6.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:780eb6383fbae12afa819ef676fc93e1548ae4b076c004a393af26a04b460742"}, {file = "jq-1.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:08ded6467f4ef89fec35b2bf310f210f8cd13fbd9d80e521500889edf8d22441"}, - {file = "jq-1.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49e44ed677713f4115bd5bf2dbae23baa4cd503be350e12a1c1f506b0687848f"}, {file = "jq-1.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:984f33862af285ad3e41e23179ac4795f1701822473e1a26bf87ff023e5a89ea"}, {file = "jq-1.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f42264fafc6166efb5611b5d4cb01058887d050a6c19334f6a3f8a13bb369df5"}, {file = "jq-1.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a67154f150aaf76cc1294032ed588436eb002097dd4fd1e283824bf753a05080"}, @@ -3447,7 +3446,7 @@ files = [ [[package]] name = "langchain-community" -version = "0.0.17" +version = "0.0.19" description = "Community contributed LangChain integrations." optional = false python-versions = ">=3.8.1,<4.0" @@ -3457,7 +3456,7 @@ develop = true [package.dependencies] aiohttp = "^3.8.3" dataclasses-json = ">= 0.5.7, < 0.7" -langchain-core = ">=0.1.16,<0.2" +langchain-core = ">=0.1.21,<0.2" langsmith = ">=0.0.83,<0.1" numpy = "^1" PyYAML = ">=5.3" @@ -3467,7 +3466,7 @@ tenacity = "^8.1.0" [package.extras] cli = ["typer (>=0.9.0,<0.10.0)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)", "zhipuai (>=1.0.7,<2.0.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)", "zhipuai (>=1.0.7,<2.0.0)"] [package.source] type = "directory" @@ -3475,7 +3474,7 @@ url = "../community" [[package]] name = "langchain-core" -version = "0.1.18" +version = "0.1.22" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" @@ -3485,7 +3484,7 @@ develop = true [package.dependencies] anyio = ">=3,<5" jsonpatch = "^1.33" -langsmith = ">=0.0.83,<0.1" +langsmith = "^0.0.87" packaging = "^23.2" pydantic = ">=1,<3" PyYAML = ">=5.3" @@ -3518,13 +3517,13 @@ tiktoken = ">=0.5.2,<0.6.0" [[package]] name = "langsmith" -version = "0.0.83" +version = "0.0.87" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.0.83-py3-none-any.whl", hash = "sha256:a5bb7ac58c19a415a9d5f51db56dd32ee2cd7343a00825bbc2018312eb3d122a"}, - {file = "langsmith-0.0.83.tar.gz", hash = "sha256:94427846b334ad9bdbec3266fee12903fe9f5448f628667689d0412012aaf392"}, + {file = "langsmith-0.0.87-py3-none-any.whl", hash = "sha256:8903d3811b9fc89eb18f5961c8e6935fbd2d0f119884fbf30dc70b8f8f4121fc"}, + {file = "langsmith-0.0.87.tar.gz", hash = "sha256:36c4cc47e5b54be57d038036a30fb19ce6e4c73048cd7a464b8f25b459694d34"}, ] [package.dependencies] @@ -5807,6 +5806,7 @@ files = [ {file = "pymongo-4.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6422b6763b016f2ef2beedded0e546d6aa6ba87910f9244d86e0ac7690f75c96"}, {file = "pymongo-4.5.0-cp312-cp312-win32.whl", hash = "sha256:77cfff95c1fafd09e940b3fdcb7b65f11442662fad611d0e69b4dd5d17a81c60"}, {file = "pymongo-4.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:e57d859b972c75ee44ea2ef4758f12821243e99de814030f69a3decb2aa86807"}, + {file = "pymongo-4.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8443f3a8ab2d929efa761c6ebce39a6c1dca1c9ac186ebf11b62c8fe1aef53f4"}, {file = "pymongo-4.5.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2b0176f9233a5927084c79ff80b51bd70bfd57e4f3d564f50f80238e797f0c8a"}, {file = "pymongo-4.5.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:89b3f2da57a27913d15d2a07d58482f33d0a5b28abd20b8e643ab4d625e36257"}, {file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:5caee7bd08c3d36ec54617832b44985bd70c4cbd77c5b313de6f7fce0bb34f93"}, @@ -6336,6 +6336,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -9149,4 +9150,4 @@ text-helpers = ["chardet"] [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "8756afa5050a3ce1c3a504ad819fb85240fa56575a32f1590cbdfbbc9102b576" +content-hash = "5ac4a6a281e7816edff5ab0f851dd0a3a5fe50fc33513b789187aaa31a0ace1b" diff --git a/libs/langchain/pyproject.toml b/libs/langchain/pyproject.toml index 539a29d4d82fbc8..55703e5db3a6f48 100644 --- a/libs/langchain/pyproject.toml +++ b/libs/langchain/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain" -version = "0.1.5" +version = "0.1.6" description = "Building applications with LLMs through composability" authors = [] license = "MIT" @@ -12,8 +12,8 @@ langchain-server = "langchain.server:main" [tool.poetry.dependencies] python = ">=3.8.1,<4.0" -langchain-core = ">=0.1.16,<0.2" -langchain-community = ">=0.0.17,<0.1" +langchain-core = ">=0.1.22,<0.2" +langchain-community = ">=0.0.18,<0.1" langsmith = ">=0.0.83,<0.1" pydantic = ">=1,<3" SQLAlchemy = ">=1.4,<3" From 72c7af0bc054daa0b1732605e15fd84578344f84 Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:39:55 -0800 Subject: [PATCH 25/35] langchain[patch]: undo redis cache import (#17275) --- libs/langchain/langchain/cache.py | 2 -- .../langchain/tests/integration_tests/cache/test_redis_cache.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libs/langchain/langchain/cache.py b/libs/langchain/langchain/cache.py index 3c249e964c5a8d1..fae1d1cf032618f 100644 --- a/libs/langchain/langchain/cache.py +++ b/libs/langchain/langchain/cache.py @@ -1,7 +1,6 @@ from langchain_community.cache import ( AstraDBCache, AstraDBSemanticCache, - AsyncRedisCache, CassandraCache, CassandraSemanticCache, FullLLMCache, @@ -23,7 +22,6 @@ "SQLAlchemyCache", "SQLiteCache", "UpstashRedisCache", - "AsyncRedisCache", "RedisCache", "RedisSemanticCache", "GPTCache", diff --git a/libs/langchain/tests/integration_tests/cache/test_redis_cache.py b/libs/langchain/tests/integration_tests/cache/test_redis_cache.py index 846c709b9716892..644d0386755d615 100644 --- a/libs/langchain/tests/integration_tests/cache/test_redis_cache.py +++ b/libs/langchain/tests/integration_tests/cache/test_redis_cache.py @@ -4,12 +4,12 @@ from typing import AsyncGenerator, Generator, List, Optional, cast import pytest +from langchain_community.cache import AsyncRedisCache, RedisCache, RedisSemanticCache from langchain_core.embeddings import Embeddings from langchain_core.load.dump import dumps from langchain_core.messages import AIMessage, BaseMessage, HumanMessage from langchain_core.outputs import ChatGeneration, Generation, LLMResult -from langchain.cache import AsyncRedisCache, RedisCache, RedisSemanticCache from langchain.globals import get_llm_cache, set_llm_cache from tests.integration_tests.cache.fake_embeddings import ( ConsistentFakeEmbeddings, From 65e97c9b535b2e8157c62d8d0b7ba989b699c6b8 Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Thu, 8 Feb 2024 17:05:43 -0800 Subject: [PATCH 26/35] infra: mv SQLDatabase tests to community (#17276) --- .../tests/unit_tests/test_sql_database.py | 3 ++- .../tests/unit_tests/test_sql_database_schema.py | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename libs/{langchain => community}/tests/unit_tests/test_sql_database.py (99%) rename libs/{langchain => community}/tests/unit_tests/test_sql_database_schema.py (100%) diff --git a/libs/langchain/tests/unit_tests/test_sql_database.py b/libs/community/tests/unit_tests/test_sql_database.py similarity index 99% rename from libs/langchain/tests/unit_tests/test_sql_database.py rename to libs/community/tests/unit_tests/test_sql_database.py index c593faae8e821ae..42aaef7134f53b0 100644 --- a/libs/langchain/tests/unit_tests/test_sql_database.py +++ b/libs/community/tests/unit_tests/test_sql_database.py @@ -2,7 +2,6 @@ """Test SQL database wrapper.""" import pytest import sqlalchemy as sa -from langchain_community.utilities.sql_database import SQLDatabase, truncate_word from sqlalchemy import ( Column, Integer, @@ -16,6 +15,8 @@ select, ) +from langchain_community.utilities.sql_database import SQLDatabase, truncate_word + metadata_obj = MetaData() user = Table( diff --git a/libs/langchain/tests/unit_tests/test_sql_database_schema.py b/libs/community/tests/unit_tests/test_sql_database_schema.py similarity index 100% rename from libs/langchain/tests/unit_tests/test_sql_database_schema.py rename to libs/community/tests/unit_tests/test_sql_database_schema.py From b18c6ab9ad6f62249c4771f1daa2687a14153164 Mon Sep 17 00:00:00 2001 From: Kartheek Yakkala Date: Thu, 8 Feb 2024 19:19:47 -0600 Subject: [PATCH 27/35] docs: Added LangGraph in framework parts of readme file (#17279) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 40ac6d9a4768a6b..a9490035ac82830 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ This framework consists of several parts. - **[LangChain Templates](templates)**: A collection of easily deployable reference architectures for a wide variety of tasks. - **[LangServe](https://github.com/langchain-ai/langserve)**: A library for deploying LangChain chains as a REST API. - **[LangSmith](https://smith.langchain.com)**: A developer platform that lets you debug, test, evaluate, and monitor chains built on any LLM framework and seamlessly integrates with LangChain. +- **[LangGraph](https://python.langchain.com/docs/langgraph)**: LangGraph is a library for building stateful, multi-actor applications with LLMs, built on top of (and intended to be used with) LangChain. It extends the LangChain Expression Language with the ability to coordinate multiple chains (or actors) across multiple steps of computation in a cyclic manner. The LangChain libraries themselves are made up of several different packages. - **[`langchain-core`](libs/core)**: Base abstractions and LangChain Expression Language. From 96b5711a0ce33236893d4f93245f64b906fac81e Mon Sep 17 00:00:00 2001 From: Ruben Hakopian Date: Thu, 8 Feb 2024 17:25:28 -0800 Subject: [PATCH 28/35] google-vertexai[patch]: Fixed SafetySettings handling in streaming API in VertexAI (#17278) The streaming API doesn't separate safety_settings from the generation_config payload. As the result the following error is observed when using `stream` API. The functionality is correct with `invoke` API. The fix separates the `safety_settings` from params and sets it as argument to the `send_message` method. ``` ERROR: Unknown field for GenerationConfig: safety_settings Traceback (most recent call last): File "/Users/user/Library/Caches/pypoetry/virtualenvs/chatbot-worker-main-Ju-qIM-X-py3.12/lib/python3.12/site-packages/langchain_core/language_models/chat_models.py", line 250, in stream raise e File "/Users/user/Library/Caches/pypoetry/virtualenvs/chatbot-worker-main-Ju-qIM-X-py3.12/lib/python3.12/site-packages/langchain_core/language_models/chat_models.py", line 234, in stream for chunk in self._stream( File "/Users/user/Library/Caches/pypoetry/virtualenvs/chatbot-worker-main-Ju-qIM-X-py3.12/lib/python3.12/site-packages/langchain_google_vertexai/chat_models.py", line 501, in _stream for response in responses: File "/Users/user/Library/Caches/pypoetry/virtualenvs/chatbot-worker-main-Ju-qIM-X-py3.12/lib/python3.12/site-packages/vertexai/generative_models/_generative_models.py", line 921, in _send_message_streaming for chunk in stream: File "/Users/user/Library/Caches/pypoetry/virtualenvs/chatbot-worker-main-Ju-qIM-X-py3.12/lib/python3.12/site-packages/vertexai/generative_models/_generative_models.py", line 514, in _generate_content_streaming request = self._prepare_request( ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/user/Library/Caches/pypoetry/virtualenvs/chatbot-worker-main-Ju-qIM-X-py3.12/lib/python3.12/site-packages/vertexai/generative_models/_generative_models.py", line 256, in _prepare_request gapic_generation_config = gapic_content_types.GenerationConfig( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/user/Library/Caches/pypoetry/virtualenvs/chatbot-worker-main-Ju-qIM-X-py3.12/lib/python3.12/site-packages/proto/message.py", line 576, in __init__ raise ValueError( ValueError: Unknown field for GenerationConfig: safety_settings ``` --------- Co-authored-by: Erick Friis --- .../langchain_google_vertexai/chat_models.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/partners/google-vertexai/langchain_google_vertexai/chat_models.py b/libs/partners/google-vertexai/langchain_google_vertexai/chat_models.py index 48709faebd7c85f..096f18006fc861f 100644 --- a/libs/partners/google-vertexai/langchain_google_vertexai/chat_models.py +++ b/libs/partners/google-vertexai/langchain_google_vertexai/chat_models.py @@ -510,8 +510,13 @@ def _stream( # set param to `functions` until core tool/function calling implemented raw_tools = params.pop("functions") if "functions" in params else None tools = _format_tools_to_vertex_tool(raw_tools) if raw_tools else None + safety_settings = params.pop("safety_settings", None) responses = chat.send_message( - message, stream=True, generation_config=params, tools=tools + message, + stream=True, + generation_config=params, + safety_settings=safety_settings, + tools=tools, ) for response in responses: message = _parse_response_candidate(response.candidates[0]) From e4da7918f37d0966b04d10649baeb54721013877 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Thu, 8 Feb 2024 17:29:53 -0800 Subject: [PATCH 29/35] google-genai[patch]: fix streaming, function calling (#17268) --- .../langchain_google_genai/chat_models.py | 41 +++++++++++++++---- libs/partners/google-genai/poetry.lock | 10 ++--- .../tests/unit_tests/test_chat_models.py | 17 +++++++- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/libs/partners/google-genai/langchain_google_genai/chat_models.py b/libs/partners/google-genai/langchain_google_genai/chat_models.py index 8d56e983c870016..420dbcfd1359584 100644 --- a/libs/partners/google-genai/langchain_google_genai/chat_models.py +++ b/libs/partners/google-genai/langchain_google_genai/chat_models.py @@ -35,6 +35,7 @@ from langchain_core.language_models.chat_models import BaseChatModel from langchain_core.messages import ( AIMessage, + AIMessageChunk, BaseMessage, FunctionMessage, HumanMessage, @@ -339,11 +340,23 @@ def _parse_chat_history( parts = _convert_to_parts(message.content) elif isinstance(message, FunctionMessage): role = "user" + response: Any + if not isinstance(message.content, str): + response = message.content + else: + try: + response = json.loads(message.content) + except json.JSONDecodeError: + response = message.content # leave as str representation parts = [ glm.Part( function_response=glm.FunctionResponse( name=message.name, - response=message.content, + response=( + {"output": response} + if not isinstance(response, dict) + else response + ), ) ) ] @@ -364,12 +377,16 @@ def _parse_chat_history( return messages -def _parse_response_candidate(response_candidate: glm.Candidate) -> AIMessage: +def _parse_response_candidate( + response_candidate: glm.Candidate, stream: bool +) -> AIMessage: first_part = response_candidate.content.parts[0] if first_part.function_call: function_call = proto.Message.to_dict(first_part.function_call) function_call["arguments"] = json.dumps(function_call.pop("args", {})) - return AIMessage(content="", additional_kwargs={"function_call": function_call}) + return (AIMessageChunk if stream else AIMessage)( + content="", additional_kwargs={"function_call": function_call} + ) else: parts = response_candidate.content.parts @@ -377,11 +394,14 @@ def _parse_response_candidate(response_candidate: glm.Candidate) -> AIMessage: content: Union[str, List[Union[str, Dict]]] = parts[0].text else: content = [proto.Message.to_dict(part) for part in parts] - return AIMessage(content=content, additional_kwargs={}) + return (AIMessageChunk if stream else AIMessage)( + content=content, additional_kwargs={} + ) def _response_to_result( response: glm.GenerateContentResponse, + stream: bool = False, ) -> ChatResult: """Converts a PaLM API response into a LangChain ChatResult.""" llm_output = {"prompt_feedback": proto.Message.to_dict(response.prompt_feedback)} @@ -397,8 +417,8 @@ def _response_to_result( for safety_rating in candidate.safety_ratings ] generations.append( - ChatGeneration( - message=_parse_response_candidate(candidate), + (ChatGenerationChunk if stream else ChatGeneration)( + message=_parse_response_candidate(candidate, stream=stream), generation_info=generation_info, ) ) @@ -411,7 +431,10 @@ def _response_to_result( f"Feedback: {response.prompt_feedback}" ) generations = [ - ChatGeneration(message=AIMessage(content=""), generation_info={}) + (ChatGenerationChunk if stream else ChatGeneration)( + message=(AIMessageChunk if stream else AIMessage)(content=""), + generation_info={}, + ) ] return ChatResult(generations=generations, llm_output=llm_output) @@ -573,7 +596,7 @@ def _stream( stream=True, ) for chunk in response: - _chat_result = _response_to_result(chunk) + _chat_result = _response_to_result(chunk, stream=True) gen = cast(ChatGenerationChunk, _chat_result.generations[0]) if run_manager: run_manager.on_llm_new_token(gen.text) @@ -597,7 +620,7 @@ async def _astream( generation_method=chat.send_message_async, stream=True, ): - _chat_result = _response_to_result(chunk) + _chat_result = _response_to_result(chunk, stream=True) gen = cast(ChatGenerationChunk, _chat_result.generations[0]) if run_manager: await run_manager.on_llm_new_token(gen.text) diff --git a/libs/partners/google-genai/poetry.lock b/libs/partners/google-genai/poetry.lock index dc37a3fc067ad0e..ad06fd99ced6062 100644 --- a/libs/partners/google-genai/poetry.lock +++ b/libs/partners/google-genai/poetry.lock @@ -228,13 +228,13 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4 [[package]] name = "google-api-core" -version = "2.16.2" +version = "2.17.0" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.16.2.tar.gz", hash = "sha256:032d37b45d1d6bdaf68fb11ff621e2593263a239fa9246e2e94325f9c47876d2"}, - {file = "google_api_core-2.16.2-py3-none-any.whl", hash = "sha256:449ca0e3f14c179b4165b664256066c7861610f70b6ffe54bb01a04e9b466929"}, + {file = "google-api-core-2.17.0.tar.gz", hash = "sha256:de7ef0450faec7c75e0aea313f29ac870fdc44cfaec9d6499a9a17305980ef66"}, + {file = "google_api_core-2.17.0-py3-none-any.whl", hash = "sha256:08ed79ed8e93e329de5e3e7452746b734e6bf8438d8d64dd3319d21d3164890c"}, ] [package.dependencies] @@ -448,7 +448,7 @@ files = [ [[package]] name = "langchain-core" -version = "0.1.19" +version = "0.1.21" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" @@ -458,7 +458,7 @@ develop = true [package.dependencies] anyio = ">=3,<5" jsonpatch = "^1.33" -langsmith = ">=0.0.83,<0.1" +langsmith = "^0.0.87" packaging = "^23.2" pydantic = ">=1,<3" PyYAML = ">=5.3" diff --git a/libs/partners/google-genai/tests/unit_tests/test_chat_models.py b/libs/partners/google-genai/tests/unit_tests/test_chat_models.py index 93d5bb323136169..e13dcccafc11c64 100644 --- a/libs/partners/google-genai/tests/unit_tests/test_chat_models.py +++ b/libs/partners/google-genai/tests/unit_tests/test_chat_models.py @@ -1,5 +1,14 @@ """Test chat model integration.""" -from langchain_core.messages import AIMessage, HumanMessage, SystemMessage + +from typing import Dict, List, Union + +import pytest +from langchain_core.messages import ( + AIMessage, + FunctionMessage, + HumanMessage, + SystemMessage, +) from langchain_core.pydantic_v1 import SecretStr from pytest import CaptureFixture @@ -58,3 +67,9 @@ def test_parse_history() -> None: "parts": [{"text": system_input}, {"text": text_question1}], } assert history[1] == {"role": "model", "parts": [{"text": text_answer1}]} + + +@pytest.mark.parametrize("content", ['["a"]', '{"a":"b"}', "function output"]) +def test_parse_function_history(content: Union[str, List[Union[str, Dict]]]) -> None: + function_message = FunctionMessage(name="search_tool", content=content) + _parse_chat_history([function_message], convert_system_message_to_human=True) From 1032faba5fe918bd7d207547926eaf1345f7e455 Mon Sep 17 00:00:00 2001 From: German Martin Date: Thu, 8 Feb 2024 22:40:21 -0300 Subject: [PATCH 30/35] langchain_google_genai : Add missing _identifying_params property. (#17224) Description: Missing _identifying_params create issues when dealing with callbacks to get current run model parameters. All other model partners implementation provide this property and also provide _default_params. I'm not sure about the default values to include or if we can re-use the same as for _VertexAICommon(), this change allows you to access the model parameters correctly. Issue: Not exactly this issue but could be related https://github.com/langchain-ai/langchain/issues/14711 Twitter handle:@musicaoriginal2 --- .../google-genai/langchain_google_genai/llms.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libs/partners/google-genai/langchain_google_genai/llms.py b/libs/partners/google-genai/langchain_google_genai/llms.py index bf147410ce8d623..d6eb16d981930fc 100644 --- a/libs/partners/google-genai/langchain_google_genai/llms.py +++ b/libs/partners/google-genai/langchain_google_genai/llms.py @@ -151,6 +151,18 @@ def lc_secrets(self) -> Dict[str, str]: def _model_family(self) -> str: return GoogleModelFamily(self.model) + @property + def _identifying_params(self) -> Dict[str, Any]: + """Get the identifying parameters.""" + return { + "model": self.model, + "temperature": self.temperature, + "top_p": self.top_p, + "top_k": self.top_k, + "max_output_tokens": self.max_output_tokens, + "candidate_count": self.n, + } + class GoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseLLM): """Google GenerativeAI models. From d8913b94287483fc6603c74278f2e793ba90bb70 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Thu, 8 Feb 2024 19:09:27 -0800 Subject: [PATCH 31/35] templates: simplify tool in gemini-functions-agent (#17282) --- .../gemini_functions_agent/agent.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/templates/gemini-functions-agent/gemini_functions_agent/agent.py b/templates/gemini-functions-agent/gemini_functions_agent/agent.py index 79aba8a9445bb95..1f1c756d7c42f40 100644 --- a/templates/gemini-functions-agent/gemini_functions_agent/agent.py +++ b/templates/gemini-functions-agent/gemini_functions_agent/agent.py @@ -32,19 +32,7 @@ ] ) -llm_with_tools = llm.bind( - functions=[ - { - "name": tavily_tool.name, - "description": tavily_tool.description, - "parameters": { - "type": "object", - "properties": {"query": {"type": "string"}}, - "required": ["query"], - }, - } - ] -) +llm_with_tools = llm.bind(functions=[tavily_tool]) def _format_chat_history(chat_history: List[Tuple[str, str]]): From febf9540b995aaf1a015a9c2531ae44f603bffec Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Thu, 8 Feb 2024 19:36:49 -0800 Subject: [PATCH 32/35] google-genai[patch]: fix tool format, use protos (#17284) --- .../langchain_google_genai/_function_utils.py | 95 ++++++++----------- 1 file changed, 38 insertions(+), 57 deletions(-) diff --git a/libs/partners/google-genai/langchain_google_genai/_function_utils.py b/libs/partners/google-genai/langchain_google_genai/_function_utils.py index 665987c352d468a..d67194536d6c3a6 100644 --- a/libs/partners/google-genai/langchain_google_genai/_function_utils.py +++ b/libs/partners/google-genai/langchain_google_genai/_function_utils.py @@ -7,6 +7,7 @@ Union, ) +import google.ai.generativelanguage as glm from langchain_core.pydantic_v1 import BaseModel from langchain_core.tools import BaseTool from langchain_core.utils.json_schema import dereference_refs @@ -14,55 +15,36 @@ FunctionCallType = Union[BaseTool, Type[BaseModel], Dict] TYPE_ENUM = { - "string": 1, - "number": 2, - "integer": 3, - "boolean": 4, - "array": 5, - "object": 6, + "string": glm.Type.STRING, + "number": glm.Type.NUMBER, + "integer": glm.Type.INTEGER, + "boolean": glm.Type.BOOLEAN, + "array": glm.Type.ARRAY, + "object": glm.Type.OBJECT, } def convert_to_genai_function_declarations( function_calls: List[FunctionCallType], -) -> Dict: - function_declarations = [] - for fc in function_calls: - function_declarations.append(_convert_to_genai_function(fc)) - return { - "function_declarations": function_declarations, - } +) -> List[glm.Tool]: + return [ + glm.Tool( + function_declarations=[_convert_to_genai_function(fc)], + ) + for fc in function_calls + ] -def _convert_to_genai_function(fc: FunctionCallType) -> Dict: - """ - Produce - - { - "name": "get_weather", - "description": "Determine weather in my location", - "parameters": { - "properties": { - "location": { - "description": "The city and state e.g. San Francisco, CA", - "type_": 1 - }, - "unit": { "enum": ["c", "f"], "type_": 1 } - }, - "required": ["location"], - "type_": 6 - } - } - - """ +def _convert_to_genai_function(fc: FunctionCallType) -> glm.FunctionDeclaration: if isinstance(fc, BaseTool): return _convert_tool_to_genai_function(fc) elif isinstance(fc, type) and issubclass(fc, BaseModel): return _convert_pydantic_to_genai_function(fc) elif isinstance(fc, dict): - return { - **fc, - "parameters": { + return glm.FunctionDeclaration( + name=fc["name"], + description=fc.get("description"), + parameters={ "properties": { k: { "type_": TYPE_ENUM[v["type"]], @@ -73,20 +55,20 @@ def _convert_to_genai_function(fc: FunctionCallType) -> Dict: "required": fc["parameters"].get("required", []), "type_": TYPE_ENUM[fc["parameters"]["type"]], }, - } + ) else: raise ValueError(f"Unsupported function call type {fc}") -def _convert_tool_to_genai_function(tool: BaseTool) -> Dict: +def _convert_tool_to_genai_function(tool: BaseTool) -> glm.FunctionDeclaration: if tool.args_schema: schema = dereference_refs(tool.args_schema.schema()) schema.pop("definitions", None) - return { - "name": tool.name or schema["title"], - "description": tool.description or schema["description"], - "parameters": { + return glm.FunctionDeclaration( + name=tool.name or schema["title"], + description=tool.description or schema["description"], + parameters={ "properties": { k: { "type_": TYPE_ENUM[v["type"]], @@ -97,31 +79,30 @@ def _convert_tool_to_genai_function(tool: BaseTool) -> Dict: "required": schema["required"], "type_": TYPE_ENUM[schema["type"]], }, - } + ) else: - return { - "name": tool.name, - "description": tool.description, - "parameters": { + return glm.FunctionDeclaration( + name=tool.name, + description=tool.description, + parameters={ "properties": { - "__arg1": {"type": "string"}, + "__arg1": {"type_": TYPE_ENUM["string"]}, }, "required": ["__arg1"], "type_": TYPE_ENUM["object"], }, - } + ) def _convert_pydantic_to_genai_function( pydantic_model: Type[BaseModel], -) -> Dict: +) -> glm.FunctionDeclaration: schema = dereference_refs(pydantic_model.schema()) schema.pop("definitions", None) - - return { - "name": schema["title"], - "description": schema.get("description", ""), - "parameters": { + return glm.FunctionDeclaration( + name=schema["title"], + description=schema.get("description", ""), + parameters={ "properties": { k: { "type_": TYPE_ENUM[v["type"]], @@ -132,4 +113,4 @@ def _convert_pydantic_to_genai_function( "required": schema["required"], "type_": TYPE_ENUM[schema["type"]], }, - } + ) From 12d3159dd66162f15c2ce466ed72bdefc7a1ac95 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Thu, 8 Feb 2024 19:39:29 -0800 Subject: [PATCH 33/35] templates: simplify tool in gemini-functions-agent 2 (#17283) --- .../gemini-functions-agent/gemini_functions_agent/agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/gemini-functions-agent/gemini_functions_agent/agent.py b/templates/gemini-functions-agent/gemini_functions_agent/agent.py index 1f1c756d7c42f40..38ffc315ee9a2f2 100644 --- a/templates/gemini-functions-agent/gemini_functions_agent/agent.py +++ b/templates/gemini-functions-agent/gemini_functions_agent/agent.py @@ -32,7 +32,7 @@ ] ) -llm_with_tools = llm.bind(functions=[tavily_tool]) +llm_with_tools = llm.bind(functions=tools) def _format_chat_history(chat_history: List[Tuple[str, str]]): From e660a1685bcb6aafd3725ce5f9565c06c6345f85 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Thu, 8 Feb 2024 19:39:44 -0800 Subject: [PATCH 34/35] google-genai[patch]: release 0.0.8 (#17285) --- libs/partners/google-genai/poetry.lock | 2 +- libs/partners/google-genai/pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/partners/google-genai/poetry.lock b/libs/partners/google-genai/poetry.lock index ad06fd99ced6062..60a87e151ec4f1d 100644 --- a/libs/partners/google-genai/poetry.lock +++ b/libs/partners/google-genai/poetry.lock @@ -448,7 +448,7 @@ files = [ [[package]] name = "langchain-core" -version = "0.1.21" +version = "0.1.22" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" diff --git a/libs/partners/google-genai/pyproject.toml b/libs/partners/google-genai/pyproject.toml index 46e16db69682362..4d8568d1888e26d 100644 --- a/libs/partners/google-genai/pyproject.toml +++ b/libs/partners/google-genai/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-google-genai" -version = "0.0.7" +version = "0.0.8" description = "An integration package connecting Google's genai package and LangChain" authors = [] readme = "README.md" From 023cb59e8aaf3dfaad684b3fcf57a1c363b9abd1 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Thu, 8 Feb 2024 19:47:58 -0800 Subject: [PATCH 35/35] templates: gemini-functions-agent genai package bump (#17286) --- templates/gemini-functions-agent/poetry.lock | 30 +++++++++---------- .../gemini-functions-agent/pyproject.toml | 10 ++----- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/templates/gemini-functions-agent/poetry.lock b/templates/gemini-functions-agent/poetry.lock index 17c00ed6251b00f..99f2932cb26fcd2 100644 --- a/templates/gemini-functions-agent/poetry.lock +++ b/templates/gemini-functions-agent/poetry.lock @@ -502,13 +502,13 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4 [[package]] name = "google-api-core" -version = "2.16.2" +version = "2.17.0" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.16.2.tar.gz", hash = "sha256:032d37b45d1d6bdaf68fb11ff621e2593263a239fa9246e2e94325f9c47876d2"}, - {file = "google_api_core-2.16.2-py3-none-any.whl", hash = "sha256:449ca0e3f14c179b4165b664256066c7861610f70b6ffe54bb01a04e9b466929"}, + {file = "google-api-core-2.17.0.tar.gz", hash = "sha256:de7ef0450faec7c75e0aea313f29ac870fdc44cfaec9d6499a9a17305980ef66"}, + {file = "google_api_core-2.17.0-py3-none-any.whl", hash = "sha256:08ed79ed8e93e329de5e3e7452746b734e6bf8438d8d64dd3319d21d3164890c"}, ] [package.dependencies] @@ -849,13 +849,13 @@ files = [ [[package]] name = "langchain" -version = "0.1.5" +version = "0.1.6" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain-0.1.5-py3-none-any.whl", hash = "sha256:4614118d4a95b2e7ba3611a0b6b21707a259a21652a04fbe3c31205bcf3fcd50"}, - {file = "langchain-0.1.5.tar.gz", hash = "sha256:69603a5bb21b044ddea69d38131dbbf47475afdf79728644faa67d1ad325d652"}, + {file = "langchain-0.1.6-py3-none-any.whl", hash = "sha256:925e180fd1ae53b7085e46b3cdc9db04c24ddc6f4ac08f171eea29498d99603a"}, + {file = "langchain-0.1.6.tar.gz", hash = "sha256:a885e16c10b9ed11f312eaa6570bc48d27305362b26f6c235cafdcc794e26e71"}, ] [package.dependencies] @@ -863,8 +863,8 @@ aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} dataclasses-json = ">=0.5.7,<0.7" jsonpatch = ">=1.33,<2.0" -langchain-community = ">=0.0.17,<0.1" -langchain-core = ">=0.1.16,<0.2" +langchain-community = ">=0.0.18,<0.1" +langchain-core = ">=0.1.22,<0.2" langsmith = ">=0.0.83,<0.1" numpy = ">=1,<2" pydantic = ">=1,<3" @@ -933,13 +933,13 @@ extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15. [[package]] name = "langchain-core" -version = "0.1.21" +version = "0.1.22" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain_core-0.1.21-py3-none-any.whl", hash = "sha256:9dd1cedc5a3a6081136352e9403d1a87befbab4d36d6ee1877b2e639e85f15ed"}, - {file = "langchain_core-0.1.21.tar.gz", hash = "sha256:b5625901d38121aa449ef73446605032ddd31ac2787be1428c52e9c793ef8229"}, + {file = "langchain_core-0.1.22-py3-none-any.whl", hash = "sha256:d1263c2707ce18bb13654c88f891e53f39edec9b11ff7d0d0f23fd920927b2d6"}, + {file = "langchain_core-0.1.22.tar.gz", hash = "sha256:deac12b3e42a08bbbaa2acf83d5f8dd2d5513256d8daf0e853e9d68ff4c99d79"}, ] [package.dependencies] @@ -957,13 +957,13 @@ extended-testing = ["jinja2 (>=3,<4)"] [[package]] name = "langchain-google-genai" -version = "0.0.7" +version = "0.0.8" description = "An integration package connecting Google's genai package and LangChain" optional = false python-versions = ">=3.9,<4.0" files = [ - {file = "langchain_google_genai-0.0.7-py3-none-any.whl", hash = "sha256:6469d11a1497964fae10cc7c779412cb3383f0c82c5b7a2adb0891b0181e2e19"}, - {file = "langchain_google_genai-0.0.7.tar.gz", hash = "sha256:031946ba396571ac8e14ed9106bf1090663db2196b68675e52326539cddac890"}, + {file = "langchain_google_genai-0.0.8-py3-none-any.whl", hash = "sha256:31d6e8b321844185d16ff512238c81cef1d4e1f1021355617a761d21142f9163"}, + {file = "langchain_google_genai-0.0.8.tar.gz", hash = "sha256:649b53c23fd7e5159806f49f2742065ade5349942a78f51274b8ad35752e85bb"}, ] [package.dependencies] @@ -1999,4 +1999,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "1a14257d1bca209fddbbc39a4378a4b737120e39505cd4a194e8bb49759530e1" +content-hash = "1fb2cf4dd988fa7e9c6791ec915264f1fc8b1655d2d85fd059d5e6a49d74dce1" diff --git a/templates/gemini-functions-agent/pyproject.toml b/templates/gemini-functions-agent/pyproject.toml index 5648cd2fdc73816..e6410fe78780263 100644 --- a/templates/gemini-functions-agent/pyproject.toml +++ b/templates/gemini-functions-agent/pyproject.toml @@ -2,16 +2,14 @@ name = "gemini-functions-agent" version = "0.1.0" description = "Agent using Gemini function calling to execute functions, including search" -authors = [ - "Harrison Chase", -] +authors = ["Harrison Chase"] readme = "README.md" [tool.poetry.dependencies] python = ">=3.9,<4.0" langchain = "^0.1" tavily-python = "^0.1.9" -langchain-google-genai = ">=0.0.7,<0.1" +langchain-google-genai = ">=0.0.8,<0.1" [tool.poetry.group.dev.dependencies] langchain-cli = ">=0.0.21" @@ -27,7 +25,5 @@ integrations = ["Google", "Tavily"] tags = ["search", "agents", "function-calling"] [build-system] -requires = [ - "poetry-core", -] +requires = ["poetry-core"] build-backend = "poetry.core.masonry.api"