This commit is contained in:
Harrison Chase committed 2023-04-15 21:06:39 -07:00
commit 5f5670eb00
86 files changed
+5145 -767

No files matched your search

+4
View File
@@ -11,3 +11,7 @@ pre {
max-width: 2560px !important;
}
}
#my-component-root *, #headlessui-portal-root * {
z-index: 1000000000000;
}
+58
View File
@@ -0,0 +1,58 @@
document.addEventListener('DOMContentLoaded', () => {
// Load the external dependencies
function loadScript(src, onLoadCallback) {
const script = document.createElement('script');
script.src = src;
script.onload = onLoadCallback;
document.head.appendChild(script);
}
function createRootElement() {
const rootElement = document.createElement('div');
rootElement.id = 'my-component-root';
document.body.appendChild(rootElement);
return rootElement;
}
function initializeMendable() {
const rootElement = createRootElement();
const { MendableFloatingButton } = Mendable;
const iconSpan1 = React.createElement('span', {
}, '🦜');
const iconSpan2 = React.createElement('span', {
}, '🔗');
const icon = React.createElement('p', {
style: { color: '#ffffff', fontSize: '22px',width: '48px', height: '48px', margin: '0px', padding: '0px', display: 'flex', alignItems: 'center', justifyContent: 'center', textAlign: 'center' },
}, [iconSpan1, iconSpan2]);
const mendableFloatingButton = React.createElement(
MendableFloatingButton,
{
style: { darkMode: false, accentColor: '#010810' },
floatingButtonStyle: { color: '#ffffff', backgroundColor: '#010810' },
anon_key: '82842b36-3ea6-49b2-9fb8-52cfc4bde6bf', // Mendable Search Public ANON key, ok to be public
messageSettings: {
openSourcesInNewTab: false,
},
icon: icon,
}
);
ReactDOM.render(mendableFloatingButton, rootElement);
}
loadScript('https://unpkg.com/react@17/umd/react.production.min.js', () => {
loadScript('https://unpkg.com/react-dom@17/umd/react-dom.production.min.js', () => {
loadScript('https://unpkg.com/@mendable/search@0.0.83/dist/umd/mendable.min.js', initializeMendable);
});
});
});
+5
View File
@@ -103,5 +103,10 @@ html_static_path = ["_static"]
html_css_files = [
"css/custom.css",
]
html_js_files = [
"js/mendablesearch.js",
]
nb_execution_mode = "off"
myst_enable_extensions = ["colon_fence"]
+5
View File
@@ -33,12 +33,17 @@ It implements a Question Answering app and contains instructions for deploying t
A minimal example on how to run LangChain on Vercel using Flask.
## [Digitalocean App Platform](https://github.com/homanp/digitalocean-langchain)
A minimal example on how to deploy LangChain to DigitalOcean App Platform.
## [SteamShip](https://github.com/steamship-core/steamship-langchain/)
This repository contains LangChain adapters for Steamship, enabling LangChain developers to rapidly deploy their apps on Steamship.
This includes: production ready endpoints, horizontal scaling across dependencies, persistant storage of app state, multi-tenancy support, etc.
## [Langchain-serve](https://github.com/jina-ai/langchain-serve)
This repository allows users to serve local chains and agents as RESTful, gRPC, or Websocket APIs thanks to [Jina](https://docs.jina.ai/). Deploy your chains & agents with ease and enjoy independent scaling, serverless and autoscaling APIs, as well as a Streamlit playground on Jina AI Cloud.
## [BentoML](https://github.com/ssheng/BentoChain)
+26 -26
View File
@@ -1,7 +1,6 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -9,7 +8,6 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -17,7 +15,6 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -31,7 +28,6 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -39,7 +35,6 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -52,14 +47,13 @@
"metadata": {},
"outputs": [],
"source": [
"!pip install comet_ml\n",
"!pip install langchain\n",
"!pip install openai\n",
"!pip install google-search-results"
"%pip install comet_ml langchain openai google-search-results spacy textstat pandas\n",
"\n",
"import sys\n",
"!{sys.executable} -m spacy download en_core_web_sm"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -67,7 +61,6 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -86,7 +79,6 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -94,7 +86,6 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -109,12 +100,12 @@
"source": [
"import os\n",
"\n",
"%env OPENAI_API_KEY=\"...\"\n",
"%env SERPAPI_API_KEY=\"...\""
"os.environ[\"OPENAI_API_KEY\"] = \"...\"\n",
"#os.environ[\"OPENAI_ORGANIZATION\"] = \"...\"\n",
"os.environ[\"SERPAPI_API_KEY\"] = \"...\""
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -149,7 +140,6 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -185,12 +175,11 @@
"synopsis_chain = LLMChain(llm=llm, prompt=prompt_template, callback_manager=manager)\n",
"\n",
"test_prompts = [{\"title\": \"Documentary about Bigfoot in Paris\"}]\n",
"synopsis_chain.apply(test_prompts)\n",
"print(synopsis_chain.apply(test_prompts))\n",
"comet_callback.flush_tracker(synopsis_chain, finish=True)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -232,7 +221,6 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -240,7 +228,6 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -256,7 +243,7 @@
"metadata": {},
"outputs": [],
"source": [
"!pip install rouge-score"
"%pip install rouge-score"
]
},
{
@@ -336,16 +323,29 @@
" \"\"\"\n",
" }\n",
"]\n",
"synopsis_chain.apply(test_prompts)\n",
"print(synopsis_chain.apply(test_prompts))\n",
"comet_callback.flush_tracker(synopsis_chain, finish=True)"
]
}
],
"metadata": {
"language_info": {
"name": "python"
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"orig_nbformat": 4
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.15"
}
},
"nbformat": 4,
"nbformat_minor": 2
+2 -2
View File
@@ -36,7 +36,7 @@ from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
callback_manager = CallbackManager([StreamingStdOutCallbackHandler()])
model = GPT4All(model="./models/gpt4all-model.bin", n_ctx=512, n_threads=8, callback_handler=callback_handler, verbose=True)
# Generate text. Tokens are streamed throught the callback manager.
# Generate text. Tokens are streamed through the callback manager.
model("Once upon a time, ")
```
@@ -44,4 +44,4 @@ model("Once upon a time, ")
You can find links to model file downloads in the [pyllamacpp](https://github.com/nomic-ai/pyllamacpp) repository.
For a more detailed walkthrough of this, see [this notebook](../modules/models/llms/integrations/gpt4all.ipynb)
For a more detailed walkthrough of this, see [this notebook](../modules/models/llms/integrations/gpt4all.ipynb)
+2 -2
View File
@@ -1,5 +1,5 @@
LangChain Gallery
=============
=================
Lots of people have built some pretty awesome stuff with LangChain.
This is a collection of our favorites.
@@ -223,7 +223,7 @@ Open Source
Answer questions about the documentation of any project
Misc. Colab Notebooks
~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~
.. panels::
:body: text-center
+7 -5
View File
@@ -9,9 +9,9 @@
}
},
"source": [
"# SQLite example\n",
"# SQL Chain example\n",
"\n",
"This example showcases hooking up an LLM to answer questions over a database."
"This example demonstrates the use of the `SQLDatabaseChain` for answering questions over a database."
]
},
{
@@ -23,8 +23,10 @@
}
},
"source": [
"This uses the example Chinook database.\n",
"To set it up follow the instructions on https://database.guide/2-sample-databases-sqlite/, placing the `.db` file in a notebooks folder at the root of this repository."
"Under the hood, LangChain uses SQLAlchemy to connect to SQL databases. The `SQLDatabaseChain` can therefore be used with any SQL dialect supported by SQLAlchemy, such as MS SQL, MySQL, MariaDB, PostgreSQL, Oracle SQL, and SQLite. Please refer to the SQLAlchemy documentation for more information about requirements for connecting to your database. For example, a connection to MySQL requires an appropriate connector such as PyMySQL. A URI for a MySQL connection might look like: `mysql+pymysql://user:pass@some_mysql_db_address/db_name`\n",
"\n",
"This demonstration uses SQLite and the example Chinook database.\n",
"To set it up, follow the instructions on https://database.guide/2-sample-databases-sqlite/, placing the `.db` file in a notebooks folder at the root of this repository."
]
},
{
@@ -679,7 +681,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
"version": "3.10.10"
}
},
"nbformat": 4,
@@ -106,7 +106,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# Specify a column to be used identify the document source\n",
"## Specify a column to be used identify the document source\n",
"\n",
"Use the `source_column` argument to specify a column to be set as the source for the document created from each row. Otherwise `file_path` will be used as the source for all documents created from the csv file.\n",
"\n",
Submodule docs/modules/indexes/document_loaders/examples/example_data/test_repo1 added at 7e525a3b91.
@@ -0,0 +1,192 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Git\n",
"\n",
"This notebook shows how to load text files from Git repository."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Load existing repository from disk"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"from git import Repo\n",
"\n",
"repo = Repo.clone_from(\n",
" \"https://github.com/hwchase17/langchain\", to_path=\"./example_data/test_repo1\"\n",
")\n",
"branch = repo.head.reference"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain.document_loaders import GitLoader"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"loader = GitLoader(repo_path=\"./example_data/test_repo1/\", branch=branch)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"data = loader.load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"len(data)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"page_content='.venv\\n.github\\n.git\\n.mypy_cache\\n.pytest_cache\\nDockerfile' metadata={'file_path': '.dockerignore', 'file_name': '.dockerignore', 'file_type': ''}\n"
]
}
],
"source": [
"print(data[0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Clone repository from url"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"from langchain.document_loaders import GitLoader"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"loader = GitLoader(\n",
" clone_url=\"https://github.com/hwchase17/langchain\",\n",
" repo_path=\"./example_data/test_repo2/\",\n",
" branch=\"master\",\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"data = loader.load()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1074"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(data)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Filtering files to load"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"from langchain.document_loaders import GitLoader\n",
"\n",
"# eg. loading only python files\n",
"loader = GitLoader(repo_path=\"./example_data/test_repo1/\", file_filter=lambda file_path: file_path.endswith(\".py\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
@@ -0,0 +1,81 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"id": "1dc7df1d",
"metadata": {},
"source": [
"# Slack (Local Exported Zipfile)\n",
"\n",
"This notebook covers how to load documents from a Zipfile generated from a Slack export.\n",
"\n",
"In order to get this Slack export, follow these instructions:\n",
"\n",
"## 🧑 Instructions for ingesting your own dataset\n",
"\n",
"Export your Slack data. You can do this by going to your Workspace Management page and clicking the Import/Export option ({your_slack_domain}.slack.com/services/export). Then, choose the right date range and click `Start export`. Slack will send you an email and a DM when the export is ready.\n",
"\n",
"The download will produce a `.zip` file in your Downloads folder (or wherever your downloads can be found, depending on your OS configuration).\n",
"\n",
"Copy the path to the `.zip` file, and assign it as `LOCAL_ZIPFILE` below."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "007c5cbf",
"metadata": {},
"outputs": [],
"source": [
"from langchain.document_loaders import SlackDirectoryLoader "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a1caec59",
"metadata": {},
"outputs": [],
"source": [
"# Optionally set your Slack URL. This will give you proper URLs in the docs sources.\n",
"SLACK_WORKSPACE_URL = \"https://xxx.slack.com\"\n",
"LOCAL_ZIPFILE = \"\" # Paste the local paty to your Slack zip file here.\n",
"\n",
"loader = SlackDirectoryLoader(LOCAL_ZIPFILE, SLACK_WORKSPACE_URL)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b1c30ff7",
"metadata": {},
"outputs": [],
"source": [
"docs = loader.load()\n",
"docs"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -112,6 +112,79 @@
"source": [
"data = loader.load()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "a2c1c79f",
"metadata": {},
"source": [
"# Playwright URL Loader\n",
"\n",
"This covers how to load HTML documents from a list of URLs using the `PlaywrightURLLoader`.\n",
"\n",
"As in the Selenium case, Playwright allows us to load pages that need JavaScript to render.\n",
"\n",
"## Setup\n",
"\n",
"To use the `PlaywrightURLLoader`, you will need to install `playwright` and `unstructured`. Additionally, you will need to install the Playwright Chromium browser:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "53158417",
"metadata": {},
"outputs": [],
"source": [
"# Install playwright\n",
"!pip install \"playwright\"\n",
"!pip install \"unstructured\"\n",
"!playwright install"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0ab4e115",
"metadata": {},
"outputs": [],
"source": [
"from langchain.document_loaders import PlaywrightURLLoader"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ce5a9a0a",
"metadata": {},
"outputs": [],
"source": [
"urls = [\n",
" \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\",\n",
" \"https://goo.gl/maps/NDSHwePEyaHMFGwh8\"\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2dc3e0bc",
"metadata": {},
"outputs": [],
"source": [
"loader = PlaywrightURLLoader(urls=urls, remove_selectors=[\"header\", \"footer\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10b79f80",
"metadata": {},
"outputs": [],
"source": [
"data = loader.load()"
]
}
],
"metadata": {
@@ -130,7 +203,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.10.6"
}
},
"nbformat": 4,
@@ -89,7 +89,7 @@
"id": "150988e6",
"metadata": {},
"source": [
"# Loading multiple webpages\n",
"## Loading multiple webpages\n",
"\n",
"You can also load multiple webpages at once by passing in a list of urls to the loader. This will return a list of documents in the same order as the urls passed in."
]
@@ -123,7 +123,7 @@
"id": "641be294",
"metadata": {},
"source": [
"## Load multiple urls concurrently\n",
"### Load multiple urls concurrently\n",
"\n",
"You can speed up the scraping process by scraping and parsing multiple urls concurrently.\n",
"\n",
+1 -1
View File
@@ -99,7 +99,7 @@
"outputs": [],
"source": [
"from langchain.document_loaders import TextLoader\n",
"loader = TextLoader('../state_of_the_union.txt')"
"loader = TextLoader('../state_of_the_union.txt', encoding='utf8')"
]
},
{
@@ -0,0 +1,128 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "ab66dd43",
"metadata": {},
"source": [
"# SVM Retriever\n",
"\n",
"This notebook goes over how to use a retriever that under the hood uses an SVM using scikit-learn.\n",
"\n",
"Largely based on https://github.com/karpathy/randomfun/blob/master/knn_vs_svm.ipynb"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "393ac030",
"metadata": {},
"outputs": [],
"source": [
"from langchain.retrievers import SVMRetriever\n",
"from langchain.embeddings import OpenAIEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "a801b57c",
"metadata": {},
"outputs": [],
"source": [
"# !pip install scikit-learn"
]
},
{
"cell_type": "markdown",
"id": "aaf80e7f",
"metadata": {},
"source": [
"## Create New Retriever with Texts"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "98b1c017",
"metadata": {},
"outputs": [],
"source": [
"retriever = SVMRetriever.from_texts([\"foo\", \"bar\", \"world\", \"hello\", \"foo bar\"], OpenAIEmbeddings())"
]
},
{
"cell_type": "markdown",
"id": "08437fa2",
"metadata": {},
"source": [
"## Use Retriever\n",
"\n",
"We can now use the retriever!"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "c0455218",
"metadata": {},
"outputs": [],
"source": [
"result = retriever.get_relevant_documents(\"foo\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "7dfa5c29",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[Document(page_content='foo', metadata={}),\n",
" Document(page_content='foo bar', metadata={}),\n",
" Document(page_content='hello', metadata={}),\n",
" Document(page_content='world', metadata={})]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"result"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "74bd9256",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -69,7 +69,7 @@
{
"data": {
"text/plain": [
"['73f8f585-9536-4240-aef7-cea205b336bd']"
"['f6303531-d3a5-44af-b7c8-e3cf76916ce5']"
]
},
"execution_count": 3,
@@ -79,7 +79,7 @@
],
"source": [
"retriever.add_documents([Document(page_content=\"hello world\")])\n",
"time.sleep(1)\n",
"time.sleep(20)\n",
"retriever.add_documents([Document(page_content=\"hello foo\")])"
]
},
@@ -90,19 +90,24 @@
"metadata": {},
"outputs": [
{
"ename": "ValueError",
"evalue": "normalize_score_fn must be provided to FAISS constructor to normalize scores",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[4], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mretriever\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_relevant_documents\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mhello world\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/workplace/langchain/langchain/retrievers/time_weighted_retriever.py:94\u001b[0m, in \u001b[0;36mTimeWeightedVectorStoreRetriever.get_relevant_documents\u001b[0;34m(self, query)\u001b[0m\n\u001b[1;32m 89\u001b[0m docs_and_scores \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 90\u001b[0m doc\u001b[38;5;241m.\u001b[39mmetadata[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbuffer_idx\u001b[39m\u001b[38;5;124m\"\u001b[39m]: (doc, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdefault_salience)\n\u001b[1;32m 91\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m doc \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmemory_stream[\u001b[38;5;241m-\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mk :]\n\u001b[1;32m 92\u001b[0m }\n\u001b[1;32m 93\u001b[0m \u001b[38;5;66;03m# If a doc is considered salient, update the salience score\u001b[39;00m\n\u001b[0;32m---> 94\u001b[0m docs_and_scores\u001b[38;5;241m.\u001b[39mupdate(\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_salient_docs\u001b[49m\u001b[43m(\u001b[49m\u001b[43mquery\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[1;32m 95\u001b[0m rescored_docs \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m 96\u001b[0m (doc, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_get_combined_score(doc, salience, current_time))\n\u001b[1;32m 97\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m doc, salience \u001b[38;5;129;01min\u001b[39;00m docs_and_scores\u001b[38;5;241m.\u001b[39mvalues()\n\u001b[1;32m 98\u001b[0m ]\n\u001b[1;32m 99\u001b[0m rescored_docs\u001b[38;5;241m.\u001b[39msort(key\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mlambda\u001b[39;00m x: x[\u001b[38;5;241m1\u001b[39m], reverse\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n",
"File \u001b[0;32m~/workplace/langchain/langchain/retrievers/time_weighted_retriever.py:75\u001b[0m, in \u001b[0;36mTimeWeightedVectorStoreRetriever.get_salient_docs\u001b[0;34m(self, query)\u001b[0m\n\u001b[1;32m 72\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Return documents that are salient to the query.\"\"\"\u001b[39;00m\n\u001b[1;32m 73\u001b[0m docs_and_scores: List[Tuple[Document, \u001b[38;5;28mfloat\u001b[39m]]\n\u001b[1;32m 74\u001b[0m docs_and_scores \u001b[38;5;241m=\u001b[39m (\n\u001b[0;32m---> 75\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mvectorstore\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msimilarity_search_with_normalized_similarities\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 76\u001b[0m \u001b[43m \u001b[49m\u001b[43mquery\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msearch_kwargs\u001b[49m\n\u001b[1;32m 77\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 78\u001b[0m )\n\u001b[1;32m 79\u001b[0m results \u001b[38;5;241m=\u001b[39m {}\n\u001b[1;32m 80\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m fetched_doc, cosine_distance \u001b[38;5;129;01min\u001b[39;00m docs_and_scores:\n",
"File \u001b[0;32m~/workplace/langchain/langchain/vectorstores/base.py:94\u001b[0m, in \u001b[0;36mVectorStore.similarity_search_with_normalized_similarities\u001b[0;34m(self, query, k, **kwargs)\u001b[0m\n\u001b[1;32m 84\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21msimilarity_search_with_normalized_similarities\u001b[39m(\n\u001b[1;32m 85\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 86\u001b[0m query: \u001b[38;5;28mstr\u001b[39m,\n\u001b[1;32m 87\u001b[0m k: \u001b[38;5;28mint\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m4\u001b[39m,\n\u001b[1;32m 88\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m 89\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m List[Tuple[Document, \u001b[38;5;28mfloat\u001b[39m]]:\n\u001b[1;32m 90\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return docs and similarity scores, normalized on a scale from 0 to 1.\u001b[39;00m\n\u001b[1;32m 91\u001b[0m \n\u001b[1;32m 92\u001b[0m \u001b[38;5;124;03m 0 is dissimilar, 1 is most similar.\u001b[39;00m\n\u001b[1;32m 93\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m---> 94\u001b[0m docs_and_similarities \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_similarity_search_with_normalized_similarities\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 95\u001b[0m \u001b[43m \u001b[49m\u001b[43mquery\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mk\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mk\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[1;32m 96\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 97\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28many\u001b[39m(\n\u001b[1;32m 98\u001b[0m similarity \u001b[38;5;241m<\u001b[39m \u001b[38;5;241m0.0\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m similarity \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1.0\u001b[39m\n\u001b[1;32m 99\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m _, similarity \u001b[38;5;129;01min\u001b[39;00m docs_and_similarities\n\u001b[1;32m 100\u001b[0m ):\n\u001b[1;32m 101\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 102\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNormalized similarity scores must be between\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 103\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m 0 and 1, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdocs_and_similarities\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 104\u001b[0m )\n",
"File \u001b[0;32m~/workplace/langchain/langchain/vectorstores/faiss.py:435\u001b[0m, in \u001b[0;36mFAISS._similarity_search_with_normalized_similarities\u001b[0;34m(self, query, k, **kwargs)\u001b[0m\n\u001b[1;32m 433\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Return docs and their similarity scores on a scale from 0 to 1.\"\"\"\u001b[39;00m\n\u001b[1;32m 434\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mnormalize_score_fn \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 435\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 436\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnormalize_score_fn must be provided to\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 437\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m FAISS constructor to normalize scores\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 438\u001b[0m )\n\u001b[1;32m 439\u001b[0m docs_and_scores \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msimilarity_search_with_score(query, k\u001b[38;5;241m=\u001b[39mk)\n\u001b[1;32m 440\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m [(doc, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mnormalize_score_fn(score)) \u001b[38;5;28;01mfor\u001b[39;00m doc, score \u001b[38;5;129;01min\u001b[39;00m docs_and_scores]\n",
"\u001b[0;31mValueError\u001b[0m: normalize_score_fn must be provided to FAISS constructor to normalize scores"
"name": "stdout",
"output_type": "stream",
"text": [
"0.9999994359334345\n",
"1.8408203353689756\n",
"0.9999428041917008\n",
"1.9999408025741263\n"
]
},
{
"data": {
"text/plain": [
"[Document(page_content='hello world', metadata={'last_accessed_at': datetime.datetime(2023, 4, 15, 21, 4, 41, 457055), 'created_at': datetime.datetime(2023, 4, 15, 21, 4, 20, 437090), 'buffer_idx': 0})]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
@@ -120,7 +125,7 @@
},
{
"cell_type": "code",
"execution_count": 30,
"execution_count": 5,
"id": "dc37669b",
"metadata": {},
"outputs": [],
@@ -131,35 +136,35 @@
"embedding_size = 1536\n",
"index = faiss.IndexFlatL2(embedding_size)\n",
"vectorstore = FAISS(embeddings_model.embed_query, index, InMemoryDocstore({}), {})\n",
"retriever = TimeWeightedVectorStoreRetriever(vectorstore=vectorstore, decay_factor=.00000001, k=1) "
"retriever = TimeWeightedVectorStoreRetriever(vectorstore=vectorstore, decay_factor=.0000000000000000000000001, k=1) "
]
},
{
"cell_type": "code",
"execution_count": 31,
"execution_count": 6,
"id": "fa284384",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['3c156c9a-ad6b-47dc-befc-87437a603973']"
"['f063e5b2-c2eb-42fc-8894-79c7a7a9038e']"
]
},
"execution_count": 31,
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"retriever.add_documents([Document(page_content=\"hello world\")])\n",
"time.sleep(1)\n",
"time.sleep(20)\n",
"retriever.add_documents([Document(page_content=\"hello foo\")])"
]
},
{
"cell_type": "code",
"execution_count": 32,
"execution_count": 7,
"id": "7558f94d",
"metadata": {},
"outputs": [
@@ -167,19 +172,19 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0.8416762384156714\n",
"1.6166791948060522\n",
"0.5781175231321124\n",
"1.577325318264064\n"
"0.9978079943966991\n",
"1.8412067636745604\n",
"0.7235696005754303\n",
"1.7230094271411442\n"
]
},
{
"data": {
"text/plain": [
"[Document(page_content='hello foo', metadata={'last_accessed_at': datetime.datetime(2023, 4, 13, 23, 35, 54, 905605), 'created_at': datetime.datetime(2023, 4, 13, 23, 35, 54, 242988), 'buffer_idx': 1})]"
"[Document(page_content='hello foo', metadata={'last_accessed_at': datetime.datetime(2023, 4, 15, 21, 5, 2, 243331), 'created_at': datetime.datetime(2023, 4, 15, 21, 5, 1, 579028), 'buffer_idx': 1})]"
]
},
"execution_count": 32,
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
@@ -17,34 +17,36 @@
"metadata": {},
"outputs": [],
"source": [
"!python3 -m pip install openai deeplake"
"!python3 -m pip install openai deeplake tiktoken"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from langchain.embeddings.openai import OpenAIEmbeddings\n",
"from langchain.text_splitter import CharacterTextSplitter\n",
"from langchain.vectorstores import DeepLake\n",
"from langchain.document_loaders import TextLoader"
"from langchain.vectorstores import DeepLake"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"os.environ['OPENAI_API_KEY'] = 'sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'"
"import getpass\n",
"\n",
"os.environ['OPENAI_API_KEY'] = getpass.getpass('OpenAI API Key:')\n",
"embeddings = OpenAIEmbeddings()"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
@@ -60,9 +62,38 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 6,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"mem://langchain loaded successfully.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Evaluating ingest: 100%|██████████| 1/1 [00:04<00:00\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset(path='mem://langchain', tensors=['embedding', 'ids', 'metadata', 'text'])\n",
"\n",
" tensor htype shape dtype compression\n",
" ------- ------- ------- ------- ------- \n",
" embedding generic (4, 1536) float32 None \n",
" ids text (4, 1) str None \n",
" metadata json (4, 1) str None \n",
" text text (4, 1) str None \n"
]
}
],
"source": [
"db = DeepLake.from_documents(docs, embeddings)\n",
"\n",
@@ -72,9 +103,23 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 7,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \n",
"\n",
"Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \n",
"\n",
"One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \n",
"\n",
"And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.\n"
]
}
],
"source": [
"print(docs[0].page_content)"
]
@@ -89,9 +134,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 9,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/media/sdb/davit/.local/lib/python3.10/site-packages/langchain/llms/openai.py:624: UserWarning: You are trying to use a chat model. This way of initializing it is no longer supported. Instead, please use: `from langchain.chat_models import ChatOpenAI`\n",
" warnings.warn(\n"
]
}
],
"source": [
"from langchain.chains import RetrievalQA\n",
"from langchain.llms import OpenAIChat\n",
@@ -101,9 +155,20 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 10,
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'The president nominated Circuit Court of Appeals Judge Ketanji Brown Jackson for the United States Supreme Court and praised her qualifications and broad support from both Democrats and Republicans.'"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"query = 'What did the president say about Ketanji Brown Jackson'\n",
"qa.run(query)"
@@ -119,9 +184,43 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 11,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"mem://langchain loaded successfully.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Evaluating ingest: 100%|██████████| 1/1 [00:04<00:00\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset(path='mem://langchain', tensors=['embedding', 'ids', 'metadata', 'text'])\n",
"\n",
" tensor htype shape dtype compression\n",
" ------- ------- ------- ------- ------- \n",
" embedding generic (42, 1536) float32 None \n",
" ids text (42, 1) str None \n",
" metadata json (42, 1) str None \n",
" text text (42, 1) str None \n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": []
}
],
"source": [
"import random\n",
"\n",
@@ -133,9 +232,30 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 12,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"100%|██████████| 42/42 [00:00<00:00, 3456.17it/s]\n"
]
},
{
"data": {
"text/plain": [
"[Document(page_content='A former top litigator in private practice. A former federal public defender. And from a family of public school educators and police officers. A consensus builder. Since she’s been nominated, she’s received a broad range of support—from the Fraternal Order of Police to former judges appointed by Democrats and Republicans. \\n\\nAnd if we are to advance liberty and justice, we need to secure the Border and fix the immigration system. \\n\\nWe can do both. At our border, we’ve installed new technology like cutting-edge scanners to better detect drug smuggling. \\n\\nWe’ve set up joint patrols with Mexico and Guatemala to catch more human traffickers. \\n\\nWe’re putting in place dedicated immigration judges so families fleeing persecution and violence can have their cases heard faster. \\n\\nWe’re securing commitments and supporting partners in South and Central America to host more refugees and secure their own borders.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2013}),\n",
" Document(page_content='And for our LGBTQ+ Americans, let’s finally get the bipartisan Equality Act to my desk. The onslaught of state laws targeting transgender Americans and their families is wrong. \\n\\nAs I said last year, especially to our younger transgender Americans, I will always have your back as your President, so you can be yourself and reach your God-given potential. \\n\\nWhile it often appears that we never agree, that isn’t true. I signed 80 bipartisan bills into law last year. From preventing government shutdowns to protecting Asian-Americans from still-too-common hate crimes to reforming military justice. \\n\\nAnd soon, we’ll strengthen the Violence Against Women Act that I first wrote three decades ago. It is important for us to show the nation that we can come together and do big things. \\n\\nSo tonight I’m offering a Unity Agenda for the Nation. Four big things we can do together. \\n\\nFirst, beat the opioid epidemic.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2013}),\n",
" Document(page_content='Vice President Harris and I ran for office with a new economic vision for America. \\n\\nInvest in America. Educate Americans. Grow the workforce. Build the economy from the bottom up \\nand the middle out, not from the top down. \\n\\nBecause we know that when the middle class grows, the poor have a ladder up and the wealthy do very well. \\n\\nAmerica used to have the best roads, bridges, and airports on Earth. \\n\\nNow our infrastructure is ranked 13th in the world. \\n\\nWe won’t be able to compete for the jobs of the 21st Century if we don’t fix that. \\n\\nThat’s why it was so important to pass the Bipartisan Infrastructure Law—the most sweeping investment to rebuild America in history. \\n\\nThis was a bipartisan effort, and I want to thank the members of both parties who worked to make it happen. \\n\\nWe’re done talking about infrastructure weeks. \\n\\nWe’re going to have an infrastructure decade.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2013}),\n",
" Document(page_content='It is going to transform America and put us on a path to win the economic competition of the 21st Century that we face with the rest of the world—particularly with China. \\n\\nAs I’ve told Xi Jinping, it is never a good bet to bet against the American people. \\n\\nWe’ll create good jobs for millions of Americans, modernizing roads, airports, ports, and waterways all across America. \\n\\nAnd we’ll do it all to withstand the devastating effects of the climate crisis and promote environmental justice. \\n\\nWe’ll build a national network of 500,000 electric vehicle charging stations, begin to replace poisonous lead pipes—so every child—and every American—has clean water to drink at home and at school, provide affordable high-speed internet for every American—urban, suburban, rural, and tribal communities. \\n\\n4,000 projects have already been announced. \\n\\nAnd tonight, I’m announcing that this year we will start fixing over 65,000 miles of highway and 1,500 bridges in disrepair.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2013})]"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"db.similarity_search('What did the president say about Ketanji Brown Jackson', filter={'year': 2013})"
]
@@ -151,9 +271,23 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 13,
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"[Document(page_content='Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \\n\\nTonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \\n\\nOne of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \\n\\nAnd I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2012}),\n",
" Document(page_content='A former top litigator in private practice. A former federal public defender. And from a family of public school educators and police officers. A consensus builder. Since she’s been nominated, she’s received a broad range of support—from the Fraternal Order of Police to former judges appointed by Democrats and Republicans. \\n\\nAnd if we are to advance liberty and justice, we need to secure the Border and fix the immigration system. \\n\\nWe can do both. At our border, we’ve installed new technology like cutting-edge scanners to better detect drug smuggling. \\n\\nWe’ve set up joint patrols with Mexico and Guatemala to catch more human traffickers. \\n\\nWe’re putting in place dedicated immigration judges so families fleeing persecution and violence can have their cases heard faster. \\n\\nWe’re securing commitments and supporting partners in South and Central America to host more refugees and secure their own borders.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2013}),\n",
" Document(page_content='And for our LGBTQ+ Americans, let’s finally get the bipartisan Equality Act to my desk. The onslaught of state laws targeting transgender Americans and their families is wrong. \\n\\nAs I said last year, especially to our younger transgender Americans, I will always have your back as your President, so you can be yourself and reach your God-given potential. \\n\\nWhile it often appears that we never agree, that isn’t true. I signed 80 bipartisan bills into law last year. From preventing government shutdowns to protecting Asian-Americans from still-too-common hate crimes to reforming military justice. \\n\\nAnd soon, we’ll strengthen the Violence Against Women Act that I first wrote three decades ago. It is important for us to show the nation that we can come together and do big things. \\n\\nSo tonight I’m offering a Unity Agenda for the Nation. Four big things we can do together. \\n\\nFirst, beat the opioid epidemic.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2013}),\n",
" Document(page_content='Tonight, I’m announcing a crackdown on these companies overcharging American businesses and consumers. \\n\\nAnd as Wall Street firms take over more nursing homes, quality in those homes has gone down and costs have gone up. \\n\\nThat ends on my watch. \\n\\nMedicare is going to set higher standards for nursing homes and make sure your loved ones get the care they deserve and expect. \\n\\nWe’ll also cut costs and keep the economy going strong by giving workers a fair shot, provide more training and apprenticeships, hire them based on their skills not degrees. \\n\\nLet’s pass the Paycheck Fairness Act and paid leave. \\n\\nRaise the minimum wage to $15 an hour and extend the Child Tax Credit, so no one has to raise a family in poverty. \\n\\nLet’s increase Pell Grants and increase our historic support of HBCUs, and invest in what Jill—our First Lady who teaches full-time—calls America’s best-kept secret: community colleges.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2014})]"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"db.similarity_search('What did the president say about Ketanji Brown Jackson?', distance_metric='cos')"
]
@@ -169,9 +303,23 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 14,
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"[Document(page_content='Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \\n\\nTonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \\n\\nOne of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \\n\\nAnd I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2012}),\n",
" Document(page_content='One was stationed at bases and breathing in toxic smoke from “burn pits” that incinerated wastes of war—medical and hazard material, jet fuel, and more. \\n\\nWhen they came home, many of the world’s fittest and best trained warriors were never the same. \\n\\nHeadaches. Numbness. Dizziness. \\n\\nA cancer that would put them in a flag-draped coffin. \\n\\nI know. \\n\\nOne of those soldiers was my son Major Beau Biden. \\n\\nWe don’t know for sure if a burn pit was the cause of his brain cancer, or the diseases of so many of our troops. \\n\\nBut I’m committed to finding out everything we can. \\n\\nCommitted to military families like Danielle Robinson from Ohio. \\n\\nThe widow of Sergeant First Class Heath Robinson. \\n\\nHe was born a soldier. Army National Guard. Combat medic in Kosovo and Iraq. \\n\\nStationed near Baghdad, just yards from burn pits the size of football fields. \\n\\nHeath’s widow Danielle is here with us tonight. They loved going to Ohio State football games. He loved building Legos with their daughter.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2014}),\n",
" Document(page_content='As Ohio Senator Sherrod Brown says, “It’s time to bury the label “Rust Belt.” \\n\\nIt’s time. \\n\\nBut with all the bright spots in our economy, record job growth and higher wages, too many families are struggling to keep up with the bills. \\n\\nInflation is robbing them of the gains they might otherwise feel. \\n\\nI get it. That’s why my top priority is getting prices under control. \\n\\nLook, our economy roared back faster than most predicted, but the pandemic meant that businesses had a hard time hiring enough workers to keep up production in their factories. \\n\\nThe pandemic also disrupted global supply chains. \\n\\nWhen factories close, it takes longer to make goods and get them from the warehouse to the store, and prices go up. \\n\\nLook at cars. \\n\\nLast year, there weren’t enough semiconductors to make all the cars that people wanted to buy. \\n\\nAnd guess what, prices of automobiles went up. \\n\\nSo—we have a choice. \\n\\nOne way to fight inflation is to drive down wages and make Americans poorer.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2012}),\n",
" Document(page_content='We can’t change how divided we’ve been. But we can change how we move forward—on COVID-19 and other issues we must face together. \\n\\nI recently visited the New York City Police Department days after the funerals of Officer Wilbert Mora and his partner, Officer Jason Rivera. \\n\\nThey were responding to a 9-1-1 call when a man shot and killed them with a stolen gun. \\n\\nOfficer Mora was 27 years old. \\n\\nOfficer Rivera was 22. \\n\\nBoth Dominican Americans who’d grown up on the same streets they later chose to patrol as police officers. \\n\\nI spoke with their families and told them that we are forever in debt for their sacrifice, and we will carry on their mission to restore the trust and safety every community deserves. \\n\\nI’ve worked on these issues a long time. \\n\\nI know what works: Investing in crime preventionand community police officers who’ll walk the beat, who’ll know the neighborhood, and who can restore trust and safety.', metadata={'source': '../../../state_of_the_union.txt', 'year': 2012})]"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"db.max_marginal_relevance_search('What did the president say about Ketanji Brown Jackson?')"
]
@@ -187,21 +335,87 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"!activeloop login -t <token>"
"os.environ['ACTIVELOOP_TOKEN'] = getpass.getpass('Activeloop Token:')"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 17,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Your Deep Lake dataset has been successfully created!\n",
"The dataset is private so make sure you are logged in!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\\"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"This dataset can be visualized in Jupyter Notebook by ds.visualize() or at https://app.activeloop.ai/davitbun/linkedin\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
" \r"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"hub://davitbun/linkedin loaded successfully.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Evaluating ingest: 100%|██████████| 1/1 [00:23<00:00\n",
"/"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset(path='hub://davitbun/linkedin', tensors=['embedding', 'ids', 'metadata', 'text'])\n",
"\n",
" tensor htype shape dtype compression\n",
" ------- ------- ------- ------- ------- \n",
" embedding generic (42, 1536) float32 None \n",
" ids text (42, 1) str None \n",
" metadata json (42, 1) str None \n",
" text text (42, 1) str None \n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
" \r"
]
}
],
"source": [
"# Embed and store the texts\n",
"dataset_path = \"hub://{username}/{dataset_name}\" # could be also ./local/path (much faster locally), s3://bucket/path/to/dataset, gcs://path/to/dataset, etc.\n",
"dataset_path = f\"hub://{USERNAME}/{DATASET_NAME}\" # could be also ./local/path (much faster locally), s3://bucket/path/to/dataset, gcs://path/to/dataset, etc.\n",
"\n",
"embedding = OpenAIEmbeddings()\n",
"vectordb = DeepLake.from_documents(documents=docs, embedding=embedding, dataset_path=dataset_path)"
@@ -209,9 +423,23 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 18,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \n",
"\n",
"Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \n",
"\n",
"One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \n",
"\n",
"And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.\n"
]
}
],
"source": [
"query = \"What did the president say about Ketanji Brown Jackson\"\n",
"docs = db.similarity_search(query)\n",
@@ -220,11 +448,35 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset(path='hub://davitbun/linkedin', tensors=['embedding', 'ids', 'metadata', 'text'])\n",
"\n",
" tensor htype shape dtype compression\n",
" ------- ------- ------- ------- ------- \n",
" embedding generic (42, 1536) float32 None \n",
" ids text (42, 1) str None \n",
" metadata json (42, 1) str None \n",
" text text (42, 1) str None \n"
]
}
],
"source": [
"vectordb.ds.summary()"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"vectordb.ds.summary()"
"embeddings = vectordb.ds.embedding.numpy()"
]
},
{
@@ -232,9 +484,7 @@
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"embeddings = vectordb.ds.embedding.numpy()"
]
"source": []
}
],
"metadata": {
@@ -16,7 +16,7 @@
"In order to add a memory with an external message store to an agent we are going to do the following steps:\n",
"\n",
"1. We are going to create a `RedisChatMessageHistory` to connect to an external database to store the messages in.\n",
"2. We are going to create an `LLMChain` useing that chat history as memory.\n",
"2. We are going to create an `LLMChain` using that chat history as memory.\n",
"3. We are going to use that `LLMChain` to create a custom Agent.\n",
"\n",
"For the purposes of this exercise, we are going to create a simple custom Agent that has access to a search tool and utilizes the `ConversationBufferMemory` class."
@@ -7,9 +7,11 @@
"source": [
"# VectorStore-Backed Memory\n",
"\n",
"`VectorStoreRetrieverMemory` stores interactions in a VectorDB and queries the top-K most \"salient\" interactions every type it is called.\n",
"`VectorStoreRetrieverMemory` stores memories in a VectorDB and queries the top-K most \"salient\" docs every time it is called.\n",
"\n",
"This differs from most of the other Memory classes in that "
"This differs from most of the other Memory classes in that it doesn't explicitly track the order of interactions.\n",
"\n",
"In this case, the \"docs\" are previous conversation snippets. This can be useful to refer to relevant pieces of information that the AI was told earlier in the conversation."
]
},
{
@@ -25,7 +27,8 @@
"from langchain.embeddings.openai import OpenAIEmbeddings\n",
"from langchain.llms import OpenAI\n",
"from langchain.memory import VectorStoreRetrieverMemory\n",
"from langchain.chains import ConversationChain"
"from langchain.chains import ConversationChain\n",
"from langchain.prompts import PromptTemplate"
]
},
{
@@ -40,7 +43,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 29,
"id": "eef56f65",
"metadata": {
"tags": []
@@ -66,12 +69,12 @@
"source": [
"### Create your the VectorStoreRetrieverMemory\n",
"\n",
"The memory object is instantiated from "
"The memory object is instantiated from any VectorStoreRetriever."
]
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 30,
"id": "e00d4938",
"metadata": {
"tags": []
@@ -84,14 +87,14 @@
"memory = VectorStoreRetrieverMemory(retriever=retriever)\n",
"\n",
"# When added to an agent, the memory object can save pertinent information from conversations or used tools\n",
"memory.save_context({\"input\": \"check the latest scores of the Warriors game\"}, {\"output\": \"the Warriors are up against the Astros 88 to 84\"})\n",
"memory.save_context({\"input\": \"I need help doing my taxes - what's the standard deduction this year?\"}, {\"output\": \"...\"})\n",
"memory.save_context({\"input\": \"What's the the time?\"}, {\"output\": f\"It's {datetime.now()}\"}) # "
"memory.save_context({\"input\": \"My favorite food is pizza\"}, {\"output\": \"thats good to know\"})\n",
"memory.save_context({\"input\": \"My favorite sport is soccer\"}, {\"output\": \"...\"})\n",
"memory.save_context({\"input\": \"I don't the Celtics\"}, {\"output\": \"ok\"}) # "
]
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 31,
"id": "2fe28a28",
"metadata": {
"tags": []
@@ -101,7 +104,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"input: I need help doing my taxes - what's the standard deduction this year?\n",
"input: My favorite sport is soccer\n",
"output: ...\n"
]
}
@@ -109,7 +112,7 @@
"source": [
"# Notice the first result returned is the memory pertaining to tax help, which the language model deems more semantically relevant\n",
"# to a 1099 than the other documents, despite them both containing numbers.\n",
"print(memory.load_memory_variables({\"prompt\": \"What's a 1099?\"})[\"history\"])"
"print(memory.load_memory_variables({\"prompt\": \"what sport should i watch?\"})[\"history\"])"
]
},
{
@@ -123,7 +126,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 32,
"id": "ebd68c10",
"metadata": {
"tags": []
@@ -139,9 +142,13 @@
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Relevant pieces of previous conversation:\n",
"input: My favorite food is pizza\n",
"output: thats good to know\n",
"\n",
"(You do not need to use these pieces of information if not relevant)\n",
"\n",
"Current conversation:\n",
"input: I need help doing my taxes - what's the standard deduction this year?\n",
"output: ...\n",
"Human: Hi, my name is Perry, what's up?\n",
"AI:\u001b[0m\n",
"\n",
@@ -151,18 +158,32 @@
{
"data": {
"text/plain": [
"\" Hi Perry, my name is AI. I'm doing great, how about you? I understand you need help with your taxes. What specifically do you need help with?\""
"\" Hi Perry, I'm doing well. How about you?\""
]
},
"execution_count": 5,
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"llm = OpenAI(temperature=0) # Can be any valid LLM\n",
"_DEFAULT_TEMPLATE = \"\"\"The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Relevant pieces of previous conversation:\n",
"{history}\n",
"\n",
"(You do not need to use these pieces of information if not relevant)\n",
"\n",
"Current conversation:\n",
"Human: {input}\n",
"AI:\"\"\"\n",
"PROMPT = PromptTemplate(\n",
" input_variables=[\"history\", \"input\"], template=_DEFAULT_TEMPLATE\n",
")\n",
"conversation_with_summary = ConversationChain(\n",
" llm=llm, \n",
" prompt=PROMPT,\n",
" # We set a very low max_token_limit for the purposes of testing.\n",
" memory=memory,\n",
" verbose=True\n",
@@ -172,7 +193,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 33,
"id": "86207a61",
"metadata": {
"tags": []
@@ -188,10 +209,14 @@
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Relevant pieces of previous conversation:\n",
"input: My favorite sport is soccer\n",
"output: ...\n",
"\n",
"(You do not need to use these pieces of information if not relevant)\n",
"\n",
"Current conversation:\n",
"input: check the latest scores of the Warriors game\n",
"output: the Warriors are up against the Astros 88 to 84\n",
"Human: If the Cavaliers were to face off against the Warriers or the Astros, who would they most stand a chance to beat?\n",
"Human: what's my favorite sport?\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
@@ -200,22 +225,22 @@
{
"data": {
"text/plain": [
"\" It's hard to say without knowing the current form of the teams. However, based on the current scores, it looks like the Cavaliers would have a better chance of beating the Astros than the Warriors.\""
"' You told me earlier that your favorite sport is soccer.'"
]
},
"execution_count": 6,
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Here, the basketball related content is surfaced\n",
"conversation_with_summary.predict(input=\"If the Cavaliers were to face off against the Warriers or the Astros, who would they most stand a chance to beat?\")"
"conversation_with_summary.predict(input=\"what's my favorite sport?\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 34,
"id": "8c669db1",
"metadata": {
"tags": []
@@ -231,10 +256,14 @@
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Relevant pieces of previous conversation:\n",
"input: My favorite food is pizza\n",
"output: thats good to know\n",
"\n",
"(You do not need to use these pieces of information if not relevant)\n",
"\n",
"Current conversation:\n",
"input: What's the the time?\n",
"output: It's 2023-04-13 09:18:55.623736\n",
"Human: What day is it tomorrow?\n",
"Human: Whats my favorite food\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
@@ -243,10 +272,10 @@
{
"data": {
"text/plain": [
"' Tomorrow is 2023-04-14.'"
"' You said your favorite food is pizza.'"
]
},
"execution_count": 7,
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
@@ -254,12 +283,12 @@
"source": [
"# Even though the language model is stateless, since relavent memory is fetched, it can \"reason\" about the time.\n",
"# Timestamping memories and data is useful in general to let the agent determine temporal relevance\n",
"conversation_with_summary.predict(input=\"What day is it tomorrow?\")"
"conversation_with_summary.predict(input=\"Whats my favorite food\")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 35,
"id": "8c09a239",
"metadata": {
"tags": []
@@ -275,10 +304,14 @@
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Current conversation:\n",
"Relevant pieces of previous conversation:\n",
"input: Hi, my name is Perry, what's up?\n",
"response: Hi Perry, my name is AI. I'm doing great, how about you? I understand you need help with your taxes. What specifically do you need help with?\n",
"Human: What's your name?\n",
"response: Hi Perry, I'm doing well. How about you?\n",
"\n",
"(You do not need to use these pieces of information if not relevant)\n",
"\n",
"Current conversation:\n",
"Human: What's my name?\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
@@ -287,10 +320,10 @@
{
"data": {
"text/plain": [
"\" My name is AI. It's nice to meet you, Perry.\""
"' Your name is Perry.'"
]
},
"execution_count": 8,
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
@@ -299,8 +332,16 @@
"# The memories from the conversation are automatically stored,\n",
"# since this query best matches the introduction chat above,\n",
"# the agent is able to 'remember' the user's name.\n",
"conversation_with_summary.predict(input=\"What's your name?\")"
"conversation_with_summary.predict(input=\"What's my name?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "df27c7dc",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
@@ -319,7 +360,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.2"
"version": "3.9.1"
}
},
"nbformat": 4,
@@ -115,7 +115,7 @@
"id": "a2d76826",
"metadata": {},
"source": [
"**The above request should now appear on your [PromptLayer dashboard](https://ww.promptlayer.com).**"
"**The above request should now appear on your [PromptLayer dashboard](https://www.promptlayer.com).**"
]
},
{
@@ -43,22 +43,18 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Total Tokens: 39\n",
"Prompt Tokens: 4\n",
"Completion Tokens: 35\n",
"Tokens Used: 42\n",
"\tPrompt Tokens: 4\n",
"\tCompletion Tokens: 38\n",
"Successful Requests: 1\n",
"Total Cost (USD): $0.0007800000000000001\n"
"Total Cost (USD): $0.00084\n"
]
}
],
"source": [
"with get_openai_callback() as cb:\n",
" result = llm(\"Tell me a joke\")\n",
" print(f\"Total Tokens: {cb.total_tokens}\")\n",
" print(f\"Prompt Tokens: {cb.prompt_tokens}\")\n",
" print(f\"Completion Tokens: {cb.completion_tokens}\")\n",
" print(f\"Successful Requests: {cb.successful_requests}\")\n",
" print(f\"Total Cost (USD): ${cb.total_cost}\")"
" print(cb)"
]
},
{
@@ -186,7 +186,7 @@
"source": [
"**Number of Tokens:** You can also estimate how many tokens a piece of text will be in that model. This is useful because models have a context length (and cost more for more tokens), which means you need to be aware of how long the text you are passing in is.\n",
"\n",
"Notice that by default the tokens are estimated using [tiktoken](https://github.com/openai/tiktoken) (except for legacy version <3.8, where a HuggingFace tokenizer is used)"
"Notice that by default the tokens are estimated using [tiktoken](https://github.com/openai/tiktoken) (except for legacy version <3.8, where a Hugging Face tokenizer is used)"
]
},
{
+61 -34
View File
@@ -38,7 +38,7 @@
"from langchain.llms import BaseLLM\n",
"from langchain.vectorstores.base import VectorStore\n",
"from pydantic import BaseModel, Field\n",
"from langchain.chains.base import Chain\n"
"from langchain.chains.base import Chain"
]
},
{
@@ -73,6 +73,7 @@
"embeddings_model = OpenAIEmbeddings()\n",
"# Initialize the vectorstore as empty\n",
"import faiss\n",
"\n",
"embedding_size = 1536\n",
"index = faiss.IndexFlatL2(embedding_size)\n",
"vectorstore = FAISS(embeddings_model.embed_query, index, InMemoryDocstore({}), {})"
@@ -116,7 +117,12 @@
" )\n",
" prompt = PromptTemplate(\n",
" template=task_creation_template,\n",
" input_variables=[\"result\", \"task_description\", \"incomplete_tasks\", \"objective\"],\n",
" input_variables=[\n",
" \"result\",\n",
" \"task_description\",\n",
" \"incomplete_tasks\",\n",
" \"objective\",\n",
" ],\n",
" )\n",
" return cls(prompt=prompt, llm=llm, verbose=verbose)"
]
@@ -147,7 +153,7 @@
" template=task_prioritization_template,\n",
" input_variables=[\"task_names\", \"next_task_id\", \"objective\"],\n",
" )\n",
" return cls(prompt=prompt, llm=llm, verbose=verbose)\n"
" return cls(prompt=prompt, llm=llm, verbose=verbose)"
]
},
{
@@ -173,7 +179,7 @@
" template=execution_template,\n",
" input_variables=[\"objective\", \"context\", \"task\"],\n",
" )\n",
" return cls(prompt=prompt, llm=llm, verbose=verbose)\n"
" return cls(prompt=prompt, llm=llm, verbose=verbose)"
]
},
{
@@ -193,11 +199,22 @@
"metadata": {},
"outputs": [],
"source": [
"def get_next_task(task_creation_chain: LLMChain, result: Dict, task_description: str, task_list: List[str], objective: str) -> List[Dict]:\n",
"def get_next_task(\n",
" task_creation_chain: LLMChain,\n",
" result: Dict,\n",
" task_description: str,\n",
" task_list: List[str],\n",
" objective: str,\n",
") -> List[Dict]:\n",
" \"\"\"Get the next task.\"\"\"\n",
" incomplete_tasks = \", \".join(task_list)\n",
" response = task_creation_chain.run(result=result, task_description=task_description, incomplete_tasks=incomplete_tasks, objective=objective)\n",
" new_tasks = response.split('\\n')\n",
" response = task_creation_chain.run(\n",
" result=result,\n",
" task_description=task_description,\n",
" incomplete_tasks=incomplete_tasks,\n",
" objective=objective,\n",
" )\n",
" new_tasks = response.split(\"\\n\")\n",
" return [{\"task_name\": task_name} for task_name in new_tasks if task_name.strip()]"
]
},
@@ -208,12 +225,19 @@
"metadata": {},
"outputs": [],
"source": [
"def prioritize_tasks(task_prioritization_chain: LLMChain, this_task_id: int, task_list: List[Dict], objective: str) -> List[Dict]:\n",
"def prioritize_tasks(\n",
" task_prioritization_chain: LLMChain,\n",
" this_task_id: int,\n",
" task_list: List[Dict],\n",
" objective: str,\n",
") -> List[Dict]:\n",
" \"\"\"Prioritize tasks.\"\"\"\n",
" task_names = [t[\"task_name\"] for t in task_list]\n",
" next_task_id = int(this_task_id) + 1\n",
" response = task_prioritization_chain.run(task_names=task_names, next_task_id=next_task_id, objective=objective)\n",
" new_tasks = response.split('\\n')\n",
" response = task_prioritization_chain.run(\n",
" task_names=task_names, next_task_id=next_task_id, objective=objective\n",
" )\n",
" new_tasks = response.split(\"\\n\")\n",
" prioritized_task_list = []\n",
" for task_string in new_tasks:\n",
" if not task_string.strip():\n",
@@ -239,9 +263,12 @@
" if not results:\n",
" return []\n",
" sorted_results, _ = zip(*sorted(results, key=lambda x: x[1], reverse=True))\n",
" return [str(item.metadata['task']) for item in sorted_results]\n",
" return [str(item.metadata[\"task\"]) for item in sorted_results]\n",
"\n",
"def execute_task(vectorstore, execution_chain: LLMChain, objective: str, task: str, k: int = 5) -> str:\n",
"\n",
"def execute_task(\n",
" vectorstore, execution_chain: LLMChain, objective: str, task: str, k: int = 5\n",
") -> str:\n",
" \"\"\"Execute a task.\"\"\"\n",
" context = _get_top_tasks(vectorstore, query=objective, k=k)\n",
" return execution_chain.run(objective=objective, context=context, task=task)"
@@ -254,7 +281,6 @@
"metadata": {},
"outputs": [],
"source": [
"\n",
"class BabyAGI(Chain, BaseModel):\n",
" \"\"\"Controller model for the BabyAGI agent.\"\"\"\n",
"\n",
@@ -265,9 +291,10 @@
" task_id_counter: int = Field(1)\n",
" vectorstore: VectorStore = Field(init=False)\n",
" max_iterations: Optional[int] = None\n",
" \n",
"\n",
" class Config:\n",
" \"\"\"Configuration for this pydantic object.\"\"\"\n",
"\n",
" arbitrary_types_allowed = True\n",
"\n",
" def add_task(self, task: Dict):\n",
@@ -285,18 +312,18 @@
" def print_task_result(self, result: str):\n",
" print(\"\\033[93m\\033[1m\" + \"\\n*****TASK RESULT*****\\n\" + \"\\033[0m\\033[0m\")\n",
" print(result)\n",
" \n",
"\n",
" @property\n",
" def input_keys(self) -> List[str]:\n",
" return [\"objective\"]\n",
" \n",
"\n",
" @property\n",
" def output_keys(self) -> List[str]:\n",
" return []\n",
"\n",
" def _call(self, inputs: Dict[str, Any]) -> Dict[str, Any]:\n",
" \"\"\"Run the agent.\"\"\"\n",
" objective = inputs['objective']\n",
" objective = inputs[\"objective\"]\n",
" first_task = inputs.get(\"first_task\", \"Make a todo list\")\n",
" self.add_task({\"task_id\": 1, \"task_name\": first_task})\n",
" num_iters = 0\n",
@@ -325,7 +352,11 @@
"\n",
" # Step 4: Create new tasks and reprioritize task list\n",
" new_tasks = get_next_task(\n",
" self.task_creation_chain, result, task[\"task_name\"], [t[\"task_name\"] for t in self.task_list], objective\n",
" self.task_creation_chain,\n",
" result,\n",
" task[\"task_name\"],\n",
" [t[\"task_name\"] for t in self.task_list],\n",
" objective,\n",
" )\n",
" for new_task in new_tasks:\n",
" self.task_id_counter += 1\n",
@@ -333,27 +364,26 @@
" self.add_task(new_task)\n",
" self.task_list = deque(\n",
" prioritize_tasks(\n",
" self.task_prioritization_chain, this_task_id, list(self.task_list), objective\n",
" self.task_prioritization_chain,\n",
" this_task_id,\n",
" list(self.task_list),\n",
" objective,\n",
" )\n",
" )\n",
" num_iters += 1\n",
" if self.max_iterations is not None and num_iters == self.max_iterations:\n",
" print(\"\\033[91m\\033[1m\" + \"\\n*****TASK ENDING*****\\n\" + \"\\033[0m\\033[0m\")\n",
" print(\n",
" \"\\033[91m\\033[1m\" + \"\\n*****TASK ENDING*****\\n\" + \"\\033[0m\\033[0m\"\n",
" )\n",
" break\n",
" return {}\n",
"\n",
" @classmethod\n",
" def from_llm(\n",
" cls,\n",
" llm: BaseLLM,\n",
" vectorstore: VectorStore,\n",
" verbose: bool = False,\n",
" **kwargs\n",
" cls, llm: BaseLLM, vectorstore: VectorStore, verbose: bool = False, **kwargs\n",
" ) -> \"BabyAGI\":\n",
" \"\"\"Initialize the BabyAGI Controller.\"\"\"\n",
" task_creation_chain = TaskCreationChain.from_llm(\n",
" llm, verbose=verbose\n",
" )\n",
" task_creation_chain = TaskCreationChain.from_llm(llm, verbose=verbose)\n",
" task_prioritization_chain = TaskPrioritizationChain.from_llm(\n",
" llm, verbose=verbose\n",
" )\n",
@@ -363,7 +393,7 @@
" task_prioritization_chain=task_prioritization_chain,\n",
" execution_chain=execution_chain,\n",
" vectorstore=vectorstore,\n",
" **kwargs\n",
" **kwargs,\n",
" )"
]
},
@@ -405,14 +435,11 @@
"outputs": [],
"source": [
"# Logging of LLMChains\n",
"verbose=False\n",
"verbose = False\n",
"# If None, will keep on going forever\n",
"max_iterations: Optional[int] = 3\n",
"baby_agi = BabyAGI.from_llm(\n",
" llm=llm,\n",
" vectorstore=vectorstore,\n",
" verbose=verbose,\n",
" max_iterations=max_iterations\n",
" llm=llm, vectorstore=vectorstore, verbose=verbose, max_iterations=max_iterations\n",
")"
]
},
+79 -45
View File
@@ -34,7 +34,7 @@
"from langchain.llms import BaseLLM\n",
"from langchain.vectorstores.base import VectorStore\n",
"from pydantic import BaseModel, Field\n",
"from langchain.chains.base import Chain\n"
"from langchain.chains.base import Chain"
]
},
{
@@ -54,7 +54,9 @@
"metadata": {},
"outputs": [],
"source": [
"%pip install faiss-cpu > /dev/null%pip install google-search-results > /dev/nullfrom langchain.vectorstores import FAISS\n",
"%pip install faiss-cpu > /dev/null\n",
"%pip install google-search-results > /dev/null\n",
"from langchain.vectorstores import FAISS\n",
"from langchain.docstore import InMemoryDocstore"
]
},
@@ -69,6 +71,7 @@
"embeddings_model = OpenAIEmbeddings()\n",
"# Initialize the vectorstore as empty\n",
"import faiss\n",
"\n",
"embedding_size = 1536\n",
"index = faiss.IndexFlatL2(embedding_size)\n",
"vectorstore = FAISS(embeddings_model.embed_query, index, InMemoryDocstore({}), {})"
@@ -115,7 +118,12 @@
" )\n",
" prompt = PromptTemplate(\n",
" template=task_creation_template,\n",
" input_variables=[\"result\", \"task_description\", \"incomplete_tasks\", \"objective\"],\n",
" input_variables=[\n",
" \"result\",\n",
" \"task_description\",\n",
" \"incomplete_tasks\",\n",
" \"objective\",\n",
" ],\n",
" )\n",
" return cls(prompt=prompt, llm=llm, verbose=verbose)"
]
@@ -146,7 +154,7 @@
" template=task_prioritization_template,\n",
" input_variables=[\"task_names\", \"next_task_id\", \"objective\"],\n",
" )\n",
" return cls(prompt=prompt, llm=llm, verbose=verbose)\n"
" return cls(prompt=prompt, llm=llm, verbose=verbose)"
]
},
{
@@ -158,20 +166,23 @@
"source": [
"from langchain.agents import ZeroShotAgent, Tool, AgentExecutor\n",
"from langchain import OpenAI, SerpAPIWrapper, LLMChain\n",
"todo_prompt = PromptTemplate.from_template(\"You are a planner who is an expert at coming up with a todo list for a given objective. Come up with a todo list for this objective: {objective}\")\n",
"\n",
"todo_prompt = PromptTemplate.from_template(\n",
" \"You are a planner who is an expert at coming up with a todo list for a given objective. Come up with a todo list for this objective: {objective}\"\n",
")\n",
"todo_chain = LLMChain(llm=OpenAI(temperature=0), prompt=todo_prompt)\n",
"search = SerpAPIWrapper()\n",
"tools = [\n",
" Tool(\n",
" name = \"Search\",\n",
" name=\"Search\",\n",
" func=search.run,\n",
" description=\"useful for when you need to answer questions about current events\"\n",
" description=\"useful for when you need to answer questions about current events\",\n",
" ),\n",
" Tool(\n",
" name = \"TODO\",\n",
" name=\"TODO\",\n",
" func=todo_chain.run,\n",
" description=\"useful for when you need to come up with todo lists. Input: an objective to create a todo list for. Output: a todo list for that objective. Please be very clear what the objective is!\"\n",
" )\n",
" description=\"useful for when you need to come up with todo lists. Input: an objective to create a todo list for. Output: a todo list for that objective. Please be very clear what the objective is!\",\n",
" ),\n",
"]\n",
"\n",
"\n",
@@ -179,10 +190,10 @@
"suffix = \"\"\"Question: {task}\n",
"{agent_scratchpad}\"\"\"\n",
"prompt = ZeroShotAgent.create_prompt(\n",
" tools, \n",
" prefix=prefix, \n",
" suffix=suffix, \n",
" input_variables=[\"objective\", \"task\", \"context\",\"agent_scratchpad\"]\n",
" tools,\n",
" prefix=prefix,\n",
" suffix=suffix,\n",
" input_variables=[\"objective\", \"task\", \"context\", \"agent_scratchpad\"],\n",
")"
]
},
@@ -203,11 +214,22 @@
"metadata": {},
"outputs": [],
"source": [
"def get_next_task(task_creation_chain: LLMChain, result: Dict, task_description: str, task_list: List[str], objective: str) -> List[Dict]:\n",
"def get_next_task(\n",
" task_creation_chain: LLMChain,\n",
" result: Dict,\n",
" task_description: str,\n",
" task_list: List[str],\n",
" objective: str,\n",
") -> List[Dict]:\n",
" \"\"\"Get the next task.\"\"\"\n",
" incomplete_tasks = \", \".join(task_list)\n",
" response = task_creation_chain.run(result=result, task_description=task_description, incomplete_tasks=incomplete_tasks, objective=objective)\n",
" new_tasks = response.split('\\n')\n",
" response = task_creation_chain.run(\n",
" result=result,\n",
" task_description=task_description,\n",
" incomplete_tasks=incomplete_tasks,\n",
" objective=objective,\n",
" )\n",
" new_tasks = response.split(\"\\n\")\n",
" return [{\"task_name\": task_name} for task_name in new_tasks if task_name.strip()]"
]
},
@@ -218,12 +240,19 @@
"metadata": {},
"outputs": [],
"source": [
"def prioritize_tasks(task_prioritization_chain: LLMChain, this_task_id: int, task_list: List[Dict], objective: str) -> List[Dict]:\n",
"def prioritize_tasks(\n",
" task_prioritization_chain: LLMChain,\n",
" this_task_id: int,\n",
" task_list: List[Dict],\n",
" objective: str,\n",
") -> List[Dict]:\n",
" \"\"\"Prioritize tasks.\"\"\"\n",
" task_names = [t[\"task_name\"] for t in task_list]\n",
" next_task_id = int(this_task_id) + 1\n",
" response = task_prioritization_chain.run(task_names=task_names, next_task_id=next_task_id, objective=objective)\n",
" new_tasks = response.split('\\n')\n",
" response = task_prioritization_chain.run(\n",
" task_names=task_names, next_task_id=next_task_id, objective=objective\n",
" )\n",
" new_tasks = response.split(\"\\n\")\n",
" prioritized_task_list = []\n",
" for task_string in new_tasks:\n",
" if not task_string.strip():\n",
@@ -249,9 +278,12 @@
" if not results:\n",
" return []\n",
" sorted_results, _ = zip(*sorted(results, key=lambda x: x[1], reverse=True))\n",
" return [str(item.metadata['task']) for item in sorted_results]\n",
" return [str(item.metadata[\"task\"]) for item in sorted_results]\n",
"\n",
"def execute_task(vectorstore, execution_chain: LLMChain, objective: str, task: str, k: int = 5) -> str:\n",
"\n",
"def execute_task(\n",
" vectorstore, execution_chain: LLMChain, objective: str, task: str, k: int = 5\n",
") -> str:\n",
" \"\"\"Execute a task.\"\"\"\n",
" context = _get_top_tasks(vectorstore, query=objective, k=k)\n",
" return execution_chain.run(objective=objective, context=context, task=task)"
@@ -264,7 +296,6 @@
"metadata": {},
"outputs": [],
"source": [
"\n",
"class BabyAGI(Chain, BaseModel):\n",
" \"\"\"Controller model for the BabyAGI agent.\"\"\"\n",
"\n",
@@ -275,9 +306,10 @@
" task_id_counter: int = Field(1)\n",
" vectorstore: VectorStore = Field(init=False)\n",
" max_iterations: Optional[int] = None\n",
" \n",
"\n",
" class Config:\n",
" \"\"\"Configuration for this pydantic object.\"\"\"\n",
"\n",
" arbitrary_types_allowed = True\n",
"\n",
" def add_task(self, task: Dict):\n",
@@ -295,18 +327,18 @@
" def print_task_result(self, result: str):\n",
" print(\"\\033[93m\\033[1m\" + \"\\n*****TASK RESULT*****\\n\" + \"\\033[0m\\033[0m\")\n",
" print(result)\n",
" \n",
"\n",
" @property\n",
" def input_keys(self) -> List[str]:\n",
" return [\"objective\"]\n",
" \n",
"\n",
" @property\n",
" def output_keys(self) -> List[str]:\n",
" return []\n",
"\n",
" def _call(self, inputs: Dict[str, Any]) -> Dict[str, Any]:\n",
" \"\"\"Run the agent.\"\"\"\n",
" objective = inputs['objective']\n",
" objective = inputs[\"objective\"]\n",
" first_task = inputs.get(\"first_task\", \"Make a todo list\")\n",
" self.add_task({\"task_id\": 1, \"task_name\": first_task})\n",
" num_iters = 0\n",
@@ -335,7 +367,11 @@
"\n",
" # Step 4: Create new tasks and reprioritize task list\n",
" new_tasks = get_next_task(\n",
" self.task_creation_chain, result, task[\"task_name\"], [t[\"task_name\"] for t in self.task_list], objective\n",
" self.task_creation_chain,\n",
" result,\n",
" task[\"task_name\"],\n",
" [t[\"task_name\"] for t in self.task_list],\n",
" objective,\n",
" )\n",
" for new_task in new_tasks:\n",
" self.task_id_counter += 1\n",
@@ -343,40 +379,41 @@
" self.add_task(new_task)\n",
" self.task_list = deque(\n",
" prioritize_tasks(\n",
" self.task_prioritization_chain, this_task_id, list(self.task_list), objective\n",
" self.task_prioritization_chain,\n",
" this_task_id,\n",
" list(self.task_list),\n",
" objective,\n",
" )\n",
" )\n",
" num_iters += 1\n",
" if self.max_iterations is not None and num_iters == self.max_iterations:\n",
" print(\"\\033[91m\\033[1m\" + \"\\n*****TASK ENDING*****\\n\" + \"\\033[0m\\033[0m\")\n",
" print(\n",
" \"\\033[91m\\033[1m\" + \"\\n*****TASK ENDING*****\\n\" + \"\\033[0m\\033[0m\"\n",
" )\n",
" break\n",
" return {}\n",
"\n",
" @classmethod\n",
" def from_llm(\n",
" cls,\n",
" llm: BaseLLM,\n",
" vectorstore: VectorStore,\n",
" verbose: bool = False,\n",
" **kwargs\n",
" cls, llm: BaseLLM, vectorstore: VectorStore, verbose: bool = False, **kwargs\n",
" ) -> \"BabyAGI\":\n",
" \"\"\"Initialize the BabyAGI Controller.\"\"\"\n",
" task_creation_chain = TaskCreationChain.from_llm(\n",
" llm, verbose=verbose\n",
" )\n",
" task_creation_chain = TaskCreationChain.from_llm(llm, verbose=verbose)\n",
" task_prioritization_chain = TaskPrioritizationChain.from_llm(\n",
" llm, verbose=verbose\n",
" )\n",
" llm_chain = LLMChain(llm=llm, prompt=prompt)\n",
" tool_names = [tool.name for tool in tools]\n",
" agent = ZeroShotAgent(llm_chain=llm_chain, allowed_tools=tool_names)\n",
" agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True)\n",
" agent_executor = AgentExecutor.from_agent_and_tools(\n",
" agent=agent, tools=tools, verbose=True\n",
" )\n",
" return cls(\n",
" task_creation_chain=task_creation_chain,\n",
" task_prioritization_chain=task_prioritization_chain,\n",
" execution_chain=agent_executor,\n",
" vectorstore=vectorstore,\n",
" **kwargs\n",
" **kwargs,\n",
" )"
]
},
@@ -418,14 +455,11 @@
"outputs": [],
"source": [
"# Logging of LLMChains\n",
"verbose=False\n",
"verbose = False\n",
"# If None, will keep on going forever\n",
"max_iterations: Optional[int] = 3\n",
"baby_agi = BabyAGI.from_llm(\n",
" llm=llm,\n",
" vectorstore=vectorstore,\n",
" verbose=verbose,\n",
" max_iterations=max_iterations\n",
" llm=llm, vectorstore=vectorstore, verbose=verbose, max_iterations=max_iterations\n",
")"
]
},
+1
View File
@@ -23,3 +23,4 @@ Query Understanding: GPT-4 processes user queries, grasping the context and extr
The full tutorial is available below.
- [Twitter the-algorithm codebase analysis with Deep Lake](code/twitter-the-algorithm-analysis-deeplake.ipynb): A notebook walking through how to parse github source code and run queries conversation.
- [LangChain codebase analysis with Deep Lake](code/code-analysis-deeplake.ipynb): A notebook walking through how to analyze and do question answering over THIS code base.
@@ -0,0 +1,644 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Use LangChain, GPT and Deep Lake to work with code base\n",
"In this tutorial, we are going to use Langchain + Deep Lake with GPT to analyze the code base of the LangChain itself. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Design"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1. Prepare data:\n",
" 1. Upload all python project files using the `langchain.document_loaders.TextLoader`. We will call these files the **documents**.\n",
" 2. Split all documents to chunks using the `langchain.text_splitter.CharacterTextSplitter`.\n",
" 3. Embed chunks and upload them into the DeepLake using `langchain.embeddings.openai.OpenAIEmbeddings` and `langchain.vectorstores.DeepLake`\n",
"2. Question-Answering:\n",
" 1. Build a chain from `langchain.chat_models.ChatOpenAI` and `langchain.chains.ConversationalRetrievalChain`\n",
" 2. Prepare questions.\n",
" 3. Get answers running the chain.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Implementation"
]
},
{
"cell_type": "markdown",
"metadata": {
"tags": []
},
"source": [
"### Integration preparations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We need to set up keys for external services and install necessary python libraries."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"#!python3 -m pip install --upgrade langchain deeplake openai"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Set up OpenAI embeddings, Deep Lake multi-modal vector store api and authenticate. \n",
"\n",
"For full documentation of Deep Lake please follow https://docs.activeloop.ai/ and API reference https://docs.deeplake.ai/en/latest/"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" ········\n"
]
}
],
"source": [
"import os\n",
"from getpass import getpass\n",
"\n",
"os.environ['OPENAI_API_KEY'] = getpass()\n",
"# Please manually enter OpenAI Key"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Authenticate into Deep Lake if you want to create your own dataset and publish it. You can get an API key from the platform at [app.activeloop.ai](https://app.activeloop.ai)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" ········\n"
]
}
],
"source": [
"os.environ['ACTIVELOOP_TOKEN'] = getpass.getpass('Activeloop Token:')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Prepare data "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Load all repository files. Here we assume this notebook is downloaded as the part of the langchain fork and we work with the python files of the `langchain` repo.\n",
"\n",
"If you want to use files from different repo, change `root_dir` to the root dir of your repo."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1147\n"
]
}
],
"source": [
"from langchain.document_loaders import TextLoader\n",
"\n",
"root_dir = '../../../..'\n",
"\n",
"docs = []\n",
"for dirpath, dirnames, filenames in os.walk(root_dir):\n",
" for file in filenames:\n",
" if file.endswith('.py') and '/.venv/' not in dirpath:\n",
" try: \n",
" loader = TextLoader(os.path.join(dirpath, file), encoding='utf-8')\n",
" docs.extend(loader.load_and_split())\n",
" except Exception as e: \n",
" pass\n",
"print(f'{len(docs)}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then, chunk the files"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Created a chunk of size 1620, which is longer than the specified 1000\n",
"Created a chunk of size 1213, which is longer than the specified 1000\n",
"Created a chunk of size 1263, which is longer than the specified 1000\n",
"Created a chunk of size 1448, which is longer than the specified 1000\n",
"Created a chunk of size 1120, which is longer than the specified 1000\n",
"Created a chunk of size 1148, which is longer than the specified 1000\n",
"Created a chunk of size 1826, which is longer than the specified 1000\n",
"Created a chunk of size 1260, which is longer than the specified 1000\n",
"Created a chunk of size 1195, which is longer than the specified 1000\n",
"Created a chunk of size 2147, which is longer than the specified 1000\n",
"Created a chunk of size 1410, which is longer than the specified 1000\n",
"Created a chunk of size 1269, which is longer than the specified 1000\n",
"Created a chunk of size 1030, which is longer than the specified 1000\n",
"Created a chunk of size 1046, which is longer than the specified 1000\n",
"Created a chunk of size 1024, which is longer than the specified 1000\n",
"Created a chunk of size 1026, which is longer than the specified 1000\n",
"Created a chunk of size 1285, which is longer than the specified 1000\n",
"Created a chunk of size 1370, which is longer than the specified 1000\n",
"Created a chunk of size 1031, which is longer than the specified 1000\n",
"Created a chunk of size 1999, which is longer than the specified 1000\n",
"Created a chunk of size 1029, which is longer than the specified 1000\n",
"Created a chunk of size 1120, which is longer than the specified 1000\n",
"Created a chunk of size 1033, which is longer than the specified 1000\n",
"Created a chunk of size 1143, which is longer than the specified 1000\n",
"Created a chunk of size 1416, which is longer than the specified 1000\n",
"Created a chunk of size 2482, which is longer than the specified 1000\n",
"Created a chunk of size 1890, which is longer than the specified 1000\n",
"Created a chunk of size 1418, which is longer than the specified 1000\n",
"Created a chunk of size 1848, which is longer than the specified 1000\n",
"Created a chunk of size 1069, which is longer than the specified 1000\n",
"Created a chunk of size 2369, which is longer than the specified 1000\n",
"Created a chunk of size 1045, which is longer than the specified 1000\n",
"Created a chunk of size 1501, which is longer than the specified 1000\n",
"Created a chunk of size 1208, which is longer than the specified 1000\n",
"Created a chunk of size 1950, which is longer than the specified 1000\n",
"Created a chunk of size 1283, which is longer than the specified 1000\n",
"Created a chunk of size 1414, which is longer than the specified 1000\n",
"Created a chunk of size 1304, which is longer than the specified 1000\n",
"Created a chunk of size 1224, which is longer than the specified 1000\n",
"Created a chunk of size 1060, which is longer than the specified 1000\n",
"Created a chunk of size 2461, which is longer than the specified 1000\n",
"Created a chunk of size 1099, which is longer than the specified 1000\n",
"Created a chunk of size 1178, which is longer than the specified 1000\n",
"Created a chunk of size 1449, which is longer than the specified 1000\n",
"Created a chunk of size 1345, which is longer than the specified 1000\n",
"Created a chunk of size 3359, which is longer than the specified 1000\n",
"Created a chunk of size 2248, which is longer than the specified 1000\n",
"Created a chunk of size 1589, which is longer than the specified 1000\n",
"Created a chunk of size 2104, which is longer than the specified 1000\n",
"Created a chunk of size 1505, which is longer than the specified 1000\n",
"Created a chunk of size 1387, which is longer than the specified 1000\n",
"Created a chunk of size 1215, which is longer than the specified 1000\n",
"Created a chunk of size 1240, which is longer than the specified 1000\n",
"Created a chunk of size 1635, which is longer than the specified 1000\n",
"Created a chunk of size 1075, which is longer than the specified 1000\n",
"Created a chunk of size 2180, which is longer than the specified 1000\n",
"Created a chunk of size 1791, which is longer than the specified 1000\n",
"Created a chunk of size 1555, which is longer than the specified 1000\n",
"Created a chunk of size 1082, which is longer than the specified 1000\n",
"Created a chunk of size 1225, which is longer than the specified 1000\n",
"Created a chunk of size 1287, which is longer than the specified 1000\n",
"Created a chunk of size 1085, which is longer than the specified 1000\n",
"Created a chunk of size 1117, which is longer than the specified 1000\n",
"Created a chunk of size 1966, which is longer than the specified 1000\n",
"Created a chunk of size 1150, which is longer than the specified 1000\n",
"Created a chunk of size 1285, which is longer than the specified 1000\n",
"Created a chunk of size 1150, which is longer than the specified 1000\n",
"Created a chunk of size 1585, which is longer than the specified 1000\n",
"Created a chunk of size 1208, which is longer than the specified 1000\n",
"Created a chunk of size 1267, which is longer than the specified 1000\n",
"Created a chunk of size 1542, which is longer than the specified 1000\n",
"Created a chunk of size 1183, which is longer than the specified 1000\n",
"Created a chunk of size 2424, which is longer than the specified 1000\n",
"Created a chunk of size 1017, which is longer than the specified 1000\n",
"Created a chunk of size 1304, which is longer than the specified 1000\n",
"Created a chunk of size 1379, which is longer than the specified 1000\n",
"Created a chunk of size 1324, which is longer than the specified 1000\n",
"Created a chunk of size 1205, which is longer than the specified 1000\n",
"Created a chunk of size 1056, which is longer than the specified 1000\n",
"Created a chunk of size 1195, which is longer than the specified 1000\n",
"Created a chunk of size 3608, which is longer than the specified 1000\n",
"Created a chunk of size 1058, which is longer than the specified 1000\n",
"Created a chunk of size 1075, which is longer than the specified 1000\n",
"Created a chunk of size 1217, which is longer than the specified 1000\n",
"Created a chunk of size 1109, which is longer than the specified 1000\n",
"Created a chunk of size 1440, which is longer than the specified 1000\n",
"Created a chunk of size 1046, which is longer than the specified 1000\n",
"Created a chunk of size 1220, which is longer than the specified 1000\n",
"Created a chunk of size 1403, which is longer than the specified 1000\n",
"Created a chunk of size 1241, which is longer than the specified 1000\n",
"Created a chunk of size 1427, which is longer than the specified 1000\n",
"Created a chunk of size 1049, which is longer than the specified 1000\n",
"Created a chunk of size 1580, which is longer than the specified 1000\n",
"Created a chunk of size 1565, which is longer than the specified 1000\n",
"Created a chunk of size 1131, which is longer than the specified 1000\n",
"Created a chunk of size 1425, which is longer than the specified 1000\n",
"Created a chunk of size 1054, which is longer than the specified 1000\n",
"Created a chunk of size 1027, which is longer than the specified 1000\n",
"Created a chunk of size 2559, which is longer than the specified 1000\n",
"Created a chunk of size 1028, which is longer than the specified 1000\n",
"Created a chunk of size 1382, which is longer than the specified 1000\n",
"Created a chunk of size 1888, which is longer than the specified 1000\n",
"Created a chunk of size 1475, which is longer than the specified 1000\n",
"Created a chunk of size 1652, which is longer than the specified 1000\n",
"Created a chunk of size 1891, which is longer than the specified 1000\n",
"Created a chunk of size 1899, which is longer than the specified 1000\n",
"Created a chunk of size 1021, which is longer than the specified 1000\n",
"Created a chunk of size 1085, which is longer than the specified 1000\n",
"Created a chunk of size 1854, which is longer than the specified 1000\n",
"Created a chunk of size 1672, which is longer than the specified 1000\n",
"Created a chunk of size 2537, which is longer than the specified 1000\n",
"Created a chunk of size 1251, which is longer than the specified 1000\n",
"Created a chunk of size 1734, which is longer than the specified 1000\n",
"Created a chunk of size 1642, which is longer than the specified 1000\n",
"Created a chunk of size 1376, which is longer than the specified 1000\n",
"Created a chunk of size 1253, which is longer than the specified 1000\n",
"Created a chunk of size 1642, which is longer than the specified 1000\n",
"Created a chunk of size 1419, which is longer than the specified 1000\n",
"Created a chunk of size 1438, which is longer than the specified 1000\n",
"Created a chunk of size 1427, which is longer than the specified 1000\n",
"Created a chunk of size 1684, which is longer than the specified 1000\n",
"Created a chunk of size 1760, which is longer than the specified 1000\n",
"Created a chunk of size 1157, which is longer than the specified 1000\n",
"Created a chunk of size 2504, which is longer than the specified 1000\n",
"Created a chunk of size 1082, which is longer than the specified 1000\n",
"Created a chunk of size 2268, which is longer than the specified 1000\n",
"Created a chunk of size 1784, which is longer than the specified 1000\n",
"Created a chunk of size 1311, which is longer than the specified 1000\n",
"Created a chunk of size 2972, which is longer than the specified 1000\n",
"Created a chunk of size 1144, which is longer than the specified 1000\n",
"Created a chunk of size 1825, which is longer than the specified 1000\n",
"Created a chunk of size 1508, which is longer than the specified 1000\n",
"Created a chunk of size 2901, which is longer than the specified 1000\n",
"Created a chunk of size 1715, which is longer than the specified 1000\n",
"Created a chunk of size 1062, which is longer than the specified 1000\n",
"Created a chunk of size 1206, which is longer than the specified 1000\n",
"Created a chunk of size 1102, which is longer than the specified 1000\n",
"Created a chunk of size 1184, which is longer than the specified 1000\n",
"Created a chunk of size 1002, which is longer than the specified 1000\n",
"Created a chunk of size 1065, which is longer than the specified 1000\n",
"Created a chunk of size 1871, which is longer than the specified 1000\n",
"Created a chunk of size 1754, which is longer than the specified 1000\n",
"Created a chunk of size 2413, which is longer than the specified 1000\n",
"Created a chunk of size 1771, which is longer than the specified 1000\n",
"Created a chunk of size 2054, which is longer than the specified 1000\n",
"Created a chunk of size 2000, which is longer than the specified 1000\n",
"Created a chunk of size 2061, which is longer than the specified 1000\n",
"Created a chunk of size 1066, which is longer than the specified 1000\n",
"Created a chunk of size 1419, which is longer than the specified 1000\n",
"Created a chunk of size 1368, which is longer than the specified 1000\n",
"Created a chunk of size 1008, which is longer than the specified 1000\n",
"Created a chunk of size 1227, which is longer than the specified 1000\n",
"Created a chunk of size 1745, which is longer than the specified 1000\n",
"Created a chunk of size 2296, which is longer than the specified 1000\n",
"Created a chunk of size 1083, which is longer than the specified 1000\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"3477\n"
]
}
],
"source": [
"from langchain.text_splitter import CharacterTextSplitter\n",
"\n",
"text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)\n",
"texts = text_splitter.split_documents(docs)\n",
"print(f\"{len(texts)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then embed chunks and upload them to the DeepLake.\n",
"\n",
"This can take several minutes. "
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"OpenAIEmbeddings(client=<class 'openai.api_resources.embedding.Embedding'>, model='text-embedding-ada-002', document_model_name='text-embedding-ada-002', query_model_name='text-embedding-ada-002', embedding_ctx_length=8191, openai_api_key=None, openai_organization=None, allowed_special=set(), disallowed_special='all', chunk_size=1000, max_retries=6)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from langchain.embeddings.openai import OpenAIEmbeddings\n",
"\n",
"embeddings = OpenAIEmbeddings()\n",
"embeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"from langchain.vectorstores import DeepLake\n",
"\n",
"db = DeepLake.from_documents(texts, embeddings, dataset_path=f\"hub://{DEEPLAKE_ACCOUNT_NAME}/langchain-code\")\n",
"db"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Question Answering\n",
"First load the dataset, construct the retriever, then construct the Conversational Chain"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"-"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"This dataset can be visualized in Jupyter Notebook by ds.visualize() or at https://app.activeloop.ai/user_name/langchain-code\n",
"\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"hub://user_name/langchain-code loaded successfully.\n",
"\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Deep Lake Dataset in hub://user_name/langchain-code already exists, loading from the storage\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset(path='hub://user_name/langchain-code', read_only=True, tensors=['embedding', 'ids', 'metadata', 'text'])\n",
"\n",
" tensor htype shape dtype compression\n",
" ------- ------- ------- ------- ------- \n",
" embedding generic (3477, 1536) float32 None \n",
" ids text (3477, 1) str None \n",
" metadata json (3477, 1) str None \n",
" text text (3477, 1) str None \n"
]
}
],
"source": [
"db = DeepLake(dataset_path=f\"hub://{DEEPLAKE_ACCOUNT_NAME}/langchain-code\", read_only=True, embedding_function=embeddings)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"retriever = db.as_retriever()\n",
"retriever.search_kwargs['distance_metric'] = 'cos'\n",
"retriever.search_kwargs['fetch_k'] = 20\n",
"retriever.search_kwargs['maximal_marginal_relevance'] = True\n",
"retriever.search_kwargs['k'] = 20"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also specify user defined functions using [Deep Lake filters](https://docs.deeplake.ai/en/latest/deeplake.core.dataset.html#deeplake.core.dataset.Dataset.filter)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def filter(x):\n",
" # filter based on source code\n",
" if 'something' in x['text'].data()['value']:\n",
" return False\n",
" \n",
" # filter based on path e.g. extension\n",
" metadata = x['metadata'].data()['value']\n",
" return 'only_this' in metadata['source'] or 'also_that' in metadata['source']\n",
"\n",
"### turn on below for custom filtering\n",
"# retriever.search_kwargs['filter'] = filter"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"from langchain.chat_models import ChatOpenAI\n",
"from langchain.chains import ConversationalRetrievalChain\n",
"\n",
"model = ChatOpenAI(model='gpt-3.5-turbo') # 'ada' 'gpt-3.5-turbo' 'gpt-4',\n",
"qa = ConversationalRetrievalChain.from_llm(model,retriever=retriever)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"questions = [\n",
" \"What is the class hierarchy?\",\n",
" # \"What classes are derived from the Chain class?\",\n",
" # \"What classes and functions in the ./langchain/utilities/ forlder are not covered by unit tests?\",\n",
" # \"What one improvement do you propose in code in relation to the class herarchy for the Chain class?\",\n",
"] \n",
"chat_history = []\n",
"\n",
"for question in questions: \n",
" result = qa({\"question\": question, \"chat_history\": chat_history})\n",
" chat_history.append((question, result['answer']))\n",
" print(f\"-> **Question**: {question} \\n\")\n",
" print(f\"**Answer**: {result['answer']} \\n\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"tags": []
},
"source": [
"-> **Question**: What is the class hierarchy? \n",
"\n",
"**Answer**: There are several class hierarchies in the provided code, so I'll list a few:\n",
"\n",
"1. `BaseModel` -> `ConstitutionalPrinciple`: `ConstitutionalPrinciple` is a subclass of `BaseModel`.\n",
"2. `BasePromptTemplate` -> `StringPromptTemplate`, `AIMessagePromptTemplate`, `BaseChatPromptTemplate`, `ChatMessagePromptTemplate`, `ChatPromptTemplate`, `HumanMessagePromptTemplate`, `MessagesPlaceholder`, `SystemMessagePromptTemplate`, `FewShotPromptTemplate`, `FewShotPromptWithTemplates`, `Prompt`, `PromptTemplate`: All of these classes are subclasses of `BasePromptTemplate`.\n",
"3. `APIChain`, `Chain`, `MapReduceDocumentsChain`, `MapRerankDocumentsChain`, `RefineDocumentsChain`, `StuffDocumentsChain`, `HypotheticalDocumentEmbedder`, `LLMChain`, `LLMBashChain`, `LLMCheckerChain`, `LLMMathChain`, `LLMRequestsChain`, `PALChain`, `QAWithSourcesChain`, `VectorDBQAWithSourcesChain`, `VectorDBQA`, `SQLDatabaseChain`: All of these classes are subclasses of `Chain`.\n",
"4. `BaseLoader`: `BaseLoader` is a subclass of `ABC`.\n",
"5. `BaseTracer` -> `ChainRun`, `LLMRun`, `SharedTracer`, `ToolRun`, `Tracer`, `TracerException`, `TracerSession`: All of these classes are subclasses of `BaseTracer`.\n",
"6. `OpenAIEmbeddings`, `HuggingFaceEmbeddings`, `CohereEmbeddings`, `JinaEmbeddings`, `LlamaCppEmbeddings`, `HuggingFaceHubEmbeddings`, `TensorflowHubEmbeddings`, `SagemakerEndpointEmbeddings`, `HuggingFaceInstructEmbeddings`, `SelfHostedEmbeddings`, `SelfHostedHuggingFaceEmbeddings`, `SelfHostedHuggingFaceInstructEmbeddings`, `FakeEmbeddings`, `AlephAlphaAsymmetricSemanticEmbedding`, `AlephAlphaSymmetricSemanticEmbedding`: All of these classes are subclasses of `BaseLLM`. \n",
"\n",
"\n",
"-> **Question**: What classes are derived from the Chain class? \n",
"\n",
"**Answer**: There are multiple classes that are derived from the Chain class. Some of them are:\n",
"- APIChain\n",
"- AnalyzeDocumentChain\n",
"- ChatVectorDBChain\n",
"- CombineDocumentsChain\n",
"- ConstitutionalChain\n",
"- ConversationChain\n",
"- GraphQAChain\n",
"- HypotheticalDocumentEmbedder\n",
"- LLMChain\n",
"- LLMCheckerChain\n",
"- LLMRequestsChain\n",
"- LLMSummarizationCheckerChain\n",
"- MapReduceChain\n",
"- OpenAPIEndpointChain\n",
"- PALChain\n",
"- QAWithSourcesChain\n",
"- RetrievalQA\n",
"- RetrievalQAWithSourcesChain\n",
"- SequentialChain\n",
"- SQLDatabaseChain\n",
"- TransformChain\n",
"- VectorDBQA\n",
"- VectorDBQAWithSourcesChain\n",
"\n",
"There might be more classes that are derived from the Chain class as it is possible to create custom classes that extend the Chain class.\n",
"\n",
"\n",
"-> **Question**: What classes and functions in the ./langchain/utilities/ forlder are not covered by unit tests? \n",
"\n",
"**Answer**: All classes and functions in the `./langchain/utilities/` folder seem to have unit tests written for them. \n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
@@ -18,31 +18,13 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Define OpenAI embeddings, Deep Lake multi-modal vector store api and authenticate. For full documentation of Deep Lake please follow https://docs.activeloop.ai/ and API reference https://docs.deeplake.ai/en/latest/"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"from langchain.embeddings.openai import OpenAIEmbeddings\n",
"from langchain.vectorstores import DeepLake\n",
"Define OpenAI embeddings, Deep Lake multi-modal vector store api and authenticate. For full documentation of Deep Lake please follow [docs](https://docs.activeloop.ai/) and [API reference](https://docs.deeplake.ai/en/latest/).\n",
"\n",
"os.environ['OPENAI_API_KEY']='sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'\n",
"embeddings = OpenAIEmbeddings()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Authenticate into Deep Lake if you want to create your own dataset and publish it. You can get an API key from the platform at https://app.activeloop.ai"
"Authenticate into Deep Lake if you want to create your own dataset and publish it. You can get an API key from the [platform](https://app.activeloop.ai)"
]
},
{
@@ -51,7 +33,15 @@
"metadata": {},
"outputs": [],
"source": [
"!activeloop login -t <TOKEN>"
"import os\n",
"import getpass\n",
"\n",
"from langchain.embeddings.openai import OpenAIEmbeddings\n",
"from langchain.vectorstores import DeepLake\n",
"\n",
"os.environ['OPENAI_API_KEY'] = getpass.getpass('OpenAI API Key:')\n",
"os.environ['ACTIVELOOP_TOKEN'] = getpass.getpass('Activeloop Token:')\n",
"embeddings = OpenAIEmbeddings()"
]
},
{
@@ -143,15 +133,35 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"-"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"This dataset can be visualized in Jupyter Notebook by ds.visualize() or at https://app.activeloop.ai/davitbun/twitter-algorithm\n",
"\n",
"\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"-"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"hub://davitbun/twitter-algorithm loaded successfully.\n",
"\n"
]
@@ -184,7 +194,7 @@
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -205,7 +215,7 @@
},
{
"cell_type": "code",
"execution_count": 16,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -224,7 +234,7 @@
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -267,9 +277,14 @@
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"-> **Question**: What does favCountParams do? \n",
"\n",
"**Answer**: `favCountParams` is an optional ThriftLinearFeatureRankingParams instance that represents the parameters related to the \"favorite count\" feature in the ranking process. It is used to control the weight of the favorite count feature while ranking tweets. The favorite count is the number of times a tweet has been marked as a favorite by users, and it is considered an important signal in the ranking of tweets. By using `favCountParams`, the system can adjust the importance of the favorite count while calculating the final ranking score of a tweet. \n",
"\n",
"-> **Question**: is it Likes + Bookmarks, or not clear from the code?\n",
"\n",
"**Answer**: From the provided code, it is not clear if the favorite count metric is determined by the sum of likes and bookmarks. The favorite count is mentioned in the code, but there is no explicit reference to how it is calculated in terms of likes and bookmarks. \n",
@@ -423,7 +438,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
"version": "3.10.0"
}
},
"nbformat": 4,
+2 -2
View File
@@ -1,5 +1,5 @@
Evaluation
==============
==========
.. note::
`Conceptual Guide <https://docs.langchain.com/docs/use-cases/evaluation>`_
@@ -83,7 +83,7 @@ The existing examples we have are:
Other Examples
------------
--------------
In addition, we also have some more generic resources for evaluation.
@@ -68,12 +68,12 @@ def reduce_openapi_spec(spec: dict, dereference: bool = True) -> ReducedOpenAPIS
I was hoping https://openapi.tools/ would have some useful bits
to this end, but doesn't seem so.
"""
# 1. Consider only get, post endpoints.
# 1. Consider only get, post, patch, delete endpoints.
endpoints = [
(f"{operation_name.upper()} {route}", docs.get("description"), docs)
for route, operation in spec["paths"].items()
for operation_name, docs in operation.items()
if operation_name in ["get", "post"]
if operation_name in ["get", "post", "patch", "delete"]
]
# 2. Replace any refs so that complete docs are retrieved.
+5 -7
View File
@@ -34,12 +34,10 @@ def _get_experiment(
) -> Any:
comet_ml = import_comet_ml()
experiment = comet_ml.config.get_global_experiment()
if experiment is None:
experiment = comet_ml.Experiment( # type: ignore
workspace=workspace,
project_name=project_name,
)
experiment = comet_ml.Experiment( # type: ignore
workspace=workspace,
project_name=project_name,
)
return experiment
@@ -132,7 +130,7 @@ class CometCallbackHandler(BaseMetadataCallbackHandler, BaseCallbackHandler):
warning = (
"The comet_ml callback is currently in beta and is subject to change "
"based on updates to `langchain`. Please report any issues to "
"https://github.com/comet_ml/issue_tracking/issues with the tag "
"https://github.com/comet-ml/issue_tracking/issues with the tag "
"`langchain`."
)
comet_ml.LOGGER.warning(warning)
+9
View File
@@ -53,6 +53,15 @@ class OpenAICallbackHandler(BaseCallbackHandler):
successful_requests: int = 0
total_cost: float = 0.0
def __repr__(self) -> str:
return (
f"Tokens Used: {self.total_tokens}\n"
f"\tPrompt Tokens: {self.prompt_tokens}\n"
f"\tCompletion Tokens: {self.completion_tokens}\n"
f"Successful Requests: {self.successful_requests}\n"
f"Total Cost (USD): ${self.total_cost}"
)
@property
def always_verbose(self) -> bool:
"""Whether to call verbose callbacks even if verbose is False."""
+1 -1
View File
@@ -7,8 +7,8 @@ from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain
from langchain.chains.llm_math.prompt import PROMPT
from langchain.prompts.base import BasePromptTemplate
from langchain.python import PythonREPL
from langchain.schema import BaseLanguageModel
from langchain.utilities import PythonREPL
class LLMMathChain(Chain):
+1 -1
View File
@@ -13,8 +13,8 @@ from langchain.chains.llm import LLMChain
from langchain.chains.pal.colored_object_prompt import COLORED_OBJECT_PROMPT
from langchain.chains.pal.math_prompt import MATH_PROMPT
from langchain.prompts.base import BasePromptTemplate
from langchain.python import PythonREPL
from langchain.schema import BaseLanguageModel
from langchain.utilities import PythonREPL
class PALChain(Chain):
@@ -196,7 +196,7 @@ def load_qa_chain(
Args:
llm: Language Model to use in the chain.
chain_type: Type of document combining chain to use. Should be one of "stuff",
"map_reduce", and "refine".
"map_reduce", "map_rerank", and "refine".
verbose: Whether chains should be run in verbose mode or not. Note that this
applies to all chains that make up the final chain.
callback_manager: Callback manager to use for the chain.
+6 -5
View File
@@ -1,13 +1,13 @@
"""Chain for interacting with SQL Database."""
from __future__ import annotations
from typing import Any, Dict, List
from typing import Any, Dict, List, Optional
from pydantic import Extra, Field
from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain
from langchain.chains.sql_database.prompt import DECIDER_PROMPT, PROMPT
from langchain.chains.sql_database.prompt import DECIDER_PROMPT, PROMPT, SQL_PROMPTS
from langchain.prompts.base import BasePromptTemplate
from langchain.schema import BaseLanguageModel
from langchain.sql_database import SQLDatabase
@@ -28,7 +28,7 @@ class SQLDatabaseChain(Chain):
"""LLM wrapper to use."""
database: SQLDatabase = Field(exclude=True)
"""SQL Database to connect to."""
prompt: BasePromptTemplate = PROMPT
prompt: Optional[BasePromptTemplate] = None
"""Prompt to use to translate natural language to SQL."""
top_k: int = 5
"""Number of results to return from the query"""
@@ -65,8 +65,9 @@ class SQLDatabaseChain(Chain):
return [self.output_key, "intermediate_steps"]
def _call(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
llm_chain = LLMChain(llm=self.llm, prompt=self.prompt)
input_text = f"{inputs[self.input_key]} \nSQLQuery:"
prompt = self.prompt or SQL_PROMPTS.get(self.database.dialect, PROMPT)
llm_chain = LLMChain(llm=self.llm, prompt=prompt)
input_text = f"{inputs[self.input_key]}\nSQLQuery:"
self.callback_manager.on_text(input_text, verbose=self.verbose)
# If not present, then defaults to None which is all tables.
table_names_to_use = inputs.get("table_names_to_use")
+147
View File
@@ -2,6 +2,7 @@
from langchain.output_parsers.list import CommaSeparatedListOutputParser
from langchain.prompts.prompt import PromptTemplate
_DEFAULT_TEMPLATE = """Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. Unless the user specifies in his question a specific number of examples he wishes to obtain, always limit your query to at most {top_k} results. You can order the results by a relevant column to return the most interesting examples in the database.
Never query for all the columns from a specific table, only ask for a the few relevant columns given the question.
@@ -38,3 +39,149 @@ DECIDER_PROMPT = PromptTemplate(
template=_DECIDER_TEMPLATE,
output_parser=CommaSeparatedListOutputParser(),
)
_mssql_prompt = """You are an MS SQL expert. Given an input question, first create a syntactically correct MS SQL query to run, then look at the results of the query and return the answer to the input question.
Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the TOP clause as per MS SQL. You can order the results to return the most informative data in the database.
Never query for all columns from a table. You must query only the columns that are needed to answer the question. Wrap each column name in square brackets ([]) to denote them as delimited identifiers.
Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Use the following format:
Question: "Question here"
SQLQuery: "SQL Query to run"
SQLResult: "Result of the SQLQuery"
Answer: "Final answer here"
Only use the following tables:
{table_info}
Question: {input}"""
MSSQL_PROMPT = PromptTemplate(
input_variables=["input", "table_info", "top_k"], template=_mssql_prompt
)
_mysql_prompt = """You are a MySQL expert. Given an input question, first create a syntactically correct MySQL query to run, then look at the results of the query and return the answer to the input question.
Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the LIMIT clause as per MySQL. You can order the results to return the most informative data in the database.
Never query for all columns from a table. You must query only the columns that are needed to answer the question. Wrap each column name in backticks (`) to denote them as delimited identifiers.
Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Use the following format:
Question: "Question here"
SQLQuery: "SQL Query to run"
SQLResult: "Result of the SQLQuery"
Answer: "Final answer here"
Only use the following tables:
{table_info}
Question: {input}"""
MYSQL_PROMPT = PromptTemplate(
input_variables=["input", "table_info", "top_k"],
template=_mysql_prompt,
)
_mariadb_prompt = """You are a MariaDB expert. Given an input question, first create a syntactically correct MariaDB query to run, then look at the results of the query and return the answer to the input question.
Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the LIMIT clause as per MariaDB. You can order the results to return the most informative data in the database.
Never query for all columns from a table. You must query only the columns that are needed to answer the question. Wrap each column name in backticks (`) to denote them as delimited identifiers.
Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Use the following format:
Question: "Question here"
SQLQuery: "SQL Query to run"
SQLResult: "Result of the SQLQuery"
Answer: "Final answer here"
Only use the following tables:
{table_info}
Question: {input}"""
MARIADB_PROMPT = PromptTemplate(
input_variables=["input", "table_info", "top_k"],
template=_mariadb_prompt,
)
_oracle_prompt = """You are an Oracle SQL expert. Given an input question, first create a syntactically correct Oracle SQL query to run, then look at the results of the query and return the answer to the input question.
Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the FETCH FIRST n ROWS ONLY clause as per Oracle SQL. You can order the results to return the most informative data in the database.
Never query for all columns from a table. You must query only the columns that are needed to answer the question. Wrap each column name in double quotes (") to denote them as delimited identifiers.
Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Use the following format:
Question: "Question here"
SQLQuery: "SQL Query to run"
SQLResult: "Result of the SQLQuery"
Answer: "Final answer here"
Only use the following tables:
{table_info}
Question: {input}"""
ORACLE_PROMPT = PromptTemplate(
input_variables=["input", "table_info", "top_k"],
template=_oracle_prompt,
)
_postgres_prompt = """You are a PostgreSQL expert. Given an input question, first create a syntactically correct PostgreSQL query to run, then look at the results of the query and return the answer to the input question.
Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the LIMIT clause as per PostgreSQL. You can order the results to return the most informative data in the database.
Never query for all columns from a table. You must query only the columns that are needed to answer the question. Wrap each column name in double quotes (") to denote them as delimited identifiers.
Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Use the following format:
Question: "Question here"
SQLQuery: "SQL Query to run"
SQLResult: "Result of the SQLQuery"
Answer: "Final answer here"
Only use the following tables:
{table_info}
Question: {input}"""
POSTGRES_PROMPT = PromptTemplate(
input_variables=["input", "table_info", "top_k"], template=_postgres_prompt
)
_sqlite_prompt = """You are a SQLite expert. Given an input question, first create a syntactically correct SQLite query to run, then look at the results of the query and return the answer to the input question.
Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the LIMIT clause as per SQLite. You can order the results to return the most informative data in the database.
Never query for all columns from a table. You must query only the columns that are needed to answer the question. Wrap each column name in double quotes (") to denote them as delimited identifiers.
Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Use the following format:
Question: "Question here"
SQLQuery: "SQL Query to run"
SQLResult: "Result of the SQLQuery"
Answer: "Final answer here"
Only use the following tables:
{table_info}
Question: {input}"""
SQLITE_PROMPT = PromptTemplate(
input_variables=["input", "table_info", "top_k"],
template=_sqlite_prompt,
)
SQL_PROMPTS = {
"mssql": MSSQL_PROMPT,
"mysql": MYSQL_PROMPT,
"mariadb": MARIADB_PROMPT,
"oracle": ORACLE_PROMPT,
"postgresql": POSTGRES_PROMPT,
"sqlite": SQLITE_PROMPT,
}
+2 -1
View File
@@ -1,5 +1,6 @@
from langchain.chat_models.anthropic import ChatAnthropic
from langchain.chat_models.azure_openai import AzureChatOpenAI
from langchain.chat_models.openai import ChatOpenAI
from langchain.chat_models.promptlayer_openai import PromptLayerChatOpenAI
__all__ = ["ChatOpenAI", "AzureChatOpenAI", "PromptLayerChatOpenAI"]
__all__ = ["ChatOpenAI", "AzureChatOpenAI", "PromptLayerChatOpenAI", "ChatAnthropic"]
+139
View File
@@ -0,0 +1,139 @@
from typing import Any, Dict, List, Optional
from pydantic import Extra
from langchain.chat_models.base import BaseChatModel
from langchain.llms.anthropic import _AnthropicCommon
from langchain.schema import (
AIMessage,
BaseMessage,
ChatGeneration,
ChatMessage,
ChatResult,
HumanMessage,
SystemMessage,
)
class ChatAnthropic(BaseChatModel, _AnthropicCommon):
r"""Wrapper around Anthropic's large language model.
To use, you should have the ``anthropic`` python package installed, and the
environment variable ``ANTHROPIC_API_KEY`` set with your API key, or pass
it as a named parameter to the constructor.
Example:
.. code-block:: python
import anthropic
from langchain.llms import Anthropic
model = ChatAnthropic(model="<model_name>", anthropic_api_key="my-api-key")
"""
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
@property
def _llm_type(self) -> str:
"""Return type of chat model."""
return "anthropic-chat"
def _convert_one_message_to_text(self, message: BaseMessage) -> str:
if isinstance(message, ChatMessage):
message_text = f"\n\n{message.role.capitalize()}: {message.content}"
elif isinstance(message, HumanMessage):
message_text = f"{self.HUMAN_PROMPT} {message.content}"
elif isinstance(message, AIMessage):
message_text = f"{self.AI_PROMPT} {message.content}"
elif isinstance(message, SystemMessage):
message_text = f"{self.HUMAN_PROMPT} <admin>{message.content}</admin>"
else:
raise ValueError(f"Got unknown type {message}")
return message_text
def _convert_messages_to_text(self, messages: List[BaseMessage]) -> str:
"""Format a list of strings into a single string with necessary newlines.
Args:
messages (List[BaseMessage]): List of BaseMessage to combine.
Returns:
str: Combined string with necessary newlines.
"""
return "".join(
self._convert_one_message_to_text(message) for message in messages
)
def _convert_messages_to_prompt(self, messages: List[BaseMessage]) -> str:
"""Format a list of messages into a full prompt for the Anthropic model
Args:
messages (List[BaseMessage]): List of BaseMessage to combine.
Returns:
str: Combined string with necessary HUMAN_PROMPT and AI_PROMPT tags.
"""
if not self.AI_PROMPT:
raise NameError("Please ensure the anthropic package is loaded")
if not isinstance(messages[-1], AIMessage):
messages.append(AIMessage(content=""))
text = self._convert_messages_to_text(messages)
return (
text.rstrip()
) # trim off the trailing ' ' that might come from the "Assistant: "
def _generate(
self, messages: List[BaseMessage], stop: Optional[List[str]] = None
) -> ChatResult:
prompt = self._convert_messages_to_prompt(messages)
params: Dict[str, Any] = {"prompt": prompt, **self._default_params}
if stop:
params["stop_sequences"] = stop
if self.streaming:
completion = ""
stream_resp = self.client.completion_stream(**params)
for data in stream_resp:
delta = data["completion"][len(completion) :]
completion = data["completion"]
self.callback_manager.on_llm_new_token(
delta,
verbose=self.verbose,
)
else:
response = self.client.completion(**params)
completion = response["completion"]
message = AIMessage(content=completion)
return ChatResult(generations=[ChatGeneration(message=message)])
async def _agenerate(
self, messages: List[BaseMessage], stop: Optional[List[str]] = None
) -> ChatResult:
prompt = self._convert_messages_to_prompt(messages)
params: Dict[str, Any] = {"prompt": prompt, **self._default_params}
if stop:
params["stop_sequences"] = stop
if self.streaming:
completion = ""
stream_resp = await self.client.acompletion_stream(**params)
async for data in stream_resp:
delta = data["completion"][len(completion) :]
completion = data["completion"]
if self.callback_manager.is_async:
await self.callback_manager.on_llm_new_token(
delta,
verbose=self.verbose,
)
else:
self.callback_manager.on_llm_new_token(
delta,
verbose=self.verbose,
)
else:
response = await self.client.acompletion(**params)
completion = response["completion"]
message = AIMessage(content=completion)
return ChatResult(generations=[ChatGeneration(message=message)])
+4 -4
View File
@@ -32,8 +32,8 @@ logger = logging.getLogger(__file__)
def _create_retry_decorator(llm: ChatOpenAI) -> Callable[[Any], Any]:
import openai
min_seconds = 4
max_seconds = 10
min_seconds = 1
max_seconds = 60
# Wait 2^x * 1 second between each retry starting with
# 4 seconds, then up to 10 seconds, then 10 seconds afterwards
return retry(
@@ -199,8 +199,8 @@ class ChatOpenAI(BaseChatModel):
def _create_retry_decorator(self) -> Callable[[Any], Any]:
import openai
min_seconds = 4
max_seconds = 10
min_seconds = 1
max_seconds = 60
# Wait 2^x * 1 second between each retry starting with
# 4 seconds, then up to 10 seconds, then 10 seconds afterwards
return retry(
+6
View File
@@ -27,6 +27,7 @@ from langchain.document_loaders.evernote import EverNoteLoader
from langchain.document_loaders.facebook_chat import FacebookChatLoader
from langchain.document_loaders.gcs_directory import GCSDirectoryLoader
from langchain.document_loaders.gcs_file import GCSFileLoader
from langchain.document_loaders.git import GitLoader
from langchain.document_loaders.gitbook import GitbookLoader
from langchain.document_loaders.googledrive import GoogleDriveLoader
from langchain.document_loaders.gutenberg import GutenbergLoader
@@ -55,6 +56,7 @@ from langchain.document_loaders.roam import RoamLoader
from langchain.document_loaders.s3_directory import S3DirectoryLoader
from langchain.document_loaders.s3_file import S3FileLoader
from langchain.document_loaders.sitemap import SitemapLoader
from langchain.document_loaders.slack_directory import SlackDirectoryLoader
from langchain.document_loaders.srt import SRTLoader
from langchain.document_loaders.telegram import TelegramChatLoader
from langchain.document_loaders.text import TextLoader
@@ -63,6 +65,7 @@ from langchain.document_loaders.unstructured import (
UnstructuredFileLoader,
)
from langchain.document_loaders.url import UnstructuredURLLoader
from langchain.document_loaders.url_playwright import PlaywrightURLLoader
from langchain.document_loaders.url_selenium import SeleniumURLLoader
from langchain.document_loaders.web_base import WebBaseLoader
from langchain.document_loaders.whatsapp_chat import WhatsAppChatLoader
@@ -81,6 +84,7 @@ __all__ = [
"UnstructuredFileIOLoader",
"UnstructuredURLLoader",
"SeleniumURLLoader",
"PlaywrightURLLoader",
"DirectoryLoader",
"NotionDirectoryLoader",
"NotionDBLoader",
@@ -138,4 +142,6 @@ __all__ = [
"DuckDBLoader",
"BigQueryLoader",
"BiliBiliLoader",
"SlackDirectoryLoader",
"GitLoader",
]
+87
View File
@@ -0,0 +1,87 @@
import os
from typing import Callable, List, Optional
from langchain.docstore.document import Document
from langchain.document_loaders.base import BaseLoader
class GitLoader(BaseLoader):
"""Loads files from a Git repository into a list of documents.
Repository can be local on disk available at `repo_path`,
or remote at `clone_url` that will be cloned to `repo_path`.
Currently supports only text files.
Each document represents one file in the repository. The `path` points to
the local Git repository, and the `branch` specifies the branch to load
files from. By default, it loads from the `main` branch.
"""
def __init__(
self,
repo_path: str,
clone_url: Optional[str] = None,
branch: Optional[str] = "main",
file_filter: Optional[Callable[[str], bool]] = None,
):
self.repo_path = repo_path
self.clone_url = clone_url
self.branch = branch
self.file_filter = file_filter
def load(self) -> List[Document]:
try:
from git import Blob, Repo # type: ignore
except ImportError as ex:
raise ImportError(
"Could not import git python package. "
"Please install it with `pip install GitPython`."
) from ex
if not os.path.exists(self.repo_path) and self.clone_url is None:
raise ValueError(f"Path {self.repo_path} does not exist")
elif self.clone_url:
repo = Repo.clone_from(self.clone_url, self.repo_path)
repo.git.checkout(self.branch)
else:
repo = Repo(self.repo_path)
repo.git.checkout(self.branch)
docs: List[Document] = []
for item in repo.tree().traverse():
if not isinstance(item, Blob):
continue
file_path = os.path.join(self.repo_path, item.path)
ignored_files = repo.ignored([file_path])
if len(ignored_files):
continue
# uses filter to skip files
if self.file_filter and not self.file_filter(file_path):
continue
rel_file_path = os.path.relpath(file_path, self.repo_path)
try:
with open(file_path, "rb") as f:
content = f.read()
file_type = os.path.splitext(item.name)[1]
# loads only text files
try:
text_content = content.decode("utf-8")
except UnicodeDecodeError:
continue
metadata = {
"file_path": rel_file_path,
"file_name": item.name,
"file_type": file_type,
}
doc = Document(page_content=text_content, metadata=metadata)
docs.append(doc)
except Exception as e:
print(f"Error reading file {file_path}: {e}")
return docs
@@ -0,0 +1,112 @@
"""Loader for documents from a Slack export."""
import json
import zipfile
from pathlib import Path
from typing import Dict, List, Optional
from langchain.docstore.document import Document
from langchain.document_loaders.base import BaseLoader
class SlackDirectoryLoader(BaseLoader):
"""Loader for loading documents from a Slack directory dump."""
def __init__(self, zip_path: str, workspace_url: Optional[str] = None):
"""Initialize the SlackDirectoryLoader.
Args:
zip_path (str): The path to the Slack directory dump zip file.
workspace_url (Optional[str]): The Slack workspace URL.
Including the URL will turn
sources into links. Defaults to None.
"""
self.zip_path = Path(zip_path)
self.workspace_url = workspace_url
self.channel_id_map = self._get_channel_id_map(self.zip_path)
@staticmethod
def _get_channel_id_map(zip_path: Path) -> Dict[str, str]:
"""Get a dictionary mapping channel names to their respective IDs."""
with zipfile.ZipFile(zip_path, "r") as zip_file:
try:
with zip_file.open("channels.json", "r") as f:
channels = json.load(f)
return {channel["name"]: channel["id"] for channel in channels}
except KeyError:
return {}
def load(self) -> List[Document]:
"""Load and return documents from the Slack directory dump."""
docs = []
with zipfile.ZipFile(self.zip_path, "r") as zip_file:
for channel_path in zip_file.namelist():
channel_name = Path(channel_path).parent.name
if not channel_name:
continue
if channel_path.endswith(".json"):
messages = self._read_json(zip_file, channel_path)
for message in messages:
document = self._convert_message_to_document(
message, channel_name
)
docs.append(document)
return docs
def _read_json(self, zip_file: zipfile.ZipFile, file_path: str) -> List[dict]:
"""Read JSON data from a zip subfile."""
with zip_file.open(file_path, "r") as f:
data = json.load(f)
return data
def _convert_message_to_document(
self, message: dict, channel_name: str
) -> Document:
"""
Convert a message to a Document object.
Args:
message (dict): A message in the form of a dictionary.
channel_name (str): The name of the channel the message belongs to.
Returns:
Document: A Document object representing the message.
"""
text = message.get("text", "")
metadata = self._get_message_metadata(message, channel_name)
return Document(
page_content=text,
metadata=metadata,
)
def _get_message_metadata(self, message: dict, channel_name: str) -> dict:
"""Create and return metadata for a given message and channel."""
timestamp = message.get("ts", "")
user = message.get("user", "")
source = self._get_message_source(channel_name, user, timestamp)
return {
"source": source,
"channel": channel_name,
"timestamp": timestamp,
"user": user,
}
def _get_message_source(self, channel_name: str, user: str, timestamp: str) -> str:
"""
Get the message source as a string.
Args:
channel_name (str): The name of the channel the message belongs to.
user (str): The user ID who sent the message.
timestamp (str): The timestamp of the message.
Returns:
str: The message source.
"""
if self.workspace_url:
channel_id = self.channel_id_map.get(channel_name, "")
return (
f"{self.workspace_url}/archives/{channel_id}"
+ f"/p{timestamp.replace('.', '')}"
)
else:
return f"{channel_name} - {user} - {timestamp}"
@@ -0,0 +1,87 @@
"""Loader that uses Playwright to load a page, then uses unstructured to load the html.
"""
import logging
from typing import List, Optional
from langchain.docstore.document import Document
from langchain.document_loaders.base import BaseLoader
logger = logging.getLogger(__file__)
class PlaywrightURLLoader(BaseLoader):
"""Loader that uses Playwright and to load a page and unstructured to load the html.
This is useful for loading pages that require javascript to render.
Attributes:
urls (List[str]): List of URLs to load.
continue_on_failure (bool): If True, continue loading other URLs on failure.
headless (bool): If True, the browser will run in headless mode.
"""
def __init__(
self,
urls: List[str],
continue_on_failure: bool = True,
headless: bool = True,
remove_selectors: Optional[List[str]] = None,
):
"""Load a list of URLs using Playwright and unstructured."""
try:
import playwright # noqa:F401
except ImportError:
raise ValueError(
"playwright package not found, please install it with "
"`pip install playwright`"
)
try:
import unstructured # noqa:F401
except ImportError:
raise ValueError(
"unstructured package not found, please install it with "
"`pip install unstructured`"
)
self.urls = urls
self.continue_on_failure = continue_on_failure
self.headless = headless
self.remove_selectors = remove_selectors
def load(self) -> List[Document]:
"""Load the specified URLs using Playwright and create Document instances.
Returns:
List[Document]: A list of Document instances with loaded content.
"""
from playwright.sync_api import sync_playwright
from unstructured.partition.html import partition_html
docs: List[Document] = list()
with sync_playwright() as p:
browser = p.chromium.launch(headless=self.headless)
for url in self.urls:
try:
page = browser.new_page()
page.goto(url)
for selector in self.remove_selectors or []:
element = page.locator(selector)
if element.is_visible():
element.evaluate("element => element.remove()")
page_source = page.content()
elements = partition_html(text=page_source)
text = "\n\n".join([str(el) for el in elements])
metadata = {"source": url}
docs.append(Document(page_content=text, metadata=metadata))
except Exception as e:
if self.continue_on_failure:
logger.error(
f"Error fetching or processing {url}, exception: {e}"
)
else:
raise e
browser.close()
return docs
+90 -82
View File
@@ -1,15 +1,100 @@
"""Wrapper around Anthropic APIs."""
import re
from typing import Any, Dict, Generator, List, Mapping, Optional
from typing import Any, Callable, Dict, Generator, List, Mapping, Optional
from pydantic import Extra, root_validator
from pydantic import BaseModel, Extra, root_validator
from langchain.llms.base import LLM
from langchain.utils import get_from_dict_or_env
class Anthropic(LLM):
r"""Wrapper around Anthropic large language models.
class _AnthropicCommon(BaseModel):
client: Any = None #: :meta private:
model: str = "claude-v1"
"""Model name to use."""
max_tokens_to_sample: int = 256
"""Denotes the number of tokens to predict per generation."""
temperature: Optional[float] = None
"""A non-negative float that tunes the degree of randomness in generation."""
top_k: Optional[int] = None
"""Number of most likely tokens to consider at each step."""
top_p: Optional[float] = None
"""Total probability mass of tokens to consider at each step."""
streaming: bool = False
"""Whether to stream the results."""
anthropic_api_key: Optional[str] = None
HUMAN_PROMPT: Optional[str] = None
AI_PROMPT: Optional[str] = None
count_tokens: Optional[Callable[[str], int]] = None
@root_validator()
def validate_environment(cls, values: Dict) -> Dict:
"""Validate that api key and python package exists in environment."""
anthropic_api_key = get_from_dict_or_env(
values, "anthropic_api_key", "ANTHROPIC_API_KEY"
)
try:
import anthropic
values["client"] = anthropic.Client(anthropic_api_key)
values["HUMAN_PROMPT"] = anthropic.HUMAN_PROMPT
values["AI_PROMPT"] = anthropic.AI_PROMPT
values["count_tokens"] = anthropic.count_tokens
except ImportError:
raise ValueError(
"Could not import anthropic python package. "
"Please it install it with `pip install anthropic`."
)
return values
@property
def _default_params(self) -> Mapping[str, Any]:
"""Get the default parameters for calling Anthropic API."""
d = {
"max_tokens_to_sample": self.max_tokens_to_sample,
"model": self.model,
}
if self.temperature is not None:
d["temperature"] = self.temperature
if self.top_k is not None:
d["top_k"] = self.top_k
if self.top_p is not None:
d["top_p"] = self.top_p
return d
@property
def _identifying_params(self) -> Mapping[str, Any]:
"""Get the identifying parameters."""
return {**{}, **self._default_params}
def _get_anthropic_stop(self, stop: Optional[List[str]] = None) -> List[str]:
if not self.HUMAN_PROMPT or not self.AI_PROMPT:
raise NameError("Please ensure the anthropic package is loaded")
if stop is None:
stop = []
# Never want model to invent new turns of Human / Assistant dialog.
stop.extend([self.HUMAN_PROMPT])
return stop
def get_num_tokens(self, text: str) -> int:
"""Calculate number of tokens."""
if not self.count_tokens:
raise NameError("Please ensure the anthropic package is loaded")
return self.count_tokens(text)
class Anthropic(LLM, _AnthropicCommon):
r"""Wrapper around Anthropic's large language models.
To use, you should have the ``anthropic`` python package installed, and the
environment variable ``ANTHROPIC_API_KEY`` set with your API key, or pass
@@ -32,73 +117,15 @@ class Anthropic(LLM):
response = model(prompt)
"""
client: Any #: :meta private:
model: str = "claude-v1"
"""Model name to use."""
max_tokens_to_sample: int = 256
"""Denotes the number of tokens to predict per generation."""
temperature: float = 1.0
"""A non-negative float that tunes the degree of randomness in generation."""
top_k: int = 0
"""Number of most likely tokens to consider at each step."""
top_p: float = 1
"""Total probability mass of tokens to consider at each step."""
streaming: bool = False
"""Whether to stream the results."""
anthropic_api_key: Optional[str] = None
HUMAN_PROMPT: Optional[str] = None
AI_PROMPT: Optional[str] = None
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
@root_validator()
def validate_environment(cls, values: Dict) -> Dict:
"""Validate that api key and python package exists in environment."""
anthropic_api_key = get_from_dict_or_env(
values, "anthropic_api_key", "ANTHROPIC_API_KEY"
)
try:
import anthropic
values["client"] = anthropic.Client(anthropic_api_key)
values["HUMAN_PROMPT"] = anthropic.HUMAN_PROMPT
values["AI_PROMPT"] = anthropic.AI_PROMPT
except ImportError:
raise ValueError(
"Could not import anthropic python package. "
"Please install it with `pip install anthropic`."
)
return values
@property
def _default_params(self) -> Mapping[str, Any]:
"""Get the default parameters for calling Anthropic API."""
return {
"max_tokens_to_sample": self.max_tokens_to_sample,
"temperature": self.temperature,
"top_k": self.top_k,
"top_p": self.top_p,
}
@property
def _identifying_params(self) -> Mapping[str, Any]:
"""Get the identifying parameters."""
return {**{"model": self.model}, **self._default_params}
@property
def _llm_type(self) -> str:
"""Return type of llm."""
return "anthropic"
return "anthropic-llm"
def _wrap_prompt(self, prompt: str) -> str:
if not self.HUMAN_PROMPT or not self.AI_PROMPT:
@@ -115,18 +142,6 @@ class Anthropic(LLM):
# As a last resort, wrap the prompt ourselves to emulate instruct-style.
return f"{self.HUMAN_PROMPT} {prompt}{self.AI_PROMPT} Sure, here you go:\n"
def _get_anthropic_stop(self, stop: Optional[List[str]] = None) -> List[str]:
if not self.HUMAN_PROMPT or not self.AI_PROMPT:
raise NameError("Please ensure the anthropic package is loaded")
if stop is None:
stop = []
# Never want model to invent new turns of Human / Assistant dialog.
stop.extend([self.HUMAN_PROMPT, self.AI_PROMPT])
return stop
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
r"""Call out to Anthropic's completion endpoint.
@@ -148,10 +163,8 @@ class Anthropic(LLM):
stop = self._get_anthropic_stop(stop)
if self.streaming:
stream_resp = self.client.completion_stream(
model=self.model,
prompt=self._wrap_prompt(prompt),
stop_sequences=stop,
stream=True,
**self._default_params,
)
current_completion = ""
@@ -163,7 +176,6 @@ class Anthropic(LLM):
)
return current_completion
response = self.client.completion(
model=self.model,
prompt=self._wrap_prompt(prompt),
stop_sequences=stop,
**self._default_params,
@@ -175,10 +187,8 @@ class Anthropic(LLM):
stop = self._get_anthropic_stop(stop)
if self.streaming:
stream_resp = await self.client.acompletion_stream(
model=self.model,
prompt=self._wrap_prompt(prompt),
stop_sequences=stop,
stream=True,
**self._default_params,
)
current_completion = ""
@@ -195,7 +205,6 @@ class Anthropic(LLM):
)
return current_completion
response = await self.client.acompletion(
model=self.model,
prompt=self._wrap_prompt(prompt),
stop_sequences=stop,
**self._default_params,
@@ -227,7 +236,6 @@ class Anthropic(LLM):
"""
stop = self._get_anthropic_stop(stop)
return self.client.completion_stream(
model=self.model,
prompt=self._wrap_prompt(prompt),
stop_sequences=stop,
**self._default_params,
+60 -37
View File
@@ -114,20 +114,7 @@ async def acompletion_with_retry(
class BaseOpenAI(BaseLLM):
"""Wrapper around OpenAI large language models.
To use, you should have the ``openai`` python package installed, and the
environment variable ``OPENAI_API_KEY`` set with your API key.
Any parameters that are valid to be passed to the openai.create call can be passed
in, even if not explicitly saved on this class.
Example:
.. code-block:: python
from langchain.llms import OpenAI
openai = OpenAI(model_name="text-davinci-003")
"""
"""Wrapper around OpenAI large language models."""
client: Any #: :meta private:
model_name: str = "text-davinci-003"
@@ -476,13 +463,6 @@ class BaseOpenAI(BaseLLM):
def modelname_to_contextsize(self, modelname: str) -> int:
"""Calculate the maximum number of tokens possible to generate for a model.
text-davinci-003: 4,097 tokens
text-curie-001: 2,048 tokens
text-babbage-001: 2,048 tokens
text-ada-001: 2,048 tokens
code-davinci-002: 8,000 tokens
code-cushman-001: 2,048 tokens
Args:
modelname: The modelname we want to know the context size for.
@@ -494,20 +474,37 @@ class BaseOpenAI(BaseLLM):
max_tokens = openai.modelname_to_contextsize("text-davinci-003")
"""
if modelname == "text-davinci-003":
return 4097
elif modelname == "text-curie-001":
return 2048
elif modelname == "text-babbage-001":
return 2048
elif modelname == "text-ada-001":
return 2048
elif modelname == "code-davinci-002":
return 8000
elif modelname == "code-cushman-001":
return 2048
else:
return 4097
model_token_mapping = {
"gpt-4": 8192,
"gpt-4-0314": 8192,
"gpt-4-32k": 32768,
"gpt-4-32k-0314": 32768,
"gpt-3.5-turbo": 4096,
"gpt-3.5-turbo-0301": 4096,
"text-ada-001": 2049,
"ada": 2049,
"text-babbage-001": 2040,
"babbage": 2049,
"text-curie-001": 2049,
"curie": 2049,
"davinci": 2049,
"text-davinci-003": 4097,
"text-davinci-002": 4097,
"code-davinci-002": 8001,
"code-davinci-001": 8001,
"code-cushman-002": 2048,
"code-cushman-001": 2048,
}
context_size = model_token_mapping.get(modelname, None)
if context_size is None:
raise ValueError(
f"Unknown model: {modelname}. Please provide a valid OpenAI model name."
"Known models are: " + ", ".join(model_token_mapping.keys())
)
return context_size
def max_tokens_for_prompt(self, prompt: str) -> int:
"""Calculate the maximum number of tokens possible to generate for a prompt.
@@ -531,7 +528,20 @@ class BaseOpenAI(BaseLLM):
class OpenAI(BaseOpenAI):
"""Generic OpenAI class that uses model name."""
"""Wrapper around OpenAI large language models.
To use, you should have the ``openai`` python package installed, and the
environment variable ``OPENAI_API_KEY`` set with your API key.
Any parameters that are valid to be passed to the openai.create call can be passed
in, even if not explicitly saved on this class.
Example:
.. code-block:: python
from langchain.llms import OpenAI
openai = OpenAI(model_name="text-davinci-003")
"""
@property
def _invocation_params(self) -> Dict[str, Any]:
@@ -539,7 +549,20 @@ class OpenAI(BaseOpenAI):
class AzureOpenAI(BaseOpenAI):
"""Azure specific OpenAI class that uses deployment name."""
"""Wrapper around Azure-specific OpenAI large language models.
To use, you should have the ``openai`` python package installed, and the
environment variable ``OPENAI_API_KEY`` set with your API key.
Any parameters that are valid to be passed to the openai.create call can be passed
in, even if not explicitly saved on this class.
Example:
.. code-block:: python
from langchain.llms import AzureOpenAI
openai = AzureOpenAI(model_name="text-davinci-003")
"""
deployment_name: str = ""
"""Deployment name to use."""
+51 -25
View File
@@ -3,7 +3,7 @@
Based on https://github.com/saharNooby/rwkv.cpp/blob/master/rwkv/chat_with_bot.py
https://github.com/BlinkDL/ChatRWKV/blob/main/v2/chat.py
"""
from typing import Any, Dict, List, Mapping, Optional, Set, SupportsIndex
from typing import Any, Dict, List, Mapping, Optional, Set
from pydantic import BaseModel, Extra, root_validator
@@ -58,7 +58,7 @@ class RWKV(LLM, BaseModel):
CHUNK_LEN: int = 256
"""Batch size for prompt processing."""
max_tokens_per_generation: SupportsIndex = 256
max_tokens_per_generation: int = 256
"""Maximum number of tokens to generate."""
client: Any = None #: :meta private:
@@ -69,6 +69,8 @@ class RWKV(LLM, BaseModel):
model_tokens: Any = None #: :meta private:
model_state: Any = None #: :meta private:
class Config:
"""Configuration for this pydantic object."""
@@ -139,42 +141,66 @@ class RWKV(LLM, BaseModel):
"""Return the type of llm."""
return "rwkv-4"
def rwkv_generate(self, prompt: str) -> str:
tokens = self.tokenizer.encode(prompt).ids
def run_rnn(self, _tokens: List[str], newline_adj: int = 0) -> Any:
AVOID_REPEAT_TOKENS = []
AVOID_REPEAT = ",:?!"
for i in AVOID_REPEAT:
dd = self.pipeline.encode(i)
assert len(dd) == 1
AVOID_REPEAT_TOKENS += dd
logits = None
state = None
tokens = [int(x) for x in _tokens]
self.model_tokens += tokens
occurrence = {}
out: Any = None
# Feed in the input string
while len(tokens) > 0:
logits, state = self.client.forward(tokens[: self.CHUNK_LEN], state)
out, self.model_state = self.client.forward(
tokens[: self.CHUNK_LEN], self.model_state
)
tokens = tokens[self.CHUNK_LEN :]
END_OF_LINE = 187
out[END_OF_LINE] += newline_adj # adjust \n probability
if self.model_tokens[-1] in AVOID_REPEAT_TOKENS:
out[self.model_tokens[-1]] = -999999999
return out
def rwkv_generate(self, prompt: str) -> str:
self.model_state = None
self.model_tokens = []
logits = self.run_rnn(self.tokenizer.encode(prompt).ids)
begin = len(self.model_tokens)
out_last = begin
occurrence: Dict = {}
decoded = ""
for i in range(self.max_tokens_per_generation):
token = self.pipeline.sample_logits(
logits, temperature=self.temperature, top_p=self.top_p
)
if token not in occurrence:
occurrence[token] = 1
else:
occurrence[token] += 1
decoded += self.tokenizer.decode([token])
if "\n" in decoded:
break
# feed back in
logits, state = self.client.forward([token], state)
for n in occurrence:
logits[n] -= (
self.penalty_alpha_presence
+ occurrence[n] * self.penalty_alpha_frequency
)
token = self.pipeline.sample_logits(
logits, temperature=self.temperature, top_p=self.top_p
)
END_OF_TEXT = 0
if token == END_OF_TEXT:
break
if token not in occurrence:
occurrence[token] = 1
else:
occurrence[token] += 1
logits = self.run_rnn([token])
xxx = self.tokenizer.decode(self.model_tokens[out_last:])
if "\ufffd" not in xxx: # avoid utf-8 display issues
decoded += xxx
out_last = begin + i + 1
if i >= self.max_tokens_per_generation - 100:
break
return decoded
+3 -25
View File
@@ -1,26 +1,4 @@
"""Mock Python REPL."""
import sys
from io import StringIO
from typing import Dict, Optional
"""For backwards compatibility."""
from langchain.utilities.python import PythonREPL
from pydantic import BaseModel, Field
class PythonREPL(BaseModel):
"""Simulates a standalone Python REPL."""
globals: Optional[Dict] = Field(default_factory=dict, alias="_globals")
locals: Optional[Dict] = Field(default_factory=dict, alias="_locals")
def run(self, command: str) -> str:
"""Run command with own globals/locals and returns anything printed."""
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
try:
exec(command, self.globals, self.locals)
sys.stdout = old_stdout
output = mystdout.getvalue()
except Exception as e:
sys.stdout = old_stdout
output = str(e)
return output
__all__ = ["PythonREPL"]
+2
View File
@@ -4,6 +4,7 @@ from langchain.retrievers.elastic_search_bm25 import ElasticSearchBM25Retriever
from langchain.retrievers.metal import MetalRetriever
from langchain.retrievers.pinecone_hybrid_search import PineconeHybridSearchRetriever
from langchain.retrievers.remote_retriever import RemoteLangChainRetriever
from langchain.retrievers.svm import SVMRetriever
from langchain.retrievers.tfidf import TFIDFRetriever
from langchain.retrievers.time_weighted_retriever import (
TimeWeightedVectorStoreRetriever,
@@ -20,4 +21,5 @@ __all__ = [
"WeaviateHybridSearchRetriever",
"DataberryRetriever",
"TimeWeightedVectorStoreRetriever",
"SVMRetriever",
]
+61
View File
@@ -0,0 +1,61 @@
"""SMV Retriever.
Largely based on
https://github.com/karpathy/randomfun/blob/master/knn_vs_svm.ipynb"""
from __future__ import annotations
from typing import Any, List
import numpy as np
from pydantic import BaseModel
from langchain.embeddings.base import Embeddings
from langchain.schema import BaseRetriever, Document
def create_index(contexts: List[str], embeddings: Embeddings) -> np.ndarray:
return np.array([embeddings.embed_query(split) for split in contexts])
class SVMRetriever(BaseRetriever, BaseModel):
embeddings: Embeddings
index: Any
texts: List[str]
k: int = 4
class Config:
"""Configuration for this pydantic object."""
arbitrary_types_allowed = True
@classmethod
def from_texts(
cls, texts: List[str], embeddings: Embeddings, **kwargs: Any
) -> SVMRetriever:
index = create_index(texts, embeddings)
return cls(embeddings=embeddings, index=index, texts=texts, **kwargs)
def get_relevant_documents(self, query: str) -> List[Document]:
from sklearn import svm
query_embeds = np.array(self.embeddings.embed_query(query))
x = np.concatenate([query_embeds[None, ...], self.index])
y = np.zeros(x.shape[0])
y[0] = 1
clf = svm.LinearSVC(
class_weight="balanced", verbose=False, max_iter=10000, tol=1e-6, C=0.1
)
clf.fit(x, y)
similarities = clf.decision_function(x)
sorted_ix = np.argsort(-similarities)
top_k_results = []
for row in sorted_ix[1 : self.k + 1]:
top_k_results.append(Document(page_content=self.texts[row - 1]))
return top_k_results
async def aget_relevant_documents(self, query: str) -> List[Document]:
raise NotImplementedError
@@ -50,7 +50,7 @@ class TimeWeightedVectorStoreRetriever(BaseRetriever, BaseModel):
def _get_combined_score(
self,
document: Document,
vector_salience: Optional[float],
vector_relevance: Optional[float],
current_time: datetime,
) -> float:
"""Return the combined score for a document."""
@@ -63,8 +63,8 @@ class TimeWeightedVectorStoreRetriever(BaseRetriever, BaseModel):
for key in self.other_score_keys:
if key in document.metadata:
score += document.metadata[key]
if vector_salience is not None:
score += vector_salience
if vector_relevance is not None:
score += vector_relevance
print(score)
return score
@@ -75,10 +75,10 @@ class TimeWeightedVectorStoreRetriever(BaseRetriever, BaseModel):
query, **self.search_kwargs
)
results = {}
for fetched_doc, cosine_distance in docs_and_scores:
for fetched_doc, relevance in docs_and_scores:
buffer_idx = fetched_doc.metadata["buffer_idx"]
doc = self.memory_stream[buffer_idx]
results[buffer_idx] = (doc, (1 - cosine_distance))
results[buffer_idx] = (doc, relevance)
return results
def get_relevant_documents(self, query: str) -> List[Document]:
@@ -91,8 +91,8 @@ class TimeWeightedVectorStoreRetriever(BaseRetriever, BaseModel):
# If a doc is considered salient, update the salience score
docs_and_scores.update(self.get_salient_docs(query))
rescored_docs = [
(doc, self._get_combined_score(doc, salience, current_time))
for doc, salience in docs_and_scores.values()
(doc, self._get_combined_score(doc, relevance, current_time))
for doc, relevance in docs_and_scores.values()
]
rescored_docs.sort(key=lambda x: x[1], reverse=True)
result = []
+1 -1
View File
@@ -7,8 +7,8 @@ from typing import Dict, Optional
from pydantic import Field, root_validator
from langchain.python import PythonREPL
from langchain.tools.base import BaseTool
from langchain.utilities import PythonREPL
def _get_default_python_repl() -> PythonREPL:
+16 -14
View File
@@ -1,6 +1,7 @@
# flake8: noqa
"""Tools for interacting with a SQL database."""
from pydantic import BaseModel, Extra, Field, validator
from pydantic import BaseModel, Extra, Field, validator, root_validator
from typing import Any, Dict
from langchain.chains.llm import LLMChain
from langchain.prompts import PromptTemplate
@@ -81,28 +82,29 @@ class QueryCheckerTool(BaseSQLDatabaseTool, BaseTool):
template: str = QUERY_CHECKER
llm: BaseLLM
llm_chain: LLMChain = Field(
default_factory=lambda: LLMChain(
llm=QueryCheckerTool.llm,
prompt=PromptTemplate(
template=QueryCheckerTool.template, input_variables=["query", "dialect"]
),
)
)
llm_chain: LLMChain = Field(init=False)
name = "query_checker_sql_db"
description = """
Use this tool to double check if your query is correct before executing it.
Always use this tool before executing a query with query_sql_db!
"""
@validator("llm_chain")
def validate_llm_chain_input_variables(cls, llm_chain: LLMChain) -> LLMChain:
"""Make sure the LLM chain has the correct input variables."""
if llm_chain.prompt.input_variables != ["query", "dialect"]:
@root_validator(pre=True)
def initialize_llm_chain(cls, values: Dict[str, Any]) -> Dict[str, Any]:
if "llm_chain" not in values:
values["llm_chain"] = LLMChain(
llm=values.get("llm"),
prompt=PromptTemplate(
template=QUERY_CHECKER, input_variables=["query", "dialect"]
),
)
if values["llm_chain"].prompt.input_variables != ["query", "dialect"]:
raise ValueError(
"LLM chain for QueryCheckerTool must have input variables ['query', 'dialect']"
)
return llm_chain
return values
def _run(self, query: str) -> str:
"""Use the LLM to check the query."""
+2 -2
View File
@@ -1,5 +1,4 @@
"""General utilities."""
from langchain.python import PythonREPL
from langchain.requests import TextRequestsWrapper
from langchain.utilities.apify import ApifyWrapper
from langchain.utilities.bash import BashProcess
@@ -7,6 +6,7 @@ from langchain.utilities.bing_search import BingSearchAPIWrapper
from langchain.utilities.google_search import GoogleSearchAPIWrapper
from langchain.utilities.google_serper import GoogleSerperAPIWrapper
from langchain.utilities.openweathermap import OpenWeatherMapAPIWrapper
from langchain.utilities.python import PythonREPL
from langchain.utilities.searx_search import SearxSearchWrapper
from langchain.utilities.serpapi import SerpAPIWrapper
from langchain.utilities.wikipedia import WikipediaAPIWrapper
@@ -16,7 +16,6 @@ __all__ = [
"ApifyWrapper",
"BashProcess",
"TextRequestsWrapper",
"PythonREPL",
"GoogleSearchAPIWrapper",
"GoogleSerperAPIWrapper",
"WolframAlphaAPIWrapper",
@@ -25,4 +24,5 @@ __all__ = [
"BingSearchAPIWrapper",
"WikipediaAPIWrapper",
"OpenWeatherMapAPIWrapper",
"PythonREPL",
]
+2 -2
View File
@@ -13,8 +13,8 @@ class OpenWeatherMapAPIWrapper(BaseModel):
Docs for using:
1. Go to OpenWeatherMap and sign up for an API key
3. Save your API KEY into OPENWEATHERMAP_API_KEY env variable
4. pip install wolframalpha
2. Save your API KEY into OPENWEATHERMAP_API_KEY env variable
3. pip install pyowm
"""
owm: Any
+25
View File
@@ -0,0 +1,25 @@
import sys
from io import StringIO
from typing import Dict, Optional
from pydantic import BaseModel, Field
class PythonREPL(BaseModel):
"""Simulates a standalone Python REPL."""
globals: Optional[Dict] = Field(default_factory=dict, alias="_globals")
locals: Optional[Dict] = Field(default_factory=dict, alias="_locals")
def run(self, command: str) -> str:
"""Run command with own globals/locals and returns anything printed."""
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
try:
exec(command, self.globals, self.locals)
sys.stdout = old_stdout
output = mystdout.getvalue()
except Exception as e:
sys.stdout = old_stdout
output = str(e)
return output
+5 -5
View File
@@ -153,7 +153,7 @@ class VectorStore(ABC):
return await asyncio.get_event_loop().run_in_executor(None, func)
def max_marginal_relevance_search(
self, query: str, k: int = 4, fetch_k: int = 20
self, query: str, k: int = 4, fetch_k: int = 20, **kwargs: Any
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance.
@@ -171,18 +171,18 @@ class VectorStore(ABC):
raise NotImplementedError
async def amax_marginal_relevance_search(
self, query: str, k: int = 4, fetch_k: int = 20
self, query: str, k: int = 4, fetch_k: int = 20, **kwargs: Any
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance."""
# This is a temporary workaround to make the similarity search
# asynchronous. The proper solution is to make the similarity search
# asynchronous in the vector store implementations.
func = partial(self.max_marginal_relevance_search, query, k, fetch_k)
func = partial(self.max_marginal_relevance_search, query, k, fetch_k, **kwargs)
return await asyncio.get_event_loop().run_in_executor(None, func)
def max_marginal_relevance_search_by_vector(
self, embedding: List[float], k: int = 4, fetch_k: int = 20
self, embedding: List[float], k: int = 4, fetch_k: int = 20, **kwargs: Any
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance.
@@ -200,7 +200,7 @@ class VectorStore(ABC):
raise NotImplementedError
async def amax_marginal_relevance_search_by_vector(
self, embedding: List[float], k: int = 4, fetch_k: int = 20
self, embedding: List[float], k: int = 4, fetch_k: int = 20, **kwargs: Any
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance."""
raise NotImplementedError
+2
View File
@@ -193,6 +193,7 @@ class Chroma(VectorStore):
k: int = 4,
fetch_k: int = 20,
filter: Optional[Dict[str, str]] = None,
**kwargs: Any,
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance.
Maximal marginal relevance optimizes for similarity to query AND diversity
@@ -227,6 +228,7 @@ class Chroma(VectorStore):
k: int = 4,
fetch_k: int = 20,
filter: Optional[Dict[str, str]] = None,
**kwargs: Any,
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance.
Maximal marginal relevance optimizes for similarity to query AND diversity
+10 -6
View File
@@ -97,6 +97,7 @@ class DeepLake(VectorStore):
read_only: Optional[bool] = False,
ingestion_batch_size: int = 1024,
num_workers: int = 4,
**kwargs: Any,
) -> None:
"""Initialize with Deep Lake client."""
self.ingestion_batch_size = ingestion_batch_size
@@ -113,14 +114,18 @@ class DeepLake(VectorStore):
self._deeplake = deeplake
if deeplake.exists(dataset_path, token=token):
self.ds = deeplake.load(dataset_path, token=token, read_only=read_only)
self.ds = deeplake.load(
dataset_path, token=token, read_only=read_only, **kwargs
)
logger.warning(
f"Deep Lake Dataset in {dataset_path} already exists, "
f"loading from the storage"
)
self.ds.summary()
else:
self.ds = deeplake.empty(dataset_path, token=token, overwrite=True)
self.ds = deeplake.empty(
dataset_path, token=token, overwrite=True, **kwargs
)
with self.ds:
self.ds.create_tensor(
@@ -386,7 +391,7 @@ class DeepLake(VectorStore):
)
def max_marginal_relevance_search_by_vector(
self, embedding: List[float], k: int = 4, fetch_k: int = 20
self, embedding: List[float], k: int = 4, fetch_k: int = 20, **kwargs: Any
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance.
Maximal marginal relevance optimizes for similarity to query AND diversity
@@ -406,7 +411,7 @@ class DeepLake(VectorStore):
)
def max_marginal_relevance_search(
self, query: str, k: int = 4, fetch_k: int = 20
self, query: str, k: int = 4, fetch_k: int = 20, **kwargs: Any
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance.
Maximal marginal relevance optimizes for similarity to query AND diversity
@@ -466,8 +471,7 @@ class DeepLake(VectorStore):
DeepLake: Deep Lake dataset.
"""
deeplake_dataset = cls(
dataset_path=dataset_path,
embedding_function=embedding,
dataset_path=dataset_path, embedding_function=embedding, **kwargs
)
deeplake_dataset.add_texts(texts=texts, metadatas=metadatas, ids=ids)
return deeplake_dataset
@@ -200,8 +200,8 @@ class ElasticVectorSearch(VectorStore, ABC):
"""
embedding = self.embedding.embed_query(query)
script_query = _default_script_query(embedding)
response = self.client.search(index=self.index_name, query=script_query)
hits = [hit["_source"] for hit in response["hits"]["hits"][:k]]
response = self.client.search(index=self.index_name, query=script_query, size=k)
hits = [hit["_source"] for hit in response["hits"]["hits"]]
documents = [
Document(page_content=hit["text"], metadata=hit["metadata"]) for hit in hits
]
+20 -8
View File
@@ -227,7 +227,7 @@ class FAISS(VectorStore):
return [doc for doc, _ in docs_and_scores]
def max_marginal_relevance_search_by_vector(
self, embedding: List[float], k: int = 4, fetch_k: int = 20
self, embedding: List[float], k: int = 4, fetch_k: int = 20, **kwargs: Any
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance.
@@ -262,7 +262,11 @@ class FAISS(VectorStore):
return docs
def max_marginal_relevance_search(
self, query: str, k: int = 4, fetch_k: int = 20
self,
query: str,
k: int = 4,
fetch_k: int = 20,
**kwargs: Any,
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance.
@@ -404,40 +408,48 @@ class FAISS(VectorStore):
**kwargs,
)
def save_local(self, folder_path: str) -> None:
def save_local(self, folder_path: str, index_name: str = "index") -> None:
"""Save FAISS index, docstore, and index_to_docstore_id to disk.
Args:
folder_path: folder path to save index, docstore,
and index_to_docstore_id to.
index_name: for saving with a specific index file name
"""
path = Path(folder_path)
path.mkdir(exist_ok=True, parents=True)
# save index separately since it is not picklable
faiss = dependable_faiss_import()
faiss.write_index(self.index, str(path / "index.faiss"))
faiss.write_index(
self.index, str(path / "{index_name}.faiss".format(index_name=index_name))
)
# save docstore and index_to_docstore_id
with open(path / "index.pkl", "wb") as f:
with open(path / "{index_name}.pkl".format(index_name=index_name), "wb") as f:
pickle.dump((self.docstore, self.index_to_docstore_id), f)
@classmethod
def load_local(cls, folder_path: str, embeddings: Embeddings) -> FAISS:
def load_local(
cls, folder_path: str, embeddings: Embeddings, index_name: str = "index"
) -> FAISS:
"""Load FAISS index, docstore, and index_to_docstore_id to disk.
Args:
folder_path: folder path to load index, docstore,
and index_to_docstore_id from.
embeddings: Embeddings to use when generating queries
index_name: for saving with a specific index file name
"""
path = Path(folder_path)
# load index separately since it is not picklable
faiss = dependable_faiss_import()
index = faiss.read_index(str(path / "index.faiss"))
index = faiss.read_index(
str(path / "{index_name}.faiss".format(index_name=index_name))
)
# load docstore and index_to_docstore_id
with open(path / "index.pkl", "rb") as f:
with open(path / "{index_name}.pkl".format(index_name=index_name), "rb") as f:
docstore, index_to_docstore_id = pickle.load(f)
return cls(embeddings.embed_query, index, docstore, index_to_docstore_id)
+1 -1
View File
@@ -218,7 +218,7 @@ class Pinecone(VectorStore):
else:
raise ValueError(
f"Index '{index_name}' not found in your Pinecone project. "
"Did you mean one of the following indexes: {', '.join(indexes)}"
f"Did you mean one of the following indexes: {', '.join(indexes)}"
)
for i in range(0, len(texts), batch_size):
+7 -3
View File
@@ -81,7 +81,7 @@ class Qdrant(VectorStore):
ids = [uuid.uuid4().hex for _ in texts]
self.client.upsert(
collection_name=self.collection_name,
points=rest.Batch(
points=rest.Batch.construct(
ids=ids,
vectors=[self.embedding_function(text) for text in texts],
payloads=self._build_payloads(
@@ -147,7 +147,11 @@ class Qdrant(VectorStore):
]
def max_marginal_relevance_search(
self, query: str, k: int = 4, fetch_k: int = 20
self,
query: str,
k: int = 4,
fetch_k: int = 20,
**kwargs: Any,
) -> List[Document]:
"""Return docs selected using the maximal marginal relevance.
@@ -314,7 +318,7 @@ class Qdrant(VectorStore):
client.upsert(
collection_name=collection_name,
points=rest.Batch(
points=rest.Batch.construct(
ids=[uuid.uuid4().hex for _ in texts],
vectors=embeddings,
payloads=cls._build_payloads(
+20 -13
View File
@@ -70,6 +70,9 @@ class Redis(VectorStore):
redis_url: str,
index_name: str,
embedding_function: Callable,
content_key: str = "content",
metadata_key: str = "metadata",
vector_key: str = "content_vector",
**kwargs: Any,
):
"""Initialize with necessary components."""
@@ -92,6 +95,9 @@ class Redis(VectorStore):
raise ValueError(f"Redis failed to connect: {e}")
self.client = redis_client
self.content_key = content_key
self.metadata_key = metadata_key
self.vector_key = vector_key
def add_texts(
self,
@@ -112,11 +118,11 @@ class Redis(VectorStore):
pipeline.hset(
key,
mapping={
"content": text,
"content_vector": np.array(
self.content_key: text,
self.vector_key: np.array(
self.embedding_function(text), dtype=np.float32
).tobytes(),
"metadata": json.dumps(metadata),
self.metadata_key: json.dumps(metadata),
},
)
ids.append(key)
@@ -191,8 +197,8 @@ class Redis(VectorStore):
embedding = self.embedding_function(query)
# Prepare the Query
return_fields = ["metadata", "content", "vector_score"]
vector_field = "content_vector"
return_fields = [self.metadata_key, self.content_key, "vector_score"]
vector_field = self.vector_key
hybrid_fields = "*"
base_query = (
f"{hybrid_fields}=>[KNN {k} @{vector_field} $vector AS vector_score]"
@@ -232,6 +238,9 @@ class Redis(VectorStore):
embedding: Embeddings,
metadatas: Optional[List[dict]] = None,
index_name: Optional[str] = None,
content_key: str = "content",
metadata_key: str = "metadata",
vector_key: str = "content_vector",
**kwargs: Any,
) -> Redis:
"""Construct RediSearch wrapper from raw documents.
@@ -287,10 +296,10 @@ class Redis(VectorStore):
"COSINE" # distance metric for the vectors (ex. COSINE, IP, L2)
)
schema = (
TextField(name="content"),
TextField(name="metadata"),
TextField(name=content_key),
TextField(name=metadata_key),
VectorField(
"content_vector",
vector_key,
"FLAT",
{
"TYPE": "FLOAT32",
@@ -313,11 +322,9 @@ class Redis(VectorStore):
pipeline.hset(
key,
mapping={
"content": text,
"content_vector": np.array(
embeddings[i], dtype=np.float32
).tobytes(),
"metadata": json.dumps(metadata),
content_key: text,
vector_key: np.array(embeddings[i], dtype=np.float32).tobytes(),
metadata_key: json.dumps(metadata),
},
)
pipeline.execute()
+96 -4
View File
@@ -6,9 +6,22 @@ from uuid import uuid4
from langchain.docstore.document import Document
from langchain.embeddings.base import Embeddings
from langchain.utils import get_from_dict_or_env
from langchain.vectorstores.base import VectorStore
def _default_schema(index_name: str) -> Dict:
return {
"class": index_name,
"properties": [
{
"name": "text",
"dataType": ["text"],
}
],
}
class Weaviate(VectorStore):
"""Wrapper around Weaviate vector database.
@@ -70,14 +83,24 @@ class Weaviate(VectorStore):
data_properties[key] = metadatas[i][key]
_id = get_valid_uuid(uuid4())
batch.add_data_object(data_properties, self._index_name, _id)
batch.add_data_object(
data_object=data_properties, class_name=self._index_name, uuid=_id
)
ids.append(_id)
return ids
def similarity_search(
self, query: str, k: int = 4, **kwargs: Any
) -> List[Document]:
"""Look up similar documents in weaviate."""
"""Return docs most similar to query.
Args:
query: Text to look up documents similar to.
k: Number of Documents to return. Defaults to 4.
Returns:
List of Documents most similar to the query.
"""
content: Dict[str, Any] = {"concepts": [query]}
if kwargs.get("search_distance"):
content["certainty"] = kwargs.get("search_distance")
@@ -114,5 +137,74 @@ class Weaviate(VectorStore):
metadatas: Optional[List[dict]] = None,
**kwargs: Any,
) -> Weaviate:
"""Not implemented for Weaviate yet."""
raise NotImplementedError("weaviate does not currently support `from_texts`.")
"""Construct Weaviate wrapper from raw documents.
This is a user-friendly interface that:
1. Embeds documents.
2. Creates a new index for the embeddings in the Weaviate instance.
3. Adds the documents to the newly created Weaviate index.
This is intended to be a quick way to get started.
Example:
.. code-block:: python
from langchain.vectorstores.weaviate import Weaviate
from langchain.embeddings import OpenAIEmbeddings
embeddings = OpenAIEmbeddings()
weaviate = Weaviate.from_texts(
texts,
embeddings,
weaviate_url="http://localhost:8080"
)
"""
weaviate_url = get_from_dict_or_env(kwargs, "weaviate_url", "WEAVIATE_URL")
try:
from weaviate import Client
from weaviate.util import get_valid_uuid
except ImportError:
raise ValueError(
"Could not import weaviate python package. "
"Please install it with `pip instal weaviate-client`"
)
client = Client(weaviate_url)
index_name = kwargs.get("index_name", f"LangChain_{uuid4().hex}")
embeddings = embedding.embed_documents(texts) if embedding else None
text_key = "text"
schema = _default_schema(index_name)
attributes = list(metadatas[0].keys()) if metadatas else None
# check whether the index already exists
if not client.schema.contains(schema):
client.schema.create_class(schema)
with client.batch as batch:
for i, text in enumerate(texts):
data_properties = {
text_key: text,
}
if metadatas is not None:
for key in metadatas[i].keys():
data_properties[key] = metadatas[i][key]
_id = get_valid_uuid(uuid4())
# if an embedding strategy is not provided, we let
# weaviate create the embedding. Note that this will only
# work if weaviate has been installed with a vectorizer module
# like text2vec-contextionary for example
params = {
"uuid": _id,
"data_object": data_properties,
"class_name": index_name,
}
if embeddings is not None:
params["vector"] = (embeddings[i],)
batch.add_data_object(**params)
batch.flush()
return cls(client, index_name, text_key, attributes)
Generated
+143 -119
View File
@@ -499,7 +499,7 @@ name = "authlib"
version = "1.2.0"
description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients."
category = "main"
optional = true
optional = false
python-versions = "*"
files = [
{file = "Authlib-1.2.0-py2.py3-none-any.whl", hash = "sha256:4ddf4fd6cfa75c9a460b361d4bd9dac71ffda0be879dbe4292a02e92349ad55a"},
@@ -743,7 +743,7 @@ name = "cachetools"
version = "5.3.0"
description = "Extensible memoizing collections and decorators"
category = "main"
optional = true
optional = false
python-versions = "~=3.7"
files = [
{file = "cachetools-5.3.0-py3-none-any.whl", hash = "sha256:429e1a1e845c008ea6c85aa35d4b98b65d6a9763eeef3e37e92728a12d1de9d4"},
@@ -1338,20 +1338,20 @@ files = [
[[package]]
name = "deeplake"
version = "3.2.21"
version = "3.2.22"
description = "Activeloop Deep Lake"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "deeplake-3.2.21.tar.gz", hash = "sha256:3ad6f81f666ba9e2951aff697babb845249b54dfdd72f22e3c7ef5838ae2e9d7"},
{file = "deeplake-3.2.22.tar.gz", hash = "sha256:068280561366dd1bd891d3ffda8638ec59860a23b9426815a484b0591ab467a6"},
]
[package.dependencies]
aioboto3 = {version = "10.4.0", markers = "python_version >= \"3.7\" and sys_platform != \"win32\""}
boto3 = "*"
click = "*"
humbug = ">=0.2.6"
humbug = ">=0.3.1"
nest_asyncio = {version = "*", markers = "python_version >= \"3.7\" and sys_platform != \"win32\""}
numcodecs = "*"
numpy = "*"
@@ -1955,14 +1955,14 @@ uritemplate = ">=3.0.1,<5"
[[package]]
name = "google-auth"
version = "2.17.2"
version = "2.17.3"
description = "Google Authentication Library"
category = "main"
optional = true
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
files = [
{file = "google-auth-2.17.2.tar.gz", hash = "sha256:295c80ebb95eac74003c07a696cf3ef6b414e9230ae8894f3843f8215fd2aa56"},
{file = "google_auth-2.17.2-py2.py3-none-any.whl", hash = "sha256:544536a43d44dff0f64222e4d027d124989fcb9c10979687e589e1694fba9c94"},
{file = "google-auth-2.17.3.tar.gz", hash = "sha256:ce311e2bc58b130fddf316df57c9b3943c2a7b4f6ec31de9663a9333e4064efc"},
{file = "google_auth-2.17.3-py2.py3-none-any.whl", hash = "sha256:f586b274d3eb7bd932ea424b1c702a30e0393a2e2bc4ca3eae8263ffd8be229f"},
]
[package.dependencies]
@@ -2064,14 +2064,14 @@ grpc = ["grpcio (>=1.44.0,<2.0.0dev)"]
[[package]]
name = "gptcache"
version = "0.1.8"
description = "GPT Cache, a powerful caching library that can be used to speed up and lower the cost of chat applications that rely on the LLM service. GPT Cache works as a memcache for AIGC applications, similar to how Redis works for traditional applications."
version = "0.1.9"
description = "GPTCache, a powerful caching library that can be used to speed up and lower the cost of chat applications that rely on the LLM service. GPTCache works as a memcache for AIGC applications, similar to how Redis works for traditional applications."
category = "main"
optional = true
optional = false
python-versions = ">=3.8.1"
files = [
{file = "gptcache-0.1.8-py3-none-any.whl", hash = "sha256:953662291819471e5461920c89367084f905237a8506f1a1605729f3e633f147"},
{file = "gptcache-0.1.8.tar.gz", hash = "sha256:23200cc0783776210cce85a588ae68222d522ce9456f74b7836945ebe8b15820"},
{file = "gptcache-0.1.9-py3-none-any.whl", hash = "sha256:c603dea4a6e835032875ccc21a9205bb4d8ef0f2696a8df3ac13ac3a060c4cf6"},
{file = "gptcache-0.1.9.tar.gz", hash = "sha256:b92f30e4d8bc22a017a71fb4801f469739d4c83734a874fea51ca6998ef833d4"},
]
[package.dependencies]
@@ -2954,14 +2954,14 @@ websockets = ["websockets"]
[[package]]
name = "jina-hubble-sdk"
version = "0.35.0"
version = "0.36.0"
description = "SDK for Hubble API at Jina AI."
category = "main"
optional = true
python-versions = ">=3.7.0"
files = [
{file = "jina-hubble-sdk-0.35.0.tar.gz", hash = "sha256:f0826dc6d22aa8da983e4f67af8fa5b78dd852274da71adea7a38d9620438b37"},
{file = "jina_hubble_sdk-0.35.0-py3-none-any.whl", hash = "sha256:957e4ce5e9400ee27aad7a6e728172cdcffb8bb6667e430fa3c97f000650beb3"},
{file = "jina-hubble-sdk-0.36.0.tar.gz", hash = "sha256:ba1a72c7a5c14963fdad9af1ff4c3bba26a03ddcced08111bd11a95b153249ec"},
{file = "jina_hubble_sdk-0.36.0-py3-none-any.whl", hash = "sha256:56db142147d7c72142ed1b6505020c3b4d8070b1603d07ff796e56d491dde294"},
]
[package.dependencies]
@@ -4794,14 +4794,14 @@ tests = ["pytest", "pytest-cov", "pytest-pep8"]
[[package]]
name = "packaging"
version = "23.0"
version = "23.1"
description = "Core utilities for Python packages"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
{file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
]
[[package]]
@@ -5188,14 +5188,14 @@ testing = ["pytest", "pytest-benchmark"]
[[package]]
name = "posthog"
version = "2.4.2"
version = "2.5.0"
description = "Integrate PostHog into any python application."
category = "dev"
optional = false
python-versions = "*"
files = [
{file = "posthog-2.4.2-py2.py3-none-any.whl", hash = "sha256:8c7c37de997d955aea61bf0aa0069970e71f0d9d79c9e6b3a134e6593d5aa3d6"},
{file = "posthog-2.4.2.tar.gz", hash = "sha256:652a628623aab26597e8421a7ddf9caaf19dd93cc1288901a6b23db9693d34e5"},
{file = "posthog-2.5.0-py2.py3-none-any.whl", hash = "sha256:3d3ece06c3fe4135497c239f211c82344962b93e4fd4ba5afd20bd4ad12d77be"},
{file = "posthog-2.5.0.tar.gz", hash = "sha256:7601ef75b483eb67a6229cafec02da9624f6d46df61066771ca9e3f986284fc3"},
]
[package.dependencies]
@@ -5309,6 +5309,22 @@ files = [
[package.dependencies]
wcwidth = "*"
[[package]]
name = "promptlayer"
version = "0.1.80"
description = "PromptLayer is a package to keep track of your GPT models training"
category = "dev"
optional = false
python-versions = "*"
files = [
{file = "promptlayer-0.1.80.tar.gz", hash = "sha256:1012018ed3e4bca4f0d9c9164cb00b7ca0936cba6a40d4de53e87ef08fdff62f"},
]
[package.dependencies]
langchain = "*"
openai = "*"
requests = "*"
[[package]]
name = "protobuf"
version = "3.19.6"
@@ -6228,14 +6244,14 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""}
[[package]]
name = "qdrant-client"
version = "1.1.3"
version = "1.1.4"
description = "Client library for the Qdrant vector search engine"
category = "main"
optional = true
python-versions = ">=3.7,<3.12"
files = [
{file = "qdrant_client-1.1.3-py3-none-any.whl", hash = "sha256:c95f59fb9e3e89d163517f8992ee4557eccb45c252147e11e45c608ef1c7dd29"},
{file = "qdrant_client-1.1.3.tar.gz", hash = "sha256:2b7de2b987fc456c643a06878a4150947c3d3d6c6515f6c29f6e707788daa6e7"},
{file = "qdrant_client-1.1.4-py3-none-any.whl", hash = "sha256:12ad9dba63228cc5493e137bf35c59af56d84ca3a2b088c4298825d4893c7100"},
{file = "qdrant_client-1.1.4.tar.gz", hash = "sha256:92ad225bd770fb6a7ac10f75e38f53ffebe63c7f239b02fc7d2bc993246eb74c"},
]
[package.dependencies]
@@ -6473,14 +6489,14 @@ files = [
[[package]]
name = "rich"
version = "13.3.3"
version = "13.3.4"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
category = "main"
optional = true
python-versions = ">=3.7.0"
files = [
{file = "rich-13.3.3-py3-none-any.whl", hash = "sha256:540c7d6d26a1178e8e8b37e9ba44573a3cd1464ff6348b99ee7061b95d1c6333"},
{file = "rich-13.3.3.tar.gz", hash = "sha256:dc84400a9d842b3a9c5ff74addd8eb798d155f36c1c91303888e0a66850d2a15"},
{file = "rich-13.3.4-py3-none-any.whl", hash = "sha256:22b74cae0278fd5086ff44144d3813be1cedc9115bdfabbfefd86400cb88b20a"},
{file = "rich-13.3.4.tar.gz", hash = "sha256:b5d573e13605423ec80bdd0cd5f8541f7844a0e71a13f74cf454ccb2f490708b"},
]
[package.dependencies]
@@ -6675,49 +6691,57 @@ transformers = ">=4.6.0,<5.0.0"
[[package]]
name = "sentencepiece"
version = "0.1.97"
version = "0.1.98"
description = "SentencePiece python wrapper"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "sentencepiece-0.1.97-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6f249c8f1852893be86eae66b19d522c5fb30bbad4fe2d1b07f06fdc86e1907e"},
{file = "sentencepiece-0.1.97-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09e1bc53178de70c557a9ba4fece07364b4416ce3d36570726b3372b68aea135"},
{file = "sentencepiece-0.1.97-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:667193c57fb48b238be7e3d7636cfc8da56cb5bac5559d8f0b647334e1175be8"},
{file = "sentencepiece-0.1.97-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2780531985af79c6163f63d4f200fec8a28b70b6768d2c19f70d01568a4524e8"},
{file = "sentencepiece-0.1.97-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:205050670c53ef9015e2a98cce3934bfbcf0aafaa14caa0c618dd5667bc217ee"},
{file = "sentencepiece-0.1.97-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28b183dadef8e8b6b4645c1c20692d7be0a13ecc3ec1a07b3885c8905516675f"},
{file = "sentencepiece-0.1.97-cp310-cp310-win32.whl", hash = "sha256:ee3c9dbd558d8d85bb1617087b86df6ea2b856a528669630ce6cedeb4353b823"},
{file = "sentencepiece-0.1.97-cp310-cp310-win_amd64.whl", hash = "sha256:f7dc55379e2f7dee86537180283db2e5f8418c6825fdd2fe436c724eb5604c05"},
{file = "sentencepiece-0.1.97-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ba1b4154f9144c5a7528b00aff5cffaa1a896a1c6ca53ca78b6e74cd2dae5244"},
{file = "sentencepiece-0.1.97-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac3d90aee5581e55d029d124ac11b6ae2fbae0817863b664b2f2302e966ababb"},
{file = "sentencepiece-0.1.97-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c27400f1ac46518a01c87cb7703650e4e48728649feb115d2e3f1102a946a42"},
{file = "sentencepiece-0.1.97-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6e12a166eba75994ca749aadc4a5056b91b31405f805d6de6e8914cc9741c60"},
{file = "sentencepiece-0.1.97-cp36-cp36m-win32.whl", hash = "sha256:ed85dff5c0a9b3dd1a414c7e1119f2a19e863fc3f81da525bf7f885ebc883de0"},
{file = "sentencepiece-0.1.97-cp36-cp36m-win_amd64.whl", hash = "sha256:91a19ab6f40ffbae6d6127119953d2c6a85e93d734953dbc8629fde0d21ace66"},
{file = "sentencepiece-0.1.97-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bae580e4a35a9314ff49561ac7c06574fe6afc71b821ed6bb00534e571458156"},
{file = "sentencepiece-0.1.97-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ad7262e7530c683b186672b5dd0082f82719a50a500a8cfbc4bbd7cde5bff8c"},
{file = "sentencepiece-0.1.97-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:620cee35279720016735a7c7103cddbd9b84fe5e2f098bd5e673834d69fee2b8"},
{file = "sentencepiece-0.1.97-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93b921b59914c0ec6697e8c6d5e6b44d99d1298fb1a0af56980a79ade0540c19"},
{file = "sentencepiece-0.1.97-cp37-cp37m-win32.whl", hash = "sha256:9b9a4c44a31d5f47616e9568dcf31e029b0bfa776e0a252c0b59247881598b09"},
{file = "sentencepiece-0.1.97-cp37-cp37m-win_amd64.whl", hash = "sha256:f31533cdacced56219e239d3459a003ece35116920dd64b2309d4ad047b77644"},
{file = "sentencepiece-0.1.97-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7d643c01d1cad13b9206a276bbe5bc1a468e3d7cf6a26bde7783f945277f859d"},
{file = "sentencepiece-0.1.97-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:542f1985b1ee279a92bef7740ec0781452372028ce01e15aa88df3228b197ba3"},
{file = "sentencepiece-0.1.97-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93701da21fea906dd244bf88cdbe640385a89c45d3c1812b76dbadf8782cdbcd"},
{file = "sentencepiece-0.1.97-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a51514047b964047b7fadb480d88a5e0f72c02f6ca1ba96258fbbc6e79274a94"},
{file = "sentencepiece-0.1.97-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3ae2e9b7a5b6f2aa64ec9240b0c185dabe597d0e787dc4344acfbaef1ffe0b2"},
{file = "sentencepiece-0.1.97-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:923ee4af16dbae1f2ab358ed09f8a0eb89e40a8198a8b343bf54181482342721"},
{file = "sentencepiece-0.1.97-cp38-cp38-win32.whl", hash = "sha256:fa6f2b88850b5fae3a05053658824cf9f147c8e3c3b40eb64539a976c83d8a24"},
{file = "sentencepiece-0.1.97-cp38-cp38-win_amd64.whl", hash = "sha256:5137ff0d0b1cc574751d178650ef800ff8d90bf21eb9f71e9567d4a0548940a5"},
{file = "sentencepiece-0.1.97-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f92876271a10494671431ad955bff2d6f8ea59baaf957f5ae5946aff56dfcb90"},
{file = "sentencepiece-0.1.97-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:35c227b6d55e473033db7e0ecc51b1e99e6ed7607cc08602fb5768132543c81d"},
{file = "sentencepiece-0.1.97-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1706a8a8188f7b3d4b7922db9bb00c64c4e16ee68ab4caaae79f55b3e18748c7"},
{file = "sentencepiece-0.1.97-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce61efc1862ccb18856c4aabbd930e13d5bfbb4b09b4f111081ac53a9dc62275"},
{file = "sentencepiece-0.1.97-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a78c03800ef9f02d320e0159f5768b15357f3e9ebea545c9c4ba7928ba8ba254"},
{file = "sentencepiece-0.1.97-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753b8088fd685ee787d9f54c84275ab347de558c7c4ebc6accb4c35bf7776f20"},
{file = "sentencepiece-0.1.97-cp39-cp39-win32.whl", hash = "sha256:24306fd86031c17a1a6ae92671e76a350390a3140a65620bc2843dad7db24e2a"},
{file = "sentencepiece-0.1.97-cp39-cp39-win_amd64.whl", hash = "sha256:c6641d0b7acec61fde5881ea6ebe098c169557ac9aa3bdabdf124eab5a5592bb"},
{file = "sentencepiece-0.1.97.tar.gz", hash = "sha256:c901305e0a710bbcd296f66d79e96f744e6e175b29812bd5178318437d4e1f6c"},
{file = "sentencepiece-0.1.98-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1daf0a79cd953e4830746c41e92b98a2f2e9e5ec0e90a9447aa10350e11bd027"},
{file = "sentencepiece-0.1.98-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:57911445fc91c80d59552adf8a749af9205458920a7328f3bd7d51308658bcd9"},
{file = "sentencepiece-0.1.98-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f9239785849ed1f55a825bcc282bef1a6073f7431cc535bdc658a94873652ea"},
{file = "sentencepiece-0.1.98-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:467740ef8af170e5b6cfe22c272114ed930c899c297619ac7a2ac463a13bdbac"},
{file = "sentencepiece-0.1.98-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b6f0b9ffb601e2699e265f3f20c353ec9a661e4b5f0cff08ad6c9909c0ae43e"},
{file = "sentencepiece-0.1.98-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6150ba525fac4fda76f5c4777ae300597e70cef739ed2a47cea02ff81a88873f"},
{file = "sentencepiece-0.1.98-cp310-cp310-win32.whl", hash = "sha256:58ca96d73ea0e5575e3f6a9524449c673d62e6ecee3b2ddd5bfb4f49cb315c0a"},
{file = "sentencepiece-0.1.98-cp310-cp310-win_amd64.whl", hash = "sha256:8abe5c4c034e497e69f485dcd2c0e6bc87bf0498ad5aef5f539a7d0f9eae6275"},
{file = "sentencepiece-0.1.98-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b6ed62f89c0bd25cec39a7075f6b9354fe4c240ed964e63009d77efcf29c34e9"},
{file = "sentencepiece-0.1.98-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c2d9a74986d3716dc6961e9dbae7a3b25bb1260118f098545fd963ae23252c1"},
{file = "sentencepiece-0.1.98-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f7dc2fc175623529fb60a2799748f8877cd48c4541b32cd97b8523465e88b69"},
{file = "sentencepiece-0.1.98-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64e32c55d04a2e21f0c2fda1b7a3dd108133ebfb8616b52896916bb30e4352ed"},
{file = "sentencepiece-0.1.98-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:443f32e94b18571231b02a51be173686114b5556b5edfcbf347fb63e7bd5ddc6"},
{file = "sentencepiece-0.1.98-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:558a373a8660bdff299d6c133c2a4f4fb0875e9e6fafe225b8080ecce8a405f9"},
{file = "sentencepiece-0.1.98-cp311-cp311-win32.whl", hash = "sha256:fcf100268cefe1774794b18cbaf3065e2bf988f168a387973eb1260d51198795"},
{file = "sentencepiece-0.1.98-cp311-cp311-win_amd64.whl", hash = "sha256:05b4eecbece0606883cd81ed86bb3c619680bb570b997b236533ec854d64a575"},
{file = "sentencepiece-0.1.98-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:35af00f5103a4779694fedea41b6e24947a9ed81166efe63864ab1e781d70a66"},
{file = "sentencepiece-0.1.98-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2766cd708e9fc2b5b9784a990a8b303b9e0b9a69fa482616fe86fa538daa1756"},
{file = "sentencepiece-0.1.98-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2531c0e9cc8cd404fabd856d80d695b373371c00f1fce29c06f41f3f7429d87"},
{file = "sentencepiece-0.1.98-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffcc78e80c55eab67ee3439ade493607a4e37e1f0b82b168ead3debf9eaeaabe"},
{file = "sentencepiece-0.1.98-cp36-cp36m-win32.whl", hash = "sha256:ef384b31ec7a06a9a6aba42e68435f3f3b38809aa65559ede3658cdd446a562c"},
{file = "sentencepiece-0.1.98-cp36-cp36m-win_amd64.whl", hash = "sha256:e7a828f1fe2e51d2d9e5e9b3283d4006f1891efb02a3d9303ed39ddafdd9c864"},
{file = "sentencepiece-0.1.98-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8663be00a68098f85d6cda1f7041a27de05c320e433fa730ecb1156a8304f21c"},
{file = "sentencepiece-0.1.98-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf05611089a075b78d353720ccc3a09a78e0846332cff0cc78fda8b2383626a"},
{file = "sentencepiece-0.1.98-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11f410cc7eeb3e1cfa8d92d128b568e5dc7829b7904b164499fd0209316ec2fa"},
{file = "sentencepiece-0.1.98-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5ea8fb2c68073fe25a08a178eed269ed382fba074ff2ba4de72f0f56d86630e"},
{file = "sentencepiece-0.1.98-cp37-cp37m-win32.whl", hash = "sha256:fa13a125417d28e84fbdebcaf6aa115e4177d3e93aa66b857a42e7179f515b88"},
{file = "sentencepiece-0.1.98-cp37-cp37m-win_amd64.whl", hash = "sha256:e54aa70b574eee895d184072d84e62824f404821e551a82c619c5d4320a93834"},
{file = "sentencepiece-0.1.98-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:515a971c2a157647ca0e60ce3c435f4b43cd5c9f5862159cfefa0b5b4d46d3c3"},
{file = "sentencepiece-0.1.98-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c23c3a562221bc40eaae42428fcd8e607e0f084ea8aa968ba3f1a7d0ea975807"},
{file = "sentencepiece-0.1.98-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c067ba22be8edc699f6365e01ec15046bf3563dbabfdc052ecc88e581b675cba"},
{file = "sentencepiece-0.1.98-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12c913493d6ebac86ee7ae109e368522a5a365a7b150d4d8cf845599262d2b21"},
{file = "sentencepiece-0.1.98-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:720f827dc69ee24951ea4f51b9fb69cc56890a7190fc52c2c0da2545caab1760"},
{file = "sentencepiece-0.1.98-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:918b4caf18b2f73c302c4e197d1c2dafba39eb143d16b4590930b45f15042fdd"},
{file = "sentencepiece-0.1.98-cp38-cp38-win32.whl", hash = "sha256:2d50edfc4649a1566b64f1a8402cd607e1893bf8e368732337d83f00df62d3fa"},
{file = "sentencepiece-0.1.98-cp38-cp38-win_amd64.whl", hash = "sha256:7425b727c3d6b3b7bad0005a3be316078b254180b712d73955ff08cae3f6a385"},
{file = "sentencepiece-0.1.98-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:00b2becbd7b98905a6de9695cf8682abe0d510ab0198e23c7d86fb2b793b6ae0"},
{file = "sentencepiece-0.1.98-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f71c4bdedb797052fb2ccad0871c2409bf6f812cb6b651917c55f9e8eced07f"},
{file = "sentencepiece-0.1.98-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7287461d2346f530928ab187f0834cb15ddfbc4553592cacdcb6470364739ec6"},
{file = "sentencepiece-0.1.98-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:472ad943eaffcb6871ece56c7850388e7b8722f520ba73c93e7a6ef965453221"},
{file = "sentencepiece-0.1.98-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7e23aaf9d5afd91ca13550968bd17f0c17b0966823188ad2a50c51544cf8ed"},
{file = "sentencepiece-0.1.98-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b0ce9efc790c209cce2463058855dceb21438213d2ff13cb5a565d52a7efe25"},
{file = "sentencepiece-0.1.98-cp39-cp39-win32.whl", hash = "sha256:8b50cbe8e46204eff7aa5a663af5652c45e7807aa560d08e5f5b10c60e795a49"},
{file = "sentencepiece-0.1.98-cp39-cp39-win_amd64.whl", hash = "sha256:14841bd2a3d77c4dbba58f02488c374866551e428d755e8d473d82325a0a94f3"},
{file = "sentencepiece-0.1.98.tar.gz", hash = "sha256:947cf0a4b8a480510d560a922f8256f34e93984a86cf870be4d05731f59fb28d"},
]
[[package]]
@@ -6809,40 +6833,40 @@ files = [
[[package]]
name = "spacy"
version = "3.5.1"
version = "3.5.2"
description = "Industrial-strength Natural Language Processing (NLP) in Python"
category = "main"
optional = true
python-versions = ">=3.6"
files = [
{file = "spacy-3.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:428925faf26a7c7a9564431d7a505af7816b22b5c68b240bbe073ae928e9ef36"},
{file = "spacy-3.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:63bc19f4b5fa5f806698e7d16828cacbfefd0ab44f770e0b2a1a0509dd07f6f9"},
{file = "spacy-3.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f5a1073cc7bb9896624682f6a5ab29c2d3d2d935cb36f88b25cbb01f12b57ef"},
{file = "spacy-3.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb9af95d1c06e23e89731d61f3fa5f28583684e10bd3d29d9e7bb161ffe02df9"},
{file = "spacy-3.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:dec30afd4916cb4f02449ccec94e2f8a3eb929686e9f96bd74f51f4c07d75577"},
{file = "spacy-3.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d2e256c44241b9a2ac3204659891d332d370dfa0e39917254574bc1ffdfb079"},
{file = "spacy-3.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d337054213f837ae295431a35638bb469c4e4796f6c5ff17d2dd18d545615a0e"},
{file = "spacy-3.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab9bbd8e34bfabd506f74d2739c6a4e47c899fd7d3f1648bbffde0c16b8a339d"},
{file = "spacy-3.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5ab0e2b406b3953c5975adcc4ac09bdc8fbcb20dd9a2a8ea2774b4d83106c24"},
{file = "spacy-3.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:9cbec19e55fcdb6e4be220c6b6335af96c374a7ac76dffb15f9da95c9d39ce62"},
{file = "spacy-3.5.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92b590c1c50eb421b6aaa0373b37fbdfb290a130771728e8d06159517cc120d"},
{file = "spacy-3.5.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2525bc1ec9e784597365daf245f65b9ca9fd8a25fa96f9c7a6b7bfd5048b87bc"},
{file = "spacy-3.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e3f113cbf4331052622ec5c27e581751beba5c62e9af2f21d2798db50a41e04c"},
{file = "spacy-3.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c9e93851a210ccc59112243fc74dcac82191383e7654731c2842326f7d1eb1d"},
{file = "spacy-3.5.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ca30de7f82ab97e054a457eeb424060091b609114ebf7c90ef1775cac40fe04"},
{file = "spacy-3.5.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3083ccbcc52102bf53ff797233ea90a7d2b01c3853d811272ebc63de0aff4df5"},
{file = "spacy-3.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1e795b3f85f229ea54ff7f91e15fb5d7afacec5e5fca302dca1bc3224547e4f0"},
{file = "spacy-3.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fa47b47142883891252dda54da7a79055cb4e703914a90928c2fbe5bd058f4ed"},
{file = "spacy-3.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d92387989fe9c3bebd60faaeb590206e34ca9c421a52460a058ee5050d9fc8c6"},
{file = "spacy-3.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1067f7ef0e87341cea2c3187f9b96965f4b0c076a87e22c1aac45ea5586f856"},
{file = "spacy-3.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ab781021e896aae4a0f9f0a5424c75fc5d6ef4c20f56fd115e8605484567fd6"},
{file = "spacy-3.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:c43b2597649549e84ceda7b658479e28c6e66995ebd9a61e0193b0c0dceffe50"},
{file = "spacy-3.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9a389f850ab1a3f17e6beb90fd92533bad21a372979496b01a99ae1a9f3e96e3"},
{file = "spacy-3.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8ca295e8381a0273b6543c1389275af98878a43ab70c781630277e49ce978f"},
{file = "spacy-3.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62a458c88c296234471fe540fe5d1ec763701d2f556870512143de8559286c0"},
{file = "spacy-3.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04ad29a306d1879cafe23e4e8a613046f62d81ceeb70e6fcab3fddb4b0fedf7f"},
{file = "spacy-3.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:c4be3508c9b4109afe3e5c7fdf91b9d7153ec2227f24270625caee96651fa9e2"},
{file = "spacy-3.5.1.tar.gz", hash = "sha256:811ae1468c58b97fc9aa31187d6b55317784258f0a47ebf69d81cab639e3fa15"},
{file = "spacy-3.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f5ac232dda9aae44caef639243695702f2e15d78c2b0e05ed6d3368386b61bd9"},
{file = "spacy-3.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9b7a1b43b778ee8f61dfac34d47b795ee1cf1d8dc26f66c178f5900fca8dd331"},
{file = "spacy-3.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b76dc9a14dc36863828d982354c025a833ee89a763c22bb83ef6ff51da4656"},
{file = "spacy-3.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1af8aae58c201ebc038be74109b8a88fbc417375122b92c82af4d7373e1dbe76"},
{file = "spacy-3.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:ee629cb45e9cb378bb0bce7d740758d1761f04da1e1463c496bddd93a1738c9b"},
{file = "spacy-3.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e3f6a44d697e8e8a304fc2ed46f3e9c564ae7b148c0500ad35c56cda285e1b41"},
{file = "spacy-3.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eb0b7ddc37ff28ba2e59fc3b88f411d570ac41b64477f56500b4ffdae582d242"},
{file = "spacy-3.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5fb40480dd611d31149b6b122c99a22d46e15d6b367da36e41dda73eaaf3036"},
{file = "spacy-3.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:572d01288e40bb57adf1a41949776e005bb0d3c19e9e830f5718355ac891ba44"},
{file = "spacy-3.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:7ac4cde010cd09775f659e57ad005276f4c52657af039769433beefa161e0288"},
{file = "spacy-3.5.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52056e71e8e1c35911494493cc3395e0d1fa4a9c7113ffe210424694dc9b7a09"},
{file = "spacy-3.5.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d296e80cb69861eaa4fd3f9f7f4be6ac812f6e711e47ee4b61f4c41df0ab2d0"},
{file = "spacy-3.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:97aa6b954964f5bc5d5bb6c12e3de81c053e66c7f5e214d5e4fde8ef467cb2de"},
{file = "spacy-3.5.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ddc1f35289b848a544bc2429497a5b11b0c60c01220efea38dcbe9e2779894c6"},
{file = "spacy-3.5.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcdb5005230af1dd269b19b41af25c657b88932b2b371be63321e079c9f04c8"},
{file = "spacy-3.5.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2bf6a44e5a87fa4a8be57cd31494609af2bc9d249a2f477d00ea8f279b59751"},
{file = "spacy-3.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4f8c5e070bef0e4cd897d0c2f54e78bd386e83afd1147221ca22ca1c3a1eea1"},
{file = "spacy-3.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:655a2a19065a129468b47a3d56e96e8404e952f6219d42f3248e6075a0e43eaa"},
{file = "spacy-3.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dcd10594641306cd697540fa68ea24aa5400556f113aa229834e803f7d8fb9cf"},
{file = "spacy-3.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:728d84a2d47d53a54a05934790ff089d8ff09982ba5ada5ab3fd89c70fc1db63"},
{file = "spacy-3.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3b06f48231c537fd05db60d050baaecbdf4322a8cc58cb540787ce8817d3817"},
{file = "spacy-3.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:4f1c1c1283da6c8206e06adc459a96abf9e3515b3c8e08e4ff722a80c5692d6f"},
{file = "spacy-3.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8ecdba339249873d7f70af5da075aaac0acc15dd93db4167c4a0514a5219e2c2"},
{file = "spacy-3.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9eb26967fd66e756ba3c90f61d3803de845255b6a0b7a08a5b4e044d9b02029d"},
{file = "spacy-3.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b1a4ed3ece6d763415e596ac312e1f6870171e557b6d26daf35a0206cb76f2a"},
{file = "spacy-3.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a168f76105c21dc4aab9f2dc9c4b1662f86910cb7799b40dd5aac8840888f017"},
{file = "spacy-3.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:f0e687e6f1d40f3ed5f250f7242cf0c1058aa396338c341fa595700b57410f43"},
{file = "spacy-3.5.2.tar.gz", hash = "sha256:22c1ffaab285b7477003d4b5b038414cc32468a690d479015b9a698c531c813b"},
]
[package.dependencies]
@@ -6869,24 +6893,24 @@ wasabi = ">=0.9.1,<1.2.0"
[package.extras]
apple = ["thinc-apple-ops (>=0.1.0.dev0,<1.0.0)"]
cuda = ["cupy (>=5.0.0b4,<12.0.0)"]
cuda-autodetect = ["cupy-wheel (>=11.0.0,<12.0.0)"]
cuda100 = ["cupy-cuda100 (>=5.0.0b4,<12.0.0)"]
cuda101 = ["cupy-cuda101 (>=5.0.0b4,<12.0.0)"]
cuda102 = ["cupy-cuda102 (>=5.0.0b4,<12.0.0)"]
cuda110 = ["cupy-cuda110 (>=5.0.0b4,<12.0.0)"]
cuda111 = ["cupy-cuda111 (>=5.0.0b4,<12.0.0)"]
cuda112 = ["cupy-cuda112 (>=5.0.0b4,<12.0.0)"]
cuda113 = ["cupy-cuda113 (>=5.0.0b4,<12.0.0)"]
cuda114 = ["cupy-cuda114 (>=5.0.0b4,<12.0.0)"]
cuda115 = ["cupy-cuda115 (>=5.0.0b4,<12.0.0)"]
cuda116 = ["cupy-cuda116 (>=5.0.0b4,<12.0.0)"]
cuda117 = ["cupy-cuda117 (>=5.0.0b4,<12.0.0)"]
cuda11x = ["cupy-cuda11x (>=11.0.0,<12.0.0)"]
cuda80 = ["cupy-cuda80 (>=5.0.0b4,<12.0.0)"]
cuda90 = ["cupy-cuda90 (>=5.0.0b4,<12.0.0)"]
cuda91 = ["cupy-cuda91 (>=5.0.0b4,<12.0.0)"]
cuda92 = ["cupy-cuda92 (>=5.0.0b4,<12.0.0)"]
cuda = ["cupy (>=5.0.0b4,<13.0.0)"]
cuda-autodetect = ["cupy-wheel (>=11.0.0,<13.0.0)"]
cuda100 = ["cupy-cuda100 (>=5.0.0b4,<13.0.0)"]
cuda101 = ["cupy-cuda101 (>=5.0.0b4,<13.0.0)"]
cuda102 = ["cupy-cuda102 (>=5.0.0b4,<13.0.0)"]
cuda110 = ["cupy-cuda110 (>=5.0.0b4,<13.0.0)"]
cuda111 = ["cupy-cuda111 (>=5.0.0b4,<13.0.0)"]
cuda112 = ["cupy-cuda112 (>=5.0.0b4,<13.0.0)"]
cuda113 = ["cupy-cuda113 (>=5.0.0b4,<13.0.0)"]
cuda114 = ["cupy-cuda114 (>=5.0.0b4,<13.0.0)"]
cuda115 = ["cupy-cuda115 (>=5.0.0b4,<13.0.0)"]
cuda116 = ["cupy-cuda116 (>=5.0.0b4,<13.0.0)"]
cuda117 = ["cupy-cuda117 (>=5.0.0b4,<13.0.0)"]
cuda11x = ["cupy-cuda11x (>=11.0.0,<13.0.0)"]
cuda80 = ["cupy-cuda80 (>=5.0.0b4,<13.0.0)"]
cuda90 = ["cupy-cuda90 (>=5.0.0b4,<13.0.0)"]
cuda91 = ["cupy-cuda91 (>=5.0.0b4,<13.0.0)"]
cuda92 = ["cupy-cuda92 (>=5.0.0b4,<13.0.0)"]
ja = ["sudachidict-core (>=20211220)", "sudachipy (>=0.5.2,!=0.6.1)"]
ko = ["natto-py (>=0.9.0)"]
lookups = ["spacy-lookups-data (>=1.0.3,<1.1.0)"]
@@ -8096,14 +8120,14 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.
[[package]]
name = "types-pyopenssl"
version = "23.1.0.1"
version = "23.1.0.2"
description = "Typing stubs for pyOpenSSL"
category = "dev"
optional = false
python-versions = "*"
files = [
{file = "types-pyOpenSSL-23.1.0.1.tar.gz", hash = "sha256:59044283c475eaa5a29b36a903c123d52bdf4a7e012f0a1ca0e41115b99216da"},
{file = "types_pyOpenSSL-23.1.0.1-py3-none-any.whl", hash = "sha256:ac7fbc240930c2f9a1cbd2d04f9cb14ad0f15b0ad8d6528732a83747b1b2086e"},
{file = "types-pyOpenSSL-23.1.0.2.tar.gz", hash = "sha256:20b80971b86240e8432a1832bd8124cea49c3088c7bfc77dfd23be27ffe4a517"},
{file = "types_pyOpenSSL-23.1.0.2-py3-none-any.whl", hash = "sha256:b050641aeff6dfebf231ad719bdac12d53b8ee818d4afb67b886333484629957"},
]
[package.dependencies]
@@ -8336,7 +8360,7 @@ name = "validators"
version = "0.20.0"
description = "Python Data Validation for Humans™."
category = "main"
optional = true
optional = false
python-versions = ">=3.4"
files = [
{file = "validators-0.20.0.tar.gz", hash = "sha256:24148ce4e64100a2d5e267233e23e7afeb55316b47d30faae7eb6e7292bc226a"},
@@ -8473,7 +8497,7 @@ name = "weaviate-client"
version = "3.15.5"
description = "A python native weaviate client"
category = "main"
optional = true
optional = false
python-versions = ">=3.7"
files = [
{file = "weaviate-client-3.15.5.tar.gz", hash = "sha256:6da7e5d08dc9bb8b7879661d1a457c50af7d73e621a5305efe131160e83da69e"},
@@ -9011,4 +9035,4 @@ qdrant = ["qdrant-client"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.8.1,<4.0"
content-hash = "26b1bbfbc3a228b892b2466af3561b799238a6d379853d325dc3c798776df0d8"
content-hash = "7e343fa8e31d8fcf1023cbda592f64c05e80015c4e0e23c1d387d2e9671ce995"
+7 -3
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "langchain"
version = "0.0.139"
version = "0.0.141"
description = "Building applications with LLMs through composability"
authors = []
license = "MIT"
@@ -28,7 +28,7 @@ spacy = {version = "^3", optional = true}
nltk = {version = "^3", optional = true}
transformers = {version = "^4", optional = true}
beautifulsoup4 = {version = "^4", optional = true}
torch = {version = "^1", optional = true}
torch = {version = ">=1,<3", optional = true}
jinja2 = {version = "^3", optional = true}
tiktoken = {version = "^0.3.2", optional = true, python="^3.9"}
pinecone-client = {version = "^2", optional = true}
@@ -36,7 +36,7 @@ pinecone-text = {version = "^0.4.2", optional = true}
weaviate-client = {version = "^3", optional = true}
google-api-python-client = {version = "2.70.0", optional = true}
wolframalpha = {version = "5.0.0", optional = true}
anthropic = {version = "^0.2.4", optional = true}
anthropic = {version = "^0.2.6", optional = true}
qdrant-client = {version = "^1.1.2", optional = true, python = ">=3.8.1,<3.12"}
dataclasses-json = "^0.5.7"
tensorflow-text = {version = "^2.11.0", optional = true, python = "^3.10, <3.12"}
@@ -101,9 +101,13 @@ pgvector = "^0.1.6"
transformers = "^4.27.4"
pandas = "^2.0.0"
deeplake = "^3.2.21"
weaviate-client = "^3.15.5"
torch = "^1.0.0"
chromadb = "^0.3.21"
tiktoken = "^0.3.3"
python-dotenv = "^1.0.0"
gptcache = "^0.1.9"
promptlayer = "^0.1.80"
[tool.poetry.group.lint.dependencies]
ruff = "^0.0.249"
+7
View File
@@ -39,6 +39,11 @@ cd tests/integration_tests/vectorstores/docker-compose
docker-compose -f elasticsearch.yml up
```
### Prepare environment variables for local testing:
- copy `tests/.env.example` to `tests/.env`
- set variables in `tests/.env` file, e.g `OPENAI_API_KEY`
Additionally, it's important to note that some integration tests may require certain
environment variables to be set, such as `OPENAI_API_KEY`. Be sure to set any required
environment variables before running the tests to ensure they run correctly.
@@ -54,7 +59,9 @@ cassettes. You can use the --vcr-record=none command-line option to disable reco
new cassettes. Here's an example:
```bash
pytest --log-cli-level=10 tests/integration_tests/vectorstores/test_pinecone.py --vcr-record=none
pytest tests/integration_tests/vectorstores/test_elasticsearch.py --vcr-record=none
```
### Run some tests with coverage:
+9
View File
@@ -0,0 +1,9 @@
# openai
# your api key from https://platform.openai.com/account/api-keys
OPENAI_API_KEY=
# pinecone
# your api key from left menu "API Keys" in https://app.pinecone.io
PINECONE_API_KEY=your_pinecone_api_key_here
# your pinecone environment from left menu "API Keys" in https://app.pinecone.io
PINECONE_ENVIRONMENT=us-west4-gcp
@@ -0,0 +1,83 @@
"""Test Anthropic API wrapper."""
from typing import List
import pytest
from langchain.callbacks.base import CallbackManager
from langchain.chat_models.anthropic import ChatAnthropic
from langchain.schema import (
AIMessage,
BaseMessage,
ChatGeneration,
HumanMessage,
LLMResult,
)
from tests.unit_tests.callbacks.fake_callback_handler import FakeCallbackHandler
def test_anthropic_call() -> None:
"""Test valid call to anthropic."""
chat = ChatAnthropic(model="test")
message = HumanMessage(content="Hello")
response = chat([message])
assert isinstance(response, AIMessage)
assert isinstance(response.content, str)
def test_anthropic_streaming() -> None:
"""Test streaming tokens from anthropic."""
chat = ChatAnthropic(model="test", streaming=True)
message = HumanMessage(content="Hello")
response = chat([message])
assert isinstance(response, AIMessage)
assert isinstance(response.content, str)
def test_anthropic_streaming_callback() -> None:
"""Test that streaming correctly invokes on_llm_new_token callback."""
callback_handler = FakeCallbackHandler()
callback_manager = CallbackManager([callback_handler])
chat = ChatAnthropic(
model="test",
streaming=True,
callback_manager=callback_manager,
verbose=True,
)
message = HumanMessage(content="Write me a sentence with 10 words.")
chat([message])
assert callback_handler.llm_streams > 1
@pytest.mark.asyncio
async def test_anthropic_async_streaming_callback() -> None:
"""Test that streaming correctly invokes on_llm_new_token callback."""
callback_handler = FakeCallbackHandler()
callback_manager = CallbackManager([callback_handler])
chat = ChatAnthropic(
model="test",
streaming=True,
callback_manager=callback_manager,
verbose=True,
)
chat_messages: List[BaseMessage] = [
HumanMessage(content="How many toes do dogs have?")
]
result: LLMResult = await chat.agenerate([chat_messages])
assert callback_handler.llm_streams > 1
assert isinstance(result, LLMResult)
for response in result.generations[0]:
assert isinstance(response, ChatGeneration)
assert isinstance(response.text, str)
assert response.text == response.message.content
def test_formatting() -> None:
chat = ChatAnthropic()
chat_messages: List[BaseMessage] = [HumanMessage(content="Hello")]
result = chat._convert_messages_to_prompt(chat_messages)
assert result == "\n\nHuman: Hello\n\nAssistant:"
chat_messages = [HumanMessage(content="Hello"), AIMessage(content="Answer:")]
result = chat._convert_messages_to_prompt(chat_messages)
assert result == "\n\nHuman: Hello\n\nAssistant: Answer:"
+21 -15
View File
@@ -1,10 +1,31 @@
import os
from pathlib import Path
import pytest
# Getting the absolute path of the current file's directory
ABS_PATH = os.path.dirname(os.path.abspath(__file__))
# Getting the absolute path of the project's root directory
PROJECT_DIR = os.path.abspath(os.path.join(ABS_PATH, os.pardir, os.pardir))
# Loading the .env file if it exists
def _load_env() -> None:
dotenv_path = os.path.join(PROJECT_DIR, "tests", "integration_tests", ".env")
if os.path.exists(dotenv_path):
from dotenv import load_dotenv
load_dotenv(dotenv_path)
_load_env()
@pytest.fixture(scope="module")
def test_dir() -> Path:
return Path(os.path.join(PROJECT_DIR, "tests", "integration_tests"))
# This fixture returns a string containing the path to the cassette directory for the
# current module
@@ -15,18 +36,3 @@ def vcr_cassette_dir(request: pytest.FixtureRequest) -> str:
"cassettes",
os.path.basename(request.module.__file__).replace(".py", ""),
)
# This fixture returns a dictionary containing filter_headers options
# for replacing certain headers with dummy values during cassette playback
# Specifically, it replaces the authorization header with a dummy value to
# prevent sensitive data from being recorded in the cassette.
@pytest.fixture(scope="module")
def vcr_config() -> dict:
return {
"filter_headers": [
("authorization", "authorization-DUMMY"),
("X-OpenAI-Client-User-Agent", "X-OpenAI-Client-User-Agent-DUMMY"),
("User-Agent", "User-Agent-DUMMY"),
],
}
@@ -0,0 +1,23 @@
"""Tests for the Slack directory loader"""
from pathlib import Path
from langchain.document_loaders import SlackDirectoryLoader
def test_slack_directory_loader() -> None:
"""Test Slack directory loader."""
file_path = Path(__file__).parent.parent / "examples/slack_export.zip"
loader = SlackDirectoryLoader(str(file_path))
docs = loader.load()
assert len(docs) == 5
def test_slack_directory_loader_urls() -> None:
"""Test workspace URLS are passed through in the SlackDirectoryloader."""
file_path = Path(__file__).parent.parent / "examples/slack_export.zip"
workspace_url = "example_workspace.com"
loader = SlackDirectoryLoader(str(file_path), workspace_url)
docs = loader.load()
for doc in docs:
assert doc.metadata["source"].startswith(workspace_url)
Binary file not shown.
@@ -32,7 +32,6 @@ def test_anthropic_streaming_callback() -> None:
callback_handler = FakeCallbackHandler()
callback_manager = CallbackManager([callback_handler])
llm = Anthropic(
model="claude-v1",
streaming=True,
callback_manager=callback_manager,
verbose=True,
@@ -55,7 +54,6 @@ async def test_anthropic_async_streaming_callback() -> None:
callback_handler = FakeCallbackHandler()
callback_manager = CallbackManager([callback_handler])
llm = Anthropic(
model="claude-v1",
streaming=True,
callback_manager=callback_manager,
verbose=True,
@@ -211,3 +211,14 @@ async def test_openai_chat_async_streaming_callback() -> None:
result = await llm.agenerate(["Write me a sentence with 100 words."])
assert callback_handler.llm_streams != 0
assert isinstance(result, LLMResult)
def test_openai_modelname_to_contextsize_valid() -> None:
"""Test model name to context size on a valid model."""
assert OpenAI().modelname_to_contextsize("davinci") == 2049
def test_openai_modelname_to_contextsize_invalid() -> None:
"""Test model name to context size on an invalid model."""
with pytest.raises(ValueError):
OpenAI().modelname_to_contextsize("foobar")
@@ -0,0 +1,489 @@
interactions:
- request:
body: '{"input": [[831, 677, 31172, 220, 19, 370, 10718, 830, 1484, 762, 3443,
22, 6043, 2437, 68, 22874, 346, 22, 65, 21, 68, 1927, 712, 2689], [2059, 7341,
527, 264, 1912, 315, 658, 10753, 677, 81, 3581, 7795, 32971, 555, 264, 7558,
321, 351, 61798, 30535, 11, 4330, 311, 8254, 342, 484, 1776, 1220, 389, 279,
11314, 315, 279, 2010, 11, 323, 281, 1279, 278, 66079, 430, 527, 539, 75754,
311, 279, 2010, 13, 18766, 61535, 527, 21771, 2949, 279, 1206, 1037, 24082,
613, 318, 269, 4055, 320, 269, 24082, 613, 3893, 8, 323, 527, 279, 13219, 1912,
311, 279, 426, 4428, 42877, 320, 66243, 323, 24890, 570, 4427, 8336, 13334,
279, 4751, 330, 939, 847, 1, 439, 459, 42887, 5699, 2737, 69918, 3697, 315,
921, 2159, 14172, 339, 9891, 320, 11707, 321, 351, 61798, 7795, 8, 449, 264,
44892, 12970, 79612, 11, 1778, 439, 6409, 65, 86815, 82, 323, 53265, 582, 276,
17323, 13, 61536, 12970, 523, 2159, 14172, 27520, 598, 1778, 439, 2493, 5670,
301, 1815, 323, 25227, 3205, 355, 1176, 9922, 304, 279, 60434, 1122, 26572,
320, 19391, 12, 19192, 11583, 705, 3582, 1063, 31376, 1534, 523, 2159, 14172,
339, 8503, 12970, 29505, 527, 439, 2362, 439, 279, 36931, 31137, 869, 12734,
320, 21209, 12, 14870, 11583, 570, 578, 24417, 6617, 61535, 320, 9697, 613,
5493, 8, 527, 3967, 505, 279, 23591, 84474, 11, 922, 220, 1049, 11583, 13, 220,
71923, 2134, 304, 1404, 505, 279, 2678, 50561, 74265, 939, 847, 320, 36, 14046,
2985, 46109, 281, 5515, 72, 705, 264, 5655, 9581, 9606, 430, 374, 1193, 220,
1114, 2960, 86366, 417, 320, 21, 13, 22, 304, 8, 304, 3160, 11, 311, 279, 51119,
44892, 320, 73262, 2910, 77152, 3666, 355, 705, 279, 7928, 7795, 304, 279, 1917,
11, 902, 25501, 13489, 220, 717, 37356, 320, 1272, 10702, 8, 304, 3160, 13,
2435, 527, 1766, 304, 682, 52840, 323, 527, 4279, 311, 43957, 709, 311, 220,
17, 11, 931, 37356, 320, 21, 11, 5067, 10702, 570, 2435, 8965, 656, 539, 3974,
304, 80744, 11, 8051, 1070, 527, 264, 2478, 3967, 20157, 11, 1778, 439, 279,
17231, 44892, 323, 279, 15140, 44892, 11, 902, 649, 387, 1766, 304, 2225, 67329,
977, 323, 80744, 8032, 18, 60, 71923, 617, 264, 18702, 315, 2761, 14991, 294,
4351, 645, 430, 36236, 872, 6930, 505, 5674, 323, 79383, 304, 5369, 311, 18899,
872, 15962, 30295, 13, 2435, 617, 12387, 7437, 315, 8454, 481, 18311, 13, 220,
26778, 9606, 527, 72627, 56217, 11, 902, 527, 44304, 430, 527, 520, 279, 1948,
315, 872, 3691, 8957, 13, 8593, 10507, 2997, 279, 52835, 44892, 11, 6437, 44892,
11, 2294, 4251, 44892, 11, 296, 29886, 44892, 11, 270, 86524, 44892, 11, 323,
24354, 2025, 44892, 13, 220, 71923, 527, 10791, 555, 12966, 369, 44892, 13339,
477, 44892, 1913, 19724, 13, 9176, 44892, 22673, 527, 21699, 555, 3823, 7640,
13, 8876, 220, 4468, 15, 11, 44892, 22673, 617, 1027, 11293, 555, 220, 6028,
13689, 10213, 505, 927, 69, 11218, 13]], "encoding_format": "base64"}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '2798'
Content-Type:
- application/json
User-Agent:
- User-Agent-DUMMY
X-OpenAI-Client-User-Agent:
- X-OpenAI-Client-User-Agent-DUMMY
authorization:
- authorization-DUMMY
method: POST
uri: https://api.openai.com/v1/engines/text-embedding-ada-002/embeddings
response:
body:
string: !!binary |
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
TqA3QQAA
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 7b6d341b6aff7597-DME
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 12 Apr 2023 17:31:33 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
access-control-allow-origin:
- '*'
alt-svc:
- h3=":443"; ma=86400, h3-29=":443"; ma=86400
openai-organization:
- own-45h3iv
openai-processing-ms:
- '35'
openai-version:
- '2020-10-01'
strict-transport-security:
- max-age=15724800; includeSubDomains
x-ratelimit-limit-requests:
- '3000'
x-ratelimit-remaining-requests:
- '2999'
x-ratelimit-reset-requests:
- 20ms
x-request-id:
- bc8dbbbf8fc5a0f091c40599c9dcf214
status:
code: 200
message: OK
- request:
body: '{"input": [[19, 370, 10718, 830, 1484, 762, 3443, 22, 6043, 2437, 68, 22874,
346, 22, 65, 21, 68, 1927]], "encoding_format": "base64"}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '134'
Content-Type:
- application/json
User-Agent:
- User-Agent-DUMMY
X-OpenAI-Client-User-Agent:
- X-OpenAI-Client-User-Agent-DUMMY
authorization:
- authorization-DUMMY
method: POST
uri: https://api.openai.com/v1/engines/text-embedding-ada-002/embeddings
response:
body:
string: !!binary |
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
AAA=
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 7b6d3423ed247597-DME
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 12 Apr 2023 17:31:34 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
access-control-allow-origin:
- '*'
alt-svc:
- h3=":443"; ma=86400, h3-29=":443"; ma=86400
openai-organization:
- own-45h3iv
openai-processing-ms:
- '24'
openai-version:
- '2020-10-01'
strict-transport-security:
- max-age=15724800; includeSubDomains
x-ratelimit-limit-requests:
- '3000'
x-ratelimit-remaining-requests:
- '2999'
x-ratelimit-reset-requests:
- 20ms
x-request-id:
- 2edcb14cac190a015b9514ed617d1cf1
status:
code: 200
message: OK
version: 1
@@ -0,0 +1,489 @@
interactions:
- request:
body: '{"input": [[831, 677, 31172, 272, 762, 14087, 68, 17, 64, 25350, 1774,
1897, 51542, 9081, 19272, 1135, 65, 1774, 67, 6069, 712, 2689], [2059, 7341,
527, 264, 1912, 315, 658, 10753, 677, 81, 3581, 7795, 32971, 555, 264, 7558,
321, 351, 61798, 30535, 11, 4330, 311, 8254, 342, 484, 1776, 1220, 389, 279,
11314, 315, 279, 2010, 11, 323, 281, 1279, 278, 66079, 430, 527, 539, 75754,
311, 279, 2010, 13, 18766, 61535, 527, 21771, 2949, 279, 1206, 1037, 24082,
613, 318, 269, 4055, 320, 269, 24082, 613, 3893, 8, 323, 527, 279, 13219, 1912,
311, 279, 426, 4428, 42877, 320, 66243, 323, 24890, 570, 4427, 8336, 13334,
279, 4751, 330, 939, 847, 1, 439, 459, 42887, 5699, 2737, 69918, 3697, 315,
921, 2159, 14172, 339, 9891, 320, 11707, 321, 351, 61798, 7795, 8, 449, 264,
44892, 12970, 79612, 11, 1778, 439, 6409, 65, 86815, 82, 323, 53265, 582, 276,
17323, 13, 61536, 12970, 523, 2159, 14172, 27520, 598, 1778, 439, 2493, 5670,
301, 1815, 323, 25227, 3205, 355, 1176, 9922, 304, 279, 60434, 1122, 26572,
320, 19391, 12, 19192, 11583, 705, 3582, 1063, 31376, 1534, 523, 2159, 14172,
339, 8503, 12970, 29505, 527, 439, 2362, 439, 279, 36931, 31137, 869, 12734,
320, 21209, 12, 14870, 11583, 570, 578, 24417, 6617, 61535, 320, 9697, 613,
5493, 8, 527, 3967, 505, 279, 23591, 84474, 11, 922, 220, 1049, 11583, 13, 220,
71923, 2134, 304, 1404, 505, 279, 2678, 50561, 74265, 939, 847, 320, 36, 14046,
2985, 46109, 281, 5515, 72, 705, 264, 5655, 9581, 9606, 430, 374, 1193, 220,
1114, 2960, 86366, 417, 320, 21, 13, 22, 304, 8, 304, 3160, 11, 311, 279, 51119,
44892, 320, 73262, 2910, 77152, 3666, 355, 705, 279, 7928, 7795, 304, 279, 1917,
11, 902, 25501, 13489, 220, 717, 37356, 320, 1272, 10702, 8, 304, 3160, 13,
2435, 527, 1766, 304, 682, 52840, 323, 527, 4279, 311, 43957, 709, 311, 220,
17, 11, 931, 37356, 320, 21, 11, 5067, 10702, 570, 2435, 8965, 656, 539, 3974,
304, 80744, 11, 8051, 1070, 527, 264, 2478, 3967, 20157, 11, 1778, 439, 279,
17231, 44892, 323, 279, 15140, 44892, 11, 902, 649, 387, 1766, 304, 2225, 67329,
977, 323, 80744, 8032, 18, 60, 71923, 617, 264, 18702, 315, 2761, 14991, 294,
4351, 645, 430, 36236, 872, 6930, 505, 5674, 323, 79383, 304, 5369, 311, 18899,
872, 15962, 30295, 13, 2435, 617, 12387, 7437, 315, 8454, 481, 18311, 13, 220,
26778, 9606, 527, 72627, 56217, 11, 902, 527, 44304, 430, 527, 520, 279, 1948,
315, 872, 3691, 8957, 13, 8593, 10507, 2997, 279, 52835, 44892, 11, 6437, 44892,
11, 2294, 4251, 44892, 11, 296, 29886, 44892, 11, 270, 86524, 44892, 11, 323,
24354, 2025, 44892, 13, 220, 71923, 527, 10791, 555, 12966, 369, 44892, 13339,
477, 44892, 1913, 19724, 13, 9176, 44892, 22673, 527, 21699, 555, 3823, 7640,
13, 8876, 220, 4468, 15, 11, 44892, 22673, 617, 1027, 11293, 555, 220, 6028,
13689, 10213, 505, 927, 69, 11218, 13]], "encoding_format": "base64"}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '2795'
Content-Type:
- application/json
User-Agent:
- User-Agent-DUMMY
X-OpenAI-Client-User-Agent:
- X-OpenAI-Client-User-Agent-DUMMY
authorization:
- authorization-DUMMY
method: POST
uri: https://api.openai.com/v1/engines/text-embedding-ada-002/embeddings
response:
body:
string: !!binary |
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
daMVN0EAAA==
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 7b6d34be9caf16f4-DME
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 12 Apr 2023 17:32:00 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
access-control-allow-origin:
- '*'
alt-svc:
- h3=":443"; ma=86400, h3-29=":443"; ma=86400
openai-organization:
- own-45h3iv
openai-processing-ms:
- '1177'
openai-version:
- '2020-10-01'
strict-transport-security:
- max-age=15724800; includeSubDomains
x-ratelimit-limit-requests:
- '3000'
x-ratelimit-remaining-requests:
- '2999'
x-ratelimit-reset-requests:
- 20ms
x-request-id:
- 3301ccd4f99ce79864700677997b0a0a
status:
code: 200
message: OK
- request:
body: '{"input": [[831, 677, 31172, 272, 762, 14087, 68, 17, 64, 25350, 1774,
1897, 51542, 9081, 19272, 1135, 65, 1774, 67, 6069, 712, 2689]], "encoding_format":
"base64"}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '164'
Content-Type:
- application/json
User-Agent:
- User-Agent-DUMMY
X-OpenAI-Client-User-Agent:
- X-OpenAI-Client-User-Agent-DUMMY
authorization:
- authorization-DUMMY
method: POST
uri: https://api.openai.com/v1/engines/text-embedding-ada-002/embeddings
response:
body:
string: !!binary |
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
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 7b6d34cd99e416f4-DME
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 12 Apr 2023 17:32:01 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
access-control-allow-origin:
- '*'
alt-svc:
- h3=":443"; ma=86400, h3-29=":443"; ma=86400
openai-organization:
- own-45h3iv
openai-processing-ms:
- '22'
openai-version:
- '2020-10-01'
strict-transport-security:
- max-age=15724800; includeSubDomains
x-ratelimit-limit-requests:
- '3000'
x-ratelimit-remaining-requests:
- '2999'
x-ratelimit-reset-requests:
- 20ms
x-request-id:
- 3dd93c4866672c1fff861e8379706c22
status:
code: 200
message: OK
version: 1
@@ -0,0 +1,557 @@
interactions:
- request:
body: '{"input": [[8134], [2308], [43673]], "encoding_format": "base64"}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '65'
Content-Type:
- application/json
User-Agent:
- User-Agent-DUMMY
X-OpenAI-Client-User-Agent:
- X-OpenAI-Client-User-Agent-DUMMY
authorization:
- authorization-DUMMY
method: POST
uri: https://api.openai.com/v1/engines/text-embedding-ada-002/embeddings
response:
body:
string: !!binary |
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
5z/+CwAA//8DAAle6cmFYQAA
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 7b6d3f542dba9d8c-DME
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 12 Apr 2023 17:39:12 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
access-control-allow-origin:
- '*'
alt-svc:
- h3=":443"; ma=86400, h3-29=":443"; ma=86400
openai-organization:
- own-45h3iv
openai-processing-ms:
- '31'
openai-version:
- '2020-10-01'
strict-transport-security:
- max-age=15724800; includeSubDomains
x-ratelimit-limit-requests:
- '3000'
x-ratelimit-remaining-requests:
- '2999'
x-ratelimit-reset-requests:
- 20ms
x-request-id:
- 067bde68ac014668b13968776001a588
status:
code: 200
message: OK
- request:
body: '{"input": [[8134]], "encoding_format": "base64"}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '48'
Content-Type:
- application/json
User-Agent:
- User-Agent-DUMMY
X-OpenAI-Client-User-Agent:
- X-OpenAI-Client-User-Agent-DUMMY
authorization:
- authorization-DUMMY
method: POST
uri: https://api.openai.com/v1/engines/text-embedding-ada-002/embeddings
response:
body:
string: !!binary |
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
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 7b6d3f5cea949d8c-DME
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 12 Apr 2023 17:39:14 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
access-control-allow-origin:
- '*'
alt-svc:
- h3=":443"; ma=86400, h3-29=":443"; ma=86400
openai-organization:
- own-45h3iv
openai-processing-ms:
- '271'
openai-version:
- '2020-10-01'
strict-transport-security:
- max-age=15724800; includeSubDomains
x-ratelimit-limit-requests:
- '3000'
x-ratelimit-remaining-requests:
- '2999'
x-ratelimit-reset-requests:
- 20ms
x-request-id:
- 029a9d93fe8a07946d39f3e957b33c11
status:
code: 200
message: OK
version: 1
@@ -1,15 +1,56 @@
import os
from typing import Generator, List
from typing import Generator, List, Union
import pytest
from vcr.request import Request
from langchain.document_loaders import TextLoader
from langchain.embeddings import OpenAIEmbeddings
from langchain.schema import Document
from langchain.text_splitter import CharacterTextSplitter
# Those environment variables turn on Deep Lake pytest mode.
# It significantly makes tests run much faster.
# Need to run before `import deeplake`
os.environ["BUGGER_OFF"] = "true"
os.environ["DEEPLAKE_DOWNLOAD_PATH"] = "./testing/local_storage"
os.environ["DEEPLAKE_PYTEST_ENABLED"] = "true"
# This fixture returns a dictionary containing filter_headers options
# for replacing certain headers with dummy values during cassette playback
# Specifically, it replaces the authorization header with a dummy value to
# prevent sensitive data from being recorded in the cassette.
# It also filters request to certain hosts (specified in the `ignored_hosts` list)
# to prevent data from being recorded in the cassette.
@pytest.fixture(scope="module")
def vcr_config() -> dict:
skipped_host = ["pinecone.io"]
def before_record_response(response: dict) -> Union[dict, None]:
return response
def before_record_request(request: Request) -> Union[Request, None]:
for host in skipped_host:
if request.host.startswith(host) or request.host.endswith(host):
return None
return request
return {
"before_record_request": before_record_request,
"before_record_response": before_record_response,
"filter_headers": [
("authorization", "authorization-DUMMY"),
("X-OpenAI-Client-User-Agent", "X-OpenAI-Client-User-Agent-DUMMY"),
("Api-Key", "Api-Key-DUMMY"),
("User-Agent", "User-Agent-DUMMY"),
],
"ignore_localhost": True,
}
# Define a fixture that yields a generator object returning a list of documents
@pytest.fixture(scope="module")
@pytest.fixture(scope="function")
def documents() -> Generator[List[Document], None, None]:
"""Return a generator that yields a list of documents."""
@@ -23,3 +64,18 @@ def documents() -> Generator[List[Document], None, None]:
# Yield the documents split into chunks
yield text_splitter.split_documents(documents)
@pytest.fixture(scope="function")
def texts() -> Generator[List[str], None, None]:
# Load the documents from a file located in the fixtures directory
documents = TextLoader(
os.path.join(os.path.dirname(__file__), "fixtures", "sharks.txt")
).load()
yield [doc.page_content for doc in documents]
@pytest.fixture(scope="module")
def embedding_openai() -> OpenAIEmbeddings:
return OpenAIEmbeddings()
@@ -0,0 +1,22 @@
version: '3.4'
services:
weaviate:
command:
- --host
- 0.0.0.0
- --port
- '8080'
- --scheme
- http
image: semitechnologies/weaviate:1.18.2
ports:
- 8080:8080
restart: on-failure:0
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
DEFAULT_VECTORIZER_MODULE: 'none'
ENABLE_MODULES: ''
CLUSTER_HOSTNAME: 'node1'
@@ -21,6 +21,11 @@ docker-compose -f elasticsearch.yml up
class TestElasticsearch:
@classmethod
def setup_class(cls) -> None:
if not os.getenv("OPENAI_API_KEY"):
raise ValueError("OPENAI_API_KEY environment variable is not set")
@pytest.fixture(scope="class", autouse=True)
def elasticsearch_url(self) -> Union[str, Generator[str, None, None]]:
"""Return the elasticsearch url."""
@@ -34,15 +39,6 @@ class TestElasticsearch:
# print(index_name)
es.indices.delete(index=index_name)
@pytest.fixture(scope="class", autouse=True)
def openai_api_key(self) -> Union[str, Generator[str, None, None]]:
"""Return the OpenAI API key."""
openai_api_key = os.getenv("OPENAI_API_KEY")
if not openai_api_key:
raise ValueError("OPENAI_API_KEY environment variable is not set")
yield openai_api_key
def test_similarity_search_without_metadata(self, elasticsearch_url: str) -> None:
"""Test end to end construction and search without metadata."""
texts = ["foo", "bar", "baz"]
@@ -67,15 +63,17 @@ class TestElasticsearch:
@pytest.mark.vcr(ignore_localhost=True)
def test_default_index_from_documents(
self, documents: List[Document], openai_api_key: str, elasticsearch_url: str
self,
documents: List[Document],
embedding_openai: OpenAIEmbeddings,
elasticsearch_url: str,
) -> None:
"""This test checks the construction of a default
ElasticSearch index using the 'from_documents'."""
embedding = OpenAIEmbeddings(openai_api_key=openai_api_key)
elastic_vector_search = ElasticVectorSearch.from_documents(
documents=documents,
embedding=embedding,
embedding=embedding_openai,
elasticsearch_url=elasticsearch_url,
)
@@ -86,16 +84,18 @@ class TestElasticsearch:
@pytest.mark.vcr(ignore_localhost=True)
def test_custom_index_from_documents(
self, documents: List[Document], openai_api_key: str, elasticsearch_url: str
self,
documents: List[Document],
embedding_openai: OpenAIEmbeddings,
elasticsearch_url: str,
) -> None:
"""This test checks the construction of a custom
ElasticSearch index using the 'from_documents'."""
index_name = f"custom_index_{uuid.uuid4().hex}"
embedding = OpenAIEmbeddings(openai_api_key=openai_api_key)
elastic_vector_search = ElasticVectorSearch.from_documents(
documents=documents,
embedding=embedding,
embedding=embedding_openai,
elasticsearch_url=elasticsearch_url,
index_name=index_name,
)
@@ -110,15 +110,17 @@ class TestElasticsearch:
@pytest.mark.vcr(ignore_localhost=True)
def test_custom_index_add_documents(
self, documents: List[Document], openai_api_key: str, elasticsearch_url: str
self,
documents: List[Document],
embedding_openai: OpenAIEmbeddings,
elasticsearch_url: str,
) -> None:
"""This test checks the construction of a custom
ElasticSearch index using the 'add_documents'."""
index_name = f"custom_index_{uuid.uuid4().hex}"
embedding = OpenAIEmbeddings(openai_api_key=openai_api_key)
elastic_vector_search = ElasticVectorSearch(
embedding=embedding,
embedding=embedding_openai,
elasticsearch_url=elasticsearch_url,
index_name=index_name,
)
@@ -1,97 +1,208 @@
"""Test Pinecone functionality."""
import importlib
import os
import uuid
from typing import List
import pinecone
import pytest
from langchain.docstore.document import Document
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores.pinecone import Pinecone
from tests.integration_tests.vectorstores.fake_embeddings import FakeEmbeddings
pinecone.init(api_key="YOUR_API_KEY", environment="YOUR_ENV")
# if the index already exists, delete it
try:
pinecone.delete_index("langchain-demo")
except Exception:
pass
index = pinecone.Index("langchain-demo")
index_name = "langchain-test-index" # name of the index
namespace_name = "langchain-test-namespace" # name of the namespace
dimension = 1536 # dimension of the embeddings
def test_pinecone() -> None:
"""Test end to end construction and search."""
texts = ["foo", "bar", "baz"]
docsearch = Pinecone.from_texts(
texts, FakeEmbeddings(), index_name="langchain-demo", namespace="test"
)
output = docsearch.similarity_search("foo", k=1, namespace="test")
assert output == [Document(page_content="foo")]
def reset_pinecone() -> None:
assert os.environ.get("PINECONE_API_KEY") is not None
assert os.environ.get("PINECONE_ENVIRONMENT") is not None
import pinecone
def test_pinecone_with_metadatas() -> None:
"""Test end to end construction and search."""
texts = ["foo", "bar", "baz"]
metadatas = [{"page": i} for i in range(len(texts))]
docsearch = Pinecone.from_texts(
texts,
FakeEmbeddings(),
index_name="langchain-demo",
metadatas=metadatas,
namespace="test-metadata",
)
output = docsearch.similarity_search("foo", k=1, namespace="test-metadata")
assert output == [Document(page_content="foo", metadata={"page": 0})]
importlib.reload(pinecone)
def test_pinecone_with_scores() -> None:
"""Test end to end construction and search with scores and IDs."""
texts = ["foo", "bar", "baz"]
metadatas = [{"page": i} for i in range(len(texts))]
docsearch = Pinecone.from_texts(
texts,
FakeEmbeddings(),
index_name="langchain-demo",
metadatas=metadatas,
namespace="test-metadata-score",
)
output = docsearch.similarity_search_with_score(
"foo", k=3, namespace="test-metadata-score"
)
docs = [o[0] for o in output]
scores = [o[1] for o in output]
assert docs == [
Document(page_content="foo", metadata={"page": 0}),
Document(page_content="bar", metadata={"page": 1}),
Document(page_content="baz", metadata={"page": 2}),
]
assert scores[0] > scores[1] > scores[2]
def test_pinecone_with_namespaces() -> None:
"Test that namespaces are properly handled." ""
# Create two indexes with the same name but different namespaces
texts = ["foo", "bar", "baz"]
metadatas = [{"page": i} for i in range(len(texts))]
Pinecone.from_texts(
texts,
FakeEmbeddings(),
index_name="langchain-demo",
metadatas=metadatas,
namespace="test-namespace",
pinecone.init(
api_key=os.environ.get("PINECONE_API_KEY"),
environment=os.environ.get("PINECONE_ENVIRONMENT"),
)
texts = ["foo2", "bar2", "baz2"]
metadatas = [{"page": i} for i in range(len(texts))]
Pinecone.from_texts(
texts,
FakeEmbeddings(),
index_name="langchain-demo",
metadatas=metadatas,
namespace="test-namespace2",
)
# Search with namespace
docsearch = Pinecone.from_existing_index(
"langchain-demo", embedding=FakeEmbeddings(), namespace="test-namespace"
)
output = docsearch.similarity_search("foo", k=6)
# check that we don't get results from the other namespace
page_contents = [o.page_content for o in output]
assert set(page_contents) == set(["foo", "bar", "baz"])
class TestPinecone:
index: pinecone.Index
@classmethod
def setup_class(cls) -> None:
reset_pinecone()
cls.index = pinecone.Index(index_name)
if index_name in pinecone.list_indexes():
index_stats = cls.index.describe_index_stats()
if index_stats["dimension"] == dimension:
# delete all the vectors in the index if the dimension is the same
# from all namespaces
index_stats = cls.index.describe_index_stats()
for _namespace_name in index_stats["namespaces"].keys():
cls.index.delete(delete_all=True, namespace=_namespace_name)
else:
pinecone.delete_index(index_name)
pinecone.create_index(name=index_name, dimension=dimension)
else:
pinecone.create_index(name=index_name, dimension=dimension)
# insure the index is empty
index_stats = cls.index.describe_index_stats()
assert index_stats["dimension"] == dimension
if index_stats["namespaces"].get(namespace_name) is not None:
assert index_stats["namespaces"][namespace_name]["vector_count"] == 0
@classmethod
def teardown_class(cls) -> None:
index_stats = cls.index.describe_index_stats()
for _namespace_name in index_stats["namespaces"].keys():
cls.index.delete(delete_all=True, namespace=_namespace_name)
reset_pinecone()
@pytest.fixture(autouse=True)
def setup(self) -> None:
# delete all the vectors in the index
index_stats = self.index.describe_index_stats()
for _namespace_name in index_stats["namespaces"].keys():
self.index.delete(delete_all=True, namespace=_namespace_name)
reset_pinecone()
@pytest.mark.vcr()
def test_from_texts(
self, texts: List[str], embedding_openai: OpenAIEmbeddings
) -> None:
"""Test end to end construction and search."""
unique_id = uuid.uuid4().hex
needs = f"foobuu {unique_id} booo"
texts.insert(0, needs)
docsearch = Pinecone.from_texts(
texts=texts,
embedding=embedding_openai,
index_name=index_name,
namespace=namespace_name,
)
output = docsearch.similarity_search(unique_id, k=1, namespace=namespace_name)
assert output == [Document(page_content=needs)]
@pytest.mark.vcr()
def test_from_texts_with_metadatas(
self, texts: List[str], embedding_openai: OpenAIEmbeddings
) -> None:
"""Test end to end construction and search."""
unique_id = uuid.uuid4().hex
needs = f"foobuu {unique_id} booo"
texts.insert(0, needs)
metadatas = [{"page": i} for i in range(len(texts))]
docsearch = Pinecone.from_texts(
texts,
embedding_openai,
index_name=index_name,
metadatas=metadatas,
namespace=namespace_name,
)
output = docsearch.similarity_search(needs, k=1, namespace=namespace_name)
# TODO: why metadata={"page": 0.0}) instead of {"page": 0}?
assert output == [Document(page_content=needs, metadata={"page": 0.0})]
@pytest.mark.vcr()
def test_from_texts_with_scores(self, embedding_openai: OpenAIEmbeddings) -> None:
"""Test end to end construction and search with scores and IDs."""
texts = ["foo", "bar", "baz"]
metadatas = [{"page": i} for i in range(len(texts))]
docsearch = Pinecone.from_texts(
texts,
embedding_openai,
index_name=index_name,
metadatas=metadatas,
namespace=namespace_name,
)
output = docsearch.similarity_search_with_score(
"foo", k=3, namespace=namespace_name
)
docs = [o[0] for o in output]
scores = [o[1] for o in output]
sorted_documents = sorted(docs, key=lambda x: x.metadata["page"])
# TODO: why metadata={"page": 0.0}) instead of {"page": 0}, etc???
assert sorted_documents == [
Document(page_content="foo", metadata={"page": 0.0}),
Document(page_content="bar", metadata={"page": 1.0}),
Document(page_content="baz", metadata={"page": 2.0}),
]
assert scores[0] > scores[1] > scores[2]
def test_from_existing_index_with_namespaces(
self, embedding_openai: OpenAIEmbeddings
) -> None:
"""Test that namespaces are properly handled."""
# Create two indexes with the same name but different namespaces
texts_1 = ["foo", "bar", "baz"]
metadatas = [{"page": i} for i in range(len(texts_1))]
Pinecone.from_texts(
texts_1,
embedding_openai,
index_name=index_name,
metadatas=metadatas,
namespace=f"{index_name}-1",
)
texts_2 = ["foo2", "bar2", "baz2"]
metadatas = [{"page": i} for i in range(len(texts_2))]
Pinecone.from_texts(
texts_2,
embedding_openai,
index_name=index_name,
metadatas=metadatas,
namespace=f"{index_name}-2",
)
# Search with namespace
docsearch = Pinecone.from_existing_index(
index_name=index_name,
embedding=embedding_openai,
namespace=f"{index_name}-1",
)
output = docsearch.similarity_search("foo", k=20, namespace=f"{index_name}-1")
# check that we don't get results from the other namespace
page_contents = sorted(set([o.page_content for o in output]))
assert all(content in ["foo", "bar", "baz"] for content in page_contents)
assert all(content not in ["foo2", "bar2", "baz2"] for content in page_contents)
def test_add_documents_with_ids(
self, texts: List[str], embedding_openai: OpenAIEmbeddings
) -> None:
ids = [uuid.uuid4().hex for _ in range(len(texts))]
Pinecone.from_texts(
texts=texts,
ids=ids,
embedding=embedding_openai,
index_name=index_name,
namespace=index_name,
)
index_stats = self.index.describe_index_stats()
assert index_stats["namespaces"][index_name]["vector_count"] == len(texts)
ids_1 = [uuid.uuid4().hex for _ in range(len(texts))]
Pinecone.from_texts(
texts=texts,
ids=ids_1,
embedding=embedding_openai,
index_name=index_name,
namespace=index_name,
)
index_stats = self.index.describe_index_stats()
assert index_stats["namespaces"][index_name]["vector_count"] == len(texts) * 2
@@ -0,0 +1,51 @@
"""Test Weaviate functionality."""
import logging
from typing import Generator, Union
import pytest
from weaviate import Client
from langchain.docstore.document import Document
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores.weaviate import Weaviate
logging.basicConfig(level=logging.DEBUG)
"""
cd tests/integration_tests/vectorstores/docker-compose
docker compose -f weaviate.yml up
"""
class TestWeaviate:
@pytest.fixture(scope="class", autouse=True)
def weaviate_url(self) -> Union[str, Generator[str, None, None]]:
"""Return the weaviate url."""
url = "http://localhost:8080"
yield url
# Clear the test index
client = Client(url)
client.schema.delete_all()
def test_similarity_search_without_metadata(self, weaviate_url: str) -> None:
"""Test end to end construction and search without metadata."""
texts = ["foo", "bar", "baz"]
docsearch = Weaviate.from_texts(
texts,
OpenAIEmbeddings(),
weaviate_url=weaviate_url,
)
output = docsearch.similarity_search("foo", k=1)
assert output == [Document(page_content="foo")]
def test_similarity_search_with_metadata(self, weaviate_url: str) -> None:
"""Test end to end construction and search with metadata."""
texts = ["foo", "bar", "baz"]
metadatas = [{"page": i} for i in range(len(texts))]
docsearch = Weaviate.from_texts(
texts, OpenAIEmbeddings(), metadatas=metadatas, weaviate_url=weaviate_url
)
output = docsearch.similarity_search("foo", k=1)
assert output == [Document(page_content="foo", metadata={"page": 0})]
+18
View File
@@ -0,0 +1,18 @@
from langchain.agents import create_sql_agent
from langchain.agents.agent_toolkits import SQLDatabaseToolkit
from langchain.sql_database import SQLDatabase
from tests.unit_tests.llms.fake_llm import FakeLLM
def test_create_sql_agent() -> None:
db = SQLDatabase.from_uri("sqlite:///:memory:")
queries = {"foo": "Final Answer: baz"}
llm = FakeLLM(queries=queries, sequential_responses=True)
toolkit = SQLDatabaseToolkit(db=db, llm=llm)
agent_executor = create_sql_agent(
llm=llm,
toolkit=toolkit,
)
assert agent_executor.run("hello") == "baz"
+25 -2
View File
@@ -1,5 +1,7 @@
"""Fake LLM wrapper for testing purposes."""
from typing import Any, List, Mapping, Optional
from typing import Any, List, Mapping, Optional, cast
from pydantic import validator
from langchain.llms.base import LLM
@@ -8,6 +10,18 @@ class FakeLLM(LLM):
"""Fake LLM wrapper for testing purposes."""
queries: Optional[Mapping] = None
sequential_responses: Optional[bool] = False
response_index: int = 0
@validator("queries", always=True)
def check_queries_required(
cls, queries: Optional[Mapping], values: Mapping[str, Any]
) -> Optional[Mapping]:
if values.get("sequential_response") and not queries:
raise ValueError(
"queries is required when sequential_response is set to True"
)
return queries
@property
def _llm_type(self) -> str:
@@ -15,7 +29,9 @@ class FakeLLM(LLM):
return "fake"
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
"""First try to lookup in queries, else return 'foo' or 'bar'."""
if self.sequential_responses:
return self._get_next_response_in_sequence
if self.queries is not None:
return self.queries[prompt]
if stop is None:
@@ -26,3 +42,10 @@ class FakeLLM(LLM):
@property
def _identifying_params(self) -> Mapping[str, Any]:
return {}
@property
def _get_next_response_in_sequence(self) -> str:
queries = cast(Mapping, self.queries)
response = queries[list(queries.keys())[self.response_index]]
self.response_index = self.response_index + 1
return response
+1 -1
View File
@@ -3,8 +3,8 @@ import sys
import pytest
from langchain.python import PythonREPL
from langchain.tools.python.tool import PythonAstREPLTool, PythonREPLTool
from langchain.utilities import PythonREPL
_SAMPLE_CODE = """
```